1 /*(LGPL)
2 ------------------------------------------------------------
3 glSDL 0.7 - SDL 2D API on top of OpenGL
4 ------------------------------------------------------------
5 * (c) David Olofson, 2001-2004
6 * This code is released under the terms of the GNU LGPL.
7 */
8
9 #define _GLSDL_NO_REDEFINES_
10 #include "glSDL.h"
11
12 #ifdef HAVE_OPENGL
13
14 #define LEAK_TRACKING
15
16 #define DBG(x) /*error messages, warnings*/
17 #define DBG2(x) /*texture allocation*/
18 #define DBG3(x) /*chopping/tiling*/
19 #define DBG4(x) /*texture uploading*/
20 #define DBG5(x) /*two-way chopping/tiling*/
21 #define DBG6(x) /*OpenGL lib loading*/
22
23 /*#define CKSTATS*/ /*colorkey statistics*/
24
25 /* Keep this on for now! Makes large surfaces faster. */
26 #define FAKE_MAXTEXSIZE 256
27
28 #include <string.h>
29 #include <stdlib.h>
30 #include <math.h>
31
32 #if HAS_SDL_OPENGL_H
33 #include "SDL_opengl.h"
34 #else
35 #ifdef WIN32
36 #include <windows.h>
37 #endif
38 #if defined(__APPLE__) && defined(__MACH__)
39 #include <OpenGL/gl.h>
40 #include <OpenGL/glu.h>
41 #else
42 #include <GL/gl.h>
43 #include <GL/glu.h>
44 #endif
45 #endif
46
47 /*----------------------------------------------------------
48 OpenGL interface
49 ----------------------------------------------------------*/
50
51 static struct
52 {
53 void (APIENTRY *Begin)(GLenum);
54 void (APIENTRY *BindTexture)(GLenum, GLuint);
55 void (APIENTRY *BlendFunc)(GLenum, GLenum);
56 void (APIENTRY *Color4ub)(GLubyte red, GLubyte green, GLubyte blue, GLubyte alpha);
57 void (APIENTRY *Color3ub)(GLubyte red, GLubyte green, GLubyte blue);
58 void (APIENTRY *DeleteTextures)(GLsizei n, const GLuint *textures);
59 void (APIENTRY *Disable)(GLenum cap);
60 void (APIENTRY *Enable)(GLenum cap);
61 void (APIENTRY *End)(void);
62 void (APIENTRY *Flush)(void);
63 void (APIENTRY *GenTextures)(GLsizei n, GLuint *textures);
64 GLenum (APIENTRY *GetError)(void);
65 void (APIENTRY *GetIntegerv)(GLenum pname, GLint *params);
66 void (APIENTRY *LoadIdentity)(void);
67 void (APIENTRY *MatrixMode)(GLenum mode);
68 void (APIENTRY *Ortho)(GLdouble left, GLdouble right, GLdouble bottom,
69 GLdouble top, GLdouble zNear, GLdouble zFar);
70 void (APIENTRY *PixelStorei)(GLenum pname, GLint param);
71 void (APIENTRY *ReadPixels)(GLint x, GLint y, GLsizei width, GLsizei height,
72 GLenum format, GLenum type, GLvoid *pixels);
73 void (APIENTRY *TexCoord2f)(GLfloat s, GLfloat t);
74 void (APIENTRY *TexImage2D)(GLenum target, GLint level, GLint internalformat,
75 GLsizei width, GLsizei height, GLint border,
76 GLenum format, GLenum type, const GLvoid *pixels);
77 void (APIENTRY *TexParameteri)(GLenum target, GLenum pname, GLint param);
78 void (APIENTRY *TexSubImage2D)(GLenum target, GLint level,
79 GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
80 GLenum format, GLenum type, const GLvoid *pixels);
81 void (APIENTRY *Translatef)(GLfloat x, GLfloat y, GLfloat z);
82 void (APIENTRY *Vertex2i)(GLint x, GLint y);
83 void (APIENTRY *Viewport)(GLint x, GLint y, GLsizei width, GLsizei height);
84 } gl;
85
86
GetGL(void)87 static int GetGL(void)
88 {
89 int i;
90 struct
91 {
92 const char *name;
93 void **fn;
94 } glfuncs[] = {
95 {"glBegin", (void *)&gl.Begin },
96 {"glBindTexture", (void *)&gl.BindTexture },
97 {"glBlendFunc", (void *)&gl.BlendFunc },
98 {"glColor4ub", (void *)&gl.Color4ub },
99 {"glColor3ub", (void *)&gl.Color3ub },
100 {"glDeleteTextures", (void *)&gl.DeleteTextures },
101 {"glDisable", (void *)&gl.Disable },
102 {"glEnable", (void *)&gl.Enable },
103 {"glEnd", (void *)&gl.End },
104 {"glFlush", (void *)&gl.Flush },
105 {"glGenTextures", (void *)&gl.GenTextures },
106 {"glGetError", (void *)&gl.GetError },
107 {"glGetIntegerv", (void *)&gl.GetIntegerv },
108 {"glLoadIdentity", (void *)&gl.LoadIdentity },
109 {"glMatrixMode", (void *)&gl.MatrixMode },
110 {"glOrtho", (void *)&gl.Ortho },
111 {"glPixelStorei", (void *)&gl.PixelStorei },
112 {"glReadPixels", (void *)&gl.ReadPixels },
113 {"glTexCoord2f", (void *)&gl.TexCoord2f },
114 {"glTexImage2D", (void *)&gl.TexImage2D },
115 {"glTexParameteri", (void *)&gl.TexParameteri },
116 {"glTexSubImage2D", (void *)&gl.TexSubImage2D },
117 {"glTranslatef", (void *)&gl.Translatef },
118 {"glVertex2i", (void *)&gl.Vertex2i },
119 {"glViewport", (void *)&gl.Viewport },
120 {NULL, NULL }
121 };
122 for(i = 0; glfuncs[i].name; ++i)
123 {
124 *glfuncs[i].fn = SDL_GL_GetProcAddress(glfuncs[i].name);
125 if(!*glfuncs[i].fn)
126 {
127 DBG6(fprintf(stderr,"glSDL/wrapper ERROR: Could not get "
128 "OpenGL function '%s'!\n",
129 glfuncs[i].name);)
130 return -1;
131 }
132 DBG6(printf("Got OpenGL function '%s'.\n", glfuncs[i].name);)
133 }
134 return 0;
135 }
136
137
LoadGL(void)138 static int LoadGL(void)
139 {
140 if(GetGL() < 0)
141 {
142 DBG6(printf("Couldn't get GL funcs! Trying to load lib...\n");)
143 SDL_GL_LoadLibrary(NULL);
144 if(GetGL() < 0)
145 {
146 DBG6(printf("Still couldn't get GL funcs!\n");)
147 return -1;
148 }
149 }
150 return 0;
151 }
152
153
UnloadGL(void)154 static void UnloadGL(void)
155 {
156 }
157
158
print_glerror(int point)159 static void print_glerror(int point)
160 {
161 #if (DBG(1)+0 == 1)
162 const char *err = "<unknown>";
163 switch(gl.GetError())
164 {
165 case GL_NO_ERROR:
166 return;
167 case GL_INVALID_ENUM:
168 err = "GL_INVALID_ENUM";
169 break;
170 case GL_INVALID_VALUE:
171 err = "GL_INVALID_VALUE";
172 break;
173 case GL_INVALID_OPERATION:
174 err = "GL_INVALID_OPERATION";
175 break;
176 case GL_STACK_OVERFLOW:
177 err = "GL_STACK_OVERFLOW";
178 break;
179 case GL_STACK_UNDERFLOW:
180 err = "GL_STACK_UNDERFLOW";
181 break;
182 case GL_OUT_OF_MEMORY:
183 err = "GL_OUT_OF_MEMORY";
184 break;
185 default:
186 err = "<unknown>";
187 break;
188 }
189 fprintf(stderr,"OpenGL error \"%s\" at point %d.\n", err, point);
190 #endif
191 }
192
193
194 static struct
195 {
196 int do_blend;
197 int do_texture;
198 GLint texture;
199 GLenum sfactor, dfactor;
200 } glstate;
201
gl_reset(void)202 static void gl_reset(void)
203 {
204 glstate.do_blend = -1;
205 glstate.do_blend = -1;
206 glstate.texture = -1;
207 glstate.sfactor = 0xffffffff;
208 glstate.dfactor = 0xffffffff;
209 }
210
gl_do_blend(int on)211 static __inline__ void gl_do_blend(int on)
212 {
213 if(glstate.do_blend == on)
214 return;
215
216 if(on)
217 gl.Enable(GL_BLEND);
218 else
219 gl.Disable(GL_BLEND);
220 glstate.do_blend = on;
221 }
222
gl_do_texture(int on)223 static __inline__ void gl_do_texture(int on)
224 {
225 if(glstate.do_texture == on)
226 return;
227
228 if(on)
229 gl.Enable(GL_TEXTURE_2D);
230 else
231 gl.Disable(GL_TEXTURE_2D);
232 glstate.do_texture = on;
233 }
234
gl_blendfunc(GLenum sfactor,GLenum dfactor)235 static __inline__ void gl_blendfunc(GLenum sfactor, GLenum dfactor)
236 {
237 if((sfactor == glstate.sfactor) && (dfactor == glstate.dfactor))
238 return;
239
240 gl.BlendFunc(sfactor, dfactor);
241
242 glstate.sfactor = sfactor;
243 glstate.dfactor = dfactor;
244 }
245
gl_texture(GLuint tx)246 static __inline__ void gl_texture(GLuint tx)
247 {
248 if(tx == glstate.texture)
249 return;
250
251 gl.BindTexture(GL_TEXTURE_2D, tx);
252 glstate.texture = tx;
253 }
254
255
256 /*----------------------------------------------------------
257 Global stuff
258 ----------------------------------------------------------*/
259
260 static int using_glsdl = 0;
261 #define USING_GLSDL (0 != using_glsdl)
262
263 #define MAX_TEXINFOS 16384
264
265 static glSDL_TexInfo **texinfotab = NULL;
266 static GLint maxtexsize = 256;
267 static SDL_PixelFormat RGBfmt, RGBAfmt;
268
269 static void UnloadTexture(glSDL_TexInfo *txi);
270
271 static int scale = 1;
272
273 static SDL_Surface *fake_screen = NULL;
274
275
276 static int glSDL_BlitGL(SDL_Surface *src, SDL_Rect *srcrect,
277 SDL_Surface *dst, SDL_Rect *dstrect);
278
279
280 /* Get texinfo for a surface. */
glSDL_GetTexInfo(SDL_Surface * surface)281 glSDL_TexInfo *glSDL_GetTexInfo(SDL_Surface *surface)
282 {
283 if(texinfotab && (surface->unused1 > 0 && surface->unused1 < MAX_TEXINFOS))
284 return texinfotab[surface->unused1];
285 else
286 return NULL;
287 }
288
289
290 /* Allocate a "blank" texinfo for a suface. */
glSDL_AllocTexInfo(SDL_Surface * surface)291 glSDL_TexInfo *glSDL_AllocTexInfo(SDL_Surface *surface)
292 {
293 int handle, i = 0;
294 glSDL_TexInfo *txi;
295 if(!surface)
296 return NULL;
297
298 txi = glSDL_GetTexInfo(surface);
299 if(txi)
300 return txi; /* There already is one! --> */
301
302 /* Find a free handle... */
303 handle = -1;
304 for(i = 1; i < MAX_TEXINFOS + 1; ++i)
305 if(NULL == texinfotab[i])
306 {
307 handle = i;
308 break;
309 }
310
311 if(handle < 0)
312 {
313 DBG(fprintf(stderr, "glSDL/wrapper: Out of handles!\n"));
314 return NULL;
315 }
316
317 /* ...and hook a new texinfo struct up to it. */
318 texinfotab[handle] = calloc(1, sizeof(glSDL_TexInfo));
319 if(!texinfotab[handle])
320 return NULL;
321
322 /* Connect the surface to the new TexInfo. */
323 surface->unused1 = (Uint32)handle;
324
325 DBG2(fprintf(stderr, "glSDL/wrapper: Allocated TexInfo %d.\n", handle));
326
327 return texinfotab[handle];
328 }
329
330
FreeTexInfo(Uint32 handle)331 static void FreeTexInfo(Uint32 handle)
332 {
333 if(handle >= MAX_TEXINFOS)
334 return;
335 if(!texinfotab[handle])
336 return;
337
338 UnloadTexture(texinfotab[handle]);
339 texinfotab[handle]->textures = 0;
340 free(texinfotab[handle]->texture);
341 texinfotab[handle]->texture = NULL;
342 free(texinfotab[handle]);
343 texinfotab[handle] = NULL;
344 DBG2(fprintf(stderr, "glSDL/wrapper: Freed TexInfo %d.\n", handle));
345 }
346
347
348 /* Detach and free the texinfo of a surface. */
glSDL_FreeTexInfo(SDL_Surface * surface)349 void glSDL_FreeTexInfo(SDL_Surface *surface)
350 {
351 if(!texinfotab)
352 return;
353
354 if(!surface)
355 return;
356
357 if(!glSDL_GetTexInfo(surface))
358 return;
359
360 FreeTexInfo(surface->unused1);
361 GLSDL_FIX_SURFACE(surface);
362 }
363
364
365 /*
366 * Calculate chopping/tiling of a surface to
367 * fit it into the smallest possible OpenGL
368 * texture.
369 */
CalcChop(SDL_Surface * s,glSDL_TexInfo * txi)370 static int CalcChop(SDL_Surface *s, glSDL_TexInfo *txi)
371 {
372 int rows, vw, vh;
373 int vertical = 0;
374 int texsize;
375 int lastw, lasth, minsize;
376
377 vw = s->w;
378 vh = s->h;
379
380 DBG3(fprintf(stderr, "w=%d, h=%d ", vw, vh));
381 if(vh > vw)
382 {
383 int t = vw;
384 vw = vh;
385 vh = t;
386 vertical = 1;
387 DBG3(fprintf(stderr, "(vertical) \t"));
388 }
389
390 /*
391 * Check whether this is a "huge" surface - at least one dimension
392 * must be <= than the maximum texture size, or we'll have to chop
393 * in both directions.
394 */
395 if(vh > maxtexsize)
396 {
397 /*
398 * Very simple hack for now; we just tile
399 * both ways with maximum size textures.
400 */
401 texsize = maxtexsize;
402
403 txi->tilemode = GLSDL_TM_HUGE;
404 txi->texsize = texsize;
405 txi->tilew = texsize;
406 txi->tileh = texsize;
407 txi->tilespertex = 1;
408
409 /* Calculate number of textures needed */
410 txi->textures = (vw + texsize - 1) / texsize;
411 txi->textures *= (vh + texsize - 1) / texsize;
412 txi->texture = malloc(txi->textures * sizeof(int));
413 memset(txi->texture, -1, txi->textures * sizeof(int));
414 DBG5(fprintf(stderr, "two-way tiling; textures=%d\n", txi->textures));
415 if(!txi->texture)
416 {
417 fprintf(stderr, "glSDL/wrapper: INTERNAL ERROR: Failed to allocate"
418 " texture name table!\n");
419 return -3;
420 }
421 return 0;
422 }
423
424 /* Calculate minimum size */
425 rows = 1;
426 lastw = vw;
427 lasth = vh;
428 minsize = lastw > lasth ? lastw : lasth;
429 while(1)
430 {
431 int w, h, size;
432 ++rows;
433 w = vw / rows;
434 h = rows * vh;
435 size = w > h ? w : h;
436 if(size >= minsize)
437 {
438 --rows;
439 break;
440 }
441 lastw = w;
442 lasth = h;
443 minsize = size;
444 }
445 if(minsize > maxtexsize)
446 {
447 /* Handle multiple textures for very wide/tall surfaces. */
448 minsize = maxtexsize;
449 rows = (vw + minsize-1) / minsize;
450 }
451 DBG3(fprintf(stderr, "==> minsize=%d ", minsize));
452 DBG3(fprintf(stderr, "(rows=%d) \t", rows));
453
454 /* Recalculate with nearest higher power-of-2 width. */
455 for(texsize = 1; texsize < minsize; texsize <<= 1)
456 ;
457 txi->texsize = texsize;
458 rows = (vw + texsize-1) / texsize;
459 DBG3(fprintf(stderr, "==> texsize=%d (rows=%d) \t", texsize, rows));
460
461 /* Calculate number of tiles per texture */
462 txi->tilespertex = txi->texsize / vh;
463 DBG3(fprintf(stderr, "tilespertex=%d \t", txi->tilespertex));
464
465 /* Calculate number of textures needed */
466 txi->textures = (rows + txi->tilespertex-1) / txi->tilespertex;
467 txi->texture = malloc(txi->textures * sizeof(int));
468 memset(txi->texture, -1, txi->textures * sizeof(int));
469 DBG3(fprintf(stderr, "textures=%d, ", txi->textures));
470 if(!txi->texture)
471 {
472 fprintf(stderr, "glSDL/wrapper: INTERNAL ERROR: Failed to allocate"
473 " texture name table!\n");
474 return -2;
475 }
476
477 /* Set up tile size. (Only one axis supported here!) */
478 if(1 == rows)
479 {
480 txi->tilemode = GLSDL_TM_SINGLE;
481 if(vertical)
482 {
483 txi->tilew = vh;
484 txi->tileh = vw;
485 }
486 else
487 {
488 txi->tilew = vw;
489 txi->tileh = vh;
490 }
491 }
492 else if(vertical)
493 {
494 txi->tilemode = GLSDL_TM_VERTICAL;
495 txi->tilew = vh;
496 txi->tileh = texsize;
497 }
498 else
499 {
500 txi->tilemode = GLSDL_TM_HORIZONTAL;
501 txi->tilew = texsize;
502 txi->tileh = vh;
503 }
504
505 DBG3(fprintf(stderr, "tilew=%d, tileh=%d\n", txi->tilew, txi->tileh));
506 return 0;
507 }
508
509
510 /* Add a glSDL_TexInfo struct to an SDL_Surface */
glSDL_AddTexInfo(SDL_Surface * surface)511 static int glSDL_AddTexInfo(SDL_Surface *surface)
512 {
513 glSDL_TexInfo *txi;
514
515 if(!surface)
516 return -1;
517 if(IS_GLSDL_SURFACE(surface))
518 return 0; /* Do nothing */
519
520 glSDL_AllocTexInfo(surface);
521 txi = glSDL_GetTexInfo(surface);
522 if(!txi)
523 return -2; /* Oops! Didn't get a texinfo... --> */
524
525 if(CalcChop(surface, txi) < 0)
526 return -3;
527
528 SDL_SetClipRect(surface, NULL);
529
530 return 0;
531 }
532
533
534 /* Create a surface of the prefered OpenGL RGB texture format */
CreateRGBSurface(int w,int h)535 static SDL_Surface *CreateRGBSurface(int w, int h)
536 {
537 SDL_Surface *s;
538 Uint32 rmask, gmask, bmask;
539 int bits = 24;
540 #if SDL_BYTEORDER == SDL_BIG_ENDIAN
541 rmask = 0x00ff0000;
542 gmask = 0x0000ff00;
543 bmask = 0x000000ff;
544 #else
545 rmask = 0x000000ff;
546 gmask = 0x0000ff00;
547 bmask = 0x00ff0000;
548 #endif
549 s = SDL_CreateRGBSurface(SDL_SWSURFACE, w, h,
550 bits, rmask, gmask, bmask, 0);
551 if(s)
552 GLSDL_FIX_SURFACE(s);
553
554 glSDL_AddTexInfo(s);
555 return s;
556 }
557
558
559 /* Create a surface of the prefered OpenGL RGBA texture format */
CreateRGBASurface(int w,int h)560 static SDL_Surface *CreateRGBASurface(int w, int h)
561 {
562 SDL_Surface *s;
563 Uint32 rmask, gmask, bmask, amask;
564 int bits = 32;
565 #if SDL_BYTEORDER == SDL_BIG_ENDIAN
566 rmask = 0xff000000;
567 gmask = 0x00ff0000;
568 bmask = 0x0000ff00;
569 amask = 0x000000ff;
570 #else
571 rmask = 0x000000ff;
572 gmask = 0x0000ff00;
573 bmask = 0x00ff0000;
574 amask = 0xff000000;
575 #endif
576 s = SDL_CreateRGBSurface(SDL_SWSURFACE, w, h,
577 bits, rmask, gmask, bmask, amask);
578 if(s)
579 GLSDL_FIX_SURFACE(s);
580
581 glSDL_AddTexInfo(s);
582 return s;
583 }
584
585
init_formats(void)586 static void init_formats(void)
587 {
588 SDL_Surface *s = CreateRGBSurface(1, 1);
589 if(!s)
590 return;
591 RGBfmt = *(s->format);
592 glSDL_FreeSurface(s);
593
594 s = CreateRGBASurface(1, 1);
595 if(!s)
596 return;
597 RGBAfmt = *(s->format);
598 glSDL_FreeSurface(s);
599 }
600
601
FormatIsOk(SDL_Surface * surface)602 static int FormatIsOk(SDL_Surface *surface)
603 {
604 SDL_PixelFormat *pf;
605 if(!surface)
606 return 1; /* Well, there ain't much we can do anyway... */
607
608 pf = surface->format;
609
610 /* Colorkeying requires an alpha channel! */
611 if(surface->flags & SDL_SRCCOLORKEY)
612 if(!pf->Amask)
613 return 0;
614
615 /* We need pitch == (width * BytesPerPixel) for glTex[Sub]Image2D() */
616 if(surface->pitch != (surface->w * pf->BytesPerPixel))
617 return 0;
618
619 if(pf->Amask)
620 {
621 if(pf->BytesPerPixel != RGBAfmt.BytesPerPixel)
622 return 0;
623 if(pf->Rmask != RGBAfmt.Rmask)
624 return 0;
625 if(pf->Gmask != RGBAfmt.Gmask)
626 return 0;
627 if(pf->Bmask != RGBAfmt.Bmask)
628 return 0;
629 if(pf->Amask != RGBAfmt.Amask)
630 return 0;
631 }
632 else
633 {
634 if(pf->BytesPerPixel != RGBfmt.BytesPerPixel)
635 return 0;
636 if(pf->Rmask != RGBfmt.Rmask)
637 return 0;
638 if(pf->Gmask != RGBfmt.Gmask)
639 return 0;
640 if(pf->Bmask != RGBfmt.Bmask)
641 return 0;
642 }
643 return 1;
644 }
645
646
647
key2alpha(SDL_Surface * surface)648 static void key2alpha(SDL_Surface *surface)
649 {
650 int x, y;
651 #ifdef CKSTATS
652 int transp = 0;
653 #endif
654 Uint32 ckey = surface->format->colorkey;
655 if(SDL_LockSurface(surface) < 0)
656 return;
657
658 for(y = 0; y < surface->h; ++y)
659 {
660 Uint32 *px = (Uint32 *)((char *)surface->pixels + y*surface->pitch);
661 for(x = 0; x < surface->w; ++x)
662 if(px[x] == ckey)
663 {
664 px[x] = 0;
665 #ifdef CKSTATS
666 ++transp;
667 #endif
668 }
669 }
670 #ifdef CKSTATS
671 printf("glSDL/wrapper: key2alpha(); %dx%d surface, %d opaque pixels.\n",
672 surface->w, surface->h,
673 surface->w * surface->h - transp);
674 #endif
675 SDL_UnlockSurface(surface);
676 }
677
678
679
680 /*----------------------------------------------------------
681 SDL style API
682 ----------------------------------------------------------*/
683
KillAllTextures(void)684 static void KillAllTextures(void)
685 {
686 if(texinfotab)
687 {
688 unsigned i;
689 #ifdef LEAK_TRACKING
690 int leaked = 0;
691 for(i = 3; i < MAX_TEXINFOS + 1; ++i)
692 if(texinfotab[i])
693 {
694 ++leaked;
695 fprintf(stderr, "glSDL/wrapper: Leaked TexInfo"
696 " %d! (%d %dx%d textures)\n",
697 i,
698 texinfotab[i]->textures,
699 texinfotab[i]->texsize,
700 texinfotab[i]->texsize
701 );
702 }
703 if(leaked)
704 fprintf(stderr, "glSDL/wrapper: Leaked %d TexInfos!\n", leaked);
705 #endif
706 for(i = 1; i < MAX_TEXINFOS + 1; ++i)
707 FreeTexInfo(i);
708 free(texinfotab);
709 texinfotab = NULL;
710 }
711 }
712
glSDL_Quit(void)713 void glSDL_Quit(void)
714 {
715 if(SDL_WasInit(SDL_INIT_VIDEO))
716 {
717 /* SDL_Surface *screen = SDL_GetVideoSurface();
718 glSDL_FreeTexInfo(screen);
719 */
720 /* if(fake_screen)
721 {
722 glSDL_FreeTexInfo(fake_screen);
723 SDL_FreeSurface(fake_screen);
724 fake_screen = NULL;
725 }
726 */
727 UnloadGL();
728 SDL_QuitSubSystem(SDL_INIT_VIDEO);
729 }
730 #ifndef LEAK_TRACKING
731 KillAllTextures();
732 #endif
733 }
734
735
glSDL_FullQuit(void)736 void glSDL_FullQuit(void)
737 {
738 #ifdef LEAK_TRACKING
739 KillAllTextures();
740 #endif
741 glSDL_Quit();
742 SDL_Quit();
743 }
744
745
glSDL_QuitSubSystem(Uint32 flags)746 void glSDL_QuitSubSystem(Uint32 flags)
747 {
748 if(flags & SDL_INIT_VIDEO)
749 glSDL_Quit();
750 SDL_QuitSubSystem(flags);
751 }
752
753
glSDL_SetVideoMode(int width,int height,int bpp,Uint32 flags)754 SDL_Surface *glSDL_SetVideoMode(int width, int height, int bpp, Uint32 flags)
755 {
756 SDL_Surface *screen;
757 GLint gl_doublebuf;
758
759 using_glsdl = 0;
760
761 if(!(flags & SDL_GLSDL))
762 {
763 screen = SDL_SetVideoMode(width, height, bpp, flags);
764 if(screen)
765 GLSDL_FIX_SURFACE(screen);
766 return screen;
767 }
768
769 if((SDL_Linked_Version()->major <= 1) &&
770 (SDL_Linked_Version()->minor <= 2) &&
771 (SDL_Linked_Version()->patch < 5))
772 fprintf(stderr, "glSDL/wrapper WARNING: Using SDL version"
773 " 1.2.5 or later is strongly"
774 " recommended!\n");
775
776 if(LoadGL() < 0)
777 {
778 fprintf(stderr, "glSDL/wrapper ERROR: Could not load OpenGL library!\n");
779 return NULL;
780 }
781
782 /*
783 * FIXME: Here's the place to insert proper handling of this call being
784 * used for resizing the window... For now, just make sure we
785 * don't end up with invalid texinfos and stuff no matter what.
786 */
787 KillAllTextures();
788
789 texinfotab = calloc(MAX_TEXINFOS + 1, sizeof(glSDL_TexInfo *));
790 if(!texinfotab)
791 return NULL;
792
793 /* Remove flag to avoid confusion inside SDL - just in case! */
794 flags &= ~SDL_GLSDL;
795
796 flags |= SDL_OPENGL;
797 if(bpp == 15)
798 {
799 SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 5);
800 SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 5);
801 SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 5);
802 }
803 else if(bpp == 16)
804 {
805 SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 5);
806 SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 6);
807 SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 5);
808 }
809 else if(bpp >= 24)
810 {
811 SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);
812 SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8);
813 SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8);
814 }
815 gl_doublebuf = flags & SDL_DOUBLEBUF;
816 SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, gl_doublebuf);
817
818 scale = 1;
819
820 screen = SDL_SetVideoMode(width*scale, height*scale, bpp, flags);
821 if(!screen)
822 {
823 KillAllTextures();
824 return NULL;
825 }
826
827 GLSDL_FIX_SURFACE(screen);
828
829 #ifdef FAKE_MAXTEXSIZE
830 maxtexsize = FAKE_MAXTEXSIZE;
831 #else
832 gl.GetIntegerv(GL_MAX_TEXTURE_SIZE, &maxtexsize);
833 #endif
834 DBG(fprintf(stderr, "glSDL/wrapper: Max texture size: %d\n", maxtexsize));
835
836 init_formats();
837 gl_reset();
838
839 if(glSDL_AddTexInfo(screen) < 0)
840 {
841 DBG(fprintf(stderr, "glSDL/wrapper: Failed to add info to screen surface!\n"));
842 SDL_QuitSubSystem(SDL_INIT_VIDEO);
843 return NULL;
844 }
845
846 glSDL_SetClipRect(screen, &screen->clip_rect);
847
848 gl.Viewport(0, 0, screen->w * scale, screen->h * scale);
849 /*
850 * Note that this projection is upside down in
851 * relation to the OpenGL coordinate system.
852 */
853 gl.MatrixMode(GL_PROJECTION);
854 gl.LoadIdentity();
855 gl.Ortho(0, scale * (float)screen->w, scale * (float)screen->h, 0,
856 -1.0, 1.0);
857
858 gl.MatrixMode(GL_MODELVIEW);
859 gl.LoadIdentity();
860 gl.Translatef(0.0f, 0.0f, 0.0f);
861
862 gl.Disable(GL_DEPTH_TEST);
863 gl.Disable(GL_CULL_FACE);
864
865 /*
866 * Create a software shadow buffer of the requested size.
867 * This is used for blit-from-screen and simulation of
868 * direct software rendering. (Dog slow crap. It's only
869 * legitimate use is probably screen shots.)
870 */
871 fake_screen = CreateRGBSurface(screen->w / scale,
872 screen->h / scale);
873 using_glsdl = 1;
874 return fake_screen;
875 }
876
877
glSDL_GetVideoSurface(void)878 SDL_Surface *glSDL_GetVideoSurface(void)
879 {
880 if(fake_screen)
881 return fake_screen;
882 else
883 return SDL_GetVideoSurface();
884 }
885
886
glSDL_UpdateRects(SDL_Surface * screen,int numrects,SDL_Rect * rects)887 void glSDL_UpdateRects(SDL_Surface *screen, int numrects, SDL_Rect *rects)
888 {
889 if(IS_GLSDL_SURFACE(screen))
890 glSDL_Flip(screen);
891 else
892 SDL_UpdateRects(screen, numrects, rects);
893 }
894
895
glSDL_UpdateRect(SDL_Surface * screen,Sint32 x,Sint32 y,Uint32 w,Uint32 h)896 void glSDL_UpdateRect(SDL_Surface *screen, Sint32 x, Sint32 y, Uint32 w, Uint32 h)
897 {
898 SDL_Rect r;
899 r.x = x;
900 r.y = y;
901 r.w = w;
902 r.h = h;
903 glSDL_UpdateRects(screen, 1, &r);
904 }
905
906
glSDL_Flip(SDL_Surface * screen)907 int glSDL_Flip(SDL_Surface *screen)
908 {
909 if(!IS_GLSDL_SURFACE(screen))
910 return SDL_Flip(screen);
911
912 SDL_GL_SwapBuffers();
913 return 0;
914 }
915
916
glSDL_FreeSurface(SDL_Surface * surface)917 void glSDL_FreeSurface(SDL_Surface *surface)
918 {
919 if(!surface)
920 return;
921 glSDL_FreeTexInfo(surface);
922 SDL_FreeSurface(surface);
923 }
924
925
glSDL_LockSurface(SDL_Surface * surface)926 int glSDL_LockSurface(SDL_Surface *surface)
927 {
928 if(!surface)
929 return 0;
930
931 if(IS_GLSDL_SURFACE(surface))
932 {
933 if((surface == fake_screen) ||
934 (SDL_GetVideoSurface() == surface))
935 {
936 if(scale > 1)
937 return -1;
938
939 glSDL_Invalidate(fake_screen, NULL);
940
941 gl.PixelStorei(GL_UNPACK_ROW_LENGTH,
942 fake_screen->pitch /
943 fake_screen->format->BytesPerPixel);
944
945 gl.ReadPixels(0, 0, fake_screen->w, fake_screen->h,
946 GL_RGB, GL_UNSIGNED_BYTE,
947 fake_screen->pixels);
948 return 0;
949 }
950 else
951 {
952 glSDL_Invalidate(surface, NULL);
953 return SDL_LockSurface(surface);
954 }
955 }
956 else
957 return SDL_LockSurface(surface);
958 }
959
960
glSDL_UnlockSurface(SDL_Surface * surface)961 void glSDL_UnlockSurface(SDL_Surface *surface)
962 {
963 if(!surface)
964 return;
965
966 if(IS_GLSDL_SURFACE(surface))
967 {
968 glSDL_UploadSurface(surface);
969 if((surface == fake_screen) ||
970 (SDL_GetVideoSurface() == surface)) {
971 glSDL_BlitGL(fake_screen, NULL,
972 SDL_GetVideoSurface(), NULL);
973 return;
974 }
975 }
976 SDL_UnlockSurface(surface);
977 }
978
979
glSDL_SetColorKey(SDL_Surface * surface,Uint32 flag,Uint32 key)980 int glSDL_SetColorKey(SDL_Surface *surface, Uint32 flag, Uint32 key)
981 {
982 int res = SDL_SetColorKey(surface, flag, key);
983 if(res < 0)
984 return res;
985 /*
986 * If an application does this *after* SDL_DisplayFormat,
987 * we're basically screwed, unless we want to do an
988 * in-place surface conversion hack here.
989 *
990 * What we do is just kill the glSDL texinfo... No big
991 * deal in most cases, as glSDL only converts once anyway,
992 * *unless* you keep modifying the surface.
993 */
994 if(IS_GLSDL_SURFACE(surface))
995 glSDL_FreeTexInfo(surface);
996 return res;
997 }
998
999
glSDL_SetAlpha(SDL_Surface * surface,Uint32 flag,Uint8 alpha)1000 int glSDL_SetAlpha(SDL_Surface *surface, Uint32 flag, Uint8 alpha)
1001 {
1002 /*
1003 * This is just parameters to OpenGL, so the actual
1004 * "work" is done in glSDL_BlitSurface().
1005 */
1006 return SDL_SetAlpha(surface, flag, alpha);
1007 }
1008
1009
glSDL_SetClipRect(SDL_Surface * surface,SDL_Rect * rect)1010 SDL_bool glSDL_SetClipRect(SDL_Surface *surface, SDL_Rect *rect)
1011 {
1012 SDL_bool res;
1013 SDL_Surface *screen;
1014 SDL_Rect fsr;
1015 if(!surface)
1016 return SDL_FALSE;
1017
1018 screen = SDL_GetVideoSurface();
1019
1020 res = SDL_SetClipRect(surface, rect);
1021 if(!res)
1022 return SDL_FALSE;
1023
1024 if(!rect)
1025 {
1026 fsr.x = 0;
1027 fsr.y = 0;
1028 fsr.w = screen->w;
1029 fsr.h = screen->h;
1030 rect = &fsr;
1031 }
1032 if(surface == fake_screen)
1033 {
1034 SDL_Rect r;
1035 r.x = rect->x;
1036 r.y = rect->y;
1037 r.w = rect->w;
1038 r.h = rect->h;
1039 surface = screen;
1040 SDL_SetClipRect(surface, rect);
1041 return SDL_TRUE;
1042 }
1043 return res;
1044 }
1045
1046
glSDL_BlitFromGL(SDL_Rect * srcrect,SDL_Surface * dst,SDL_Rect * dstrect)1047 static int glSDL_BlitFromGL(SDL_Rect *srcrect,
1048 SDL_Surface *dst, SDL_Rect *dstrect)
1049 {
1050 int i, sy0, dy0;
1051 SDL_Rect sr, dr;
1052
1053 if(scale > 1)
1054 return -1;
1055 /*
1056 FIXME: Some clipping, perhaps...? :-)
1057 */
1058 /* In case the destination has an OpenGL texture... */
1059 glSDL_Invalidate(dst, dstrect);
1060
1061 /* Abuse the fake screen buffer a little. */
1062 gl.PixelStorei(GL_UNPACK_ROW_LENGTH, fake_screen->pitch /
1063 fake_screen->format->BytesPerPixel);
1064 if(srcrect)
1065 gl.ReadPixels(srcrect->x, srcrect->y, srcrect->w, srcrect->h,
1066 GL_RGB, GL_UNSIGNED_BYTE, fake_screen->pixels);
1067 else
1068 gl.ReadPixels(0, 0, fake_screen->w, fake_screen->h,
1069 GL_RGB, GL_UNSIGNED_BYTE, fake_screen->pixels);
1070
1071 /* Blit to the actual target! (Vert. flip... Uuurgh!) */
1072 if(srcrect)
1073 sr = *srcrect;
1074 else
1075 {
1076 sr.x = sr.y = 0;
1077 sr.w = dst->w;
1078 srcrect = &sr;
1079 }
1080
1081 if(dstrect)
1082 dr = *dstrect;
1083 else
1084 {
1085 dr.x = dr.y = 0;
1086 dstrect = &dr;
1087 }
1088
1089 i = srcrect->h;
1090 sy0 = srcrect->y;
1091 dy0 = dstrect->y + dstrect->h - 1;
1092 while(i--)
1093 {
1094 sr.y = sy0 + i;
1095 dr.y = dy0 - i;
1096 sr.h = 1;
1097 if(SDL_BlitSurface(fake_screen, &sr, dst, &dr) < 0)
1098 return -1;
1099 }
1100 return 0;
1101 }
1102
1103
BlitGL_single(glSDL_TexInfo * txi,float sx1,float sy1,SDL_Rect * dst,unsigned char alpha)1104 static __inline__ void BlitGL_single(glSDL_TexInfo *txi,
1105 float sx1, float sy1, SDL_Rect *dst, unsigned char alpha)
1106 {
1107 float sx2, sy2, texscale;
1108 if(!txi->textures)
1109 return;
1110 if(-1 == txi->texture[0])
1111 return;
1112 gl_texture(txi->texture[0]);
1113
1114 texscale = 1.0 / (float)txi->texsize;
1115 sx2 = (sx1 + (float)dst->w) * texscale;
1116 sy2 = (sy1 + (float)dst->h) * texscale;
1117 sx1 *= texscale;
1118 sy1 *= texscale;
1119
1120 gl.Begin(GL_QUADS);
1121 gl.Color4ub(255, 255, 255, alpha);
1122 gl.TexCoord2f(sx1, sy1);
1123 gl.Vertex2i(dst->x, dst->y);
1124 gl.TexCoord2f(sx2, sy1);
1125 gl.Vertex2i(dst->x + dst->w, dst->y);
1126 gl.TexCoord2f(sx2, sy2);
1127 gl.Vertex2i(dst->x + dst->w, dst->y + dst->h);
1128 gl.TexCoord2f(sx1, sy2);
1129 gl.Vertex2i(dst->x, dst->y + dst->h);
1130 gl.End();
1131 }
1132
1133
BlitGL_htile(glSDL_TexInfo * txi,float sx1,float sy1,SDL_Rect * dst,unsigned char alpha)1134 static void BlitGL_htile(glSDL_TexInfo *txi,
1135 float sx1, float sy1, SDL_Rect *dst, unsigned char alpha)
1136 {
1137 int tex;
1138 float tile, sx2, sy2, yo;
1139 float texscale = 1.0 / (float)txi->texsize;
1140 float tileh = (float)txi->tileh * texscale;
1141 sx2 = (sx1 + (float)dst->w) * texscale;
1142 sy2 = (sy1 + (float)dst->h) * texscale;
1143 sx1 *= texscale;
1144 sy1 *= texscale;
1145 tile = floor(sx1);
1146 tex = (int)tile / txi->tilespertex;
1147 yo = ((int)tile % txi->tilespertex) * tileh;
1148
1149 if(tex >= txi->textures)
1150 return;
1151 if(-1 == txi->texture[tex])
1152 return;
1153 gl_texture(txi->texture[tex]);
1154
1155 gl.Begin(GL_QUADS);
1156 while(tile < sx2)
1157 {
1158 int tdx1 = dst->x;
1159 int tdx2 = dst->x + dst->w;
1160 float tsx1 = sx1 - tile;
1161 float tsx2 = sx2 - tile;
1162
1163 /* Clip to current tile */
1164 if(tsx1 < 0.0)
1165 {
1166 tdx1 -= tsx1 * txi->texsize;
1167 tsx1 = 0.0;
1168 }
1169 if(tsx2 > 1.0)
1170 {
1171 tdx2 -= (tsx2 - 1.0) * txi->texsize;
1172 tsx2 = 1.0;
1173 }
1174
1175 /* Maybe select next texture? */
1176 if(yo + tileh > 1.0)
1177 {
1178 ++tex;
1179 gl.End();
1180 if(tex >= txi->textures)
1181 return;
1182 if(-1 == txi->texture[tex])
1183 return;
1184 gl_texture(txi->texture[tex]);
1185 yo = 0.0;
1186 gl.Begin(GL_QUADS);
1187 }
1188
1189 gl.Color4ub(255, 255, 255, alpha);
1190 gl.TexCoord2f(tsx1, yo + sy1);
1191 gl.Vertex2i(tdx1, dst->y);
1192 gl.TexCoord2f(tsx2, yo + sy1);
1193 gl.Vertex2i(tdx2, dst->y);
1194 gl.TexCoord2f(tsx2, yo + sy2);
1195 gl.Vertex2i(tdx2, dst->y + dst->h);
1196 gl.TexCoord2f(tsx1, yo + sy2);
1197 gl.Vertex2i(tdx1, dst->y + dst->h);
1198
1199 tile += 1.0;
1200 yo += tileh;
1201 }
1202 gl.End();
1203 }
1204
1205
BlitGL_vtile(glSDL_TexInfo * txi,float sx1,float sy1,SDL_Rect * dst,unsigned char alpha)1206 static void BlitGL_vtile(glSDL_TexInfo *txi,
1207 float sx1, float sy1, SDL_Rect *dst, unsigned char alpha)
1208 {
1209 int tex;
1210 float tile, sx2, sy2, xo;
1211 float texscale = 1.0 / (float)txi->texsize;
1212 float tilew = (float)txi->tilew * texscale;
1213 sx2 = (sx1 + (float)dst->w) * texscale;
1214 sy2 = (sy1 + (float)dst->h) * texscale;
1215 sx1 *= texscale;
1216 sy1 *= texscale;
1217 tile = floor(sy1);
1218 tex = (int)tile / txi->tilespertex;
1219 xo = ((int)tile % txi->tilespertex) * tilew;
1220
1221 if(tex >= txi->textures)
1222 return;
1223 if(-1 == txi->texture[tex])
1224 return;
1225 gl_texture(txi->texture[tex]);
1226
1227 gl.Begin(GL_QUADS);
1228 while(tile < sy2)
1229 {
1230 int tdy1 = dst->y;
1231 int tdy2 = dst->y + dst->h;
1232 float tsy1 = sy1 - tile;
1233 float tsy2 = sy2 - tile;
1234
1235 /* Clip to current tile */
1236 if(tsy1 < 0.0)
1237 {
1238 tdy1 -= tsy1 * txi->texsize;
1239 tsy1 = 0.0;
1240 }
1241 if(tsy2 > 1.0)
1242 {
1243 tdy2 -= (tsy2 - 1.0) * txi->texsize;
1244 tsy2 = 1.0;
1245 }
1246
1247 /* Maybe select next texture? */
1248 if(xo + tilew > 1.0)
1249 {
1250 ++tex;
1251 gl.End();
1252 if(tex >= txi->textures)
1253 return;
1254 if(-1 == txi->texture[tex])
1255 return;
1256 gl_texture(txi->texture[tex]);
1257 xo = 0.0;
1258 gl.Begin(GL_QUADS);
1259 }
1260
1261 gl.Color4ub(255, 255, 255, alpha);
1262 gl.TexCoord2f(xo + sx1, tsy1);
1263 gl.Vertex2i(dst->x, tdy1);
1264 gl.TexCoord2f(xo + sx2, tsy1);
1265 gl.Vertex2i(dst->x + dst->w, tdy1);
1266 gl.TexCoord2f(xo + sx2, tsy2);
1267 gl.Vertex2i(dst->x + dst->w, tdy2);
1268 gl.TexCoord2f(xo + sx1, tsy2);
1269 gl.Vertex2i(dst->x, tdy2);
1270
1271 tile += 1.0;
1272 xo += tilew;
1273 }
1274 gl.End();
1275 }
1276
1277
BlitGL_hvtile(SDL_Surface * src,glSDL_TexInfo * txi,float sx1,float sy1,SDL_Rect * dst,unsigned char alpha)1278 static void BlitGL_hvtile(SDL_Surface *src, glSDL_TexInfo *txi,
1279 float sx1, float sy1, SDL_Rect *dst, unsigned char alpha)
1280 {
1281 int x, y, last_tex, tex;
1282 float sx2, sy2;
1283 float texscale = 1.0 / (float)txi->texsize;
1284 int tilesperrow = (src->w + txi->tilew - 1) / txi->tilew;
1285 sx2 = (sx1 + (float)dst->w) * texscale;
1286 sy2 = (sy1 + (float)dst->h) * texscale;
1287 sx1 *= texscale;
1288 sy1 *= texscale;
1289
1290 last_tex = tex = floor(sy1) * tilesperrow + floor(sx1);
1291 if(tex >= txi->textures)
1292 return;
1293 if(-1 == txi->texture[tex])
1294 return;
1295 gl_texture(txi->texture[tex]);
1296
1297 gl.Begin(GL_QUADS);
1298 for(y = floor(sy1); y < sy2; ++y)
1299 {
1300 int tdy1 = dst->y;
1301 int tdy2 = dst->y + dst->h;
1302 float tsy1 = sy1 - y;
1303 float tsy2 = sy2 - y;
1304
1305 /* Clip to current tile */
1306 if(tsy1 < 0.0)
1307 {
1308 tdy1 -= tsy1 * txi->texsize;
1309 tsy1 = 0.0;
1310 }
1311 if(tsy2 > 1.0)
1312 {
1313 tdy2 -= (tsy2 - 1.0) * txi->texsize;
1314 tsy2 = 1.0;
1315 }
1316 for(x = floor(sx1); x < sx2; ++x)
1317 {
1318 int tdx1 = dst->x;
1319 int tdx2 = dst->x + dst->w;
1320 float tsx1 = sx1 - x;
1321 float tsx2 = sx2 - x;
1322
1323 /* Clip to current tile */
1324 if(tsx1 < 0.0)
1325 {
1326 tdx1 -= tsx1 * txi->texsize;
1327 tsx1 = 0.0;
1328 }
1329 if(tsx2 > 1.0)
1330 {
1331 tdx2 -= (tsx2 - 1.0) * txi->texsize;
1332 tsx2 = 1.0;
1333 }
1334
1335 /* Select texture */
1336 tex = y * tilesperrow + x;
1337 if(tex != last_tex)
1338 {
1339 gl.End();
1340 if(tex >= txi->textures)
1341 return;
1342 if(-1 == txi->texture[tex])
1343 return;
1344 gl_texture(txi->texture[tex]);
1345 last_tex = tex;
1346 gl.Begin(GL_QUADS);
1347 }
1348
1349 gl.Color4ub(255, 255, 255, alpha);
1350 gl.TexCoord2f(tsx1, tsy1);
1351 gl.Vertex2i(tdx1, tdy1);
1352 gl.TexCoord2f(tsx2, tsy1);
1353 gl.Vertex2i(tdx2, tdy1);
1354 gl.TexCoord2f(tsx2, tsy2);
1355 gl.Vertex2i(tdx2, tdy2);
1356 gl.TexCoord2f(tsx1, tsy2);
1357 gl.Vertex2i(tdx1, tdy2);
1358 }
1359 }
1360 gl.End();
1361 }
1362
1363
1364 /*
1365 * Calculate the actual blit rectangle and source offset
1366 * for a blit from a rectangle in a surface with specified
1367 * size to a surface with a cliprect.
1368 *
1369 * In: rect source rectangle
1370 * w, h source surface size
1371 * (x, y) destination coordinate
1372 * clip destination clip rectangle
1373 *
1374 * Out: (x, y) source top-left offset
1375 * rect destination rectangle
1376 *
1377 * Returns 1 if the result is visible, otherwise 0.
1378 */
blitclip(SDL_Rect * rect,int w,int h,int * x,int * y,SDL_Rect * clip)1379 static __inline__ int blitclip(SDL_Rect *rect, int w, int h,
1380 int *x, int *y, SDL_Rect *clip)
1381 {
1382 int sx1, sy1, sx2, sy2;
1383 int dx1, dy1, dx2, dy2;
1384
1385 /* Get source and destination coordinates */
1386 sx1 = rect->x;
1387 sy1 = rect->y;
1388 sx2 = sx1 + rect->w;
1389 sy2 = sy1 + rect->h;
1390 dx1 = *x;
1391 dy1 = *y;
1392
1393 /* Keep source rect inside source surface */
1394 if(sx1 < 0)
1395 {
1396 dx1 -= sx1;
1397 sx1 = 0;
1398 }
1399 if(sy1 < 0)
1400 {
1401 dy1 -= sy1;
1402 sy1 = 0;
1403 }
1404 if(sx2 > w)
1405 sx2 = w;
1406 if(sy2 > h)
1407 sy2 = h;
1408
1409 /* Cull blits from void space */
1410 if(sx1 >= sx2 || sy1 >= sy2)
1411 return 0;
1412
1413 /* Calculate destination lower-right */
1414 dx2 = dx1 + (sx2 - sx1);
1415 dy2 = dy1 + (sy2 - sy1);
1416
1417 /* Clip to destination cliprect */
1418 if(dx1 < clip->x)
1419 {
1420 sx1 += clip->x - dx1;
1421 dx1 = clip->x;
1422 }
1423 if(dy1 < clip->y)
1424 {
1425 sy1 += clip->y - dy1;
1426 dy1 = clip->y;
1427 }
1428 if(dx2 > clip->x + clip->w)
1429 dx2 = clip->x + clip->w;
1430 if(dy2 > clip->y + clip->h)
1431 dy2 = clip->y + clip->h;
1432
1433 /* Cull nop/off-screen blits */
1434 if(dx1 >= dx2 || dy1 >= dy2)
1435 return 0;
1436
1437 *x = sx1;
1438 *y = sy1;
1439 rect->x = dx1;
1440 rect->y = dy1;
1441 rect->w = dx2 - dx1;
1442 rect->h = dy2 - dy1;
1443 return 1;
1444 }
1445
1446
glSDL_BlitGL(SDL_Surface * src,SDL_Rect * srcrect,SDL_Surface * dst,SDL_Rect * dstrect)1447 static int glSDL_BlitGL(SDL_Surface *src, SDL_Rect *srcrect,
1448 SDL_Surface *dst, SDL_Rect *dstrect)
1449 {
1450 glSDL_TexInfo *txi;
1451 SDL_Rect r;
1452 int x, y;
1453 unsigned char alpha;
1454 if(!src || !dst)
1455 return -1;
1456
1457 /* Get source and destination coordinates */
1458 if(srcrect)
1459 r = *srcrect;
1460 else
1461 {
1462 r.x = r.y = 0;
1463 r.w = src->w;
1464 r.h = src->h;
1465 }
1466 if(dstrect)
1467 {
1468 x = dstrect->x;
1469 y = dstrect->y;
1470 }
1471 else
1472 x = y = 0;
1473
1474 /* Clip! */
1475 if(!blitclip(&r, src->w, src->h, &x, &y, &dst->clip_rect))
1476 {
1477 if(dstrect)
1478 dstrect->w = dstrect->h = 0;
1479 return 0;
1480 }
1481
1482 /* Write back the resulting cliprect */
1483 if(dstrect)
1484 *dstrect = r;
1485
1486 /* Make sure we have a source with a valid texture */
1487 glSDL_UploadSurface(src);
1488 txi = glSDL_GetTexInfo(src);
1489 if(!txi)
1490 return -1;
1491
1492 /* Set up blending */
1493 if(src->flags & (SDL_SRCALPHA | SDL_SRCCOLORKEY))
1494 {
1495 gl_blendfunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1496 gl_do_blend(1);
1497 }
1498 else
1499 gl_do_blend(0);
1500
1501 /* Enable texturing */
1502 gl_do_texture(1);
1503
1504 /*
1505 * Note that we actually *prevent* the use of "full surface alpha"
1506 * and alpha channel in combination - to stay SDL 2D compatible.
1507 */
1508 if((src->flags & SDL_SRCALPHA) &&
1509 (!src->format->Amask || (src->flags & SDL_SRCCOLORKEY)))
1510 alpha = src->format->alpha;
1511 else
1512 alpha = 255;
1513
1514 /* Render! */
1515 switch(txi->tilemode)
1516 {
1517 case GLSDL_TM_SINGLE:
1518 BlitGL_single(txi, x, y, &r, alpha);
1519 break;
1520 case GLSDL_TM_HORIZONTAL:
1521 BlitGL_htile(txi, x, y, &r, alpha);
1522 break;
1523 case GLSDL_TM_VERTICAL:
1524 BlitGL_vtile(txi, x, y, &r, alpha);
1525 break;
1526 case GLSDL_TM_HUGE:
1527 BlitGL_hvtile(src, txi, x, y, &r, alpha);
1528 break;
1529 }
1530 return 0;
1531 }
1532
1533
glSDL_BlitSurface(SDL_Surface * src,SDL_Rect * srcrect,SDL_Surface * dst,SDL_Rect * dstrect)1534 int glSDL_BlitSurface(SDL_Surface *src, SDL_Rect *srcrect,
1535 SDL_Surface *dst, SDL_Rect *dstrect)
1536 {
1537 SDL_Surface *vs;
1538 if(!src || !dst)
1539 return -1;
1540
1541 /*
1542 * Figure out what to do:
1543 * Not using glSDL: SDL_BlitSurface()
1544 * screen->screen: _glSDL_BlitFromGL() + _glSDL_BlitGL()
1545 * surface->screen: _glSDL_BlitGL()
1546 * screen->surface: _glSDL_BlitFromGL()
1547 * surface->surface: SDL_BlitSurface()
1548 */
1549 if(!USING_GLSDL)
1550 return SDL_BlitSurface(src, srcrect, dst, dstrect);
1551
1552 vs = SDL_GetVideoSurface();
1553 if(src == fake_screen)
1554 src = vs;
1555 if(dst == fake_screen)
1556 dst = vs;
1557 if(src == vs)
1558 {
1559 if(dst == vs)
1560 {
1561 glSDL_BlitFromGL(srcrect, fake_screen, dstrect);
1562 return glSDL_BlitGL(fake_screen, srcrect,
1563 dst, dstrect);
1564 }
1565 else
1566 {
1567 return glSDL_BlitFromGL(srcrect, dst, dstrect);
1568 }
1569 }
1570 else
1571 {
1572 if(dst == vs)
1573 {
1574 return glSDL_BlitGL(src, srcrect,
1575 dst, dstrect);
1576 }
1577 else
1578 {
1579 glSDL_Invalidate(dst, dstrect);
1580 return SDL_BlitSurface(src, srcrect, dst, dstrect);
1581 }
1582 }
1583 }
1584
1585
glSDL_FillRect(SDL_Surface * dst,SDL_Rect * dstrect,Uint32 color)1586 int glSDL_FillRect(SDL_Surface *dst, SDL_Rect *dstrect, Uint32 color)
1587 {
1588 SDL_Surface *vs = SDL_GetVideoSurface();
1589 SDL_PixelFormat *pf = dst->format;
1590 int dx1, dy1, dx2, dy2;
1591 Uint32 r, g, b;
1592
1593 if(dst == fake_screen)
1594 dst = vs;
1595 if(vs != dst)
1596 glSDL_Invalidate(dst, dstrect);
1597 if((vs != dst) || !USING_GLSDL)
1598 return SDL_FillRect(dst, dstrect, color);
1599
1600 if(dstrect)
1601 {
1602 dx1 = dstrect->x;
1603 dy1 = dstrect->y;
1604 dx2 = dx1 + dstrect->w;
1605 dy2 = dy1 + dstrect->h;
1606 if(dx1 < dst->clip_rect.x)
1607 dx1 = dst->clip_rect.x;
1608 if(dy1 < dst->clip_rect.y)
1609 dy1 = dst->clip_rect.y;
1610 if(dx2 > dst->clip_rect.x + dst->clip_rect.w)
1611 dx2 = dst->clip_rect.x + dst->clip_rect.w;
1612 if(dy2 > dst->clip_rect.y + dst->clip_rect.h)
1613 dy2 = dst->clip_rect.y + dst->clip_rect.h;
1614 dstrect->x = dx1;
1615 dstrect->y = dy1;
1616 dstrect->w = dx2 - dx1;
1617 dstrect->h = dy2 - dy1;
1618 if(!dstrect->w || !dstrect->h)
1619 return 0;
1620 }
1621 else
1622 {
1623 dx1 = dst->clip_rect.x;
1624 dy1 = dst->clip_rect.y;
1625 dx2 = dx1 + dst->clip_rect.w;
1626 dy2 = dy1 + dst->clip_rect.h;
1627 }
1628
1629 r = color & pf->Rmask;
1630 r = r >> pf->Rshift;
1631 r = r << pf->Rloss;
1632 g = color & pf->Gmask;
1633 g = g >> pf->Gshift;
1634 g = g << pf->Gloss;
1635 b = color & pf->Bmask;
1636 b = b >> pf->Bshift;
1637 b = b << pf->Bloss;
1638
1639 gl_do_texture(0);
1640 gl_do_blend(0);
1641
1642 gl.Begin(GL_QUADS);
1643 gl.Color3ub(r, g, b);
1644 gl.Vertex2i(dx1, dy1);
1645 gl.Vertex2i(dx2, dy1);
1646 gl.Vertex2i(dx2, dy2);
1647 gl.Vertex2i(dx1, dy2);
1648 gl.End();
1649 return 0;
1650 }
1651
1652
glSDL_DisplayFormat(SDL_Surface * surface)1653 SDL_Surface *glSDL_DisplayFormat(SDL_Surface *surface)
1654 {
1655 SDL_Surface *s, *tmp;
1656 if(USING_GLSDL)
1657 {
1658 int use_rgba = (surface->flags & SDL_SRCCOLORKEY) ||
1659 ((surface->flags & SDL_SRCALPHA) &&
1660 surface->format->Amask);
1661 if(use_rgba)
1662 tmp = SDL_ConvertSurface(surface, &RGBAfmt, SDL_SWSURFACE);
1663 else
1664 tmp = SDL_ConvertSurface(surface, &RGBfmt, SDL_SWSURFACE);
1665 if(!tmp)
1666 return NULL;
1667 GLSDL_FIX_SURFACE(tmp);
1668 SDL_SetAlpha(tmp, 0, 0);
1669
1670 if(surface->flags & SDL_SRCCOLORKEY)
1671 {
1672 /*
1673 * We drop colorkey data here, but we have to,
1674 * or we'll run into trouble when converting,
1675 * in particular from indexed color formats.
1676 */
1677 SDL_SetColorKey(tmp, SDL_SRCCOLORKEY,
1678 surface->format->colorkey);
1679 key2alpha(tmp);
1680 }
1681 SDL_SetColorKey(tmp, 0, 0);
1682
1683 if(use_rgba)
1684 s = CreateRGBASurface(surface->w, surface->h);
1685 else
1686 s = CreateRGBSurface(surface->w, surface->h);
1687 if(!s)
1688 {
1689 glSDL_FreeSurface(tmp);
1690 return NULL;
1691 }
1692 SDL_BlitSurface(tmp, NULL, s, NULL);
1693 glSDL_FreeSurface(tmp);
1694
1695 if(surface->flags & SDL_SRCALPHA)
1696 SDL_SetAlpha(s, SDL_SRCALPHA,
1697 surface->format->alpha);
1698 return s;
1699 }
1700 else
1701 {
1702 s = SDL_DisplayFormat(surface);
1703 if(s)
1704 GLSDL_FIX_SURFACE(s);
1705 return s;
1706 }
1707 }
1708
1709
glSDL_DisplayFormatAlpha(SDL_Surface * surface)1710 SDL_Surface *glSDL_DisplayFormatAlpha(SDL_Surface *surface)
1711 {
1712 SDL_Surface *s, *tmp;
1713 if(USING_GLSDL)
1714 {
1715 tmp = SDL_ConvertSurface(surface, &RGBAfmt, SDL_SWSURFACE);
1716 if(!tmp)
1717 return NULL;
1718 GLSDL_FIX_SURFACE(tmp);
1719
1720 SDL_SetAlpha(tmp, 0, 0);
1721 SDL_SetColorKey(tmp, 0, 0);
1722 s = CreateRGBASurface(surface->w, surface->h);
1723 if(!s)
1724 {
1725 glSDL_FreeSurface(tmp);
1726 return NULL;
1727 }
1728 SDL_BlitSurface(tmp, NULL, s, NULL);
1729 glSDL_FreeSurface(tmp);
1730
1731 if(surface->flags & SDL_SRCCOLORKEY)
1732 {
1733 SDL_SetColorKey(s, SDL_SRCCOLORKEY,
1734 surface->format->colorkey);
1735 key2alpha(s);
1736 }
1737 if(surface->flags & SDL_SRCALPHA)
1738 SDL_SetAlpha(s, SDL_SRCALPHA,
1739 surface->format->alpha);
1740 return s;
1741 }
1742 else
1743 {
1744 s = SDL_DisplayFormatAlpha(surface);
1745 if(s)
1746 GLSDL_FIX_SURFACE(s);
1747 return s;
1748 }
1749 }
1750
1751
glSDL_ConvertSurface(SDL_Surface * src,SDL_PixelFormat * fmt,Uint32 flags)1752 SDL_Surface *glSDL_ConvertSurface
1753 (SDL_Surface *src, SDL_PixelFormat *fmt, Uint32 flags)
1754 {
1755 SDL_Surface *s = SDL_ConvertSurface(src, fmt, flags);
1756 if(s)
1757 GLSDL_FIX_SURFACE(s);
1758 return s;
1759 }
1760
1761
glSDL_CreateRGBSurface(Uint32 flags,int width,int height,int depth,Uint32 Rmask,Uint32 Gmask,Uint32 Bmask,Uint32 Amask)1762 SDL_Surface *glSDL_CreateRGBSurface
1763 (Uint32 flags, int width, int height, int depth,
1764 Uint32 Rmask, Uint32 Gmask, Uint32 Bmask, Uint32 Amask)
1765 {
1766 SDL_Surface *s = SDL_CreateRGBSurface(flags, width, height, depth,
1767 Rmask, Gmask, Bmask, Amask);
1768 if(s)
1769 GLSDL_FIX_SURFACE(s);
1770 return s;
1771 }
1772
1773
glSDL_CreateRGBSurfaceFrom(void * pixels,int width,int height,int depth,int pitch,Uint32 Rmask,Uint32 Gmask,Uint32 Bmask,Uint32 Amask)1774 SDL_Surface *glSDL_CreateRGBSurfaceFrom(void *pixels,
1775 int width, int height, int depth, int pitch,
1776 Uint32 Rmask, Uint32 Gmask, Uint32 Bmask, Uint32 Amask)
1777 {
1778 SDL_Surface *s = SDL_CreateRGBSurfaceFrom(pixels,
1779 width, height, depth, pitch,
1780 Rmask, Gmask, Bmask, Amask);
1781 if(s)
1782 GLSDL_FIX_SURFACE(s);
1783 return s;
1784 }
1785
1786
glSDL_LoadBMP(const char * file)1787 SDL_Surface *glSDL_LoadBMP(const char *file)
1788 {
1789 SDL_Surface *s = SDL_LoadBMP(file);
1790 if(s)
1791 GLSDL_FIX_SURFACE(s);
1792 return s;
1793 }
1794
1795
glSDL_SaveBMP(SDL_Surface * surface,const char * file)1796 int glSDL_SaveBMP(SDL_Surface *surface, const char *file)
1797 {
1798 SDL_Rect r;
1799 SDL_Surface *buf;
1800 SDL_Surface *screen = SDL_GetVideoSurface();
1801
1802 if(!USING_GLSDL)
1803 return SDL_SaveBMP(surface, file);
1804
1805 if((surface != screen) && (surface != fake_screen))
1806 return SDL_SaveBMP(surface, file);
1807
1808 buf = CreateRGBSurface(fake_screen->w, fake_screen->h);
1809
1810 r.x = 0;
1811 r.y = 0;
1812 r.w = fake_screen->w;
1813 r.h = fake_screen->h;
1814 if(glSDL_BlitFromGL(&r, buf, &r) < 0)
1815 return -1;
1816
1817 return SDL_SaveBMP(buf, file);
1818
1819 glSDL_FreeSurface(buf);
1820 }
1821
1822
1823
1824
1825 /*----------------------------------------------------------
1826 glSDL specific API extensions
1827 ----------------------------------------------------------*/
1828
glSDL_Invalidate(SDL_Surface * surface,SDL_Rect * area)1829 void glSDL_Invalidate(SDL_Surface *surface, SDL_Rect *area)
1830 {
1831 glSDL_TexInfo *txi;
1832 if(!surface)
1833 return;
1834 txi = glSDL_GetTexInfo(surface);
1835 if(!txi)
1836 return;
1837 if(!area)
1838 {
1839 txi->invalid_area.x = 0;
1840 txi->invalid_area.y = 0;
1841 txi->invalid_area.w = surface->w;
1842 txi->invalid_area.h = surface->h;
1843 return;
1844 }
1845 txi->invalid_area = *area;
1846 }
1847
1848
InitTexture(SDL_Surface * datasurf,glSDL_TexInfo * txi,int tex)1849 static int InitTexture(SDL_Surface *datasurf, glSDL_TexInfo *txi, int tex)
1850 {
1851 gl.GenTextures(1, (unsigned int *)&txi->texture[tex]);
1852 gl.BindTexture(GL_TEXTURE_2D, txi->texture[tex]);
1853 gl.PixelStorei(GL_UNPACK_ROW_LENGTH, datasurf->pitch /
1854 datasurf->format->BytesPerPixel);
1855 gl.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1856 gl.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1857 gl.TexImage2D(GL_TEXTURE_2D, 0,
1858 datasurf->format->Amask ? GL_RGBA8 : GL_RGB8,
1859 txi->texsize, txi->texsize, 0,
1860 datasurf->format->Amask ? GL_RGBA : GL_RGB,
1861 GL_UNSIGNED_BYTE, NULL);
1862 print_glerror(1);
1863 return 0;
1864 }
1865
1866
1867 /* Image tiled horizontally (wide surface), or not at all */
UploadHoriz(SDL_Surface * datasurf,glSDL_TexInfo * txi)1868 static int UploadHoriz(SDL_Surface *datasurf, glSDL_TexInfo *txi)
1869 {
1870 int bpp = datasurf->format->BytesPerPixel;
1871 int res;
1872 int tex = 0;
1873 int fromx = 0;
1874 int toy = txi->texsize; /* To init first texture */
1875 while(1)
1876 {
1877 int thistw = datasurf->w - fromx;
1878 if(thistw > txi->tilew)
1879 thistw = txi->tilew;
1880 else if(thistw <= 0)
1881 break;
1882 if(toy + txi->tileh > txi->texsize)
1883 {
1884 toy = 0;
1885 res = InitTexture(datasurf, txi, tex);
1886 if(res < 0)
1887 return res;
1888 ++tex;
1889 }
1890 gl.TexSubImage2D(GL_TEXTURE_2D, 0, 0, toy,
1891 thistw, txi->tileh,
1892 datasurf->format->Amask ? GL_RGBA : GL_RGB,
1893 GL_UNSIGNED_BYTE,
1894 (char *)datasurf->pixels + bpp * fromx);
1895 print_glerror(2);
1896 fromx += txi->tilew;
1897 toy += txi->tileh;
1898 gl.Flush();
1899 }
1900 return 0;
1901 }
1902
1903
1904 /* Image tiled vertically (tall surface) */
UploadVert(SDL_Surface * datasurf,glSDL_TexInfo * txi)1905 static int UploadVert(SDL_Surface *datasurf, glSDL_TexInfo *txi)
1906 {
1907 int res;
1908 int tex = 0;
1909 int fromy = 0;
1910 int tox = txi->texsize; /* To init first texture */
1911 while(1)
1912 {
1913 int thisth = datasurf->h - fromy;
1914 if(thisth > txi->tileh)
1915 thisth = txi->tileh;
1916 else if(thisth <= 0)
1917 break;
1918 if(tox + txi->tilew > txi->texsize)
1919 {
1920 tox = 0;
1921 res = InitTexture(datasurf, txi, tex);
1922 if(res < 0)
1923 return res;
1924 ++tex;
1925 }
1926 gl.TexSubImage2D(GL_TEXTURE_2D, 0, tox, 0,
1927 txi->tilew, thisth,
1928 datasurf->format->Amask ? GL_RGBA : GL_RGB,
1929 GL_UNSIGNED_BYTE,
1930 (char *)datasurf->pixels + datasurf->pitch * fromy);
1931 print_glerror(3);
1932 fromy += txi->tileh;
1933 tox += txi->tilew;
1934 gl.Flush();
1935 }
1936 return 0;
1937 }
1938
1939
1940 /* Image tiled two-way (huge surface) */
UploadHuge(SDL_Surface * datasurf,glSDL_TexInfo * txi)1941 static int UploadHuge(SDL_Surface *datasurf, glSDL_TexInfo *txi)
1942 {
1943 int bpp = datasurf->format->BytesPerPixel;
1944 int res;
1945 int tex = 0;
1946 int y = 0;
1947 while(y < datasurf->h)
1948 {
1949 int x;
1950 int thisth = datasurf->h - y;
1951 if(thisth > txi->tileh)
1952 thisth = txi->tileh;
1953 x = 0;
1954 while(x < datasurf->w)
1955 {
1956 int thistw = datasurf->w - x;
1957 if(thistw > txi->tilew)
1958 thistw = txi->tilew;
1959 res = InitTexture(datasurf, txi, tex++);
1960 if(res < 0)
1961 return res;
1962 /* DBG5(printf("glTexSubImage(x = %d, y = %d, w = %d, h = %d)\n",
1963 x, y, thistw, thisth);) */
1964 gl.TexSubImage2D(GL_TEXTURE_2D, 0, 0, 0,
1965 thistw, thisth,
1966 datasurf->format->Amask ? GL_RGBA : GL_RGB,
1967 GL_UNSIGNED_BYTE,
1968 (char *)datasurf->pixels +
1969 datasurf->pitch * y + bpp * x);
1970 print_glerror(4);
1971 x += txi->tilew;
1972 gl.Flush();
1973 }
1974 y += txi->tileh;
1975 }
1976 return 0;
1977 }
1978
1979
1980 /* Upload all textures for a surface. */
UploadTextures(SDL_Surface * datasurf,glSDL_TexInfo * txi)1981 static int UploadTextures(SDL_Surface *datasurf, glSDL_TexInfo *txi)
1982 {
1983 switch(txi->tilemode)
1984 {
1985 case GLSDL_TM_SINGLE:
1986 case GLSDL_TM_HORIZONTAL:
1987 UploadHoriz(datasurf, txi);
1988 break;
1989 case GLSDL_TM_VERTICAL:
1990 UploadVert(datasurf, txi);
1991 break;
1992 case GLSDL_TM_HUGE:
1993 UploadHuge(datasurf, txi);
1994 break;
1995 }
1996 return 0;
1997 }
1998
1999
glSDL_UploadSurface(SDL_Surface * surface)2000 int glSDL_UploadSurface(SDL_Surface *surface)
2001 {
2002 SDL_Surface *datasurf = surface;
2003 glSDL_TexInfo *txi;
2004 int i;
2005 /*
2006 * For now, we just assume that *every* texture needs
2007 * conversion before uploading.
2008 */
2009
2010 /* If there's no TexInfo, add one. */
2011 if(!IS_GLSDL_SURFACE(surface))
2012 glSDL_AddTexInfo(surface);
2013
2014 txi = glSDL_GetTexInfo(surface);
2015 if(!txi)
2016 return -1;
2017
2018 /* No partial updates implemented yet... */
2019 if(txi->invalid_area.w)
2020 glSDL_UnloadSurface(surface);
2021 else
2022 {
2023 int missing = 0;
2024 if(txi->textures)
2025 {
2026 for(i = 0; i < txi->textures; ++i)
2027 if(-1 == txi->texture[i])
2028 {
2029 missing = 1;
2030 break;
2031 }
2032 if(!missing)
2033 return 0; /* They're already there! */
2034 }
2035 }
2036
2037 if(txi->texsize > maxtexsize)
2038 {
2039 fprintf(stderr, "glSDL/wrapper: INTERNAL ERROR: Too large texture!\n");
2040 return -1; /* This surface wasn't tiled properly... */
2041 }
2042
2043 /*
2044 * Kludge: Convert if not of preferred RGB or RGBA format.
2045 *
2046 * Conversion should only be done when *really* needed.
2047 * That is, it should rarely have to be done with OpenGL
2048 * 1.2+.
2049 *
2050 * Besides, any surface that's been SDL_DisplayFormat()ed
2051 * should already be in the best known OpenGL format -
2052 * preferably one that makes DMA w/o conversion possible.
2053 */
2054 if(FormatIsOk(surface))
2055 datasurf = surface;
2056 else
2057 {
2058 DBG(fprintf(stderr, "glSDL/wrapper: WARNING: On-the-fly conversion performed!\n"));
2059 if(surface->format->Amask)
2060 datasurf = glSDL_DisplayFormatAlpha(surface);
2061 else
2062 datasurf = glSDL_DisplayFormat(surface);
2063 if(!datasurf)
2064 return -2;
2065 }
2066
2067 if(UploadTextures(datasurf, txi) < 0)
2068 return -3;
2069
2070 if(datasurf != surface)
2071 glSDL_FreeSurface(datasurf);
2072 return 0;
2073 }
2074
2075
UnloadTexture(glSDL_TexInfo * txi)2076 static void UnloadTexture(glSDL_TexInfo *txi)
2077 {
2078 int i;
2079 for(i = 0; i < txi->textures; ++i)
2080 gl.DeleteTextures(1, (unsigned int *)&txi->texture[i]);
2081 memset(&txi->invalid_area, 0, sizeof(txi->invalid_area));
2082 }
2083
2084
glSDL_UnloadSurface(SDL_Surface * surface)2085 void glSDL_UnloadSurface(SDL_Surface *surface)
2086 {
2087 glSDL_TexInfo *txi;
2088 if(!IS_GLSDL_SURFACE(surface))
2089 return;
2090
2091 txi = glSDL_GetTexInfo(surface);
2092 if(txi)
2093 UnloadTexture(txi);
2094 }
2095
2096
glSDL_IMG_Load(const char * file)2097 SDL_Surface *glSDL_IMG_Load(const char *file)
2098 {
2099 SDL_Surface *s;
2100 s = IMG_Load(file);
2101 if(s)
2102 GLSDL_FIX_SURFACE(s);
2103 return s;
2104 }
2105
2106 #endif /* HAVE_OPENGL */
2107