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