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