This repository has been archived by the owner on Feb 11, 2021. It is now read-only.
/
SDL_render_gl.c
executable file
·1014 lines (867 loc) · 31.7 KB
/
SDL_render_gl.c
OlderNewer
1
2
/*
SDL - Simple DirectMedia Layer
3
Copyright (C) 1997-2011 Sam Lantinga
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Sam Lantinga
slouken@libsdl.org
*/
#include "SDL_config.h"
24
#if SDL_VIDEO_RENDER_OGL && !SDL_RENDER_DISABLED
25
26
27
#include "SDL_hints.h"
#include "SDL_log.h"
28
#include "SDL_opengl.h"
29
#include "../SDL_sysrender.h"
30
#include "SDL_shaders_gl.h"
31
32
33
34
35
#ifdef __MACOSX__
#include <OpenGL/OpenGL.h>
#endif
36
37
38
/* OpenGL renderer implementation */
39
/* Details on optimizing the texture path on Mac OS X:
40
http://developer.apple.com/library/mac/#documentation/GraphicsImaging/Conceptual/OpenGL-MacProgGuide/opengl_texturedata/opengl_texturedata.html
41
42
*/
43
44
/* Used to re-create the window with OpenGL capability */
extern int SDL_RecreateWindow(SDL_Window * window, Uint32 flags);
45
46
47
static const float inv255f = 1.0f / 255.0f;
48
static SDL_Renderer *GL_CreateRenderer(SDL_Window * window, Uint32 flags);
49
50
static void GL_WindowEvent(SDL_Renderer * renderer,
const SDL_WindowEvent *event);
51
52
53
54
55
static int GL_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture);
static int GL_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture,
const SDL_Rect * rect, const void *pixels,
int pitch);
static int GL_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture,
56
const SDL_Rect * rect, void **pixels, int *pitch);
57
static void GL_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture);
58
static int GL_UpdateViewport(SDL_Renderer * renderer);
59
60
61
62
63
64
static int GL_RenderClear(SDL_Renderer * renderer);
static int GL_RenderDrawPoints(SDL_Renderer * renderer,
const SDL_Point * points, int count);
static int GL_RenderDrawLines(SDL_Renderer * renderer,
const SDL_Point * points, int count);
static int GL_RenderFillRects(SDL_Renderer * renderer,
65
const SDL_Rect * rects, int count);
66
static int GL_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
67
const SDL_Rect * srcrect, const SDL_Rect * dstrect);
68
static int GL_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect,
69
Uint32 pixel_format, void * pixels, int pitch);
70
71
72
73
74
75
76
77
78
static void GL_RenderPresent(SDL_Renderer * renderer);
static void GL_DestroyTexture(SDL_Renderer * renderer, SDL_Texture * texture);
static void GL_DestroyRenderer(SDL_Renderer * renderer);
SDL_RenderDriver GL_RenderDriver = {
GL_CreateRenderer,
{
"opengl",
79
(SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC),
80
81
1,
{SDL_PIXELFORMAT_ARGB8888},
82
83
84
85
86
87
88
0,
0}
};
typedef struct
{
SDL_GLContext context;
89
SDL_bool GL_ARB_texture_rectangle_supported;
90
91
92
93
94
95
struct {
GL_Shader shader;
Uint32 color;
int blendMode;
GLenum scaleMode;
} current;
96
97
98
/* OpenGL functions */
#define SDL_PROC(ret,func,params) ret (APIENTRY *func) params;
99
#include "SDL_glfuncs.h"
100
#undef SDL_PROC
101
102
103
104
/* Multitexture support */
SDL_bool GL_ARB_multitexture_supported;
PFNGLACTIVETEXTUREARBPROC glActiveTextureARB;
105
GLint num_texture_units;
106
107
108
109
/* Shader support */
GL_ShaderContext *shaders;
110
111
112
113
114
} GL_RenderData;
typedef struct
{
GLuint texture;
115
GLenum type;
116
117
GLfloat texw;
GLfloat texh;
118
119
GLenum format;
GLenum formattype;
120
121
void *pixels;
int pitch;
122
int scaleMode;
123
SDL_Rect locked_rect;
124
125
126
127
128
/* YV12 texture support */
SDL_bool yuv;
GLuint utexture;
GLuint vtexture;
129
130
131
} GL_TextureData;
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
static void
GL_SetError(const char *prefix, GLenum result)
{
const char *error;
switch (result) {
case GL_NO_ERROR:
error = "GL_NO_ERROR";
break;
case GL_INVALID_ENUM:
error = "GL_INVALID_ENUM";
break;
case GL_INVALID_VALUE:
error = "GL_INVALID_VALUE";
break;
case GL_INVALID_OPERATION:
error = "GL_INVALID_OPERATION";
break;
case GL_STACK_OVERFLOW:
error = "GL_STACK_OVERFLOW";
break;
case GL_STACK_UNDERFLOW:
error = "GL_STACK_UNDERFLOW";
break;
case GL_OUT_OF_MEMORY:
error = "GL_OUT_OF_MEMORY";
break;
case GL_TABLE_TOO_LARGE:
error = "GL_TABLE_TOO_LARGE";
break;
default:
error = "UNKNOWN";
break;
}
SDL_SetError("%s: %s", prefix, error);
}
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
static int
GL_LoadFunctions(GL_RenderData * data)
{
#ifdef __SDL_NOGETPROCADDR__
#define SDL_PROC(ret,func,params) data->func=func;
#else
#define SDL_PROC(ret,func,params) \
do { \
data->func = SDL_GL_GetProcAddress(#func); \
if ( ! data->func ) { \
SDL_SetError("Couldn't load GL function %s: %s\n", #func, SDL_GetError()); \
return -1; \
} \
} while ( 0 );
#endif /* __SDL_NOGETPROCADDR__ */
185
#include "SDL_glfuncs.h"
186
187
188
189
#undef SDL_PROC
return 0;
}
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
static SDL_GLContext SDL_CurrentContext = NULL;
static int
GL_ActivateRenderer(SDL_Renderer * renderer)
{
GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
if (SDL_CurrentContext != data->context) {
if (SDL_GL_MakeCurrent(renderer->window, data->context) < 0) {
return -1;
}
SDL_CurrentContext = data->context;
GL_UpdateViewport(renderer);
}
return 0;
}
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
/* This is called if we need to invalidate all of the SDL OpenGL state */
static void
GL_ResetState(SDL_Renderer *renderer)
{
GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
if (SDL_CurrentContext == data->context) {
GL_UpdateViewport(renderer);
} else {
GL_ActivateRenderer(renderer);
}
data->current.shader = SHADER_NONE;
data->current.color = 0;
data->current.blendMode = -1;
data->current.scaleMode = 0;
data->glDisable(GL_DEPTH_TEST);
data->glDisable(GL_CULL_FACE);
/* This ended up causing video discrepancies between OpenGL and Direct3D */
/*data->glEnable(GL_LINE_SMOOTH);*/
data->glMatrixMode(GL_MODELVIEW);
data->glLoadIdentity();
}
234
235
236
237
238
SDL_Renderer *
GL_CreateRenderer(SDL_Window * window, Uint32 flags)
{
SDL_Renderer *renderer;
GL_RenderData *data;
239
const char *hint;
240
GLint value;
241
Uint32 window_flags;
242
243
244
245
window_flags = SDL_GetWindowFlags(window);
if (!(window_flags & SDL_WINDOW_OPENGL)) {
if (SDL_RecreateWindow(window, window_flags | SDL_WINDOW_OPENGL) < 0) {
246
247
return NULL;
}
248
249
}
250
renderer = (SDL_Renderer *) SDL_calloc(1, sizeof(*renderer));
251
252
253
254
255
if (!renderer) {
SDL_OutOfMemory();
return NULL;
}
256
data = (GL_RenderData *) SDL_calloc(1, sizeof(*data));
257
258
259
260
261
262
if (!data) {
GL_DestroyRenderer(renderer);
SDL_OutOfMemory();
return NULL;
}
263
renderer->WindowEvent = GL_WindowEvent;
264
265
266
267
renderer->CreateTexture = GL_CreateTexture;
renderer->UpdateTexture = GL_UpdateTexture;
renderer->LockTexture = GL_LockTexture;
renderer->UnlockTexture = GL_UnlockTexture;
268
renderer->UpdateViewport = GL_UpdateViewport;
269
270
271
272
renderer->RenderClear = GL_RenderClear;
renderer->RenderDrawPoints = GL_RenderDrawPoints;
renderer->RenderDrawLines = GL_RenderDrawLines;
renderer->RenderFillRects = GL_RenderFillRects;
273
renderer->RenderCopy = GL_RenderCopy;
274
renderer->RenderReadPixels = GL_RenderReadPixels;
275
276
277
278
renderer->RenderPresent = GL_RenderPresent;
renderer->DestroyTexture = GL_DestroyTexture;
renderer->DestroyRenderer = GL_DestroyRenderer;
renderer->info = GL_RenderDriver.info;
279
renderer->info.flags = SDL_RENDERER_ACCELERATED;
280
renderer->driverdata = data;
281
282
data->context = SDL_GL_CreateContext(window);
283
284
285
286
if (!data->context) {
GL_DestroyRenderer(renderer);
return NULL;
}
287
if (SDL_GL_MakeCurrent(window, data->context) < 0) {
288
289
290
GL_DestroyRenderer(renderer);
return NULL;
}
291
292
293
294
295
296
if (GL_LoadFunctions(data) < 0) {
GL_DestroyRenderer(renderer);
return NULL;
}
297
298
299
#ifdef __MACOSX__
/* Enable multi-threaded rendering */
/* Disabled until Ryan finishes his VBO/PBO code...
300
301
CGLEnable(CGLGetCurrentContext(), kCGLCEMPEngine);
*/
302
303
#endif
304
if (flags & SDL_RENDERER_PRESENTVSYNC) {
305
306
307
308
309
SDL_GL_SetSwapInterval(1);
} else {
SDL_GL_SetSwapInterval(0);
}
if (SDL_GL_GetSwapInterval() > 0) {
310
renderer->info.flags |= SDL_RENDERER_PRESENTVSYNC;
311
312
}
313
314
315
316
data->glGetIntegerv(GL_MAX_TEXTURE_SIZE, &value);
renderer->info.max_texture_width = value;
data->glGetIntegerv(GL_MAX_TEXTURE_SIZE, &value);
renderer->info.max_texture_height = value;
317
318
319
320
321
if (SDL_GL_ExtensionSupported("GL_ARB_texture_rectangle")
|| SDL_GL_ExtensionSupported("GL_EXT_texture_rectangle")) {
data->GL_ARB_texture_rectangle_supported = SDL_TRUE;
}
322
323
324
325
326
327
328
329
330
331
332
/* Check for multitexture support */
if (SDL_GL_ExtensionSupported("GL_ARB_multitexture")) {
data->glActiveTextureARB = (PFNGLACTIVETEXTUREARBPROC) SDL_GL_GetProcAddress("glActiveTextureARB");
if (data->glActiveTextureARB) {
data->GL_ARB_multitexture_supported = SDL_TRUE;
data->glGetIntegerv(GL_MAX_TEXTURE_UNITS_ARB, &data->num_texture_units);
}
}
/* Check for shader support */
333
334
335
336
337
338
hint = SDL_GetHint(SDL_HINT_RENDER_OPENGL_SHADERS);
if (!hint || *hint != '0') {
data->shaders = GL_CreateShaderContext();
}
SDL_LogInfo(SDL_LOG_CATEGORY_RENDER, "OpenGL shaders: %s",
data->shaders ? "ENABLED" : "DISABLED");
339
340
341
342
/* We support YV12 textures using 3 textures and a shader */
if (data->shaders && data->num_texture_units >= 3) {
renderer->info.texture_formats[renderer->info.num_texture_formats++] = SDL_PIXELFORMAT_YV12;
343
renderer->info.texture_formats[renderer->info.num_texture_formats++] = SDL_PIXELFORMAT_IYUV;
344
345
}
346
/* Set up parameters for rendering */
347
GL_ResetState(renderer);
348
349
350
351
return renderer;
}
352
353
static void
GL_WindowEvent(SDL_Renderer * renderer, const SDL_WindowEvent *event)
354
355
356
{
GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
357
if (event->event == SDL_WINDOWEVENT_SIZE_CHANGED) {
358
359
360
/* Rebind the context to the window area and update matrices */
SDL_CurrentContext = NULL;
}
361
362
}
363
364
365
366
367
368
369
370
371
372
373
static __inline__ int
power_of_2(int input)
{
int value = 1;
while (value < input) {
value <<= 1;
}
return value;
}
374
375
376
static __inline__ SDL_bool
convert_format(GL_RenderData *renderdata, Uint32 pixel_format,
GLint* internalFormat, GLenum* format, GLenum* type)
377
{
378
switch (pixel_format) {
379
case SDL_PIXELFORMAT_ARGB8888:
380
381
*internalFormat = GL_RGBA8;
*format = GL_BGRA;
382
*type = GL_UNSIGNED_INT_8_8_8_8_REV;
383
break;
384
385
386
387
388
389
case SDL_PIXELFORMAT_YV12:
case SDL_PIXELFORMAT_IYUV:
*internalFormat = GL_LUMINANCE;
*format = GL_LUMINANCE;
*type = GL_UNSIGNED_BYTE;
break;
390
default:
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
return SDL_FALSE;
}
return SDL_TRUE;
}
static int
GL_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture)
{
GL_RenderData *renderdata = (GL_RenderData *) renderer->driverdata;
GL_TextureData *data;
GLint internalFormat;
GLenum format, type;
int texture_w, texture_h;
GLenum result;
406
407
GL_ActivateRenderer(renderer);
408
409
if (!convert_format(renderdata, texture->format, &internalFormat,
&format, &type)) {
410
411
SDL_SetError("Texture format %s not supported by OpenGL",
SDL_GetPixelFormatName(texture->format));
412
413
return -1;
}
414
415
data = (GL_TextureData *) SDL_calloc(1, sizeof(*data));
416
417
418
419
420
if (!data) {
SDL_OutOfMemory();
return -1;
}
421
if (texture->access == SDL_TEXTUREACCESS_STREAMING) {
422
size_t size;
423
data->pitch = texture->w * SDL_BYTESPERPIXEL(texture->format);
424
425
426
427
428
429
430
size = texture->h * data->pitch;
if (texture->format == SDL_PIXELFORMAT_YV12 ||
texture->format == SDL_PIXELFORMAT_IYUV) {
/* Need to add size for the U and V planes */
size += (2 * (texture->h * data->pitch) / 4);
}
data->pixels = SDL_malloc(size);
431
432
433
434
435
436
437
if (!data->pixels) {
SDL_OutOfMemory();
SDL_free(data);
return -1;
}
}
438
439
texture->driverdata = data;
440
441
renderdata->glGetError();
renderdata->glGenTextures(1, &data->texture);
442
443
444
445
if (renderdata->GL_ARB_texture_rectangle_supported) {
data->type = GL_TEXTURE_RECTANGLE_ARB;
texture_w = texture->w;
texture_h = texture->h;
446
447
data->texw = (GLfloat) texture_w;
data->texh = (GLfloat) texture_h;
448
449
450
451
} else {
data->type = GL_TEXTURE_2D;
texture_w = power_of_2(texture->w);
texture_h = power_of_2(texture->h);
452
data->texw = (GLfloat) (texture->w) / texture_w;
453
454
data->texh = (GLfloat) texture->h / texture_h;
}
455
456
457
data->format = format;
data->formattype = type;
458
data->scaleMode = GL_LINEAR;
459
renderdata->glEnable(data->type);
460
renderdata->glBindTexture(data->type, data->texture);
461
462
463
464
renderdata->glTexParameteri(data->type, GL_TEXTURE_WRAP_S,
GL_CLAMP_TO_EDGE);
renderdata->glTexParameteri(data->type, GL_TEXTURE_WRAP_T,
GL_CLAMP_TO_EDGE);
465
#ifdef __MACOSX__
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
#ifndef GL_TEXTURE_STORAGE_HINT_APPLE
#define GL_TEXTURE_STORAGE_HINT_APPLE 0x85BC
#endif
#ifndef STORAGE_CACHED_APPLE
#define STORAGE_CACHED_APPLE 0x85BE
#endif
#ifndef STORAGE_SHARED_APPLE
#define STORAGE_SHARED_APPLE 0x85BF
#endif
if (texture->access == SDL_TEXTUREACCESS_STREAMING) {
renderdata->glTexParameteri(data->type, GL_TEXTURE_STORAGE_HINT_APPLE,
GL_STORAGE_SHARED_APPLE);
} else {
renderdata->glTexParameteri(data->type, GL_TEXTURE_STORAGE_HINT_APPLE,
GL_STORAGE_CACHED_APPLE);
}
482
if (texture->access == SDL_TEXTUREACCESS_STREAMING
483
484
&& texture->format == SDL_PIXELFORMAT_ARGB8888
&& (texture->w % 8) == 0) {
485
renderdata->glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
486
487
488
renderdata->glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
renderdata->glPixelStorei(GL_UNPACK_ROW_LENGTH,
(data->pitch / SDL_BYTESPERPIXEL(texture->format)));
489
490
renderdata->glTexImage2D(data->type, 0, internalFormat, texture_w,
texture_h, 0, format, type, data->pixels);
491
renderdata->glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
492
493
}
else
494
495
496
497
498
#endif
{
renderdata->glTexImage2D(data->type, 0, internalFormat, texture_w,
texture_h, 0, format, type, NULL);
}
499
renderdata->glDisable(data->type);
500
result = renderdata->glGetError();
501
502
503
504
if (result != GL_NO_ERROR) {
GL_SetError("glTexImage2D()", result);
return -1;
}
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
if (texture->format == SDL_PIXELFORMAT_YV12 ||
texture->format == SDL_PIXELFORMAT_IYUV) {
data->yuv = SDL_TRUE;
renderdata->glGenTextures(1, &data->utexture);
renderdata->glGenTextures(1, &data->vtexture);
renderdata->glEnable(data->type);
renderdata->glBindTexture(data->type, data->utexture);
renderdata->glTexParameteri(data->type, GL_TEXTURE_WRAP_S,
GL_CLAMP_TO_EDGE);
renderdata->glTexParameteri(data->type, GL_TEXTURE_WRAP_T,
GL_CLAMP_TO_EDGE);
renderdata->glTexImage2D(data->type, 0, internalFormat, texture_w/2,
texture_h/2, 0, format, type, NULL);
renderdata->glBindTexture(data->type, data->vtexture);
renderdata->glTexParameteri(data->type, GL_TEXTURE_WRAP_S,
GL_CLAMP_TO_EDGE);
renderdata->glTexParameteri(data->type, GL_TEXTURE_WRAP_T,
GL_CLAMP_TO_EDGE);
renderdata->glTexImage2D(data->type, 0, internalFormat, texture_w/2,
texture_h/2, 0, format, type, NULL);
renderdata->glDisable(data->type);
}
532
533
534
535
536
537
538
return 0;
}
static int
GL_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture,
const SDL_Rect * rect, const void *pixels, int pitch)
{
539
GL_RenderData *renderdata = (GL_RenderData *) renderer->driverdata;
540
GL_TextureData *data = (GL_TextureData *) texture->driverdata;
541
GLenum result;
542
543
544
GL_ActivateRenderer(renderer);
545
renderdata->glGetError();
546
547
renderdata->glEnable(data->type);
renderdata->glBindTexture(data->type, data->texture);
548
549
550
renderdata->glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
renderdata->glPixelStorei(GL_UNPACK_ROW_LENGTH,
(pitch / SDL_BYTESPERPIXEL(texture->format)));
551
552
553
renderdata->glTexSubImage2D(data->type, 0, rect->x, rect->y, rect->w,
rect->h, data->format, data->formattype,
pixels);
554
if (data->yuv) {
555
556
557
558
const void *top;
renderdata->glPixelStorei(GL_UNPACK_ROW_LENGTH, (pitch / 2));
559
/* Skip to the top of the next texture */
560
top = (const void*)((const Uint8*)pixels + (texture->h-rect->y) * pitch - rect->x);
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
/* Skip to the correct offset into the next texture */
pixels = (const void*)((const Uint8*)top + (rect->y / 2) * pitch + rect->x / 2);
if (texture->format == SDL_PIXELFORMAT_YV12) {
renderdata->glBindTexture(data->type, data->vtexture);
} else {
renderdata->glBindTexture(data->type, data->utexture);
}
renderdata->glTexSubImage2D(data->type, 0, rect->x/2, rect->y/2,
rect->w/2, rect->h/2,
data->format, data->formattype, pixels);
/* Skip to the top of the next texture */
top = (const void*)((const Uint8*)top + (texture->h * pitch)/4);
/* Skip to the correct offset into the next texture */
pixels = (const void*)((const Uint8*)top + (rect->y / 2) * pitch + rect->x / 2);
if (texture->format == SDL_PIXELFORMAT_YV12) {
renderdata->glBindTexture(data->type, data->utexture);
} else {
renderdata->glBindTexture(data->type, data->vtexture);
}
renderdata->glTexSubImage2D(data->type, 0, rect->x/2, rect->y/2,
rect->w/2, rect->h/2,
data->format, data->formattype, pixels);
}
587
renderdata->glDisable(data->type);
588
result = renderdata->glGetError();
589
590
591
592
if (result != GL_NO_ERROR) {
GL_SetError("glTexSubImage2D()", result);
return -1;
}
593
594
595
596
597
return 0;
}
static int
GL_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture,
598
const SDL_Rect * rect, void **pixels, int *pitch)
599
600
601
{
GL_TextureData *data = (GL_TextureData *) texture->driverdata;
602
603
data->locked_rect = *rect;
*pixels =
604
(void *) ((Uint8 *) data->pixels + rect->y * data->pitch +
605
rect->x * SDL_BYTESPERPIXEL(texture->format));
606
*pitch = data->pitch;
607
608
609
610
611
612
613
return 0;
}
static void
GL_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture)
{
GL_TextureData *data = (GL_TextureData *) texture->driverdata;
614
615
const SDL_Rect *rect;
void *pixels;
616
617
618
619
620
621
rect = &data->locked_rect;
pixels =
(void *) ((Uint8 *) data->pixels + rect->y * data->pitch +
rect->x * SDL_BYTESPERPIXEL(texture->format));
GL_UpdateTexture(renderer, texture, rect, pixels, data->pitch);
622
623
}
624
625
static int
GL_UpdateViewport(SDL_Renderer * renderer)
626
627
628
{
GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
629
630
631
632
if (SDL_CurrentContext != data->context) {
/* We'll update the viewport after we rebind the context */
return 0;
}
633
634
635
data->glViewport(renderer->viewport.x, renderer->viewport.y,
renderer->viewport.w, renderer->viewport.h);
636
637
638
639
640
641
642
643
data->glMatrixMode(GL_PROJECTION);
data->glLoadIdentity();
data->glOrtho((GLdouble) 0,
(GLdouble) renderer->viewport.w,
(GLdouble) renderer->viewport.h,
(GLdouble) 0, 0.0, 1.0);
return 0;
644
645
}
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
static void
GL_SetShader(GL_RenderData * data, GL_Shader shader)
{
if (data->shaders && shader != data->current.shader) {
GL_SelectShader(data->shaders, shader);
data->current.shader = shader;
}
}
static void
GL_SetColor(GL_RenderData * data, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
{
Uint32 color = ((a << 24) | (r << 16) | (g << 8) | b);
if (color != data->current.color) {
data->glColor4f((GLfloat) r * inv255f,
(GLfloat) g * inv255f,
(GLfloat) b * inv255f,
(GLfloat) a * inv255f);
data->current.color = color;
}
}
669
static void
670
GL_SetBlendMode(GL_RenderData * data, int blendMode)
671
{
672
if (blendMode != data->current.blendMode) {
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
switch (blendMode) {
case SDL_BLENDMODE_NONE:
data->glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
data->glDisable(GL_BLEND);
break;
case SDL_BLENDMODE_BLEND:
data->glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
data->glEnable(GL_BLEND);
data->glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
break;
case SDL_BLENDMODE_ADD:
data->glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
data->glEnable(GL_BLEND);
data->glBlendFunc(GL_SRC_ALPHA, GL_ONE);
break;
688
689
690
691
692
case SDL_BLENDMODE_MOD:
data->glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
data->glEnable(GL_BLEND);
data->glBlendFunc(GL_ZERO, GL_SRC_COLOR);
break;
693
}
694
data->current.blendMode = blendMode;
695
696
697
}
}
698
699
700
701
702
703
704
static void
GL_SetDrawingState(SDL_Renderer * renderer)
{
GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
GL_ActivateRenderer(renderer);
705
706
707
708
GL_SetColor(data, renderer->r,
renderer->g,
renderer->b,
renderer->a);
709
710
711
712
713
714
GL_SetBlendMode(data, renderer->blendMode);
GL_SetShader(data, SHADER_SOLID);
}
715
static int
716
717
718
719
GL_RenderClear(SDL_Renderer * renderer)
{
GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
720
721
GL_ActivateRenderer(renderer);
722
723
724
725
726
727
728
729
730
731
732
733
734
data->glClearColor((GLfloat) renderer->r * inv255f,
(GLfloat) renderer->g * inv255f,
(GLfloat) renderer->b * inv255f,
(GLfloat) renderer->a * inv255f);
data->glClear(GL_COLOR_BUFFER_BIT);
return 0;
}
static int
GL_RenderDrawPoints(SDL_Renderer * renderer, const SDL_Point * points,
int count)
735
736
{
GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
737
int i;
738
739
GL_SetDrawingState(renderer);
740
741
data->glBegin(GL_POINTS);
742
743
744
for (i = 0; i < count; ++i) {
data->glVertex2f(0.5f + points[i].x, 0.5f + points[i].y);
}
745
data->glEnd();
746
747
748
749
return 0;
}
750
static int
751
752
GL_RenderDrawLines(SDL_Renderer * renderer, const SDL_Point * points,
int count)
753
754
{
GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
755
int i;
756
757
GL_SetDrawingState(renderer);
758
759
760
761
762
763
764
765
766
767
768
if (count > 2 &&
points[0].x == points[count-1].x && points[0].y == points[count-1].y) {
data->glBegin(GL_LINE_LOOP);
/* GL_LINE_LOOP takes care of the final segment */
--count;
for (i = 0; i < count; ++i) {
data->glVertex2f(0.5f + points[i].x, 0.5f + points[i].y);
}
data->glEnd();
} else {
769
#if defined(__APPLE__) || defined(__WIN32__)
770
#else
771
int x1, y1, x2, y2;
772
#endif
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
data->glBegin(GL_LINE_STRIP);
for (i = 0; i < count; ++i) {
data->glVertex2f(0.5f + points[i].x, 0.5f + points[i].y);
}
data->glEnd();
/* The line is half open, so we need one more point to complete it.
* http://www.opengl.org/documentation/specs/version1.1/glspec1.1/node47.html
* If we have to, we can use vertical line and horizontal line textures
* for vertical and horizontal lines, and then create custom textures
* for diagonal lines and software render those. It's terrible, but at
* least it would be pixel perfect.
*/
data->glBegin(GL_POINTS);
788
#if defined(__APPLE__) || defined(__WIN32__)
789
790
/* Mac OS X and Windows seem to always leave the second point open */
data->glVertex2f(0.5f + points[count-1].x, 0.5f + points[count-1].y);
791
#else
792
/* Linux seems to leave the right-most or bottom-most point open */
793
794
795
796
x1 = points[0].x;
y1 = points[0].y;
x2 = points[count-1].x;
y2 = points[count-1].y;
797
798
799
800
801
802
803
804
805
806
if (x1 > x2) {
data->glVertex2f(0.5f + x1, 0.5f + y1);
} else if (x2 > x1) {
data->glVertex2f(0.5f + x2, 0.5f + y2);
} else if (y1 > y2) {
data->glVertex2f(0.5f + x1, 0.5f + y1);
} else if (y2 > y1) {
data->glVertex2f(0.5f + x2, 0.5f + y2);
}
807
#endif
808
809
data->glEnd();
}
810
811
812
813
return 0;
}
814
static int
815
GL_RenderFillRects(SDL_Renderer * renderer, const SDL_Rect * rects, int count)
816
817
{
GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
818
int i;
819
820
GL_SetDrawingState(renderer);
821
822
for (i = 0; i < count; ++i) {
823
const SDL_Rect *rect = &rects[i];
824
825
826
data->glRecti(rect->x, rect->y, rect->x + rect->w, rect->y + rect->h);
}
827
828
829
830
831
832
return 0;
}
static int
GL_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
833
const SDL_Rect * srcrect, const SDL_Rect * dstrect)
834
835
836
837
838
839
{
GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
GL_TextureData *texturedata = (GL_TextureData *) texture->driverdata;
int minx, miny, maxx, maxy;
GLfloat minu, maxu, minv, maxv;
840
841
GL_ActivateRenderer(renderer);
842
data->glEnable(texturedata->type);
843
844
845
if (texturedata->yuv) {
data->glActiveTextureARB(GL_TEXTURE2_ARB);
data->glBindTexture(texturedata->type, texturedata->vtexture);
846
847
848
849
850
851
852
if (texturedata->scaleMode != data->current.scaleMode) {
data->glTexParameteri(texturedata->type, GL_TEXTURE_MIN_FILTER,
texturedata->scaleMode);
data->glTexParameteri(texturedata->type, GL_TEXTURE_MAG_FILTER,
texturedata->scaleMode);
}
853
854
data->glActiveTextureARB(GL_TEXTURE1_ARB);
data->glBindTexture(texturedata->type, texturedata->utexture);
855
856
857
858
859
860
861
if (texturedata->scaleMode != data->current.scaleMode) {
data->glTexParameteri(texturedata->type, GL_TEXTURE_MIN_FILTER,
texturedata->scaleMode);
data->glTexParameteri(texturedata->type, GL_TEXTURE_MAG_FILTER,
texturedata->scaleMode);
}
862
863
data->glActiveTextureARB(GL_TEXTURE0_ARB);
}
864
865
data->glBindTexture(texturedata->type, texturedata->texture);
866
867
868
869
870
871
872
873
if (texturedata->scaleMode != data->current.scaleMode) {
data->glTexParameteri(texturedata->type, GL_TEXTURE_MIN_FILTER,
texturedata->scaleMode);
data->glTexParameteri(texturedata->type, GL_TEXTURE_MAG_FILTER,
texturedata->scaleMode);
data->current.scaleMode = texturedata->scaleMode;
}
874
if (texture->modMode) {
875
GL_SetColor(data, texture->r, texture->g, texture->b, texture->a);
876
} else {
877
GL_SetColor(data, 255, 255, 255, 255);
878
879
}
880
GL_SetBlendMode(data, texture->blendMode);
881
882
if (texturedata->yuv) {
883
GL_SetShader(data, SHADER_YV12);
884
} else {
885
GL_SetShader(data, SHADER_RGB);
886
}
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
minx = dstrect->x;
miny = dstrect->y;
maxx = dstrect->x + dstrect->w;
maxy = dstrect->y + dstrect->h;
minu = (GLfloat) srcrect->x / texture->w;
minu *= texturedata->texw;
maxu = (GLfloat) (srcrect->x + srcrect->w) / texture->w;
maxu *= texturedata->texw;
minv = (GLfloat) srcrect->y / texture->h;
minv *= texturedata->texh;
maxv = (GLfloat) (srcrect->y + srcrect->h) / texture->h;
maxv *= texturedata->texh;
902
903
data->glBegin(GL_TRIANGLE_STRIP);
data->glTexCoord2f(minu, minv);
904
data->glVertex2f((GLfloat) minx, (GLfloat) miny);
905
data->glTexCoord2f(maxu, minv);
906
data->glVertex2f((GLfloat) maxx, (GLfloat) miny);
907
data->glTexCoord2f(minu, maxv);
908
data->glVertex2f((GLfloat) minx, (GLfloat) maxy);
909
data->glTexCoord2f(maxu, maxv);
910
data->glVertex2f((GLfloat) maxx, (GLfloat) maxy);
911
data->glEnd();
912
913
914
data->glDisable(texturedata->type);
915
916
917
return 0;
}
918
919
static int
GL_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect,
920
Uint32 pixel_format, void * pixels, int pitch)
921
{
922
GL_RenderData *data = (GL_RenderData *) renderer->driverdata;
923
SDL_Window *window = renderer->window;
924
925
GLint internalFormat;
GLenum format, type;
926
Uint8 *src, *dst, *tmp;
927
int w, h, length, rows;
928
929
930
GL_ActivateRenderer(renderer);
931
if (!convert_format(data, pixel_format, &internalFormat, &format, &type)) {
932
/* FIXME: Do a temp copy to a format that is supported */
933
934
935
936
SDL_SetError("Unsupported pixel format");
return -1;
}
937
938
SDL_GetWindowSize(window, &w, &h);
939
940
data->glPixelStorei(GL_PACK_ALIGNMENT, 1);
data->glPixelStorei(GL_PACK_ROW_LENGTH,
941
(pitch / SDL_BYTESPERPIXEL(pixel_format)));
942
943
data->glReadPixels(rect->x, (h-rect->y)-rect->h, rect->w, rect->h,
944
945
946
format, type, pixels);
/* Flip the rows to be top-down */
947
length = rect->w * SDL_BYTESPERPIXEL(pixel_format);
948
949
950
951
952
953
954
955
src = (Uint8*)pixels + (rect->h-1)*pitch;
dst = (Uint8*)pixels;
tmp = SDL_stack_alloc(Uint8, length);
rows = rect->h / 2;
while (rows--) {
SDL_memcpy(tmp, dst, length);
SDL_memcpy(dst, src, length);
SDL_memcpy(src, tmp, length);
956
957
dst += pitch;
src -= pitch;
958
959
}
SDL_stack_free(tmp);
960
961
return 0;
962
963
}
964
965
966
static void
GL_RenderPresent(SDL_Renderer * renderer)
{
967
968
GL_ActivateRenderer(renderer);
969
970
971
972
973
974
SDL_GL_SwapWindow(renderer->window);
}
static void
GL_DestroyTexture(SDL_Renderer * renderer, SDL_Texture * texture)
{
975
GL_RenderData *renderdata = (GL_RenderData *) renderer->driverdata;
976
977
GL_TextureData *data = (GL_TextureData *) texture->driverdata;
978
979
GL_ActivateRenderer(renderer);
980
981
982
983
if (!data) {
return;
}
if (data->texture) {
984
renderdata->glDeleteTextures(1, &data->texture);
985
}
986
987
988
989
if (data->yuv) {
renderdata->glDeleteTextures(1, &data->utexture);
renderdata->glDeleteTextures(1, &data->vtexture);
}
990
991
if (data->pixels) {
SDL_free(data->pixels);
992
993
994
995
996
}
SDL_free(data);
texture->driverdata = NULL;
}
997
static void
998
999
1000
GL_DestroyRenderer(SDL_Renderer * renderer)
{
GL_RenderData *data = (GL_RenderData *) renderer->driverdata;