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