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