]> Shamusworld >> Repos - virtualjaguar/blob - src/sdlemu_opengl.c
Expended OpenGL rendering with 16, 24 and 32 bit texture types.
[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 absolete 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 inline int power_of_two(int input)
51 {
52         int value = 1;
53
54         while (value < input)
55                 value <<= 1;
56
57         return value;
58 }
59
60 void sdlemu_init_opengl(SDL_Surface * src, SDL_Surface * dst, int texturetype, int filter, int src_bpp)
61 {
62
63         printf("\nOpenGL driver information :\n");
64         printf("\n");
65         printf("Vendor:             %s\n", glGetString(GL_VENDOR));
66         printf("Renderer:           %s\n", glGetString(GL_RENDERER));
67         printf("Version:            %s\n", glGetString(GL_VERSION));
68         printf("OpenGL drawmethod: ");
69
70         switch (texturetype)
71         {
72         case 1:
73                 printf("GL_QUAD rendering\n\n");
74                 break;
75         default:
76                 printf("GL_TRIANGLE rendering\n\n");
77                 break;
78         }
79
80         glFilter = filter;
81
82         // Let us create the texture information :
83         sdlemu_create_texture( src, dst, filter , src_bpp);
84
85 }
86
87 void sdlemu_draw_texture(SDL_Surface * dst, SDL_Surface * src, int texturetype)
88 {
89 /*
90     This is needed when we want to render OpenGL textures with the Alpha mask set.
91     Be warned! This only works with the bpp of texture en *src set to 32.
92 */
93 #ifdef WANT_OPENGL_ALPHA
94         Uint32 saved_flags;                
95         Uint8  saved_alpha;                
96
97         /* Save the alpha blending attributes */
98         saved_flags = src->flags&(SDL_SRCALPHA|SDL_RLEACCELOK);
99         saved_alpha = src->format->alpha;
100         if ( (saved_flags & SDL_SRCALPHA) == SDL_SRCALPHA ) {
101                 SDL_SetAlpha(src, 0, 0);
102         }
103
104         // Blit the src display to the texture.
105         SDL_BlitSurface(src, NULL, texture, NULL);
106
107         /* Restore the alpha blending attributes */
108         if ( (saved_flags & SDL_SRCALPHA) == SDL_SRCALPHA ) {
109                 SDL_SetAlpha(src, saved_flags, saved_alpha);
110         }
111 #else
112         SDL_BlitSurface(src, NULL, texture, NULL);
113 #endif
114
115         // Texturemap complete texture to surface so we have free scaling 
116         // and antialiasing
117     switch ( texturebpp )
118     {
119     case 16:
120         glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, texture->w, texture->h,
121                         GL_RGB, GL_UNSIGNED_SHORT_5_6_5, texture->pixels);
122         break;
123     case 24:
124         glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, texture->w, texture->h,
125                         GL_RGB, GL_UNSIGNED_BYTE, texture->pixels);
126         break;
127     case 32:
128     default:
129         glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, texture->w, texture->h,
130                         GL_RGBA, GL_UNSIGNED_BYTE, texture->pixels);
131         break;
132     }     
133         
134         // Render the texture to the screen using OpenGL!
135         switch (texturetype)
136         {
137         case 1:
138         glBegin(GL_QUADS);
139                 glTexCoord2f(texcoord[0], texcoord[1]);
140                 glVertex2f(0, 0);
141                 glTexCoord2f(texcoord[2], texcoord[1]);
142                 glVertex2f(dst->w , 0);
143                 glTexCoord2f(texcoord[2], texcoord[3]);
144                 glVertex2f(dst->w , dst->h );
145                 glTexCoord2f(texcoord[0], texcoord[3]);
146                 glVertex2f(0, dst->h );
147         glEnd();      
148
149         default:
150                 glBegin(GL_TRIANGLE_STRIP);
151                                 glTexCoord2f(texcoord[0], texcoord[1]); glVertex3i(0, 0, 0);
152                                 glTexCoord2f(texcoord[2], texcoord[1]); glVertex3i(dst->w, 0, 0);
153                                 glTexCoord2f(texcoord[0], texcoord[3]); glVertex3i(0, dst->h, 0);
154                                 glTexCoord2f(texcoord[2], texcoord[3]); glVertex3i(dst->w, dst->h, 0);
155                 glEnd();
156         }
157         
158 //  glFlush();
159         SDL_GL_SwapBuffers();    
160 //      glFinish();
161
162 }
163
164 void sdlemu_close_opengl(void)
165 {
166         if (texture)
167                 SDL_FreeSurface(texture);
168 }
169
170 void sdlemu_create_texture(SDL_Surface * src, SDL_Surface * dst, int filter, int src_bpp)
171 {
172     // Local variables.
173         int w , h;                         // w and h contain the width and height of the OpenGL texture.
174         Uint32 rmask, gmask, bmask, amask; // Needed for creating RGBA masks.
175         int bpp;
176         
177         // Delete old texture (if allocated). Usefull when there is a screen resize.
178         if (texture)
179                 SDL_FreeSurface(texture);
180  
181     // Texture width/height should be power of 2 of the SDL_Surface *src when using OpenGL.
182         // So, find the largest power of two that will contain both the width and height
183     w = power_of_two(src->w);
184     h = power_of_two(src->h);
185         
186         printf("OpenGL - Texture size : %d x %d\n", w, h);
187         
188         // Setting bpp based upon src_bpp.
189         bpp = src_bpp;
190         
191         // We allow the developer to set its own texture bpp. But if the value is NULL or
192         // not equal to 16, 24 or 32, we make the texturebpp the same as the BPP from src.
193         if ( (bpp != NULL) && ( (bpp == 16) || (bpp == 24) || (bpp == 32) ) )
194        texturebpp = bpp;
195     else
196        texturebpp = src->format->BitsPerPixel;
197     
198     printf("OpenGL - Texture depth : %d bpp\n", texturebpp);
199
200         // Now were are going to create a SDL_Surface named texture. This will be our surface
201         // which will function as a buffer between the SDL_Surface *src and SDL_Surface *dst.
202         // This buffer is needed because we need to convert the SDL_Surface *src to an OpenGL
203         // texture with a depth of 16, 24 or 32 bpp, before we can blit the pixels to *dst
204         // using OpenGL.
205         // 
206         // NOTE: Seems the byte order here *is* important!
207         switch ( texturebpp )
208         {
209     case 16: // *src has depth of 16 bpp
210
211 /*
212         According to information on the SDL mailinglist and on internet, the following
213         rgba masks should be the ones to use. But somehow the screen gets f*cked up and
214         the RGB colours are incorrect (at least in Virtual Jaguar/SDL). 
215         
216         Compile with -DOPENGL_16BPP_CORRECT_RGBA to use this RGBA values.
217 */        
218         
219 #ifdef OPENGL_16BPP_CORRECT_RGBA     
220        
221         rmask = 0x7c00;
222         gmask = 0x03e0;
223         bmask = 0x001f;
224         amask = 0x0000;
225         
226 #else
227
228         rmask = 0x0000;
229                 gmask = 0x0000;
230                 bmask = 0x0000;
231                 amask = 0x0000;
232                 
233 #endif
234         break;
235     case 24: // *src has depth of 24 bpp
236     #if SDL_BYTEORDER == SDL_BIG_ENDIAN
237             rmask = 0x00ff0000;
238                 gmask = 0x0000ff00;
239                 bmask = 0x000000ff;
240                 amask = 0x00000000; // IMPORTANT! 24 bpp doesn't use Alpha (at least in our case).
241         #else
242             rmask = 0x000000ff;
243             gmask = 0x0000ff00;
244             bmask = 0x00ff0000;
245             amask = 0x00000000; // IMPORTANT! 24 bpp doesn't use Alpha (at least in our case).
246     #endif
247        break;
248     case 32: //*src has depth of 32 bpp
249     default: //which is also the default.
250     #if SDL_BYTEORDER == SDL_BIG_ENDIAN
251             rmask = 0xff000000;
252                 gmask = 0x00ff0000;
253                 bmask = 0x0000ff00;
254                 amask = 0x000000ff;
255         #else
256             rmask = 0x000000ff;
257             gmask = 0x0000ff00;
258             bmask = 0x00ff0000;
259             amask = 0xff000000;
260     #endif
261         break;
262     }    
263
264         // Creating SDL_Surface texture based upon the above settings.
265         texture = SDL_CreateRGBSurface(SDL_SWSURFACE, w, h, texturebpp, rmask, gmask, bmask, amask);
266         
267         // Setting up OpenGL
268         glDisable(GL_FOG);
269         glDisable(GL_LIGHTING);
270         glDisable(GL_CULL_FACE);
271         glDisable(GL_DEPTH_TEST);
272         glDisable(GL_BLEND);
273         glDisable(GL_NORMALIZE);
274         glDisable(GL_ALPHA_TEST);
275         glEnable(GL_TEXTURE_2D);
276         glBlendFunc (GL_SRC_ALPHA, GL_ONE);
277
278         // Definately needed for screen resolution larger then the *src.
279         // This way we can have automatic scaling fucntionality.
280         glViewport(0, 0, dst->w, dst->h);
281         glMatrixMode(GL_PROJECTION);
282         glPushMatrix();
283         glLoadIdentity();
284         glOrtho(0.0, (GLdouble)dst->w, (GLdouble)dst->h, 0.0, 0.0, 1.0);
285         glMatrixMode(GL_MODELVIEW);
286         glPushMatrix();
287         glLoadIdentity();
288
289         // Setting up the texture coordinates.
290         texcoord[0] = 0.0f;
291     texcoord[1] = 0.0f;
292         texcoord[2] = (GLfloat)(src->w) / texture->w;
293         texcoord[3] = (GLfloat)(src->h) / texture->h;
294
295         // create a RGB(A) texture for the texture surface
296         glGenTextures(1, &texid);
297         glBindTexture(GL_TEXTURE_2D, texid);
298         
299     // Srtting up the OpenGL Filters. These filters are important when we/you
300     // want to scale the texture. 
301         if (filter)
302         {
303        // Textures are rendered in best quality. 
304        printf("OpenGL filters: enabled\n");
305            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
306            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
307         }
308         else
309         {
310        // Textures are rendered in normal quality.
311        printf("OpenGL filters: disabled\n");
312            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
313            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
314     }
315
316     // Genereate the texture using the above information.
317     switch ( texturebpp )
318     {
319     case 16:
320         // Normal 16bpp depth based textures consist out of GL_RGB5 and doesn't have support for Alpha channels.
321             glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB5, texture->w, texture->h, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
322         break;
323     case 24:
324         // The 24bpp depth based textures consist out of GL_RGB8 and doesn't have support for Alpha channels.
325         //
326         // IMPORTANT : If you don't use Alpha. Use textures with a depth of 16bpp.
327         //             If you use Alpha. Use textures with a depth of 32bpp.
328         //             24bpp textures are SLOW and avoid them at all costst!        
329             glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, texture->w, texture->h, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
330         break;
331     case 32:
332     default:
333         // The 32bpp depth based textures consist out of GL_RGBA8 and has support for Alpha channels.
334             glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, texture->w, texture->h, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
335         break;        
336     }    
337
338 }