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