1 /*
2 * OpenBOR - http://www.LavaLit.com
3 * -----------------------------------------------------------------------
4 * All rights reserved, see LICENSE in OpenBOR root for details.
5 *
6 * Copyright (c) 2004 - 2011 OpenBOR Team
7 */
8
9 /************************ OpenGL video backend *************************/
10 /*
11 * New video backend that uses OpenGL as a cross-platform API for optimized
12 * hardware blitting and scaling. Supports both OpenGL 1.2+ and OpenGL ES 1.x.
13
14 * It also offers better fullscreen than software SDL because the picture is
15 * guaranteed to display at the correct aspect ratio and not have black bars on
16 * all 4 sides.
17 */
18
19 #ifdef OPENGL
20
21 #include "SDL.h"
22 #include <math.h>
23 #include "openbor.h"
24 #include "opengl.h"
25 #include "video.h"
26 #include "sdlport.h"
27 #include "loadgl.h"
28
29 #ifdef SDL2
30 #include "SDL2_framerate.h"
31 #else
32 #include "SDL_framerate.h"
33 #endif
34
35 #define nextpowerof2(x) pow(2,ceil(log(x)/log(2)))
36 #define abs(x) ((x<0)?-(x):(x))
37
38 #if SDL2
39 static SDL_GLContext context = NULL;
40 #else
41 static SDL_Surface* context = NULL;
42 #endif
43
44 static SDL_Surface* bscreen = NULL; // FIXME: unnecessary SDL dependency; this should be an s_screen
45
46 static int textureDepths[4] = {16,16,24,32};
47 static const char* glExtensions;
48
49 static float ycompress = 1.0;
50
51 static GLushort glpalette[256];
52 static GLuint gltexture;
53
54 static GLint textureTarget;
55 static GLint textureInternalColorFormat;
56 static GLint textureColorFormat;
57 static GLint texturePixelFormat;
58
59 static int viewportWidth, viewportHeight; // dimensions of display area
60 static int scaledWidth, scaledHeight; // dimensions of game screen after scaling
61 static int textureWidth, textureHeight; // dimensions of game screen and GL texture
62 static int xOffset, yOffset; // offset of game screen on display area
63 static int bytesPerPixel;
64
65 #ifdef GLES
66 static GLfixed tcx, tcy; // maximum x and y texture coords in fixed-point form
67 #else
68 static GLfloat tcx, tcy; // maximum x and y texture coords in floating-point form
69 #endif
70
71 // use some variables declared in video.c that are common to both backends
72 extern s_videomodes stored_videomodes;
73 extern FPSmanager framerate_manager;
74 extern int stretch;
75 extern int nativeWidth, nativeHeight;
76 #if SDL2
77 extern SDL_Window* window;
78 #endif
79
80 // Macros for compatibility between OpenGL ES and normal OpenGL
81 #ifdef GLES
82 #define glOrtho(l,r,b,t,n,f) glOrthox((l)<<16,(r)<<16,(b)<<16,(t)<<16,(n)<<16,(f)<<16)
83 #define glTexParameter glTexParameterx
84 #define BOR_UNSIGNED_SHORT_5_6_5 GL_UNSIGNED_SHORT_5_6_5
85 #define BOR_CLAMP GL_CLAMP_TO_EDGE
86 #else
87 #define glTexParameter glTexParameteri
88 #define BOR_UNSIGNED_SHORT_5_6_5 GL_UNSIGNED_SHORT_5_6_5_REV
89 #define BOR_CLAMP GL_CLAMP
90 #endif
91
92 // SDL 1.2 and SDL 2.0 use different calls for SwapBuffers
93 #if SDL2
94 #define SwapBuffers() SDL_GL_SwapWindow(window)
95 #else
96 #define SwapBuffers() SDL_GL_SwapBuffers()
97 #endif
98
99 // calculates scale factors and offsets based on viewport and texture sizes
video_gl_setup_screen()100 void video_gl_setup_screen()
101 {
102 // set up the viewport
103 glViewport(0, 0, viewportWidth, viewportHeight);
104
105 // set up orthographic projection
106 glMatrixMode(GL_PROJECTION);
107 glLoadIdentity();
108 glOrtho(0, viewportWidth-1, 0, viewportHeight-1, -1, 1);
109
110 // reset the model view
111 glMatrixMode(GL_MODELVIEW);
112 glLoadIdentity();
113 }
114
115 // initializes the OpenGL texture for the game screen
video_gl_init_textures()116 void video_gl_init_textures()
117 {
118 int allocTextureWidth, allocTextureHeight;
119 bool npotTexturesSupported;
120
121 // set texture target, format, etc.
122 textureTarget = GL_TEXTURE_2D;
123 textureColorFormat = (bytesPerPixel == 4) ? GL_RGBA : GL_RGB;
124 textureInternalColorFormat = textureColorFormat;
125 texturePixelFormat = (bytesPerPixel <= 2) ? BOR_UNSIGNED_SHORT_5_6_5 : GL_UNSIGNED_BYTE;
126
127 // enable 2D textures
128 glEnable(textureTarget);
129
130 // detect support for non-power-of-two texture dimensions
131 #ifdef GLES
132 npotTexturesSupported = strstr(glExtensions, "GL_IMG_texture_npot") || strstr(glExtensions, "GL_OES_texture_npot");
133 #else
134 npotTexturesSupported = strstr(glExtensions, "GL_ARB_texture_non_power_of_two") ? true : false;
135 #endif
136
137 /*
138 * FIXME: NPOT textures are disabled for now because they cause a software fallback with
139 * a few drivers for older Nvidia cards. But POT textures eat up more memory than
140 * is necessary on computers with NPOT texture support. There has to be a
141 * better solution to this problem than just disabling them for everyone...the
142 * "GL_*_texture_rectangle" extensions might solve the problem in some cases.
143 */
144 npotTexturesSupported = false;
145
146 if(npotTexturesSupported)
147 {
148 allocTextureWidth = textureWidth;
149 allocTextureHeight = textureHeight;
150 }
151 else
152 {
153 allocTextureWidth = nextpowerof2(textureWidth);
154 allocTextureHeight = nextpowerof2(textureHeight);
155 }
156
157 // calculate maximum texture coordinates
158 #ifdef GLES
159 tcx = (textureWidth == 0) ? 0 : (textureWidth<<16) / allocTextureWidth;
160 tcy = (textureHeight == 0) ? 0 : (textureHeight<<16) / allocTextureHeight;
161 #else
162 tcx = (textureWidth == 0) ? 0 : (float)textureWidth / (float)allocTextureWidth;
163 tcy = (textureHeight == 0) ? 0 : (float)textureHeight / (float)allocTextureHeight;
164 #endif
165
166 // allocate a surface to initialize the texture with
167 bscreen = SDL_CreateRGBSurface(SDL_SWSURFACE, allocTextureWidth, allocTextureHeight, textureDepths[bytesPerPixel-1], 0,0,0,0);
168
169 // create texture object
170 glDeleteTextures(1, &gltexture);
171 glGenTextures(1, &gltexture);
172 glBindTexture(textureTarget, gltexture);
173 glTexImage2D(textureTarget, 0, textureInternalColorFormat, allocTextureWidth,
174 allocTextureHeight, 0, textureColorFormat, texturePixelFormat, bscreen->pixels);
175 glTexParameter(textureTarget, GL_TEXTURE_WRAP_S, BOR_CLAMP);
176 glTexParameter(textureTarget, GL_TEXTURE_WRAP_T, BOR_CLAMP);
177
178 // we don't need bscreen anymore, except in 8-bit mode
179 SDL_FreeSurface(bscreen);
180 bscreen = NULL;
181
182 if(bytesPerPixel == 1) bscreen = SDL_CreateRGBSurface(SDL_SWSURFACE, textureWidth, textureHeight, 16, 0,0,0,0);
183 }
184
video_gl_set_mode(s_videomodes videomodes)185 int video_gl_set_mode(s_videomodes videomodes)
186 {
187 GLint maxTextureSize;
188
189 bytesPerPixel = videomodes.pixel;
190 textureWidth = videomodes.hRes;
191 textureHeight = videomodes.vRes;
192
193 // use the current monitor resolution in fullscreen mode to prevent aspect ratio distortion
194 viewportWidth = savedata.fullscreen ? nativeWidth : (int)(videomodes.hRes * MAX(0.25,savedata.glscale));
195 viewportHeight = savedata.fullscreen ? nativeHeight : (int)(videomodes.vRes * MAX(0.25,savedata.glscale));
196
197 // zero width/height means close the window, not make it enormous!
198 if((viewportWidth == 0) || (viewportHeight == 0)) return 0;
199
200 // set up OpenGL double buffering
201 if(SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1) != 0)
202 {
203 printf("Can't set up OpenGL double buffering (%s)...", SDL_GetError());
204 goto error;
205 }
206
207 // try to disable vertical retrace syncing (VSync)
208 #ifdef SDL2
209 if(SDL_GL_SetSwapInterval(0) < 0)
210 #else
211 if(SDL_GL_SetAttribute(SDL_GL_SWAP_CONTROL, 0) != 0)
212 #endif
213 {
214 printf("Warning: can't disable vertical retrace sync (%s)\n", SDL_GetError());
215 }
216
217 #if SDL2 && defined(GLES)
218 SDL_GL_SetAttribute(SDL_GL_CONTEXT_EGL, 1);
219 SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 1);
220 SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);
221 #elif SDL2
222 SDL_GL_SetAttribute(SDL_GL_CONTEXT_EGL, 0);
223 #endif
224
225 // free existing surfaces
226 if(bscreen) { SDL_FreeSurface(bscreen); bscreen=NULL; }
227
228 // create main video surface and initialize OpenGL context
229 #if SDL2
230 SetVideoMode(viewportWidth, viewportHeight, 0, true);
231 if(!window)
232 {
233 printf("Failed to create OpenGL-compatible window (%s)...", SDL_GetError());
234 goto error;
235 }
236 context = SDL_GL_CreateContext(window);
237 #else
238 context = SDL_SetVideoMode(viewportWidth, viewportHeight, 0, savedata.fullscreen ? (SDL_OPENGL|SDL_FULLSCREEN) : SDL_OPENGL);
239 #endif
240
241 // make sure the surface was created successfully
242 if(!context)
243 {
244 printf("OpenGL initialization failed (%s)...", SDL_GetError());
245 goto error;
246 }
247
248 // update viewport size based on actual dimensions
249 #if SDL2
250 SDL_GL_MakeCurrent(window, context);
251 SDL_GetWindowSize(window, &viewportWidth, &viewportHeight);
252 #else
253 viewportWidth = context->w;
254 viewportHeight = context->h;
255 #endif
256
257 #ifdef LOADGL
258 // load OpenGL functions dynamically in Linux/Windows/OSX
259 if(LoadGLFunctions() == 0) goto error;
260 #endif
261
262 // reject the MesaGL software renderer (swrast) because it's much slower than SDL software blitting
263 if(stricmp((const char*)glGetString(GL_RENDERER), "Software Rasterizer") == 0)
264 {
265 printf("Not going to use the Mesa software renderer...");
266 goto error;
267 }
268
269 // get the list of available extensions
270 glExtensions = (const char*)glGetString(GL_EXTENSIONS);
271
272 // don't try to create a texture larger than the maximum allowed dimensions
273 glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize);
274 if((textureWidth > maxTextureSize) || (textureHeight > maxTextureSize))
275 {
276 printf("Unable to create a %ix%i OpenGL texture (max texture size %i)...", textureWidth, textureHeight, maxTextureSize);
277 goto error;
278 }
279
280 // set background to black
281 glClearColor(0.0, 0.0, 0.0, 0.0);
282 glClear(GL_COLOR_BUFFER_BIT);
283
284 // disable unneeded features
285 glDisable(GL_BLEND);
286 glDisable(GL_LIGHTING);
287 glDisable(GL_DEPTH_TEST);
288 glDisable(GL_DITHER);
289
290 #ifdef GLES
291 // enable vertex/texcoord arrays in OpenGL ES since we can't use glBegin()/glEnd()
292 glEnableClientState(GL_VERTEX_ARRAY);
293 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
294 #endif
295
296 // initialize texture object
297 video_gl_init_textures();
298
299 // set up offsets, scale factors, and viewport
300 video_gl_setup_screen();
301
302 // FIXME: don't use savedata for this; use the previous brightness and gamma (will need to coordinate with software SDL)
303 video_gl_set_color_correction(savedata.gamma, savedata.brightness);
304
305 opengl = 1;
306 return 1;
307 error:
308 printf("falling back on SDL video backend\n");
309 if(bscreen) { SDL_FreeSurface(bscreen); bscreen=NULL; }
310 opengl = 0;
311 savedata.usegl[savedata.fullscreen] = 0;
312 return 0;
313 }
314
video_gl_clearscreen()315 void video_gl_clearscreen()
316 {
317 // clear both buffers in a double-buffered setup
318 glClear(GL_COLOR_BUFFER_BIT);
319 SwapBuffers();
320 glClear(GL_COLOR_BUFFER_BIT);
321 SwapBuffers();
322 }
323
video_gl_fullscreen_flip()324 void video_gl_fullscreen_flip()
325 {
326 savedata.fullscreen ^= 1;
327 video_set_mode(stored_videomodes);
328 }
329
video_gl_draw_quad(int x,int y,int width,int height)330 void video_gl_draw_quad(int x, int y, int width, int height)
331 {
332 #ifdef GLES
333 // OpenGL ES supports neither quads nor glBegin()/glEnd() :(
334 GLshort box[] = {x,y, x+width-1,y, x+width-1,y+height-1, x,y+height-1};
335 GLfixed tex[] = {0,tcy, tcx,tcy, tcx,0, 0,0, };
336 GLubyte indices[] = {0,1,3,2};
337
338 glActiveTexture(GL_TEXTURE0);
339 glTexCoordPointer(2, GL_FIXED, 0, tex);
340 glActiveTexture(GL_TEXTURE1);
341 glTexCoordPointer(2, GL_FIXED, 0, tex);
342 glVertexPointer(2, GL_SHORT, 0, box);
343 glDrawElements(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_BYTE, indices);
344 #else
345 glBegin(GL_QUADS);
346 // Top left
347 glMultiTexCoord2f(GL_TEXTURE0, 0.0, tcy);
348 glMultiTexCoord2f(GL_TEXTURE1, 0.0, tcy);
349 glVertex2i(x, y);
350
351 // Top right
352 glMultiTexCoord2f(GL_TEXTURE0, tcx, tcy);
353 glMultiTexCoord2f(GL_TEXTURE1, tcx, tcy);
354 glVertex2i(x+width-1, y);
355
356 // Bottom right
357 glMultiTexCoord2f(GL_TEXTURE0, tcx, 0.0);
358 glMultiTexCoord2f(GL_TEXTURE1, tcx, 0.0);
359 glVertex2i(x+width-1, y+height-1);
360
361 // Bottom left
362 glMultiTexCoord2f(GL_TEXTURE0, 0.0, 0.0);
363 glMultiTexCoord2f(GL_TEXTURE1, 0.0, 0.0);
364 glVertex2i(x, y+height-1);
365 glEnd();
366 #endif
367 }
368
video_gl_copy_screen(s_screen * src)369 int video_gl_copy_screen(s_screen* src)
370 {
371 unsigned char *sp;
372 unsigned char *dp;
373 int width, height, linew, slinew;
374 int h, i;
375 float texScale;
376 SDL_Surface* ds = NULL;
377
378 // Convert 8-bit s_screen to a 16-bit SDL_Surface
379 if(bscreen)
380 {
381 if(SDL_MUSTLOCK(bscreen)) SDL_LockSurface(bscreen);
382
383 width = bscreen->w;
384 if(width > src->width) width = src->width;
385 height = bscreen->h;
386 if(height > src->height) height = src->height;
387 if(!width || !height) return 0;
388 h = height;
389
390 sp = (unsigned char*)src->data;
391 ds = bscreen;
392 dp = ds->pixels;
393
394 linew = width*bytesPerPixel;
395 slinew = src->width*bytesPerPixel;
396
397 do{
398 //u16pcpy((unsigned short*)dp, sp, glpalette, linew);
399 i=linew-1;
400 do
401 {
402 ((unsigned short*)dp)[i] = glpalette[sp[i]];
403 }while(i--);
404 sp += slinew;
405 dp += ds->pitch;
406 }while(--h);
407
408 if(SDL_MUSTLOCK(bscreen)) SDL_UnlockSurface(bscreen);
409 }
410
411 glClear(GL_COLOR_BUFFER_BIT);
412
413 // update texture contents with new surface contents
414 glActiveTexture(GL_TEXTURE0);
415 glBindTexture(textureTarget, gltexture);
416 glTexSubImage2D(textureTarget, 0, 0, 0, textureWidth, textureHeight, textureColorFormat,
417 texturePixelFormat, bscreen ? bscreen->pixels : src->data);
418
419 // determine x and y scale factors
420 texScale = MIN((float)viewportWidth/(float)textureWidth, (float)viewportHeight/(float)textureHeight);
421
422 // determine on-screen dimensions
423 scaledWidth = (int)(textureWidth * texScale);
424 scaledHeight = (int)(textureHeight * texScale) * ycompress;
425
426 // determine offsets
427 xOffset = (viewportWidth - scaledWidth) / 2;
428 yOffset = (viewportHeight - scaledHeight) / 2;
429
430 // set texture scaling type
431 if((savedata.glfilter[savedata.fullscreen]) || (textureWidth == (stretch ? viewportWidth : scaledWidth)))
432 {
433 glTexParameter(textureTarget, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
434 glTexParameter(textureTarget, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
435 }
436 else
437 {
438 glTexParameter(textureTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
439 glTexParameter(textureTarget, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
440 }
441
442 // render the quad
443 if(stretch)
444 video_gl_draw_quad(0, 0, viewportWidth, viewportHeight);
445 else
446 video_gl_draw_quad(xOffset, yOffset, scaledWidth, scaledHeight);
447
448 // blit the image to the screen
449 SwapBuffers();
450
451 #if !SDL2 && (WIN || LINUX)
452 // limit framerate to 200 fps
453 SDL_framerateDelay(&framerate_manager);
454 #endif
455
456 return 1;
457 }
458
video_gl_setpalette(unsigned char * pal)459 void video_gl_setpalette(unsigned char* pal)
460 {
461 int i;
462 for(i=0; i<256; i++)
463 {
464 glpalette[i] = colour16(pal[0], pal[1], pal[2]);
465 pal += 3;
466 }
467 }
468
469 // Set the brightness and gamma values
video_gl_set_color_correction(int gamma,int brightness)470 void video_gl_set_color_correction(int gamma, int brightness)
471 {
472 int numTexEnvStages = 0;
473
474 #ifdef GLES
475 // FIXME: color correction is broken with OpenGL ES
476 return;
477 #endif
478
479 if(gamma < -256) gamma = -256;
480 if(gamma > 256) gamma = 256;
481 if(brightness < -256) brightness = -256;
482 if(brightness > 256) brightness = 256;
483 glColor4f(abs(gamma / 256.0), abs(gamma / 256.0), abs(gamma / 256.0), abs(brightness / 256.0));
484
485 #if GLES
486 if(gamma)
487 #else
488 if(strstr(glExtensions, "GL_ARB_texture_env_combine"))
489 #endif
490 {
491 if(gamma > 0)
492 {
493 numTexEnvStages = 3;
494
495 // first stage: c*g
496 glActiveTexture(GL_TEXTURE0);
497 glBindTexture(textureTarget, gltexture);
498 glEnable(textureTarget);
499 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
500 glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE);
501 glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_RGB, GL_TEXTURE);
502 glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
503 glTexEnvi(GL_TEXTURE_ENV, GL_SRC1_RGB, GL_PRIMARY_COLOR);
504 glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR);
505
506 // second stage: (1.0-c)*(1.0-prev) = (1.0-c)*(1.0-(c*g))
507 glActiveTexture(GL_TEXTURE1);
508 glBindTexture(textureTarget, gltexture);
509 glEnable(textureTarget);
510 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
511 glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE);
512 glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_RGB, GL_TEXTURE);
513 glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_ONE_MINUS_SRC_COLOR);
514 glTexEnvi(GL_TEXTURE_ENV, GL_SRC1_RGB, GL_PREVIOUS);
515 glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_ONE_MINUS_SRC_COLOR);
516
517 // third stage: 1.0-prev = 1.0-((1.0-c)*(1.0-(c*g)))
518 glActiveTexture(GL_TEXTURE2);
519 glBindTexture(textureTarget, gltexture);
520 glEnable(textureTarget);
521 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
522 glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_REPLACE);
523 glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_RGB, GL_PREVIOUS);
524 glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_ONE_MINUS_SRC_COLOR);
525 }
526 else if(gamma < 0)
527 {
528 numTexEnvStages = 2;
529
530 // first stage: (1.0-c)*g
531 glActiveTexture(GL_TEXTURE0);
532 glBindTexture(textureTarget, gltexture);
533 glEnable(textureTarget);
534 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
535 glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE);
536 glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_RGB, GL_TEXTURE);
537 glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_ONE_MINUS_SRC_COLOR);
538 glTexEnvi(GL_TEXTURE_ENV, GL_SRC1_RGB, GL_PRIMARY_COLOR);
539 glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR);
540
541 // second stage: c*(1.0-prev) = c*(1.0-((1.0-c)*g))
542 glActiveTexture(GL_TEXTURE1);
543 glBindTexture(textureTarget, gltexture);
544 glEnable(textureTarget);
545 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
546 glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE);
547 glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_RGB, GL_TEXTURE);
548 glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
549 glTexEnvi(GL_TEXTURE_ENV, GL_SRC1_RGB, GL_PREVIOUS);
550 glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_ONE_MINUS_SRC_COLOR);
551
552 // third stage: disabled
553 glActiveTexture(GL_TEXTURE2);
554 glBindTexture(textureTarget, 0);
555 glDisable(textureTarget);
556 }
557 else // gamma == 0 -> no gamma correction
558 {
559 numTexEnvStages = 0;
560
561 // first stage: sampled color from texture
562 glActiveTexture(GL_TEXTURE0);
563 glBindTexture(textureTarget, gltexture);
564 glEnable(textureTarget);
565 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
566
567 // second stage: disabled
568 glActiveTexture(GL_TEXTURE1);
569 glBindTexture(textureTarget, 0);
570 glDisable(textureTarget);
571
572 // third stage: disabled
573 glActiveTexture(GL_TEXTURE2);
574 glBindTexture(textureTarget, 0);
575 glDisable(textureTarget);
576 }
577 }
578
579 if(brightness)
580 {
581 // brightness correction
582 GLfloat blendColor = brightness > 0 ? 1.0 : 0.0; // white (positive brightess) or black (0 or negative)
583 GLfloat rgba[4] = {blendColor, blendColor, blendColor, 1.0};
584
585 glActiveTexture(GL_TEXTURE0 + numTexEnvStages);
586 glBindTexture(textureTarget, gltexture);
587 glEnable(textureTarget);
588 glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, rgba);
589 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
590 glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_INTERPOLATE);
591 glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_RGB, numTexEnvStages > 0 ? GL_PREVIOUS : GL_TEXTURE);
592 glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
593 glTexEnvi(GL_TEXTURE_ENV, GL_SRC1_RGB, GL_CONSTANT);
594 glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR);
595 glTexEnvi(GL_TEXTURE_ENV, GL_SRC2_RGB, GL_PRIMARY_COLOR);
596 glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB, GL_ONE_MINUS_SRC_ALPHA);
597 }
598
599 //fprintf(stderr, "set brightness=%d and gamma=%d in %d texenv stages\n", brightness, gamma, numTexEnvStages + 1);
600 }
601
602 #endif
603