]> Shamusworld >> Repos - virtualjaguar/blob - src/sdlemu_opengl.c
Fixed fullscreen<-->windowed mode swith in OpenGL mode, phase one of
[virtualjaguar] / src / sdlemu_opengl.c
1 /*
2  * SDLEMU library - Free sdl related functions library
3  * Copyrigh(c) 1999-2004 sdlemu development crew
4  *
5  *  This program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; either version 2 of the License, or
8  *  (at your option) any later version.
9  *
10  *  This program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with this program; if not, write to the Free Software
17  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18  */
19
20 /*  SDLEMU_OPENGL.C
21     SDLEMU related sources for using OpenGL with SDL.
22     By Niels Wagenaar | http://sdlemu.ngemu.com | shalafi@xs4all.nl
23
24     Version 1.0.001 - 4-10-2004
25
26     - Added support for 16, 24 and 32 bit textures;
27     - Added support for 16, 24 and 32 bit texture rendering;
28
29     Version 1.0.002 - 6-10-2004
30
31     - Cleaned up a lot of code and removed non functional and obsolete code;
32     - Removed sdlemu_resize_texture function because of double code;
33     - Removed the texture creation from the sdlemu_init_opengl;
34     - Added sdlemu_create_texture function to replace the sdlemu_resize_texture function
35       and the texture creation in sdlemu_init_opengl;
36     - Added the usage of OPENGL_16BPP_CORRECT_RGBA for activating the correct 16bpp RGBA masks;
37     - Added the usage of WANT_OPENGL_ALPHA for using ALPHA blending with 32bpp textures;
38     - Added automatic and override texture bpp depth setting (based upon the src surface);
39
40 */
41
42 #include "sdlemu_opengl.h"
43
44 // We want alpha on our OpenGL contexts...!
45 // Or do we? Seems to kill performance on X...
46 // Or does it? Could it be bad blitter performance?
47 #define WANT_OPENGL_ALPHA
48
49 static SDL_Surface *texture      = 0;
50 static GLuint       texid        = 0;
51 static GLfloat      texcoord[4];
52 static unsigned int glFilter;
53 static unsigned int texturebpp  = 0; // 16, 24 or 32 bpp
54
55 static SDL_Surface * overlay = 0;
56 static GLuint overlayID = 0;
57 static GLfloat overlayCoord[4];
58 void sdlemu_create_overlay(SDL_Surface * dst, int src_bpp);
59
60 static int showOverlay = 0;
61
62 static inline int power_of_two(int input)
63 {
64         int value = 1;
65
66         while (value < input)
67                 value <<= 1;
68
69         return value;
70 }
71
72 void sdlemu_init_opengl(SDL_Surface * src, SDL_Surface * dst, int texturetype, int filter, int src_bpp)
73 {
74         printf("\nOpenGL driver information :\n");
75         printf("\n");
76         printf("Vendor:             %s\n", glGetString(GL_VENDOR));
77         printf("Renderer:           %s\n", glGetString(GL_RENDERER));
78         printf("Version:            %s\n", glGetString(GL_VERSION));
79         printf("OpenGL drawmethod: ");
80
81         switch (texturetype)
82         {
83         case 1:
84                 printf("GL_QUAD rendering\n\n");
85                 break;
86         default:
87                 printf("GL_TRIANGLE rendering\n\n");
88                 break;
89         }
90
91         glFilter = filter;
92
93         // Let us create the texture information :
94         sdlemu_create_texture(src, dst, filter, src_bpp);
95         sdlemu_create_overlay(dst, src_bpp);
96 }
97
98 void sdlemu_draw_texture(SDL_Surface * dst, SDL_Surface * src, int texturetype)
99 {
100 /*
101         This is needed when we want to render OpenGL textures with the Alpha mask set.
102         Be warned! This only works with the bpp of texture en *src set to 32.
103 */
104 #ifdef WANT_OPENGL_ALPHA
105         Uint32 saved_flags;
106         Uint8  saved_alpha;
107
108         /* Save the alpha blending attributes */
109         saved_flags = src->flags&(SDL_SRCALPHA|SDL_RLEACCELOK);
110         saved_alpha = src->format->alpha;
111         if ( (saved_flags & SDL_SRCALPHA) == SDL_SRCALPHA ) {
112                 SDL_SetAlpha(src, 0, 0);
113         }
114
115         // Blit the src display to the texture.
116         SDL_BlitSurface(src, NULL, texture, NULL);
117
118         /* Restore the alpha blending attributes */
119         if ( (saved_flags & SDL_SRCALPHA) == SDL_SRCALPHA ) {
120                 SDL_SetAlpha(src, saved_flags, saved_alpha);
121         }
122 #else
123         SDL_BlitSurface(src, NULL, texture, NULL);
124 #endif
125 //      SDL_BlitSurface(src, NULL, overlay, NULL);
126 /*Uint32 * pix = (Uint32 *)overlay->pixels;
127 Uint32 y,x;
128 for(y=10; y<200; y++)
129 for(x=30; x<250; x++)
130 pix[x+(y*1024)] = 0x800000FF;//*/
131
132 glBlendFunc(GL_ONE, GL_ZERO);
133 glBindTexture(GL_TEXTURE_2D, texid);
134         // Texturemap complete texture to surface so we have free scaling
135         // and antialiasing
136         switch (texturebpp)
137         {
138         case 16:
139                 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, texture->w, texture->h,
140                         GL_RGB, GL_UNSIGNED_SHORT_5_6_5, texture->pixels);
141                 break;
142         case 24:
143                 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, texture->w, texture->h,
144                         GL_RGB, GL_UNSIGNED_BYTE, texture->pixels);
145                 break;
146         case 32:
147         default:
148                 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, texture->w, texture->h,
149                         GL_RGBA, GL_UNSIGNED_BYTE, texture->pixels);
150                 break;
151         }
152
153         // Render the texture to the screen using OpenGL!
154         switch (texturetype)
155         {
156         case 1:
157                 glBegin(GL_QUADS);
158                         glTexCoord2f(texcoord[0], texcoord[1]);
159                         glVertex2f(0, 0);
160                         glTexCoord2f(texcoord[2], texcoord[1]);
161                         glVertex2f(dst->w, 0);
162                         glTexCoord2f(texcoord[2], texcoord[3]);
163                         glVertex2f(dst->w, dst->h);
164                         glTexCoord2f(texcoord[0], texcoord[3]);
165                         glVertex2f(0, dst->h);
166                 glEnd();
167
168         default:
169                 glBegin(GL_TRIANGLE_STRIP);
170                         glTexCoord2f(texcoord[0], texcoord[1]); glVertex3i(0, 0, 0);
171                         glTexCoord2f(texcoord[2], texcoord[1]); glVertex3i(dst->w, 0, 0);
172                         glTexCoord2f(texcoord[0], texcoord[3]); glVertex3i(0, dst->h, 0);
173                         glTexCoord2f(texcoord[2], texcoord[3]); glVertex3i(dst->w, dst->h, 0);
174                 glEnd();
175         }//*/
176
177         if (showOverlay)
178         {
179                 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
180                 glBindTexture(GL_TEXTURE_2D, overlayID);
181                 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, overlay->w, overlay->h, GL_RGBA, GL_UNSIGNED_BYTE, overlay->pixels);
182                 glBegin(GL_QUADS);
183                         glTexCoord2f(overlayCoord[0], overlayCoord[1]);
184                         glVertex2f(0, 0);
185                         glTexCoord2f(overlayCoord[2], overlayCoord[1]);
186                         glVertex2f(dst->w, 0);
187                         glTexCoord2f(overlayCoord[2], overlayCoord[3]);
188                         glVertex2f(dst->w, dst->h);
189                         glTexCoord2f(overlayCoord[0], overlayCoord[3]);
190                         glVertex2f(0, dst->h);
191                 glEnd();
192         }
193
194 //Do some OpenGL stuff here...
195 //Doesn't work...
196 /*unsigned long int map[25] = {
197         0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
198         0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
199         0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
200         0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
201         0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF
202 };
203 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
204 glRasterPos2i(10, 10);
205 glDrawPixels(5, 5, GL_RGBA, GL_UNSIGNED_INT, map);//*/
206
207 //  glFlush();
208         SDL_GL_SwapBuffers();
209 //      glFinish();
210
211 }
212
213 void sdlemu_close_opengl(void)
214 {
215         if (texture)
216                 SDL_FreeSurface(texture);
217
218         if (overlay)
219                 SDL_FreeSurface(overlay);
220 }
221
222 void sdlemu_create_overlay(SDL_Surface * dst, int src_bpp)
223 {
224     // Local variables.
225         Uint32 rmask, gmask, bmask, amask; // Needed for creating RGBA masks.
226
227         // Delete old texture (if allocated). Useful when there is a screen resize.
228         if (overlay)
229                 SDL_FreeSurface(overlay);
230
231         // Texture width/height should be power of 2 of the SDL_Surface *src when using OpenGL.
232         // So, find the largest power of two that will contain both the width and height
233         int w = power_of_two(dst->w);
234         int h = power_of_two(dst->h);
235
236         printf("OpenGL - Overlay size : %d x %d\n", w, h);
237
238         // Setting bpp based upon src_bpp.
239         int bpp = src_bpp;
240
241         // We allow the developer to set its own texture bpp. But if the value is NULL or
242         // not equal to 16, 24 or 32, we make the texturebpp the same as the BPP from src.
243         if (bpp == 16 || bpp == 24 || bpp == 32)
244                 texturebpp = bpp;
245         else
246                 texturebpp = dst->format->BitsPerPixel;
247
248         printf("OpenGL - Overlay depth : %d bpp\n", texturebpp);
249
250         // Now were are going to create a SDL_Surface named texture. This will be our surface
251         // which will function as a buffer between the SDL_Surface *src and SDL_Surface *dst.
252         // This buffer is needed because we need to convert the SDL_Surface *src to an OpenGL
253         // texture with a depth of 16, 24 or 32 bpp, before we can blit the pixels to *dst
254         // using OpenGL.
255         //
256         // NOTE: Seems the byte order here *is* important!
257         switch (texturebpp)
258         {
259         case 16: // *src has depth of 16 bpp
260 /*
261         According to information on the SDL mailinglist and on internet, the following
262         rgba masks should be the ones to use. But somehow the screen gets f*cked up and
263         the RGB colours are incorrect (at least in Virtual Jaguar/SDL).
264
265         Compile with -DOPENGL_16BPP_CORRECT_RGBA to use this RGBA values.
266 */
267 #ifdef OPENGL_16BPP_CORRECT_RGBA
268                 rmask = 0x7C00;
269                 gmask = 0x03E0;
270                 bmask = 0x001F;
271                 amask = 0x0000;
272 #else
273                 rmask = 0x0000;
274                 gmask = 0x0000;
275                 bmask = 0x0000;
276                 amask = 0x0000;
277 #endif
278                 break;
279         case 24: // *src has depth of 24 bpp
280         #if SDL_BYTEORDER == SDL_BIG_ENDIAN
281                 rmask = 0x00FF0000;
282                 gmask = 0x0000FF00;
283                 bmask = 0x000000FF;
284                 amask = 0x00000000; // IMPORTANT! 24 bpp doesn't use Alpha (at least in our case).
285         #else
286                 rmask = 0x000000FF;
287                 gmask = 0x0000FF00;
288                 bmask = 0x00FF0000;
289                 amask = 0x00000000; // IMPORTANT! 24 bpp doesn't use Alpha (at least in our case).
290         #endif
291                 break;
292         case 32: //*src has depth of 32 bpp
293         default: //which is also the default.
294         #if SDL_BYTEORDER == SDL_BIG_ENDIAN
295                 rmask = 0xFF000000;
296                 gmask = 0x00FF0000;
297                 bmask = 0x0000FF00;
298                 amask = 0x000000FF;
299         #else
300                 rmask = 0x000000FF;
301                 gmask = 0x0000FF00;
302                 bmask = 0x00FF0000;
303                 amask = 0xFF000000;
304         #endif
305                 break;
306         }
307
308         // Creating SDL_Surface texture based upon the above settings.
309         overlay = SDL_CreateRGBSurface(SDL_SWSURFACE, w, h, texturebpp, rmask, gmask, bmask, amask);
310
311         // Setting up the texture coordinates.
312         overlayCoord[0] = 0.0f;
313         overlayCoord[1] = 0.0f;
314         overlayCoord[2] = (GLfloat)(dst->w) / overlay->w;
315         overlayCoord[3] = (GLfloat)(dst->h) / overlay->h;
316
317         // create a RGB(A) texture for the texture surface
318         glGenTextures(1, &overlayID);
319         glBindTexture(GL_TEXTURE_2D, overlayID);
320
321         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
322         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
323
324         // Setting texture mode.
325         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
326         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
327
328         // Generate the texture using the above information.
329         switch (texturebpp)
330         {
331         case 16:
332                 // Normal 16bpp depth based textures consist out of GL_RGB5 and doesn't have support for Alpha channels.
333                 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB5, overlay->w, overlay->h, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
334                 break;
335         case 24:
336                 // The 24bpp depth based textures consist out of GL_RGB8 and doesn't have support for Alpha channels.
337                 //
338                 // IMPORTANT : If you don't use Alpha. Use textures with a depth of 16bpp.
339                 //             If you use Alpha. Use textures with a depth of 32bpp.
340                 //             24bpp textures are SLOW and avoid them at all costs!
341                 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, overlay->w, overlay->h, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
342                 break;
343         case 32:
344         default:
345                 // The 32bpp depth based textures consist out of GL_RGBA8 and has support for Alpha channels.
346                 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, overlay->w, overlay->h, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
347                 break;
348         }
349 }
350
351 void * sdlemuGetOverlayPixels(void)
352 {
353         return overlay->pixels;
354 }
355
356 Uint32 sdlemuGetOverlayWidthInPixels(void)
357 {
358         return overlay->pitch / 4;
359 }
360
361 void sdlemuEnableOverlay(void)
362 {
363         showOverlay = 1;
364 }
365
366 void sdlemuDisableOverlay(void)
367 {
368         showOverlay = 0;
369 }
370
371 void sdlemu_create_texture(SDL_Surface * src, SDL_Surface * dst, int filter, int src_bpp)
372 {
373     // Local variables.
374         int w , h;                         // w and h contain the width and height of the OpenGL texture.
375         Uint32 rmask, gmask, bmask, amask; // Needed for creating RGBA masks.
376         int bpp;
377
378         // Delete old texture (if allocated). Useful when there is a screen resize.
379         if (texture)
380                 SDL_FreeSurface(texture);
381
382         // Texture width/height should be power of 2 of the SDL_Surface *src when using OpenGL.
383         // So, find the largest power of two that will contain both the width and height
384         w = power_of_two(src->w);
385         h = power_of_two(src->h);
386
387         printf("OpenGL - Texture size : %d x %d\n", w, h);
388
389         // Setting bpp based upon src_bpp.
390         bpp = src_bpp;
391
392         // We allow the developer to set its own texture bpp. But if the value is NULL or
393         // not equal to 16, 24 or 32, we make the texturebpp the same as the BPP from src.
394         if (bpp == 16 || bpp == 24 || bpp == 32)
395                 texturebpp = bpp;
396         else
397                 texturebpp = src->format->BitsPerPixel;
398
399         printf("OpenGL - Texture depth : %d bpp\n", texturebpp);
400
401         // Now were are going to create a SDL_Surface named texture. This will be our surface
402         // which will function as a buffer between the SDL_Surface *src and SDL_Surface *dst.
403         // This buffer is needed because we need to convert the SDL_Surface *src to an OpenGL
404         // texture with a depth of 16, 24 or 32 bpp, before we can blit the pixels to *dst
405         // using OpenGL.
406         //
407         // NOTE: Seems the byte order here *is* important!
408         switch (texturebpp)
409         {
410         case 16: // *src has depth of 16 bpp
411 /*
412         According to information on the SDL mailinglist and on internet, the following
413         rgba masks should be the ones to use. But somehow the screen gets f*cked up and
414         the RGB colours are incorrect (at least in Virtual Jaguar/SDL).
415
416         Compile with -DOPENGL_16BPP_CORRECT_RGBA to use this RGBA values.
417 */
418 #ifdef OPENGL_16BPP_CORRECT_RGBA
419                 rmask = 0x7C00;
420                 gmask = 0x03E0;
421                 bmask = 0x001F;
422                 amask = 0x0000;
423 #else
424                 rmask = 0x0000;
425                 gmask = 0x0000;
426                 bmask = 0x0000;
427                 amask = 0x0000;
428 #endif
429                 break;
430         case 24: // *src has depth of 24 bpp
431         #if SDL_BYTEORDER == SDL_BIG_ENDIAN
432                 rmask = 0x00FF0000;
433                 gmask = 0x0000FF00;
434                 bmask = 0x000000FF;
435                 amask = 0x00000000; // IMPORTANT! 24 bpp doesn't use Alpha (at least in our case).
436         #else
437                 rmask = 0x000000FF;
438                 gmask = 0x0000FF00;
439                 bmask = 0x00FF0000;
440                 amask = 0x00000000; // IMPORTANT! 24 bpp doesn't use Alpha (at least in our case).
441         #endif
442                 break;
443         case 32: //*src has depth of 32 bpp
444         default: //which is also the default.
445         #if SDL_BYTEORDER == SDL_BIG_ENDIAN
446                 rmask = 0xFF000000;
447                 gmask = 0x00FF0000;
448                 bmask = 0x0000FF00;
449                 amask = 0x000000FF;
450         #else
451                 rmask = 0x000000FF;
452                 gmask = 0x0000FF00;
453                 bmask = 0x00FF0000;
454                 amask = 0xFF000000;
455         #endif
456                 break;
457         }
458
459         // Creating SDL_Surface texture based upon the above settings.
460         texture = SDL_CreateRGBSurface(SDL_SWSURFACE, w, h, texturebpp, rmask, gmask, bmask, amask);
461
462         // Setting up OpenGL
463         glDisable(GL_FOG);
464         glDisable(GL_LIGHTING);
465         glDisable(GL_CULL_FACE);
466         glDisable(GL_DEPTH_TEST);
467 //      glDisable(GL_BLEND);
468         glEnable(GL_BLEND);
469         glDisable(GL_NORMALIZE);
470         glDisable(GL_ALPHA_TEST);
471         glEnable(GL_TEXTURE_2D);
472 //      glBlendFunc(GL_SRC_ALPHA, GL_ONE);
473 //      glBlendFunc(GL_ONE, GL_SRC_ALPHA);
474 //This works, but in a wrong way...
475 //      glBlendFunc(GL_ONE, GL_ONE);
476
477         // Definitely needed for screen resolution larger then the *src.
478         // This way we can have automatic scaling functionality.
479         glViewport(0, 0, dst->w, dst->h);
480         glMatrixMode(GL_PROJECTION);
481         glPushMatrix();
482         glLoadIdentity();
483         glOrtho(0.0, (GLdouble)dst->w, (GLdouble)dst->h, 0.0, 0.0, 1.0);
484         glMatrixMode(GL_MODELVIEW);
485         glPushMatrix();
486         glLoadIdentity();
487
488         // Setting up the texture coordinates.
489         texcoord[0] = 0.0f;
490         texcoord[1] = 0.0f;
491         texcoord[2] = (GLfloat)(src->w) / texture->w;
492         texcoord[3] = (GLfloat)(src->h) / texture->h;
493
494         // create a RGB(A) texture for the texture surface
495         glGenTextures(1, &texid);
496         glBindTexture(GL_TEXTURE_2D, texid);
497
498         // Setting up the OpenGL Filters. These filters are important when we/you
499         // want to scale the texture.
500         if (filter)
501         {
502                 // Textures are rendered in best quality.
503                 printf("OpenGL filters: enabled\n");
504                 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
505                 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
506         }
507         else
508         {
509                 // Textures are rendered in normal quality.
510                 printf("OpenGL filters: disabled\n");
511                 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
512                 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
513         }
514
515         // Setting texture mode.
516         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
517         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
518
519         // Generate the texture using the above information.
520         switch (texturebpp)
521         {
522         case 16:
523                 // Normal 16bpp depth based textures consist out of GL_RGB5 and doesn't have support for Alpha channels.
524                 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB5, texture->w, texture->h, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
525                 break;
526         case 24:
527                 // The 24bpp depth based textures consist out of GL_RGB8 and doesn't have support for Alpha channels.
528                 //
529                 // IMPORTANT : If you don't use Alpha. Use textures with a depth of 16bpp.
530                 //             If you use Alpha. Use textures with a depth of 32bpp.
531                 //             24bpp textures are SLOW and avoid them at all costs!
532                 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, texture->w, texture->h, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
533                 break;
534         case 32:
535         default:
536                 // The 32bpp depth based textures consist out of GL_RGBA8 and has support for Alpha channels.
537                 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, texture->w, texture->h, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
538                 break;
539         }
540 }