2 * SDLEMU library - Free sdl related functions library
3 * Copyrigh(c) 1999-2004 sdlemu development crew
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.
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.
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
21 SDLEMU related sources for using OpenGL with SDL.
22 By Niels Wagenaar | http://sdlemu.ngemu.com | shalafi@xs4all.nl
24 Version 1.0.001 - 4-10-2004
26 - Added support for 16, 24 and 32 bit textures;
27 - Added support for 16, 24 and 32 bit texture rendering;
29 Version 1.0.002 - 6-10-2004
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);
42 #include "sdlemu_opengl.h"
46 // We want alpha on our OpenGL contexts...!
47 // Or do we? Seems to kill performance on X...
48 // Or does it? Could it be bad blitter performance?
49 #define WANT_OPENGL_ALPHA
51 static SDL_Surface *texture = 0;
52 static GLuint texid = 0;
53 static GLfloat texcoord[4];
54 static unsigned int glFilter;
55 static unsigned int texturebpp = 0; // 16, 24 or 32 bpp
57 static SDL_Surface * overlay = 0;
58 static GLuint overlayID = 0;
59 static GLfloat overlayCoord[4];
60 void sdlemu_create_overlay(SDL_Surface * dst, int src_bpp);
62 static int showOverlay = 0;
64 static inline int power_of_two(int input)
74 void sdlemu_init_opengl(SDL_Surface * src, SDL_Surface * dst, int texturetype, int filter, int src_bpp)
76 WriteLog("\nOpenGL driver information :\n");
78 WriteLog("Vendor: %s\n", glGetString(GL_VENDOR));
79 WriteLog("Renderer: %s\n", glGetString(GL_RENDERER));
80 WriteLog("Version: %s\n", glGetString(GL_VERSION));
81 WriteLog("OpenGL drawmethod: ");
86 WriteLog("GL_QUAD rendering\n\n");
89 WriteLog("GL_TRIANGLE rendering\n\n");
95 // Let us create the texture information :
96 sdlemu_create_texture(src, dst, filter, src_bpp);
97 sdlemu_create_overlay(dst, src_bpp);
100 void sdlemu_draw_texture(SDL_Surface * dst, SDL_Surface * src, int texturetype)
103 This is needed when we want to render OpenGL textures with the Alpha mask set.
104 Be warned! This only works with the bpp of texture en *src set to 32.
106 #ifdef WANT_OPENGL_ALPHA
110 /* Save the alpha blending attributes */
111 saved_flags = src->flags&(SDL_SRCALPHA|SDL_RLEACCELOK);
112 saved_alpha = src->format->alpha;
113 if ( (saved_flags & SDL_SRCALPHA) == SDL_SRCALPHA ) {
114 SDL_SetAlpha(src, 0, 0);
117 // Blit the src display to the texture.
118 SDL_BlitSurface(src, NULL, texture, NULL);
120 /* Restore the alpha blending attributes */
121 if ( (saved_flags & SDL_SRCALPHA) == SDL_SRCALPHA ) {
122 SDL_SetAlpha(src, saved_flags, saved_alpha);
125 SDL_BlitSurface(src, NULL, texture, NULL);
127 // SDL_BlitSurface(src, NULL, overlay, NULL);
128 /*Uint32 * pix = (Uint32 *)overlay->pixels;
130 for(y=10; y<200; y++)
131 for(x=30; x<250; x++)
132 pix[x+(y*1024)] = 0x800000FF;//*/
134 glBlendFunc(GL_ONE, GL_ZERO);
135 glBindTexture(GL_TEXTURE_2D, texid);
136 // Texturemap complete texture to surface so we have free scaling
141 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, texture->w, texture->h,
142 GL_RGB, GL_UNSIGNED_SHORT_5_6_5, texture->pixels);
145 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, texture->w, texture->h,
146 GL_RGB, GL_UNSIGNED_BYTE, texture->pixels);
150 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, texture->w, texture->h,
151 GL_RGBA, GL_UNSIGNED_BYTE, texture->pixels);
155 // Render the texture to the screen using OpenGL!
160 glTexCoord2f(texcoord[0], texcoord[1]);
162 glTexCoord2f(texcoord[2], texcoord[1]);
163 glVertex2f(dst->w, 0);
164 glTexCoord2f(texcoord[2], texcoord[3]);
165 glVertex2f(dst->w, dst->h);
166 glTexCoord2f(texcoord[0], texcoord[3]);
167 glVertex2f(0, dst->h);
171 glBegin(GL_TRIANGLE_STRIP);
172 glTexCoord2f(texcoord[0], texcoord[1]); glVertex3i(0, 0, 0);
173 glTexCoord2f(texcoord[2], texcoord[1]); glVertex3i(dst->w, 0, 0);
174 glTexCoord2f(texcoord[0], texcoord[3]); glVertex3i(0, dst->h, 0);
175 glTexCoord2f(texcoord[2], texcoord[3]); glVertex3i(dst->w, dst->h, 0);
181 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
182 glBindTexture(GL_TEXTURE_2D, overlayID);
183 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, overlay->w, overlay->h, GL_RGBA, GL_UNSIGNED_BYTE, overlay->pixels);
185 glTexCoord2f(overlayCoord[0], overlayCoord[1]);
187 glTexCoord2f(overlayCoord[2], overlayCoord[1]);
188 glVertex2f(dst->w, 0);
189 glTexCoord2f(overlayCoord[2], overlayCoord[3]);
190 glVertex2f(dst->w, dst->h);
191 glTexCoord2f(overlayCoord[0], overlayCoord[3]);
192 glVertex2f(0, dst->h);
196 //Do some OpenGL stuff here...
198 /*unsigned long int map[25] = {
199 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
200 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
201 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
202 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
203 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF
205 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
206 glRasterPos2i(10, 10);
207 glDrawPixels(5, 5, GL_RGBA, GL_UNSIGNED_INT, map);//*/
210 SDL_GL_SwapBuffers();
214 void sdlemu_close_opengl(void)
217 SDL_FreeSurface(texture);
220 SDL_FreeSurface(overlay);
223 void sdlemu_create_texture(SDL_Surface * src, SDL_Surface * dst, int filter, int src_bpp)
226 int w , h; // w and h contain the width and height of the OpenGL texture.
227 Uint32 rmask, gmask, bmask, amask; // Needed for creating RGBA masks.
230 // Delete old texture (if allocated). Useful when there is a screen resize.
232 SDL_FreeSurface(texture);
234 // Texture width/height should be power of 2 of the SDL_Surface *src when using OpenGL.
235 // So, find the largest power of two that will contain both the width and height
236 w = power_of_two(src->w);
237 h = power_of_two(src->h);
239 WriteLog("OpenGL - Texture size : %d x %d\n", w, h);
241 // Setting bpp based upon src_bpp.
244 // We allow the developer to set its own texture bpp. But if the value is NULL or
245 // not equal to 16, 24 or 32, we make the texturebpp the same as the BPP from src.
246 if (bpp == 16 || bpp == 24 || bpp == 32)
249 texturebpp = src->format->BitsPerPixel;
251 WriteLog("OpenGL - Texture depth : %d bpp\n", texturebpp);
253 // Now were are going to create a SDL_Surface named texture. This will be our surface
254 // which will function as a buffer between the SDL_Surface *src and SDL_Surface *dst.
255 // This buffer is needed because we need to convert the SDL_Surface *src to an OpenGL
256 // texture with a depth of 16, 24 or 32 bpp, before we can blit the pixels to *dst
259 // NOTE: Seems the byte order here *is* important!
262 case 16: // *src has depth of 16 bpp
264 According to information on the SDL mailinglist and on internet, the following
265 rgba masks should be the ones to use. But somehow the screen gets f*cked up and
266 the RGB colours are incorrect (at least in Virtual Jaguar/SDL).
268 Compile with -DOPENGL_16BPP_CORRECT_RGBA to use this RGBA values.
270 #ifdef OPENGL_16BPP_CORRECT_RGBA
282 case 24: // *src has depth of 24 bpp
283 #if SDL_BYTEORDER == SDL_BIG_ENDIAN
287 amask = 0x00000000; // IMPORTANT! 24 bpp doesn't use Alpha (at least in our case).
292 amask = 0x00000000; // IMPORTANT! 24 bpp doesn't use Alpha (at least in our case).
295 case 32: //*src has depth of 32 bpp
296 default: //which is also the default.
297 #if SDL_BYTEORDER == SDL_BIG_ENDIAN
311 // Creating SDL_Surface texture based upon the above settings.
312 texture = SDL_CreateRGBSurface(SDL_SWSURFACE, w, h, texturebpp, rmask, gmask, bmask, amask);
316 WriteLog("sdlemu_opengl: Could not create texture surface! (SDL: %s)\n", SDL_GetError());
321 glDisable(GL_LIGHTING);
322 glDisable(GL_CULL_FACE);
323 glDisable(GL_DEPTH_TEST);
324 // glDisable(GL_BLEND);
326 glDisable(GL_NORMALIZE);
327 glDisable(GL_ALPHA_TEST);
328 glEnable(GL_TEXTURE_2D);
329 // glBlendFunc(GL_SRC_ALPHA, GL_ONE);
330 // glBlendFunc(GL_ONE, GL_SRC_ALPHA);
331 //This works, but in a wrong way...
332 // glBlendFunc(GL_ONE, GL_ONE);
334 // Definitely needed for screen resolution larger then the *src.
335 // This way we can have automatic scaling functionality.
336 glViewport(0, 0, dst->w, dst->h);
337 glMatrixMode(GL_PROJECTION);
340 glOrtho(0.0, (GLdouble)dst->w, (GLdouble)dst->h, 0.0, 0.0, 1.0);
341 glMatrixMode(GL_MODELVIEW);
345 // Setting up the texture coordinates.
348 texcoord[2] = (GLfloat)(src->w) / texture->w;
349 texcoord[3] = (GLfloat)(src->h) / texture->h;
351 // create a RGB(A) texture for the texture surface
352 glGenTextures(1, &texid);
353 glBindTexture(GL_TEXTURE_2D, texid);
355 // Setting up the OpenGL Filters. These filters are important when we/you
356 // want to scale the texture.
359 // Textures are rendered in best quality.
360 WriteLog("OpenGL filters: enabled\n");
361 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
362 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
366 // Textures are rendered in normal quality.
367 WriteLog("OpenGL filters: disabled\n");
368 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
369 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
372 // Setting texture mode.
373 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
374 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
376 // Generate the texture using the above information.
380 // Normal 16bpp depth based textures consist out of GL_RGB5 and doesn't have support for Alpha channels.
381 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB5, texture->w, texture->h, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
384 // The 24bpp depth based textures consist out of GL_RGB8 and doesn't have support for Alpha channels.
386 // IMPORTANT : If you don't use Alpha. Use textures with a depth of 16bpp.
387 // If you use Alpha. Use textures with a depth of 32bpp.
388 // 24bpp textures are SLOW and avoid them at all costs!
389 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, texture->w, texture->h, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
393 // The 32bpp depth based textures consist out of GL_RGBA8 and has support for Alpha channels.
394 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, texture->w, texture->h, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
399 void sdlemu_create_overlay(SDL_Surface * dst, int src_bpp)
402 Uint32 rmask, gmask, bmask, amask; // Needed for creating RGBA masks.
404 // Delete old texture (if allocated). Useful when there is a screen resize.
406 SDL_FreeSurface(overlay);
408 // Texture width/height should be power of 2 of the SDL_Surface *src when using OpenGL.
409 // So, find the largest power of two that will contain both the width and height
410 int w = power_of_two(dst->w);
411 int h = power_of_two(dst->h);
413 WriteLog("OpenGL - Overlay size : %d x %d\n", w, h);
415 // Setting bpp based upon src_bpp.
418 // We allow the developer to set its own texture bpp. But if the value is NULL or
419 // not equal to 16, 24 or 32, we make the texturebpp the same as the BPP from src.
420 if (bpp == 16 || bpp == 24 || bpp == 32)
423 texturebpp = dst->format->BitsPerPixel;
425 WriteLog("OpenGL - Overlay depth : %d bpp\n", texturebpp);
427 // Now were are going to create a SDL_Surface named texture. This will be our surface
428 // which will function as a buffer between the SDL_Surface *src and SDL_Surface *dst.
429 // This buffer is needed because we need to convert the SDL_Surface *src to an OpenGL
430 // texture with a depth of 16, 24 or 32 bpp, before we can blit the pixels to *dst
433 // NOTE: Seems the byte order here *is* important!
436 case 16: // *src has depth of 16 bpp
438 According to information on the SDL mailinglist and on internet, the following
439 rgba masks should be the ones to use. But somehow the screen gets f*cked up and
440 the RGB colours are incorrect (at least in Virtual Jaguar/SDL).
442 Compile with -DOPENGL_16BPP_CORRECT_RGBA to use this RGBA values.
444 #ifdef OPENGL_16BPP_CORRECT_RGBA
456 case 24: // *src has depth of 24 bpp
457 #if SDL_BYTEORDER == SDL_BIG_ENDIAN
461 amask = 0x00000000; // IMPORTANT! 24 bpp doesn't use Alpha (at least in our case).
466 amask = 0x00000000; // IMPORTANT! 24 bpp doesn't use Alpha (at least in our case).
469 case 32: //*src has depth of 32 bpp
470 default: //which is also the default.
471 #if SDL_BYTEORDER == SDL_BIG_ENDIAN
485 // Creating SDL_Surface texture based upon the above settings.
486 overlay = SDL_CreateRGBSurface(SDL_SWSURFACE, w, h, texturebpp, rmask, gmask, bmask, amask);
490 WriteLog("sdlemu_opengl: Could not create overlay surface! (SDL: %s)\n", SDL_GetError());
493 // Setting up the texture coordinates.
494 overlayCoord[0] = 0.0f;
495 overlayCoord[1] = 0.0f;
496 overlayCoord[2] = (GLfloat)(dst->w) / overlay->w;
497 overlayCoord[3] = (GLfloat)(dst->h) / overlay->h;
499 // create a RGB(A) texture for the texture surface
500 glGenTextures(1, &overlayID);
501 glBindTexture(GL_TEXTURE_2D, overlayID);
503 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
504 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
506 // Setting texture mode.
507 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
508 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
510 // Generate the texture using the above information.
514 // Normal 16bpp depth based textures consist out of GL_RGB5 and doesn't have support for Alpha channels.
515 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB5, overlay->w, overlay->h, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
518 // The 24bpp depth based textures consist out of GL_RGB8 and doesn't have support for Alpha channels.
520 // IMPORTANT : If you don't use Alpha. Use textures with a depth of 16bpp.
521 // If you use Alpha. Use textures with a depth of 32bpp.
522 // 24bpp textures are SLOW and avoid them at all costs!
523 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, overlay->w, overlay->h, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
527 // The 32bpp depth based textures consist out of GL_RGBA8 and has support for Alpha channels.
528 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, overlay->w, overlay->h, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
533 void * sdlemuGetOverlayPixels(void)
535 return overlay->pixels;
538 Uint32 sdlemuGetOverlayWidthInPixels(void)
540 return overlay->pitch / 4;
543 void sdlemuEnableOverlay(void)
548 void sdlemuDisableOverlay(void)