Mercurial > sdl-ios-xcode
comparison src/video/glsdl/SDL_glsdl.c @ 1895:c121d94672cb
SDL 1.2 is moving to a branch, and SDL 1.3 is becoming the head.
author | Sam Lantinga <slouken@libsdl.org> |
---|---|
date | Mon, 10 Jul 2006 21:04:37 +0000 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
1894:c69cee13dd76 | 1895:c121d94672cb |
---|---|
1 /* | |
2 SDL - Simple DirectMedia Layer | |
3 Copyright (C) 1997-2006 Sam Lantinga | |
4 | |
5 This library is free software; you can redistribute it and/or | |
6 modify it under the terms of the GNU Lesser General Public | |
7 License as published by the Free Software Foundation; either | |
8 version 2.1 of the License, or (at your option) any later version. | |
9 | |
10 This library is distributed in the hope that it will be useful, | |
11 but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
13 Lesser General Public License for more details. | |
14 | |
15 You should have received a copy of the GNU Lesser General Public | |
16 License along with this library; if not, write to the Free Software | |
17 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | |
18 | |
19 Sam Lantinga | |
20 slouken@libsdl.org | |
21 */ | |
22 #include "SDL_config.h" | |
23 | |
24 /* | |
25 * glSDL "SDL-over-OpenGL" video driver implemented by | |
26 * David Olofson <david@olofson.net> and | |
27 * Stephane Marchesin <stephane.marchesin@wanadoo.fr> | |
28 */ | |
29 #include <math.h> | |
30 | |
31 #include "SDL.h" | |
32 #include "SDL_error.h" | |
33 #include "SDL_video.h" | |
34 #include "SDL_mouse.h" | |
35 #include "../SDL_sysvideo.h" | |
36 #include "../SDL_pixels_c.h" | |
37 | |
38 #include "SDL_glsdl.h" | |
39 | |
40 #undef DEBUG_GLSDL | |
41 #undef DEBUG_GLSDL_CHOP | |
42 #define FAKE_MAXTEXSIZE 256 | |
43 #undef GLSDL_GRAPHICAL_DEBUG | |
44 | |
45 /* Initialization/Query functions */ | |
46 | |
47 /* Hardware surface functions */ | |
48 static int glSDL_SetColors(_THIS, int firstcolor, int ncolors, | |
49 SDL_Color * colors); | |
50 static int glSDL_AllocHWSurface(_THIS, SDL_Surface * surface); | |
51 static int glSDL_LockHWSurface(_THIS, SDL_Surface * surface); | |
52 static int glSDL_FlipHWSurface(_THIS, SDL_Surface * surface); | |
53 static void glSDL_UnlockHWSurface(_THIS, SDL_Surface * surface); | |
54 static void glSDL_FreeHWSurface(_THIS, SDL_Surface * surface); | |
55 static int glSDL_FillHWRect(_THIS, SDL_Surface * dst, SDL_Rect * rect, | |
56 Uint32 color); | |
57 static int glSDL_CheckHWBlit(_THIS, SDL_Surface * src, SDL_Surface * dst); | |
58 static int glSDL_SetHWColorKey(_THIS, SDL_Surface * surface, Uint32 key); | |
59 static int glSDL_SetHWAlpha(_THIS, SDL_Surface * surface, Uint8 alpha); | |
60 static int glSDL_VideoInit(_THIS, SDL_PixelFormat * vformat); | |
61 static SDL_Rect **glSDL_ListModes(_THIS, SDL_PixelFormat * format, | |
62 Uint32 flags); | |
63 static void glSDL_VideoQuit(_THIS); | |
64 static void glSDL_UpdateRects(_THIS, int numrects, SDL_Rect * rects); | |
65 static SDL_Surface *glSDL_SetVideoMode(_THIS, SDL_Surface * current, | |
66 int width, int height, int bpp, | |
67 Uint32 flags); | |
68 | |
69 #define IS_GLSDL_SURFACE(s) ((s) && glSDL_GetTexInfo(s)) | |
70 | |
71 #define LOGIC_W(s) ( IS_GLSDL_SURFACE(this,s) ? TEXINFO(s)->lw : (s)->w ) | |
72 #define LOGIC_H(s) ( IS_GLSDL_SURFACE(this,s) ? TEXINFO(s)->lh : (s)->h ) | |
73 | |
74 #define GLSDL_NOTEX (~0) | |
75 | |
76 /* | |
77 * Special version for glSDL, which ignores the fake SDL_HWSURFACE | |
78 * flags, so we don't have SDL calling us back whenever we want to | |
79 * do some internal blitting... | |
80 */ | |
81 static void | |
82 glSDL_SoftBlit(SDL_Surface * src, SDL_Rect * srcrect, | |
83 SDL_Surface * dst, SDL_Rect * dstrect) | |
84 { | |
85 SDL_BlitInfo info; | |
86 | |
87 if (srcrect) | |
88 if (!srcrect->w || !srcrect->h) | |
89 return; | |
90 | |
91 /* Check to make sure the blit mapping is valid */ | |
92 if ((src->map->dst != dst) || | |
93 (src->map->dst->format_version != src->map->format_version)) | |
94 if (SDL_MapSurface(src, dst) < 0) | |
95 return; | |
96 | |
97 /* Set up the blit information */ | |
98 if (srcrect) { | |
99 info.s_pixels = (Uint8 *) src->pixels + | |
100 (Uint16) srcrect->y * src->pitch + | |
101 (Uint16) srcrect->x * src->format->BytesPerPixel; | |
102 info.s_width = srcrect->w; | |
103 info.s_height = srcrect->h; | |
104 } else { | |
105 info.s_pixels = (Uint8 *) src->pixels; | |
106 info.s_width = src->w; | |
107 info.s_height = src->h; | |
108 } | |
109 info.s_skip = src->pitch - info.s_width * src->format->BytesPerPixel; | |
110 if (dstrect) { | |
111 info.d_pixels = (Uint8 *) dst->pixels + | |
112 (Uint16) dstrect->y * dst->pitch + | |
113 (Uint16) dstrect->x * dst->format->BytesPerPixel; | |
114 /* | |
115 * NOTE: SDL_SoftBlit() uses the 'dstrect' for this! | |
116 * This version is more like SDL_BlitSurface(). | |
117 */ | |
118 info.d_width = srcrect->w; | |
119 info.d_height = srcrect->h; | |
120 } else { | |
121 info.d_pixels = (Uint8 *) dst->pixels; | |
122 info.d_width = dst->w; | |
123 info.d_height = dst->h; | |
124 } | |
125 info.d_skip = dst->pitch - info.d_width * dst->format->BytesPerPixel; | |
126 info.aux_data = src->map->sw_data->aux_data; | |
127 info.src = src->format; | |
128 info.table = src->map->table; | |
129 info.dst = dst->format; | |
130 | |
131 src->map->sw_data->blit(&info); | |
132 } | |
133 | |
134 | |
135 /* | |
136 * Another special version. Doesn't lock/unlock, and doesn't mess | |
137 * with flags and stuff. It just converts the surface, period. | |
138 * Does not convert into palletized formats. | |
139 */ | |
140 static SDL_Surface * | |
141 glSDL_ConvertSurface(SDL_Surface * surface, | |
142 SDL_PixelFormat * format, Uint32 flags) | |
143 { | |
144 SDL_Surface *convert; | |
145 Uint32 colorkey = 0; | |
146 Uint8 alpha = 0; | |
147 Uint32 surface_flags; | |
148 SDL_Rect bounds; | |
149 | |
150 /* Create a new surface with the desired format */ | |
151 convert = SDL_CreateRGBSurface(flags, | |
152 surface->w, surface->h, | |
153 format->BitsPerPixel, format->Rmask, | |
154 format->Gmask, format->Bmask, | |
155 format->Amask); | |
156 if (convert == NULL) { | |
157 return (NULL); | |
158 } | |
159 | |
160 /* Save the original surface color key and alpha */ | |
161 surface_flags = surface->flags; | |
162 if ((surface_flags & SDL_SRCCOLORKEY) == SDL_SRCCOLORKEY) { | |
163 /* Convert colourkeyed surfaces to RGBA if requested */ | |
164 if ((flags & SDL_SRCCOLORKEY) != SDL_SRCCOLORKEY && format->Amask) { | |
165 surface_flags &= ~SDL_SRCCOLORKEY; | |
166 } else { | |
167 colorkey = surface->format->colorkey; | |
168 SDL_SetColorKey(surface, 0, 0); | |
169 } | |
170 } | |
171 if ((surface_flags & SDL_SRCALPHA) == SDL_SRCALPHA) { | |
172 /* Copy over the alpha channel to RGBA if requested */ | |
173 if (format->Amask) { | |
174 surface->flags &= ~SDL_SRCALPHA; | |
175 } else { | |
176 alpha = surface->format->alpha; | |
177 SDL_SetAlpha(surface, 0, 0); | |
178 } | |
179 } | |
180 | |
181 /* Copy over the image data */ | |
182 bounds.x = 0; | |
183 bounds.y = 0; | |
184 bounds.w = surface->w; | |
185 bounds.h = surface->h; | |
186 glSDL_SoftBlit(surface, &bounds, convert, &bounds); | |
187 | |
188 /* Clean up the original surface, and update converted surface */ | |
189 if (convert != NULL) { | |
190 SDL_SetClipRect(convert, &surface->clip_rect); | |
191 } | |
192 if ((surface_flags & SDL_SRCCOLORKEY) == SDL_SRCCOLORKEY) { | |
193 Uint32 cflags = surface_flags & (SDL_SRCCOLORKEY | SDL_RLEACCELOK); | |
194 if (convert != NULL) { | |
195 Uint8 keyR, keyG, keyB; | |
196 | |
197 SDL_GetRGB(colorkey, surface->format, &keyR, &keyG, &keyB); | |
198 SDL_SetColorKey(convert, cflags | (flags & SDL_RLEACCELOK), | |
199 SDL_MapRGB(convert->format, keyR, keyG, keyB)); | |
200 } | |
201 SDL_SetColorKey(surface, cflags, colorkey); | |
202 } | |
203 if ((surface_flags & SDL_SRCALPHA) == SDL_SRCALPHA) { | |
204 Uint32 aflags = surface_flags & (SDL_SRCALPHA | SDL_RLEACCELOK); | |
205 if (convert != NULL) { | |
206 SDL_SetAlpha(convert, aflags | (flags & SDL_RLEACCELOK), alpha); | |
207 } | |
208 if (format->Amask) { | |
209 surface->flags |= SDL_SRCALPHA; | |
210 } else { | |
211 SDL_SetAlpha(surface, aflags, alpha); | |
212 } | |
213 } | |
214 | |
215 /* We're ready to go! */ | |
216 return (convert); | |
217 } | |
218 | |
219 | |
220 /*---------------------------------------------------------- | |
221 Some OpenGL function wrappers | |
222 ----------------------------------------------------------*/ | |
223 | |
224 static struct | |
225 { | |
226 int do_blend; | |
227 int do_texture; | |
228 GLuint texture; | |
229 GLenum sfactor, dfactor; | |
230 } glstate; | |
231 | |
232 static void | |
233 glSDL_reset(void) | |
234 { | |
235 glstate.do_blend = -1; | |
236 glstate.do_blend = -1; | |
237 glstate.texture = GLSDL_NOTEX; | |
238 glstate.sfactor = 0xffffffff; | |
239 glstate.dfactor = 0xffffffff; | |
240 } | |
241 | |
242 static __inline__ void | |
243 glSDL_do_blend(_THIS, int on) | |
244 { | |
245 if (glstate.do_blend == on) | |
246 return; | |
247 | |
248 if (on) | |
249 this->glEnable(GL_BLEND); | |
250 else | |
251 this->glDisable(GL_BLEND); | |
252 glstate.do_blend = on; | |
253 } | |
254 | |
255 static __inline__ void | |
256 glSDL_do_texture(_THIS, int on) | |
257 { | |
258 if (glstate.do_texture == on) | |
259 return; | |
260 | |
261 if (on) | |
262 this->glEnable(GL_TEXTURE_2D); | |
263 else | |
264 this->glDisable(GL_TEXTURE_2D); | |
265 glstate.do_texture = on; | |
266 } | |
267 | |
268 static __inline__ void | |
269 glSDL_blendfunc(_THIS, GLenum sfactor, GLenum dfactor) | |
270 { | |
271 if ((sfactor == glstate.sfactor) && (dfactor == glstate.dfactor)) | |
272 return; | |
273 | |
274 this->glBlendFunc(sfactor, dfactor); | |
275 | |
276 glstate.sfactor = sfactor; | |
277 glstate.dfactor = dfactor; | |
278 } | |
279 | |
280 static __inline__ void | |
281 glSDL_texture(_THIS, GLuint tx) | |
282 { | |
283 if (tx == glstate.texture) | |
284 return; | |
285 | |
286 this->glBindTexture(GL_TEXTURE_2D, tx); | |
287 glstate.texture = tx; | |
288 } | |
289 | |
290 | |
291 | |
292 | |
293 /*---------------------------------------------------------- | |
294 glSDL specific data types | |
295 ----------------------------------------------------------*/ | |
296 | |
297 typedef enum | |
298 { | |
299 GLSDL_TM_SINGLE, | |
300 GLSDL_TM_HORIZONTAL, | |
301 GLSDL_TM_VERTICAL, | |
302 GLSDL_TM_HUGE | |
303 } GLSDL_TileModes; | |
304 | |
305 | |
306 typedef struct private_hwdata | |
307 { | |
308 /* Size of surface in logic screen pixels */ | |
309 int lw, lh; | |
310 | |
311 int textures; | |
312 GLuint *texture; | |
313 int texsize; /* width/height of OpenGL texture */ | |
314 GLSDL_TileModes tilemode; | |
315 int tilew, tileh; /* At least one must equal texsize! */ | |
316 int tilespertex; | |
317 SDL_Rect virt; /* Total size of assembled surface */ | |
318 | |
319 /* Area of surface to upload when/after unlocking */ | |
320 SDL_Rect invalid_area; | |
321 | |
322 int temporary; /* Throw away after one use. */ | |
323 | |
324 SDL_Surface *next; /* The next Surface in our linked list of hardware surfaces ; == NULL if first surface */ | |
325 SDL_Surface *prev; /* The prev Surface in our linked list of hardware surfaces ; == NULL if last surface */ | |
326 } private_hwdata; | |
327 | |
328 /* some function prototypes */ | |
329 static void glSDL_Invalidate(SDL_Surface * surface, SDL_Rect * area); | |
330 static void glSDL_SetLogicSize(_THIS, SDL_Surface * surface, int w, int h); | |
331 static private_hwdata *glSDL_UploadSurface(_THIS, SDL_Surface * surface); | |
332 static private_hwdata *glSDL_GetTexInfo(SDL_Surface * surface); | |
333 static void glSDL_init_formats(_THIS); | |
334 static private_hwdata *glSDL_AddTexInfo(_THIS, SDL_Surface * surface); | |
335 static void glSDL_RemoveTexInfo(_THIS, SDL_Surface * surface); | |
336 static void glSDL_UnloadTexture(_THIS, private_hwdata * txi); | |
337 static int glSDL_BlitGL(_THIS, SDL_Surface * src, | |
338 SDL_Rect * srcrect, SDL_Rect * dstrect); | |
339 | |
340 /* some variables */ | |
341 static GLint maxtexsize = -1; | |
342 static SDL_PixelFormat *RGBfmt = NULL; | |
343 static SDL_PixelFormat *RGBAfmt = NULL; | |
344 static void *mirrorbuf = NULL; | |
345 /* the raw 888 opengl surface, hidden from the application */ | |
346 SDL_Surface *OpenGL_Surface; | |
347 | |
348 /* pointer to the beggining of the list used for memory allocation */ | |
349 SDL_Surface *first = NULL; | |
350 | |
351 #ifdef DEBUG_GLSDL | |
352 static __inline__ int | |
353 GLERET(const char *txt) | |
354 { | |
355 fprintf(stderr, "glSDL ERROR: '%s'\n", txt); | |
356 return -1; | |
357 } | |
358 static __inline__ void | |
359 GLERR(const char *txt) | |
360 { | |
361 fprintf(stderr, "glSDL ERROR: '%s'\n", txt); | |
362 } | |
363 #else | |
364 #define GLERET(x) (-1) | |
365 #define GLERR(x) | |
366 #endif | |
367 | |
368 static SDL_VideoDevice underlying_device; | |
369 static int old_screen_flags; | |
370 | |
371 /* | |
372 * List of video drivers known to support OpenGL | |
373 * The purpose of this is to make glSDL "portable" across | |
374 * all video backends that support OpenGL | |
375 */ | |
376 static VideoBootStrap *opengl_bootstrap = | |
377 #if SDL_VIDEO_DRIVER_QUARTZ | |
378 &QZ_bootstrap; | |
379 #elif SDL_VIDEO_DRIVER_X11 | |
380 &X11_bootstrap; | |
381 #elif SDL_VIDEO_DRIVER_WINDIB | |
382 &WINDIB_bootstrap; | |
383 #elif SDL_VIDEO_DRIVER_BWINDOW | |
384 &BWINDOW_bootstrap; | |
385 #elif SDL_VIDEO_DRIVER_TOOLBOX | |
386 &TOOLBOX_bootstrap; | |
387 #elif SDL_VIDEO_DRIVER_CYBERGRAPHICS | |
388 &CGX_bootstrap; | |
389 #elif SDL_VIDEO_DRIVER_PHOTON | |
390 &ph_bootstrap; | |
391 #elif SDL_VIDEO_DRIVER_DC | |
392 &DC_bootstrap; | |
393 #else | |
394 NULL; | |
395 #endif | |
396 | |
397 static int | |
398 glSDL_Available(void) | |
399 { | |
400 #ifdef DEBUG_GLSDL | |
401 fprintf(stderr, "available\n"); | |
402 #endif | |
403 if (opengl_bootstrap == NULL) | |
404 return 0; | |
405 return (opengl_bootstrap->available()); | |
406 } | |
407 | |
408 static void | |
409 glSDL_DeleteDevice(SDL_VideoDevice * device) | |
410 { | |
411 SDL_free(device->hidden); | |
412 SDL_free(device); | |
413 } | |
414 | |
415 /* Create a glSDL device */ | |
416 static SDL_VideoDevice * | |
417 glSDL_CreateDevice(int devindex) | |
418 { | |
419 SDL_VideoDevice *device; | |
420 #ifdef DEBUG_GLSDL | |
421 fprintf(stderr, "entering createdevice\n"); | |
422 #endif | |
423 | |
424 /* Create the device with the underlying driver */ | |
425 device = opengl_bootstrap->create(devindex); | |
426 | |
427 /* Save the video device contents for future use */ | |
428 SDL_memcpy(&underlying_device, device, sizeof(SDL_VideoDevice)); | |
429 | |
430 /* Hook glSDL on the video device */ | |
431 device->VideoInit = glSDL_VideoInit; | |
432 device->ListModes = glSDL_ListModes; | |
433 device->VideoQuit = glSDL_VideoQuit; | |
434 device->UpdateRects = glSDL_UpdateRects; | |
435 device->FillHWRect = glSDL_FillHWRect; | |
436 device->SetHWColorKey = glSDL_SetHWColorKey; | |
437 device->SetHWAlpha = glSDL_SetHWAlpha; | |
438 device->AllocHWSurface = glSDL_AllocHWSurface; | |
439 device->LockHWSurface = glSDL_LockHWSurface; | |
440 device->UnlockHWSurface = glSDL_UnlockHWSurface; | |
441 device->FlipHWSurface = glSDL_FlipHWSurface; | |
442 device->FreeHWSurface = glSDL_FreeHWSurface; | |
443 device->CheckHWBlit = glSDL_CheckHWBlit; | |
444 device->SetColors = glSDL_SetColors; | |
445 device->SetVideoMode = glSDL_SetVideoMode; | |
446 device->info.hw_available = 1; | |
447 device->info.blit_hw = 1; | |
448 device->info.blit_hw_CC = 1; | |
449 device->info.blit_hw_A = 1; | |
450 device->info.blit_sw = 1; | |
451 device->info.blit_sw_CC = 1; | |
452 device->info.blit_sw_A = 1; | |
453 device->info.blit_fill = 1; | |
454 | |
455 /* These functions are not supported by glSDL, so we NULLify them */ | |
456 device->SetGamma = NULL; | |
457 device->GetGamma = NULL; | |
458 device->SetGammaRamp = NULL; | |
459 device->GetGammaRamp = NULL; | |
460 device->ToggleFullScreen = NULL; | |
461 | |
462 device->free = glSDL_DeleteDevice; | |
463 | |
464 #ifdef DEBUG_GLSDL | |
465 fprintf(stderr, "leaving createdevice\n"); | |
466 #endif | |
467 | |
468 return device; | |
469 } | |
470 | |
471 /* Our bootstraping structure */ | |
472 VideoBootStrap glSDL_bootstrap = { | |
473 "glSDL", "glSDL - SDL over OpenGL", | |
474 glSDL_Available, glSDL_CreateDevice | |
475 }; | |
476 | |
477 static int | |
478 glSDL_VideoInit(_THIS, SDL_PixelFormat * vformat) | |
479 { | |
480 int r; | |
481 printf("glSDL videoinit\n"); | |
482 #ifdef DEBUG_GLSDL | |
483 fprintf(stderr, "videoinit\n"); | |
484 #endif | |
485 r = underlying_device.VideoInit(this, vformat); | |
486 this->info.hw_available = 1; | |
487 this->info.blit_hw = 1; | |
488 this->info.blit_hw_CC = 1; | |
489 this->info.blit_hw_A = 1; | |
490 this->info.blit_sw = 1; | |
491 this->info.blit_sw_CC = 1; | |
492 this->info.blit_sw_A = 1; | |
493 this->info.blit_fill = 1; | |
494 | |
495 return r; | |
496 } | |
497 | |
498 SDL_Rect ** | |
499 glSDL_ListModes(_THIS, SDL_PixelFormat * format, Uint32 flags) | |
500 { | |
501 return ((SDL_Rect **) - 1); | |
502 } | |
503 | |
504 static void | |
505 glSDL_VideoQuit(_THIS) | |
506 { | |
507 SDL_Surface *scr; | |
508 | |
509 /* free all hwdata structures */ | |
510 while (first != NULL) | |
511 glSDL_RemoveTexInfo(this, first); | |
512 | |
513 SDL_free(mirrorbuf); | |
514 mirrorbuf = NULL; | |
515 | |
516 SDL_FreeFormat(RGBfmt); | |
517 SDL_FreeFormat(RGBAfmt); | |
518 RGBfmt = RGBAfmt = NULL; | |
519 | |
520 SDL_FreeFormat(this->displayformatalphapixel); | |
521 this->displayformatalphapixel = NULL; | |
522 | |
523 SDL_FreeSurface(OpenGL_Surface); | |
524 OpenGL_Surface = NULL; | |
525 | |
526 /* restore the flags to gracefully exit from fullscreen */ | |
527 this->screen->flags = old_screen_flags; | |
528 | |
529 /* keep the screen */ | |
530 scr = this->screen; | |
531 | |
532 /* we cleaned up our stuff, now restore the underlying video driver */ | |
533 SDL_memcpy(this, &underlying_device, sizeof(SDL_VideoDevice)); | |
534 | |
535 this->screen = scr; | |
536 | |
537 /* call the underlying video driver's VideoQuit function */ | |
538 this->VideoQuit(this); | |
539 } | |
540 | |
541 static SDL_Surface * | |
542 glSDL_SetVideoMode(_THIS, SDL_Surface * current, int width, int height, | |
543 int bpp, Uint32 flags) | |
544 { | |
545 SDL_Surface *hooked_screen; | |
546 int i; | |
547 int flag_doublebuf = 0; | |
548 | |
549 if (opengl_bootstrap == NULL) { | |
550 GLERR("No bootstrap for glSDL compiled in !\n"); | |
551 return NULL; | |
552 } | |
553 | |
554 /* we don't have OpenGL */ | |
555 if ((flags & SDL_INTERNALOPENGL) == SDL_INTERNALOPENGL) { | |
556 GLERR("OpenGL video modes are not supported by glSDL !\n"); | |
557 return (NULL); | |
558 } | |
559 | |
560 /* | |
561 * Adjust the flags | |
562 */ | |
563 flags &= ~SDL_HWPALETTE; | |
564 flags |= SDL_INTERNALOPENGL; | |
565 | |
566 /* remember whether the user requested DOUBLEBUF */ | |
567 | |
568 if (flags & SDL_DOUBLEBUF) { | |
569 SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); | |
570 flag_doublebuf = 1; | |
571 } else { | |
572 SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 0); | |
573 flag_doublebuf = 0; | |
574 } | |
575 | |
576 hooked_screen = | |
577 underlying_device.SetVideoMode(this, current, width, height, 0, | |
578 flags); | |
579 | |
580 if (!hooked_screen) { | |
581 GLERR("Unable to open an OpenGL window !\n"); | |
582 return (NULL); | |
583 } | |
584 | |
585 /* save the screen flags for restore time */ | |
586 old_screen_flags = hooked_screen->flags; | |
587 | |
588 #ifdef DEBUG_GLSDL | |
589 fprintf(stderr, "got %d bpp\n", bpp); | |
590 #endif | |
591 | |
592 /* setup the public surface format | |
593 * glSDL always returns the bpp its asked | |
594 */ | |
595 switch (bpp) { | |
596 case 32: | |
597 this->is_32bit = 1; | |
598 this->screen = SDL_CreateRGBSurface(flags, width, height, bpp, | |
599 #if SDL_BYTEORDER == SDL_LIL_ENDIAN | |
600 0x00FF0000, | |
601 0x0000FF00, 0x000000FF, 0x00000000 | |
602 #else | |
603 0x0000FF00, | |
604 0x00FF0000, 0xFF000000, 0x00000000 | |
605 #endif | |
606 ); | |
607 break; | |
608 case 24: | |
609 this->is_32bit = 0; | |
610 this->screen = SDL_CreateRGBSurface(flags, width, height, bpp, | |
611 #if SDL_BYTEORDER == SDL_LIL_ENDIAN | |
612 0x00FF0000, | |
613 0x0000FF00, 0x000000FF, 0x00000000 | |
614 #else | |
615 0x0000FF00, | |
616 0x00FF0000, 0xFF000000, 0x00000000 | |
617 #endif | |
618 ); | |
619 break; | |
620 case 16: | |
621 this->is_32bit = 0; | |
622 this->screen = SDL_CreateRGBSurface(flags, width, height, bpp, | |
623 #if SDL_BYTEORDER == SDL_LIL_ENDIAN | |
624 0x0000F800, | |
625 0x000007E0, 0x0000001F, 0x00000000 | |
626 #else | |
627 0x0000001F, | |
628 0x000007E0, 0x0000F800, 0x00000000 | |
629 #endif | |
630 ); | |
631 break; | |
632 case 15: | |
633 this->is_32bit = 0; | |
634 this->screen = SDL_CreateRGBSurface(flags, width, height, bpp, | |
635 #if SDL_BYTEORDER == SDL_LIL_ENDIAN | |
636 0x00007C00, | |
637 0x000003E0, 0x0000001F, 0x00000000 | |
638 #else | |
639 0x0000001F, | |
640 0x000003E0, 0x00007C00, 0x00000000 | |
641 #endif | |
642 ); | |
643 break; | |
644 case 8: | |
645 default: | |
646 this->is_32bit = 0; | |
647 this->screen = | |
648 SDL_CreateRGBSurface(flags, width, height, bpp, 0, 0, 0, 0); | |
649 /* give it a default palette if 8 bpp | |
650 * note : SDL already takes care of the palette for 4 bits & 1 bit surfaces | |
651 */ | |
652 /* if (bpp==8) | |
653 { | |
654 this->screen->format->palette->ncolors=255; | |
655 SDL_DitherColors(this->screen->format->palette->colors,bpp); | |
656 }*/ | |
657 break; | |
658 } | |
659 | |
660 /* also, we add SDL_HWSURFACE all the time, and let SDL create a shadow surface accordingly */ | |
661 this->screen->flags = | |
662 hooked_screen->flags | SDL_HWSURFACE | SDL_INTERNALOPENGL; | |
663 /* add SDL_DOUBLEBUF if it was requested */ | |
664 if (flag_doublebuf) | |
665 this->screen->flags |= SDL_DOUBLEBUF; | |
666 | |
667 /* Tell SDL the alpha pixel format we'd like to have */ | |
668 this->displayformatalphapixel = SDL_AllocFormat(32, | |
669 #if SDL_BYTEORDER == SDL_BIG_ENDIAN | |
670 0xFF000000, | |
671 0x00FF0000, | |
672 0x0000FF00, 0x000000FF | |
673 #else | |
674 0x000000FF, | |
675 0x0000FF00, | |
676 0x00FF0000, 0xFF000000 | |
677 #endif | |
678 ); | |
679 | |
680 /* Now create the raw OpenGL surface */ | |
681 OpenGL_Surface = SDL_CreateRGBSurface(flags, width, height, 24, | |
682 #if SDL_BYTEORDER == SDL_LIL_ENDIAN | |
683 0x000000FF, | |
684 0x0000FF00, 0x00FF0000, 0x00000000 | |
685 #else | |
686 0xFF000000, | |
687 0x00FF0000, 0x0000FF00, 0x00000000 | |
688 #endif | |
689 ); | |
690 | |
691 /* Here we have to setup OpenGL funcs ourselves */ | |
692 #ifndef __QNXNTO__ | |
693 #define SDL_PROC(ret,func,params) \ | |
694 do { \ | |
695 this->func = SDL_GL_GetProcAddress(#func); \ | |
696 if ( ! this->func ) { \ | |
697 SDL_SetError("Couldn't load GL function: %s\n", #func); \ | |
698 return(NULL); \ | |
699 } \ | |
700 } while ( 0 ); | |
701 #else | |
702 #define SDL_PROC(ret,func,params) this->func=func; | |
703 #endif /* __QNXNTO__ */ | |
704 #include "../SDL_glfuncs.h" | |
705 #undef SDL_PROC | |
706 | |
707 if (this->GL_MakeCurrent(this) < 0) | |
708 return (NULL); | |
709 #define SDL_PROC(ret,func,params) \ | |
710 do { \ | |
711 this->func = SDL_GL_GetProcAddress(#func); \ | |
712 if ( ! this->func ) { \ | |
713 SDL_SetError("Couldn't load GL function: %s\n", #func); \ | |
714 return(NULL); \ | |
715 } \ | |
716 } while ( 0 ); | |
717 #include "../SDL_glfuncs.h" | |
718 #undef SDL_PROC | |
719 | |
720 | |
721 #ifdef FAKE_MAXTEXSIZE | |
722 maxtexsize = FAKE_MAXTEXSIZE; | |
723 #else | |
724 this->glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxtexsize); | |
725 #endif | |
726 #ifdef DEBUG_GLSDL | |
727 fprintf(stderr, "glSDL: Max texture size: %d\n", maxtexsize); | |
728 #endif | |
729 | |
730 glSDL_init_formats(this); | |
731 | |
732 if (flag_doublebuf) | |
733 this->glDrawBuffer(GL_BACK); | |
734 else | |
735 this->glDrawBuffer(GL_FRONT); | |
736 | |
737 this->glDisable(GL_DITHER); | |
738 | |
739 if (glSDL_AddTexInfo(this, this->screen) < 0) { | |
740 GLERR("HookDevice() failed to add info to screen surface!"); | |
741 return NULL; | |
742 } | |
743 | |
744 glSDL_SetLogicSize(this, this->screen, this->screen->w, this->screen->h); | |
745 | |
746 glSDL_do_texture(this, 0); | |
747 glSDL_do_blend(this, 0); | |
748 | |
749 for (i = 0; i < 1 + flag_doublebuf; ++i) { | |
750 this->glBegin(GL_TRIANGLE_FAN); | |
751 this->glColor3ub(0, 0, 0); | |
752 this->glVertex2i(0, 0); | |
753 this->glVertex2i(this->screen->w, 0); | |
754 this->glVertex2i(this->screen->w, this->screen->h); | |
755 this->glVertex2i(0, this->screen->h); | |
756 this->glEnd(); | |
757 if (!i) | |
758 this->GL_SwapBuffers(this); | |
759 } | |
760 | |
761 mirrorbuf = SDL_malloc(this->screen->h * this->screen->pitch); | |
762 if (!mirrorbuf) { | |
763 GLERR("HookDevice() failed to allocate temp buffer for mirroring!"); | |
764 return NULL; | |
765 } | |
766 | |
767 return this->screen; | |
768 } | |
769 | |
770 static int | |
771 glSDL_SetColors(_THIS, int firstcolor, int ncolors, SDL_Color * colors) | |
772 { | |
773 /* We don't need to fill this one */ | |
774 return 0; | |
775 } | |
776 | |
777 | |
778 #ifdef DEBUG_GLSDL | |
779 static void | |
780 glSDL_print_glerror(_THIS, int point) | |
781 { | |
782 const char *err = "<unknown>"; | |
783 switch (this->glGetError()) { | |
784 case GL_NO_ERROR: | |
785 return; | |
786 case GL_INVALID_ENUM: | |
787 err = "GL_INVALID_ENUM"; | |
788 break; | |
789 case GL_INVALID_VALUE: | |
790 err = "GL_INVALID_VALUE"; | |
791 break; | |
792 case GL_INVALID_OPERATION: | |
793 err = "GL_INVALID_OPERATION"; | |
794 break; | |
795 case GL_STACK_OVERFLOW: | |
796 err = "GL_STACK_OVERFLOW"; | |
797 break; | |
798 case GL_STACK_UNDERFLOW: | |
799 err = "GL_STACK_UNDERFLOW"; | |
800 break; | |
801 case GL_OUT_OF_MEMORY: | |
802 err = "GL_OUT_OF_MEMORY"; | |
803 default: | |
804 break; | |
805 } | |
806 fprintf(stderr, "OpenGL error \"%s\" at point %d.\n", err, point); | |
807 } | |
808 #endif | |
809 | |
810 /* Get texinfo for a surface. */ | |
811 static __inline__ private_hwdata * | |
812 glSDL_GetTexInfo(SDL_Surface * surface) | |
813 { | |
814 if (!surface) | |
815 return NULL; | |
816 return surface->hwdata; | |
817 } | |
818 | |
819 | |
820 /* Allocate a "blank" texinfo for a suface. */ | |
821 static private_hwdata * | |
822 glSDL_AllocTexInfo(SDL_Surface * surface) | |
823 { | |
824 private_hwdata *txi; | |
825 if (!surface) | |
826 return NULL; | |
827 | |
828 txi = glSDL_GetTexInfo(surface); | |
829 if (txi) | |
830 return txi; /* There already is one! --> */ | |
831 | |
832 /* ...and hook a new texinfo struct up to it. */ | |
833 txi = (private_hwdata *) SDL_calloc(1, sizeof(private_hwdata)); | |
834 if (!txi) { | |
835 GLERR("AllocTexInfo(): Failed allocating TexInfo struct!"); | |
836 return NULL; | |
837 } | |
838 txi->temporary = 1; | |
839 #ifdef DEBUG_GLSDL | |
840 fprintf(stderr, "glSDL: Allocated TexInfo %p.\n", txi); | |
841 #endif | |
842 return txi; | |
843 } | |
844 | |
845 | |
846 static void | |
847 glSDL_FreeTexInfo(_THIS, private_hwdata * txi) | |
848 { | |
849 if (!txi) | |
850 return; | |
851 | |
852 glSDL_UnloadTexture(this, txi); | |
853 SDL_free(txi->texture); | |
854 SDL_free(txi); | |
855 #ifdef DEBUG_GLSDL | |
856 fprintf(stderr, "glSDL: Freed TexInfo %p.\n", txi); | |
857 #endif | |
858 } | |
859 | |
860 | |
861 /* Detach and free the texinfo of a surface. */ | |
862 static void | |
863 glSDL_RemoveTexInfo(_THIS, SDL_Surface * surface) | |
864 { | |
865 SDL_Surface *next, *prev; | |
866 if (!glSDL_GetTexInfo(surface)) | |
867 return; | |
868 | |
869 /* maintain our doubly linked list */ | |
870 next = surface->hwdata->next; | |
871 prev = surface->hwdata->prev; | |
872 if (prev != NULL) { | |
873 prev->hwdata->next = next; | |
874 } else { | |
875 first = next; | |
876 } | |
877 if (next != NULL) { | |
878 next->hwdata->prev = prev; | |
879 } | |
880 | |
881 glSDL_FreeTexInfo(this, surface->hwdata); | |
882 surface->hwdata = NULL; | |
883 } | |
884 | |
885 | |
886 /* | |
887 * Calculate chopping/tiling of a surface to | |
888 * fit it into the smallest possible OpenGL | |
889 * texture. | |
890 */ | |
891 static int | |
892 glSDL_CalcChop(private_hwdata * txi) | |
893 { | |
894 int rows, vw, vh; | |
895 int vertical = 0; | |
896 int texsize; | |
897 int lastw, lasth, minsize; | |
898 | |
899 vw = txi->virt.w; | |
900 vh = txi->virt.h; | |
901 | |
902 #ifdef DEBUG_GLSDL_CHOP | |
903 fprintf(stderr, "w=%d, h=%d ", vw, vh); | |
904 #endif | |
905 if (vh > vw) { | |
906 int t = vw; | |
907 vw = vh; | |
908 vh = t; | |
909 vertical = 1; | |
910 #ifdef DEBUG_GLSDL_CHOP | |
911 fprintf(stderr, "(vertical) \t"); | |
912 #endif | |
913 } | |
914 | |
915 /* | |
916 * Check whether this is a "huge" surface - at least one dimension | |
917 * must be <= than the maximum texture size, or we'll have to chop | |
918 * in both directions. | |
919 */ | |
920 #ifdef DEBUG_GLSDL | |
921 if (maxtexsize < 0) | |
922 return GLERET("glSDL_CalcChop() called before OpenGL init!"); | |
923 #endif | |
924 if (vh > maxtexsize) { | |
925 /* | |
926 * Very simple hack for now; we just tile | |
927 * both ways with maximum size textures. | |
928 */ | |
929 texsize = maxtexsize; | |
930 | |
931 txi->tilemode = GLSDL_TM_HUGE; | |
932 txi->texsize = texsize; | |
933 txi->tilew = texsize; | |
934 txi->tileh = texsize; | |
935 txi->tilespertex = 1; | |
936 | |
937 /* Calculate number of textures needed */ | |
938 txi->textures = (vw + texsize - 1) / texsize; | |
939 txi->textures *= (vh + texsize - 1) / texsize; | |
940 txi->texture = SDL_malloc(txi->textures * sizeof(int)); | |
941 SDL_memset(txi->texture, -1, txi->textures * sizeof(int)); | |
942 #ifdef DEBUG_GLSDL | |
943 fprintf(stderr, "two-way tiling; textures=%d\n", txi->textures); | |
944 #endif | |
945 if (!txi->texture) { | |
946 fprintf(stderr, "glSDL: INTERNAL ERROR: Failed to allocate" | |
947 " texture name table!\n"); | |
948 return -3; | |
949 } | |
950 return 0; | |
951 } | |
952 | |
953 /* Calculate minimum size */ | |
954 rows = 1; | |
955 lastw = vw; | |
956 lasth = vh; | |
957 minsize = lastw > lasth ? lastw : lasth; | |
958 while (1) { | |
959 int w, h, size; | |
960 ++rows; | |
961 w = vw / rows; | |
962 h = rows * vh; | |
963 size = w > h ? w : h; | |
964 if (size >= minsize) { | |
965 --rows; | |
966 break; | |
967 } | |
968 lastw = w; | |
969 lasth = h; | |
970 minsize = size; | |
971 } | |
972 if (minsize > maxtexsize) { | |
973 /* Handle multiple textures for very wide/tall surfaces. */ | |
974 minsize = maxtexsize; | |
975 rows = (vw + minsize - 1) / minsize; | |
976 } | |
977 #ifdef DEBUG_GLSDL_CHOP | |
978 fprintf(stderr, "==> minsize=%d ", minsize); | |
979 fprintf(stderr, "(rows=%d) \t", rows); | |
980 #endif | |
981 | |
982 /* Recalculate with nearest higher power-of-2 width. */ | |
983 for (texsize = 1; texsize < minsize; texsize <<= 1); | |
984 txi->texsize = texsize; | |
985 rows = (vw + texsize - 1) / texsize; | |
986 #ifdef DEBUG_GLSDL_CHOP | |
987 fprintf(stderr, "==> texsize=%d (rows=%d) \t", texsize, rows); | |
988 #endif | |
989 | |
990 /* Calculate number of tiles per texture */ | |
991 txi->tilespertex = txi->texsize / vh; | |
992 #ifdef DEBUG_GLSDL_CHOP | |
993 fprintf(stderr, "tilespertex=%d \t", txi->tilespertex); | |
994 #endif | |
995 | |
996 /* Calculate number of textures needed */ | |
997 txi->textures = (rows + txi->tilespertex - 1) / txi->tilespertex; | |
998 txi->texture = (GLuint *) SDL_malloc(txi->textures * sizeof(GLuint)); | |
999 SDL_memset(txi->texture, GLSDL_NOTEX, txi->textures * sizeof(GLuint)); | |
1000 #ifdef DEBUG_GLSDL_CHOP | |
1001 fprintf(stderr, "textures=%d, ", txi->textures); | |
1002 #endif | |
1003 if (!txi->texture) | |
1004 return GLERET("Failed to allocate texture name table!"); | |
1005 | |
1006 /* Set up tile size. (Only one axis supported here!) */ | |
1007 if (1 == rows) { | |
1008 txi->tilemode = GLSDL_TM_SINGLE; | |
1009 if (vertical) { | |
1010 txi->tilew = vh; | |
1011 txi->tileh = vw; | |
1012 } else { | |
1013 txi->tilew = vw; | |
1014 txi->tileh = vh; | |
1015 } | |
1016 } else if (vertical) { | |
1017 txi->tilemode = GLSDL_TM_VERTICAL; | |
1018 txi->tilew = vh; | |
1019 txi->tileh = texsize; | |
1020 } else { | |
1021 txi->tilemode = GLSDL_TM_HORIZONTAL; | |
1022 txi->tilew = texsize; | |
1023 txi->tileh = vh; | |
1024 } | |
1025 | |
1026 #ifdef DEBUG_GLSDL_CHOP | |
1027 fprintf(stderr, "tilew=%d, tileh=%d\n", txi->tilew, txi->tileh); | |
1028 #endif | |
1029 return 0; | |
1030 } | |
1031 | |
1032 | |
1033 /* Create a temporary TexInfo struct for an SDL_Surface */ | |
1034 static private_hwdata * | |
1035 glSDL_CreateTempTexInfo(_THIS, SDL_Surface * surface) | |
1036 { | |
1037 private_hwdata *txi; | |
1038 if (!surface) { | |
1039 GLERR("CreateTempTexInfo(); no surface!"); | |
1040 return NULL; | |
1041 } | |
1042 if (IS_GLSDL_SURFACE(surface)) | |
1043 return glSDL_GetTexInfo(surface); /* Do nothing */ | |
1044 | |
1045 txi = glSDL_AllocTexInfo(surface); | |
1046 if (!txi) { | |
1047 GLERR("CreateTempTexInfo(); Could not alloc TexInfo!"); | |
1048 return NULL; | |
1049 } | |
1050 txi->virt.w = txi->lw = surface->w; | |
1051 txi->virt.h = txi->lh = surface->h; | |
1052 | |
1053 if (glSDL_CalcChop(txi) < 0) { | |
1054 glSDL_FreeTexInfo(this, txi); | |
1055 GLERR("CreateTempTexInfo(); CalcChop() failed!"); | |
1056 return NULL; | |
1057 } | |
1058 | |
1059 return txi; | |
1060 } | |
1061 | |
1062 /* Add a glSDL_TexInfo struct to an SDL_Surface */ | |
1063 static private_hwdata * | |
1064 glSDL_AddTexInfo(_THIS, SDL_Surface * surface) | |
1065 { | |
1066 private_hwdata *txi = glSDL_CreateTempTexInfo(this, surface); | |
1067 if (!txi) | |
1068 return NULL; | |
1069 | |
1070 /* Connect the surface to the new TexInfo. */ | |
1071 txi->temporary = 0; | |
1072 surface->hwdata = txi; | |
1073 | |
1074 /* add this new surface in front of the list of hw surfaces */ | |
1075 txi->next = first; | |
1076 txi->prev = NULL; | |
1077 first = surface; | |
1078 if (txi->next != NULL) { | |
1079 txi->next->hwdata->prev = surface; | |
1080 } | |
1081 | |
1082 SDL_SetClipRect(surface, &txi->virt); | |
1083 return txi; | |
1084 } | |
1085 | |
1086 | |
1087 /* Create a surface of the prefered OpenGL RGB texture format */ | |
1088 /*static SDL_Surface *glSDL_CreateRGBSurface(int w, int h) | |
1089 { | |
1090 SDL_Surface *s; | |
1091 Uint32 rmask, gmask, bmask; | |
1092 int bits = 24; | |
1093 #if SDL_BYTEORDER == SDL_LIL_ENDIAN | |
1094 rmask = 0x000000FF; | |
1095 gmask = 0x0000FF00; | |
1096 bmask = 0x00FF0000; | |
1097 #else | |
1098 rmask = 0x00FF0000; | |
1099 gmask = 0x0000FF00; | |
1100 bmask = 0x000000FF; | |
1101 #endif | |
1102 s = SDL_CreateRGBSurface(SDL_SWSURFACE, w, h, | |
1103 bits, rmask, gmask, bmask, 0); | |
1104 if(s) | |
1105 s->flags |= SDL_HWACCEL; | |
1106 | |
1107 return s; | |
1108 } | |
1109 */ | |
1110 | |
1111 /* Create a surface of the prefered OpenGL RGBA texture format */ | |
1112 static SDL_Surface * | |
1113 glSDL_CreateRGBASurface(int w, int h) | |
1114 { | |
1115 SDL_Surface *s; | |
1116 Uint32 rmask, gmask, bmask, amask; | |
1117 int bits = 32; | |
1118 #if SDL_BYTEORDER == SDL_LIL_ENDIAN | |
1119 rmask = 0x000000FF; | |
1120 gmask = 0x0000FF00; | |
1121 bmask = 0x00FF0000; | |
1122 amask = 0xFF000000; | |
1123 #else | |
1124 rmask = 0xFF000000; | |
1125 gmask = 0x00FF0000; | |
1126 bmask = 0x0000FF00; | |
1127 amask = 0x000000FF; | |
1128 #endif | |
1129 s = SDL_CreateRGBSurface(SDL_SWSURFACE, w, h, | |
1130 bits, rmask, gmask, bmask, amask); | |
1131 if (s) | |
1132 s->flags |= SDL_HWACCEL; | |
1133 | |
1134 return s; | |
1135 } | |
1136 | |
1137 | |
1138 static void | |
1139 glSDL_init_formats(_THIS) | |
1140 { | |
1141 RGBfmt = SDL_AllocFormat(24, | |
1142 #if SDL_BYTEORDER == SDL_LIL_ENDIAN | |
1143 0x000000FF, 0x0000FF00, 0x00FF0000, 0); | |
1144 #else | |
1145 0x00FF0000, 0x0000FF00, 0x000000FF, 0); | |
1146 #endif | |
1147 RGBAfmt = SDL_AllocFormat(32, | |
1148 #if SDL_BYTEORDER == SDL_LIL_ENDIAN | |
1149 0x000000FF, 0x0000FF00, 0x00FF0000, 0xFF000000); | |
1150 #else | |
1151 0xFF000000, 0x00FF0000, 0x0000FF00, 0x000000FF); | |
1152 #endif | |
1153 } | |
1154 | |
1155 | |
1156 static int | |
1157 glSDL_FormatIsOk(SDL_Surface * surface) | |
1158 { | |
1159 SDL_PixelFormat *pf; | |
1160 if (!surface) | |
1161 return 1; /* Well, there ain't much we can do anyway... */ | |
1162 | |
1163 pf = surface->format; | |
1164 | |
1165 /* Colorkeying requires an alpha channel! */ | |
1166 if (surface->flags & SDL_SRCCOLORKEY) | |
1167 if (!pf->Amask) | |
1168 return 0; | |
1169 | |
1170 /* We need pitch == (width * BytesPerPixel) for glTex[Sub]Image2D() */ | |
1171 if (surface->pitch != (surface->w * pf->BytesPerPixel)) | |
1172 return 0; | |
1173 | |
1174 if (pf->Amask) { | |
1175 if (pf->BytesPerPixel != RGBAfmt->BytesPerPixel) | |
1176 return 0; | |
1177 if (pf->Rmask != RGBAfmt->Rmask) | |
1178 return 0; | |
1179 if (pf->Gmask != RGBAfmt->Gmask) | |
1180 return 0; | |
1181 if (pf->Bmask != RGBAfmt->Bmask) | |
1182 return 0; | |
1183 if (pf->Amask != RGBAfmt->Amask) | |
1184 return 0; | |
1185 } else { | |
1186 if (pf->BytesPerPixel != RGBfmt->BytesPerPixel) | |
1187 return 0; | |
1188 if (pf->Rmask != RGBfmt->Rmask) | |
1189 return 0; | |
1190 if (pf->Gmask != RGBfmt->Gmask) | |
1191 return 0; | |
1192 if (pf->Bmask != RGBfmt->Bmask) | |
1193 return 0; | |
1194 } | |
1195 return 1; | |
1196 } | |
1197 | |
1198 static void | |
1199 glSDL_key2alpha(SDL_Surface * surface) | |
1200 { | |
1201 int x, y; | |
1202 Uint32 ckey = surface->format->colorkey; | |
1203 | |
1204 #ifdef DEBUG_GLSDL | |
1205 fprintf(stderr, "glSDL_key2alpha()\n"); | |
1206 #endif | |
1207 for (y = 0; y < surface->h; ++y) { | |
1208 Uint32 *px = | |
1209 (Uint32 *) ((char *) surface->pixels + y * surface->pitch); | |
1210 for (x = 0; x < surface->w; ++x) | |
1211 if (px[x] == ckey) | |
1212 px[x] = 0; | |
1213 } | |
1214 } | |
1215 | |
1216 | |
1217 | |
1218 /*---------------------------------------------------------- | |
1219 SDL style API | |
1220 ----------------------------------------------------------*/ | |
1221 | |
1222 static int | |
1223 glSDL_FlipHWSurface(_THIS, SDL_Surface * surface) | |
1224 { | |
1225 #ifdef GLSDL_GRAPHICAL_DEBUG | |
1226 this->glDisable(GL_TEXTURE_2D); | |
1227 this->glBegin(GL_LINE_LOOP); | |
1228 this->glColor4ub(0, 0, 255, 128); | |
1229 this->glVertex2i(0, 0); | |
1230 this->glVertex2i(surface->w, 0); | |
1231 this->glVertex2i(surface->w, surface->h); | |
1232 this->glVertex2i(0, surface->h); | |
1233 this->glEnd(); | |
1234 this->glEnable(GL_TEXTURE_2D); | |
1235 #endif | |
1236 if (this->screen->flags & SDL_DOUBLEBUF) | |
1237 this->GL_SwapBuffers(this); | |
1238 else | |
1239 this->glFinish(); | |
1240 return 0; | |
1241 } | |
1242 | |
1243 | |
1244 static void | |
1245 glSDL_UpdateRects(_THIS, int numrects, SDL_Rect * rects) | |
1246 { | |
1247 #ifdef GLSDL_GRAPHICAL_DEBUG | |
1248 int i; | |
1249 this->glDisable(GL_TEXTURE_2D); | |
1250 for (i = 0; i < numrects; i++) { | |
1251 this->glColor4ub(255, 0, 0, 128); | |
1252 this->glBegin(GL_LINE_LOOP); | |
1253 this->glVertex2i(rects[i].x, rects[i].y); | |
1254 this->glVertex2i(rects[i].x + rects[i].w, rects[i].y); | |
1255 this->glVertex2i(rects[i].x + rects[i].w, rects[i].y + rects[i].h); | |
1256 this->glVertex2i(rects[i].x, rects[i].y + rects[i].h); | |
1257 this->glEnd(); | |
1258 } | |
1259 this->glEnable(GL_TEXTURE_2D); | |
1260 #endif | |
1261 if (this->screen->flags & SDL_DOUBLEBUF) | |
1262 this->GL_SwapBuffers(this); | |
1263 else | |
1264 this->glFinish(); | |
1265 } | |
1266 | |
1267 | |
1268 static int | |
1269 glSDL_AllocHWSurface(_THIS, SDL_Surface * surface) | |
1270 { | |
1271 surface->flags |= (SDL_HWSURFACE | SDL_HWACCEL); | |
1272 | |
1273 surface->pixels = SDL_malloc(surface->h * surface->pitch); | |
1274 if (surface->pixels == NULL) { | |
1275 SDL_FreeSurface(surface); | |
1276 SDL_OutOfMemory(); | |
1277 return (-1); | |
1278 } | |
1279 SDL_memset(surface->pixels, 0, surface->h * surface->pitch); | |
1280 return 0; | |
1281 } | |
1282 | |
1283 | |
1284 static void | |
1285 glSDL_FreeHWSurface(_THIS, SDL_Surface * surface) | |
1286 { | |
1287 if (!surface) | |
1288 return; | |
1289 glSDL_RemoveTexInfo(this, surface); | |
1290 } | |
1291 | |
1292 | |
1293 static int | |
1294 glSDL_LockHWSurface(_THIS, SDL_Surface * surface) | |
1295 { | |
1296 int y; | |
1297 | |
1298 if (!surface) | |
1299 return -1; | |
1300 | |
1301 #ifdef DEBUG_GLSDL | |
1302 fprintf(stderr, "glSDL: Lock Surface.\n"); | |
1303 #endif | |
1304 | |
1305 if (SDL_VideoSurface == surface) { | |
1306 glSDL_Invalidate(surface, NULL); | |
1307 this->glPixelStorei(GL_UNPACK_ROW_LENGTH, | |
1308 surface->pitch / surface->format->BytesPerPixel); | |
1309 this->glReadPixels(0, 0, OpenGL_Surface->w, OpenGL_Surface->h, | |
1310 GL_RGB, GL_UNSIGNED_BYTE, OpenGL_Surface->pixels); | |
1311 for (y = 0; y < OpenGL_Surface->h / 2; ++y) { | |
1312 void *upper = (Uint8 *) OpenGL_Surface->pixels + | |
1313 OpenGL_Surface->pitch * y; | |
1314 void *lower = (Uint8 *) OpenGL_Surface->pixels + | |
1315 OpenGL_Surface->pitch * (OpenGL_Surface->h - y - 1); | |
1316 SDL_memcpy(mirrorbuf, upper, OpenGL_Surface->pitch); | |
1317 SDL_memcpy(upper, lower, OpenGL_Surface->pitch); | |
1318 SDL_memcpy(lower, mirrorbuf, OpenGL_Surface->pitch); | |
1319 } | |
1320 /* the mapping has to be invalidated on 8bpp video surfaces in case of a hw palette change. | |
1321 * Now if someone could tell me why this is not handled by SDL... */ | |
1322 if (SDL_VideoSurface->format->BitsPerPixel == 8) | |
1323 SDL_InvalidateMap(OpenGL_Surface->map); | |
1324 | |
1325 /* convert this raw surface to the application-requested format | |
1326 * FIXME this is sometimes overkill, we could use glPixelStore smartly | |
1327 * But this would be slow anyway :) */ | |
1328 | |
1329 glSDL_SoftBlit(OpenGL_Surface, NULL, SDL_VideoSurface, NULL); | |
1330 } else | |
1331 glSDL_Invalidate(surface, NULL); | |
1332 | |
1333 return 0; | |
1334 } | |
1335 | |
1336 | |
1337 static void | |
1338 glSDL_UnlockHWSurface(_THIS, SDL_Surface * surface) | |
1339 { | |
1340 private_hwdata *txi; | |
1341 | |
1342 if (!surface) | |
1343 return; | |
1344 | |
1345 /* upload this surface ONLY if this is a glSDL surface | |
1346 * because sometimes (during displayformating for ex.) surfaces are unlocked that aren't glSDL | |
1347 */ | |
1348 if (!IS_GLSDL_SURFACE(surface)) | |
1349 return; | |
1350 | |
1351 #ifdef DEBUG_GLSDL | |
1352 fprintf(stderr, "glSDL: Unlock Surface.\n"); | |
1353 #endif | |
1354 | |
1355 txi = glSDL_UploadSurface(this, surface); | |
1356 | |
1357 if (!txi) { | |
1358 GLERR("glSDL_UnlockHWSurface() failed to upload surface!"); | |
1359 return; | |
1360 } | |
1361 if (txi->temporary) { | |
1362 GLERR | |
1363 ("Weirdness... glSDL_UnlockHWSurface() got a temporary TexInfo."); | |
1364 return; | |
1365 } | |
1366 if (surface == SDL_VideoSurface) | |
1367 glSDL_BlitGL(this, SDL_VideoSurface, NULL, NULL); | |
1368 } | |
1369 | |
1370 | |
1371 static int | |
1372 glSDL_SetHWColorKey(_THIS, SDL_Surface * surface, Uint32 key) | |
1373 { | |
1374 /* | |
1375 * If an application does this *after* SDL_DisplayFormat, | |
1376 * we're basically screwed, unless we want to do an | |
1377 * in-place surface conversion hack here. | |
1378 * | |
1379 * What we do is just kill the glSDL texinfo... No big | |
1380 * deal in most cases, as glSDL only converts once anyway, | |
1381 * *unless* you keep modifying the surface. | |
1382 */ | |
1383 if (IS_GLSDL_SURFACE(surface)) | |
1384 glSDL_RemoveTexInfo(this, surface); | |
1385 return 0; | |
1386 } | |
1387 | |
1388 | |
1389 static int | |
1390 glSDL_SetHWAlpha(_THIS, SDL_Surface * surface, Uint8 alpha) | |
1391 { | |
1392 /* | |
1393 * If an application does this *after* SDL_DisplayFormat, | |
1394 * we're basically screwed, unless we want to do an | |
1395 * in-place surface conversion hack here. | |
1396 * | |
1397 * What we do is just kill the glSDL texinfo... No big | |
1398 * deal in most cases, as glSDL only converts once anyway, | |
1399 * *unless* you keep modifying the surface. | |
1400 */ | |
1401 if (IS_GLSDL_SURFACE(surface)) | |
1402 glSDL_RemoveTexInfo(this, surface); | |
1403 return 0; | |
1404 } | |
1405 | |
1406 static SDL_bool | |
1407 glSDL_SetClipRect(_THIS, SDL_Surface * surface, SDL_Rect * rect) | |
1408 { | |
1409 SDL_bool res; | |
1410 if (!surface) | |
1411 return SDL_FALSE; | |
1412 | |
1413 res = SDL_SetClipRect(surface, rect); | |
1414 if (!res) | |
1415 return SDL_FALSE; | |
1416 | |
1417 rect = &surface->clip_rect; | |
1418 | |
1419 if (surface == SDL_VideoSurface) { | |
1420 SDL_Rect r; | |
1421 float xscale, yscale; | |
1422 private_hwdata *txi; | |
1423 | |
1424 r.x = rect->x; | |
1425 r.y = rect->y; | |
1426 r.w = rect->w; | |
1427 r.h = rect->h; | |
1428 SDL_SetClipRect(surface, rect); | |
1429 | |
1430 txi = glSDL_GetTexInfo(surface); | |
1431 if (!txi) | |
1432 return GLERET("SetClipRect(): Could not get TexInfo!"); | |
1433 | |
1434 this->glViewport(rect->x, | |
1435 surface->h - (rect->y + rect->h), rect->w, rect->h); | |
1436 /* | |
1437 * Note that this projection is upside down in | |
1438 * relation to the OpenGL coordinate system. | |
1439 */ | |
1440 this->glMatrixMode(GL_PROJECTION); | |
1441 this->glLoadIdentity(); | |
1442 xscale = (float) txi->lw / (float) surface->w; | |
1443 yscale = (float) txi->lh / (float) surface->h; | |
1444 this->glOrtho(xscale * (float) rect->x, | |
1445 xscale * (float) (rect->w + rect->x), | |
1446 yscale * (float) (rect->h + rect->y), | |
1447 yscale * (float) rect->y, -1.0, 1.0); | |
1448 return SDL_TRUE; | |
1449 } | |
1450 return res; | |
1451 } | |
1452 | |
1453 static int | |
1454 glSDL_BlitFromGL(_THIS, SDL_Rect * srcrect, | |
1455 SDL_Surface * dst, SDL_Rect * dstrect) | |
1456 { | |
1457 SDL_Rect sr, dr; | |
1458 | |
1459 /* In case the destination has an OpenGL texture... */ | |
1460 glSDL_Invalidate(dst, dstrect); | |
1461 | |
1462 /* Abuse the fake screen buffer a little. */ | |
1463 this->glPixelStorei(GL_UNPACK_ROW_LENGTH, SDL_VideoSurface->pitch / | |
1464 SDL_VideoSurface->format->BytesPerPixel); | |
1465 if (srcrect) | |
1466 this->glReadPixels(srcrect->x, | |
1467 OpenGL_Surface->h - (srcrect->y + srcrect->h - 1), | |
1468 srcrect->w, srcrect->h, GL_RGB, GL_UNSIGNED_BYTE, | |
1469 OpenGL_Surface->pixels); | |
1470 else | |
1471 this->glReadPixels(0, 0, OpenGL_Surface->w, OpenGL_Surface->h, | |
1472 GL_RGB, GL_UNSIGNED_BYTE, OpenGL_Surface->pixels); | |
1473 sr = *srcrect; | |
1474 dr = *dstrect; | |
1475 glSDL_SoftBlit(OpenGL_Surface, &sr, dst, &dr); | |
1476 return 0; | |
1477 } | |
1478 | |
1479 static __inline__ void | |
1480 glSDL_BlitGL_single(_THIS, private_hwdata * txi, | |
1481 float sx1, float sy1, SDL_Rect * dst, unsigned char alpha) | |
1482 { | |
1483 float sx2, sy2, texscale; | |
1484 if (!txi->textures) | |
1485 return; | |
1486 if (-1 == txi->texture[0]) | |
1487 return; | |
1488 glSDL_texture(this, txi->texture[0]); | |
1489 | |
1490 texscale = 1.0 / (float) txi->texsize; | |
1491 sx2 = (sx1 + (float) dst->w) * texscale; | |
1492 sy2 = (sy1 + (float) dst->h) * texscale; | |
1493 sx1 *= texscale; | |
1494 sy1 *= texscale; | |
1495 | |
1496 #ifdef GLSDL_GRAPHICAL_DEBUG | |
1497 this->glDisable(GL_TEXTURE_2D); | |
1498 this->glBegin(GL_LINE_LOOP); | |
1499 this->glColor4ub(0, 255, 0, 128); | |
1500 this->glVertex2i(dst->x, dst->y); | |
1501 this->glVertex2i(dst->x + dst->w, dst->y); | |
1502 this->glVertex2i(dst->x + dst->w, dst->y + dst->h); | |
1503 this->glVertex2i(dst->x, dst->y + dst->h); | |
1504 this->glEnd(); | |
1505 this->glEnable(GL_TEXTURE_2D); | |
1506 #endif | |
1507 | |
1508 this->glBegin(GL_TRIANGLE_FAN); | |
1509 this->glColor4ub(255, 255, 255, alpha); | |
1510 this->glTexCoord2f(sx1, sy1); | |
1511 this->glVertex2i(dst->x, dst->y); | |
1512 this->glTexCoord2f(sx2, sy1); | |
1513 this->glVertex2i(dst->x + dst->w, dst->y); | |
1514 this->glTexCoord2f(sx2, sy2); | |
1515 this->glVertex2i(dst->x + dst->w, dst->y + dst->h); | |
1516 this->glTexCoord2f(sx1, sy2); | |
1517 this->glVertex2i(dst->x, dst->y + dst->h); | |
1518 this->glEnd(); | |
1519 } | |
1520 | |
1521 | |
1522 static void | |
1523 glSDL_BlitGL_htile(_THIS, private_hwdata * txi, | |
1524 float sx1, float sy1, SDL_Rect * dst, unsigned char alpha) | |
1525 { | |
1526 int tex; | |
1527 float tile, sx2, sy2, yo; | |
1528 float texscale = 1.0 / (float) txi->texsize; | |
1529 float tileh = (float) txi->tileh * texscale; | |
1530 sx2 = (sx1 + (float) dst->w) * texscale; | |
1531 sy2 = (sy1 + (float) dst->h) * texscale; | |
1532 sx1 *= texscale; | |
1533 sy1 *= texscale; | |
1534 tile = floor(sx1); | |
1535 tex = (int) tile / txi->tilespertex; | |
1536 yo = ((int) tile % txi->tilespertex) * tileh; | |
1537 | |
1538 if (tex >= txi->textures) | |
1539 return; | |
1540 if (-1 == txi->texture[tex]) | |
1541 return; | |
1542 glSDL_texture(this, txi->texture[tex]); | |
1543 | |
1544 while (tile < sx2) { | |
1545 int tdx1 = dst->x; | |
1546 int tdx2 = dst->x + dst->w; | |
1547 float tsx1 = sx1 - tile; | |
1548 float tsx2 = sx2 - tile; | |
1549 | |
1550 /* Clip to current tile */ | |
1551 if (tsx1 < 0.0) { | |
1552 tdx1 -= tsx1 * txi->texsize; | |
1553 tsx1 = 0.0; | |
1554 } | |
1555 if (tsx2 > 1.0) { | |
1556 tdx2 -= (tsx2 - 1.0) * txi->texsize; | |
1557 tsx2 = 1.0; | |
1558 } | |
1559 | |
1560 /* Maybe select next texture? */ | |
1561 if (yo + tileh > 1.0) { | |
1562 ++tex; | |
1563 if (tex >= txi->textures) | |
1564 return; | |
1565 if (-1 == txi->texture[tex]) | |
1566 return; | |
1567 glSDL_texture(this, txi->texture[tex]); | |
1568 yo = 0.0; | |
1569 } | |
1570 #ifdef GLSDL_GRAPHICAL_DEBUG | |
1571 this->glDisable(GL_TEXTURE_2D); | |
1572 this->glBegin(GL_LINE_LOOP); | |
1573 this->glColor4ub(0, 255, 0, 128); | |
1574 this->glVertex2i(tdx1, dst->y); | |
1575 this->glVertex2i(tdx2, dst->y); | |
1576 this->glVertex2i(tdx2, dst->y + dst->h); | |
1577 this->glVertex2i(tdx1, dst->y + dst->h); | |
1578 this->glEnd(); | |
1579 this->glEnable(GL_TEXTURE_2D); | |
1580 #endif | |
1581 | |
1582 this->glBegin(GL_TRIANGLE_FAN); | |
1583 this->glColor4ub(255, 255, 255, alpha); | |
1584 this->glTexCoord2f(tsx1, yo + sy1); | |
1585 this->glVertex2i(tdx1, dst->y); | |
1586 this->glTexCoord2f(tsx2, yo + sy1); | |
1587 this->glVertex2i(tdx2, dst->y); | |
1588 this->glTexCoord2f(tsx2, yo + sy2); | |
1589 this->glVertex2i(tdx2, dst->y + dst->h); | |
1590 this->glTexCoord2f(tsx1, yo + sy2); | |
1591 this->glVertex2i(tdx1, dst->y + dst->h); | |
1592 this->glEnd(); | |
1593 tile += 1.0; | |
1594 yo += tileh; | |
1595 } | |
1596 } | |
1597 | |
1598 | |
1599 static void | |
1600 glSDL_BlitGL_vtile(_THIS, private_hwdata * txi, | |
1601 float sx1, float sy1, SDL_Rect * dst, unsigned char alpha) | |
1602 { | |
1603 int tex; | |
1604 float tile, sx2, sy2, xo; | |
1605 float texscale = 1.0 / (float) txi->texsize; | |
1606 float tilew = (float) txi->tilew * texscale; | |
1607 sx2 = (sx1 + (float) dst->w) * texscale; | |
1608 sy2 = (sy1 + (float) dst->h) * texscale; | |
1609 sx1 *= texscale; | |
1610 sy1 *= texscale; | |
1611 tile = floor(sy1); | |
1612 tex = (int) tile / txi->tilespertex; | |
1613 xo = ((int) tile % txi->tilespertex) * tilew; | |
1614 | |
1615 if (tex >= txi->textures) | |
1616 return; | |
1617 if (-1 == txi->texture[tex]) | |
1618 return; | |
1619 glSDL_texture(this, txi->texture[tex]); | |
1620 | |
1621 while (tile < sy2) { | |
1622 int tdy1 = dst->y; | |
1623 int tdy2 = dst->y + dst->h; | |
1624 float tsy1 = sy1 - tile; | |
1625 float tsy2 = sy2 - tile; | |
1626 | |
1627 /* Clip to current tile */ | |
1628 if (tsy1 < 0.0) { | |
1629 tdy1 -= tsy1 * txi->texsize; | |
1630 tsy1 = 0.0; | |
1631 } | |
1632 if (tsy2 > 1.0) { | |
1633 tdy2 -= (tsy2 - 1.0) * txi->texsize; | |
1634 tsy2 = 1.0; | |
1635 } | |
1636 | |
1637 /* Maybe select next texture? */ | |
1638 if (xo + tilew > 1.0) { | |
1639 ++tex; | |
1640 if (tex >= txi->textures) | |
1641 return; | |
1642 if (-1 == txi->texture[tex]) | |
1643 return; | |
1644 glSDL_texture(this, txi->texture[tex]); | |
1645 xo = 0.0; | |
1646 } | |
1647 #ifdef GLSDL_GRAPHICAL_DEBUG | |
1648 this->glDisable(GL_TEXTURE_2D); | |
1649 this->glBegin(GL_LINE_LOOP); | |
1650 this->glColor4ub(0, 255, 0, 128); | |
1651 this->glVertex2i(dst->x, tdy1); | |
1652 this->glVertex2i(dst->x + dst->w, tdy1); | |
1653 this->glVertex2i(dst->x + dst->w, tdy2); | |
1654 this->glVertex2i(dst->x, tdy2); | |
1655 this->glEnd(); | |
1656 this->glEnable(GL_TEXTURE_2D); | |
1657 #endif | |
1658 | |
1659 this->glBegin(GL_TRIANGLE_FAN); | |
1660 this->glColor4ub(255, 255, 255, alpha); | |
1661 this->glTexCoord2f(xo + sx1, tsy1); | |
1662 this->glVertex2i(dst->x, tdy1); | |
1663 this->glTexCoord2f(xo + sx2, tsy1); | |
1664 this->glVertex2i(dst->x + dst->w, tdy1); | |
1665 this->glTexCoord2f(xo + sx2, tsy2); | |
1666 this->glVertex2i(dst->x + dst->w, tdy2); | |
1667 this->glTexCoord2f(xo + sx1, tsy2); | |
1668 this->glVertex2i(dst->x, tdy2); | |
1669 this->glEnd(); | |
1670 | |
1671 tile += 1.0; | |
1672 xo += tilew; | |
1673 } | |
1674 } | |
1675 | |
1676 | |
1677 static void | |
1678 glSDL_BlitGL_hvtile(_THIS, SDL_Surface * src, private_hwdata * txi, | |
1679 float sx1, float sy1, SDL_Rect * dst, unsigned char alpha) | |
1680 { | |
1681 int x, y, last_tex, tex; | |
1682 float sx2, sy2; | |
1683 float texscale = 1.0 / (float) txi->texsize; | |
1684 int tilesperrow = (src->w + txi->tilew - 1) / txi->tilew; | |
1685 sx2 = (sx1 + (float) dst->w) * texscale; | |
1686 sy2 = (sy1 + (float) dst->h) * texscale; | |
1687 sx1 *= texscale; | |
1688 sy1 *= texscale; | |
1689 | |
1690 last_tex = tex = floor(sy1) * tilesperrow + floor(sx1); | |
1691 if (tex >= txi->textures) | |
1692 return; | |
1693 if (-1 == txi->texture[tex]) | |
1694 return; | |
1695 glSDL_texture(this, txi->texture[tex]); | |
1696 | |
1697 for (y = floor(sy1); y < sy2; ++y) { | |
1698 int tdy1 = dst->y; | |
1699 int tdy2 = dst->y + dst->h; | |
1700 float tsy1 = sy1 - y; | |
1701 float tsy2 = sy2 - y; | |
1702 | |
1703 /* Clip to current tile */ | |
1704 if (tsy1 < 0.0) { | |
1705 tdy1 -= tsy1 * txi->texsize; | |
1706 tsy1 = 0.0; | |
1707 } | |
1708 if (tsy2 > 1.0) { | |
1709 tdy2 -= (tsy2 - 1.0) * txi->texsize; | |
1710 tsy2 = 1.0; | |
1711 } | |
1712 for (x = floor(sx1); x < sx2; ++x) { | |
1713 int tdx1 = dst->x; | |
1714 int tdx2 = dst->x + dst->w; | |
1715 float tsx1 = sx1 - x; | |
1716 float tsx2 = sx2 - x; | |
1717 | |
1718 /* Clip to current tile */ | |
1719 if (tsx1 < 0.0) { | |
1720 tdx1 -= tsx1 * txi->texsize; | |
1721 tsx1 = 0.0; | |
1722 } | |
1723 if (tsx2 > 1.0) { | |
1724 tdx2 -= (tsx2 - 1.0) * txi->texsize; | |
1725 tsx2 = 1.0; | |
1726 } | |
1727 | |
1728 /* Select texture */ | |
1729 tex = y * tilesperrow + x; | |
1730 if (tex != last_tex) { | |
1731 if (tex >= txi->textures) | |
1732 return; | |
1733 if (-1 == txi->texture[tex]) | |
1734 return; | |
1735 glSDL_texture(this, txi->texture[tex]); | |
1736 last_tex = tex; | |
1737 } | |
1738 #ifdef GLSDL_GRAPHICAL_DEBUG | |
1739 this->glDisable(GL_TEXTURE_2D); | |
1740 this->glBegin(GL_LINE_LOOP); | |
1741 this->glColor4ub(0, 255, 0, 128); | |
1742 this->glVertex2i(tdx1, tdy1); | |
1743 this->glVertex2i(tdx2, tdy1); | |
1744 this->glVertex2i(tdx2, tdy2); | |
1745 this->glVertex2i(tdx1, tdy2); | |
1746 this->glEnd(); | |
1747 this->glEnable(GL_TEXTURE_2D); | |
1748 #endif | |
1749 | |
1750 this->glBegin(GL_TRIANGLE_FAN); | |
1751 this->glColor4ub(255, 255, 255, alpha); | |
1752 this->glTexCoord2f(tsx1, tsy1); | |
1753 this->glVertex2i(tdx1, tdy1); | |
1754 this->glTexCoord2f(tsx2, tsy1); | |
1755 this->glVertex2i(tdx2, tdy1); | |
1756 this->glTexCoord2f(tsx2, tsy2); | |
1757 this->glVertex2i(tdx2, tdy2); | |
1758 this->glTexCoord2f(tsx1, tsy2); | |
1759 this->glVertex2i(tdx1, tdy2); | |
1760 this->glEnd(); | |
1761 } | |
1762 } | |
1763 } | |
1764 | |
1765 /* | |
1766 * Calculate the actual blit rectangle and source offset | |
1767 * for a blit from a rectangle in a surface with specified | |
1768 * size to a surface with a cliprect. | |
1769 * | |
1770 * In: rect source rectangle | |
1771 * w, h source surface size | |
1772 * (x, y) destination coordinate | |
1773 * clip destination clip rectangle | |
1774 * | |
1775 * Out: (x, y) source top-left offset | |
1776 * rect destination rectangle | |
1777 * | |
1778 * Returns 1 if the result is visible, otherwise 0. | |
1779 */ | |
1780 static __inline__ int | |
1781 blitclip(SDL_Rect * rect, int w, int h, int *x, int *y, SDL_Rect * clip) | |
1782 { | |
1783 int sx1, sy1, sx2, sy2; | |
1784 int dx1, dy1, dx2, dy2; | |
1785 | |
1786 /* Get source and destination coordinates */ | |
1787 sx1 = rect->x; | |
1788 sy1 = rect->y; | |
1789 sx2 = sx1 + rect->w; | |
1790 sy2 = sy1 + rect->h; | |
1791 dx1 = *x; | |
1792 dy1 = *y; | |
1793 | |
1794 /* Keep source rect inside source surface */ | |
1795 if (sx1 < 0) { | |
1796 dx1 -= sx1; | |
1797 sx1 = 0; | |
1798 } | |
1799 if (sy1 < 0) { | |
1800 dy1 -= sy1; | |
1801 sy1 = 0; | |
1802 } | |
1803 if (sx2 > w) | |
1804 sx2 = w; | |
1805 if (sy2 > h) | |
1806 sy2 = h; | |
1807 | |
1808 /* Cull blits from void space */ | |
1809 if (sx1 >= sx2 || sy1 >= sy2) | |
1810 return 0; | |
1811 | |
1812 /* Calculate destination lower-right */ | |
1813 dx2 = dx1 + (sx2 - sx1); | |
1814 dy2 = dy1 + (sy2 - sy1); | |
1815 | |
1816 /* Clip to destination cliprect */ | |
1817 if (dx1 < clip->x) { | |
1818 sx1 += clip->x - dx1; | |
1819 dx1 = clip->x; | |
1820 } | |
1821 if (dy1 < clip->y) { | |
1822 sy1 += clip->y - dy1; | |
1823 dy1 = clip->y; | |
1824 } | |
1825 if (dx2 > clip->x + clip->w) | |
1826 dx2 = clip->x + clip->w; | |
1827 if (dy2 > clip->y + clip->h) | |
1828 dy2 = clip->y + clip->h; | |
1829 | |
1830 /* Cull nop/off-screen blits */ | |
1831 if (dx1 >= dx2 || dy1 >= dy2) | |
1832 return 0; | |
1833 | |
1834 *x = sx1; | |
1835 *y = sy1; | |
1836 rect->x = dx1; | |
1837 rect->y = dy1; | |
1838 rect->w = dx2 - dx1; | |
1839 rect->h = dy2 - dy1; | |
1840 return 1; | |
1841 } | |
1842 | |
1843 static int | |
1844 glSDL_BlitGL(_THIS, SDL_Surface * src, SDL_Rect * srcrect, SDL_Rect * dstrect) | |
1845 { | |
1846 private_hwdata *txi; | |
1847 float x1, y1; | |
1848 unsigned char alpha; | |
1849 SDL_Rect d; | |
1850 int x, y; | |
1851 SDL_Rect r; | |
1852 | |
1853 if (!src) | |
1854 return GLERET("BlitGL(): No src surface!"); | |
1855 | |
1856 /* Get source and destination coordinates */ | |
1857 if (srcrect) | |
1858 r = *srcrect; | |
1859 else { | |
1860 r.x = r.y = 0; | |
1861 r.w = src->w; | |
1862 r.h = src->h; | |
1863 } | |
1864 if (dstrect) { | |
1865 x = dstrect->x; | |
1866 y = dstrect->y; | |
1867 } else | |
1868 x = y = 0; | |
1869 | |
1870 /* Clip! */ | |
1871 if (!blitclip(&r, src->w, src->h, &x, &y, &this->screen->clip_rect)) { | |
1872 if (dstrect) | |
1873 dstrect->w = dstrect->h = 0; | |
1874 return 0; | |
1875 } | |
1876 | |
1877 /* Write back the resulting cliprect */ | |
1878 if (dstrect) | |
1879 *dstrect = r; | |
1880 | |
1881 /* Make sure we have a source with a valid texture */ | |
1882 txi = glSDL_UploadSurface(this, src); | |
1883 if (!txi) | |
1884 return GLERET("BlitGL(): Could not get a TexInfo!"); | |
1885 | |
1886 /* Set up blending */ | |
1887 if (src->flags & (SDL_SRCALPHA | SDL_SRCCOLORKEY)) { | |
1888 glSDL_blendfunc(this, GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); | |
1889 glSDL_do_blend(this, 1); | |
1890 } else | |
1891 glSDL_do_blend(this, 0); | |
1892 | |
1893 /* Enable texturing */ | |
1894 glSDL_do_texture(this, 1); | |
1895 | |
1896 /* Calculate texcoords */ | |
1897 if (!srcrect) | |
1898 srcrect = &txi->virt; | |
1899 x1 = (float) srcrect->x; | |
1900 y1 = (float) srcrect->y; | |
1901 | |
1902 /* Calculate screen coords. */ | |
1903 if (dstrect) { | |
1904 d.x = dstrect->x; | |
1905 d.y = dstrect->y; | |
1906 d.w = (int) (srcrect->w * (float) txi->lw / (float) txi->virt.w); | |
1907 d.h = (int) (srcrect->h * (float) txi->lh / (float) txi->virt.h); | |
1908 } else { | |
1909 d.x = 0; | |
1910 d.y = 0; | |
1911 d.w = (int) (srcrect->w * (float) txi->lw / (float) txi->virt.w); | |
1912 d.h = (int) (srcrect->h * (float) txi->lh / (float) txi->virt.h); | |
1913 } | |
1914 | |
1915 /* | |
1916 * Note that we actually *prevent* the use of "full surface alpha" | |
1917 * and alpha channel in combination - to stay SDL 2D compatible. | |
1918 */ | |
1919 if ((src->flags & SDL_SRCALPHA) && (src->format->Amask)) | |
1920 alpha = 255; | |
1921 else | |
1922 alpha = src->format->alpha; | |
1923 | |
1924 /* Render! */ | |
1925 switch (txi->tilemode) { | |
1926 case GLSDL_TM_SINGLE: | |
1927 glSDL_BlitGL_single(this, txi, x1, y1, &d, alpha); | |
1928 break; | |
1929 case GLSDL_TM_HORIZONTAL: | |
1930 glSDL_BlitGL_htile(this, txi, x1, y1, &d, alpha); | |
1931 break; | |
1932 case GLSDL_TM_VERTICAL: | |
1933 glSDL_BlitGL_vtile(this, txi, x1, y1, &d, alpha); | |
1934 break; | |
1935 case GLSDL_TM_HUGE: | |
1936 glSDL_BlitGL_hvtile(this, src, txi, x1, y1, &d, alpha); | |
1937 break; | |
1938 } | |
1939 | |
1940 if (txi->temporary) | |
1941 glSDL_FreeTexInfo(this, txi); | |
1942 | |
1943 return 0; | |
1944 } | |
1945 | |
1946 | |
1947 static int | |
1948 glSDL_HWAccelBlit(SDL_Surface * src, SDL_Rect * srcrect, | |
1949 SDL_Surface * dst, SDL_Rect * dstrect) | |
1950 { | |
1951 SDL_Surface *vs; | |
1952 | |
1953 if (!src) | |
1954 return GLERET("HWAccelBlit(): No src surface!"); | |
1955 if (!dst) | |
1956 return GLERET("HWAccelBlit(): No dst surface!"); | |
1957 | |
1958 /* | |
1959 * Figure out what to do: | |
1960 * screen->screen: glSDL_BlitFromGL() + glSDL_BlitGL() | |
1961 * surface->screen: glSDL_BlitGL() | |
1962 * screen->surface: glSDL_BlitFromGL() | |
1963 * surface->surface: glSDL_SoftBlit() | |
1964 */ | |
1965 vs = SDL_VideoSurface; | |
1966 if (src == vs) { | |
1967 if (dst == vs) { | |
1968 /* | |
1969 FIXME: Try glCopyPixels() instead... | |
1970 */ | |
1971 glSDL_BlitFromGL(current_video, srcrect, vs, dstrect); | |
1972 return glSDL_BlitGL(current_video, vs, srcrect, dstrect); | |
1973 } else { | |
1974 return glSDL_BlitFromGL(current_video, srcrect, dst, dstrect); | |
1975 } | |
1976 } else { | |
1977 if (dst == vs) { | |
1978 return glSDL_BlitGL(current_video, src, srcrect, dstrect); | |
1979 } else { | |
1980 glSDL_Invalidate(dst, dstrect); | |
1981 glSDL_SoftBlit(src, srcrect, dst, dstrect); | |
1982 return 0; | |
1983 } | |
1984 } | |
1985 } | |
1986 | |
1987 | |
1988 static int | |
1989 glSDL_FillHWRect(_THIS, SDL_Surface * dst, SDL_Rect * dstrect, Uint32 color) | |
1990 { | |
1991 SDL_Surface *vs = SDL_VideoSurface; | |
1992 int dx1, dy1, dx2, dy2; | |
1993 Uint32 r, g, b; | |
1994 Uint8 br, bg, bb; | |
1995 | |
1996 /* | |
1997 * Some ugly reverse conversion for compatibility... | |
1998 * (We must do this before losing the dst pointer, | |
1999 * as the pixel formats of the screen and | |
2000 * SDL_VideoSurface may differ!) | |
2001 */ | |
2002 | |
2003 if (dst->format->palette) { | |
2004 /* this a paletted color */ | |
2005 SDL_GetRGB(color, dst->format, &br, &bg, &bb); | |
2006 } else { | |
2007 /* this a RGB color */ | |
2008 r = color & dst->format->Rmask; | |
2009 r = r >> dst->format->Rshift; | |
2010 r = r << dst->format->Rloss; | |
2011 br = r; | |
2012 | |
2013 g = color & dst->format->Gmask; | |
2014 g = g >> dst->format->Gshift; | |
2015 g = g << dst->format->Gloss; | |
2016 bg = g; | |
2017 | |
2018 b = color & dst->format->Bmask; | |
2019 b = b >> dst->format->Bshift; | |
2020 b = b << dst->format->Bloss; | |
2021 bb = b; | |
2022 } | |
2023 | |
2024 if (vs != dst) { | |
2025 /* draw a rect offscreen */ | |
2026 glSDL_Invalidate(dst, dstrect); | |
2027 /* software-fill the surface by faking it as a SW_SURFACE */ | |
2028 dst->flags &= ~SDL_HWSURFACE; | |
2029 SDL_FillRect(dst, dstrect, color); | |
2030 dst->flags |= SDL_HWSURFACE; | |
2031 } else { | |
2032 /* draw a rect onscreen */ | |
2033 glSDL_do_texture(this, 0); | |
2034 glSDL_do_blend(this, 0); | |
2035 | |
2036 dx1 = dstrect->x; | |
2037 dy1 = dstrect->y; | |
2038 dx2 = dx1 + dstrect->w; | |
2039 dy2 = dy1 + dstrect->h; | |
2040 | |
2041 this->glBegin(GL_TRIANGLE_FAN); | |
2042 this->glColor3ub(br, bg, bb); | |
2043 this->glVertex2i(dx1, dy1); | |
2044 this->glVertex2i(dx2, dy1); | |
2045 this->glVertex2i(dx2, dy2); | |
2046 this->glVertex2i(dx1, dy2); | |
2047 this->glEnd(); | |
2048 } | |
2049 return 0; | |
2050 } | |
2051 | |
2052 static int | |
2053 glSDL_CheckHWBlit(_THIS, SDL_Surface * src, SDL_Surface * dst) | |
2054 { | |
2055 src->flags |= SDL_HWACCEL; | |
2056 src->map->hw_blit = glSDL_HWAccelBlit; | |
2057 return 1; | |
2058 } | |
2059 | |
2060 | |
2061 static SDL_Surface * | |
2062 glSDL_DisplayFormat(SDL_Surface * surface) | |
2063 { | |
2064 SDL_Surface *tmp; | |
2065 int use_rgba = (surface->flags & SDL_SRCCOLORKEY) || | |
2066 ((surface->flags & SDL_SRCALPHA) && surface->format->Amask); | |
2067 #ifdef DEBUG_GLSDL | |
2068 fprintf(stderr, "#### glSDL_DisplayFormat()\n"); | |
2069 #endif | |
2070 if (use_rgba) | |
2071 tmp = glSDL_ConvertSurface(surface, RGBAfmt, SDL_SWSURFACE); | |
2072 else | |
2073 tmp = glSDL_ConvertSurface(surface, RGBfmt, SDL_SWSURFACE); | |
2074 if (!tmp) { | |
2075 GLERR("glSDL_DisplayFormat() could not convert surface!"); | |
2076 return NULL; | |
2077 } | |
2078 SDL_SetAlpha(tmp, 0, 0); | |
2079 | |
2080 if (surface->flags & SDL_SRCCOLORKEY) { | |
2081 /* | |
2082 * We drop colorkey data here, but we have to, | |
2083 * or we'll run into trouble when converting, | |
2084 * in particular from indexed color formats. | |
2085 */ | |
2086 SDL_SetColorKey(tmp, SDL_SRCCOLORKEY, surface->format->colorkey); | |
2087 glSDL_key2alpha(tmp); | |
2088 SDL_SetColorKey(tmp, 0, 0); | |
2089 } | |
2090 | |
2091 return tmp; | |
2092 } | |
2093 | |
2094 | |
2095 static SDL_Surface * | |
2096 glSDL_DisplayFormatAlpha(SDL_Surface * surface) | |
2097 { | |
2098 SDL_Surface *s, *tmp; | |
2099 tmp = glSDL_ConvertSurface(surface, RGBAfmt, SDL_SWSURFACE); | |
2100 #ifdef DEBUG_GLSDL | |
2101 fprintf(stderr, "#### glSDL_DisplayFormatAlpha()\n"); | |
2102 #endif | |
2103 if (!tmp) | |
2104 return NULL; | |
2105 | |
2106 SDL_SetAlpha(tmp, 0, 0); | |
2107 SDL_SetColorKey(tmp, 0, 0); | |
2108 s = glSDL_CreateRGBASurface(surface->w, surface->h); | |
2109 if (!s) { | |
2110 SDL_FreeSurface(tmp); | |
2111 return NULL; | |
2112 } | |
2113 glSDL_SoftBlit(tmp, NULL, s, NULL); | |
2114 SDL_FreeSurface(tmp); | |
2115 | |
2116 if (surface->flags & SDL_SRCCOLORKEY) { | |
2117 SDL_SetColorKey(s, SDL_SRCCOLORKEY, surface->format->colorkey); | |
2118 glSDL_key2alpha(s); | |
2119 SDL_SetColorKey(s, 0, 0); | |
2120 } | |
2121 | |
2122 if (surface->flags & SDL_SRCALPHA) | |
2123 SDL_SetAlpha(s, SDL_SRCALPHA, surface->format->alpha); | |
2124 return s; | |
2125 } | |
2126 | |
2127 | |
2128 /*---------------------------------------------------------- | |
2129 glSDL specific API extensions | |
2130 ----------------------------------------------------------*/ | |
2131 | |
2132 static void | |
2133 glSDL_Invalidate(SDL_Surface * surface, SDL_Rect * area) | |
2134 { | |
2135 private_hwdata *txi; | |
2136 if (!surface) | |
2137 return; | |
2138 txi = glSDL_GetTexInfo(surface); | |
2139 if (!txi) | |
2140 return; | |
2141 if (!area) { | |
2142 txi->invalid_area.x = 0; | |
2143 txi->invalid_area.y = 0; | |
2144 txi->invalid_area.w = surface->w; | |
2145 txi->invalid_area.h = surface->h; | |
2146 return; | |
2147 } | |
2148 txi->invalid_area = *area; | |
2149 } | |
2150 | |
2151 | |
2152 static void | |
2153 glSDL_SetLogicSize(_THIS, SDL_Surface * surface, int w, int h) | |
2154 { | |
2155 SDL_Rect r; | |
2156 private_hwdata *txi; | |
2157 if (!IS_GLSDL_SURFACE(surface)) | |
2158 return; | |
2159 | |
2160 txi = glSDL_GetTexInfo(surface); | |
2161 | |
2162 txi->lw = w; | |
2163 txi->lh = h; | |
2164 | |
2165 if (SDL_VideoSurface != surface) | |
2166 return; | |
2167 | |
2168 r.x = r.y = 0; | |
2169 r.w = w; | |
2170 r.h = h; | |
2171 glSDL_SetClipRect(this, surface, &r); | |
2172 | |
2173 this->glMatrixMode(GL_MODELVIEW); | |
2174 this->glLoadIdentity(); | |
2175 this->glTranslated(0.0f, 0.0f, 0.0f); | |
2176 | |
2177 this->glDisable(GL_DEPTH_TEST); | |
2178 this->glDisable(GL_CULL_FACE); | |
2179 | |
2180 glSDL_reset(); | |
2181 } | |
2182 | |
2183 static int | |
2184 glSDL_InitTexture(_THIS, SDL_Surface * datasurf, private_hwdata * txi, | |
2185 int tex) | |
2186 { | |
2187 this->glGenTextures(1, (GLuint *) & txi->texture[tex]); | |
2188 this->glBindTexture(GL_TEXTURE_2D, txi->texture[tex]); | |
2189 glstate.texture = txi->texture[tex]; | |
2190 this->glPixelStorei(GL_UNPACK_ROW_LENGTH, datasurf->pitch / | |
2191 datasurf->format->BytesPerPixel); | |
2192 this->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); | |
2193 this->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); | |
2194 this->glTexImage2D(GL_TEXTURE_2D, 0, | |
2195 datasurf->format->Amask ? GL_RGBA8 : GL_RGB8, | |
2196 txi->texsize, txi->texsize, 0, | |
2197 datasurf->format->Amask ? GL_RGBA : GL_RGB, | |
2198 GL_UNSIGNED_BYTE, NULL); | |
2199 #ifdef DEBUG_GLSDL | |
2200 glSDL_print_glerror(this, 1); | |
2201 #endif | |
2202 return 0; | |
2203 } | |
2204 | |
2205 | |
2206 /* Image tiled horizontally (wide surface), or not at all */ | |
2207 static int | |
2208 glSDL_UploadHoriz(_THIS, SDL_Surface * datasurf, private_hwdata * txi) | |
2209 { | |
2210 int bpp = datasurf->format->BytesPerPixel; | |
2211 int res; | |
2212 int tex = 0; | |
2213 int fromx = 0; | |
2214 int toy = txi->texsize; /* To init first texture */ | |
2215 while (1) { | |
2216 int thistw = datasurf->w - fromx; | |
2217 if (thistw > txi->tilew) | |
2218 thistw = txi->tilew; | |
2219 else if (thistw <= 0) | |
2220 break; | |
2221 if (toy + txi->tileh > txi->texsize) { | |
2222 toy = 0; | |
2223 res = glSDL_InitTexture(this, datasurf, txi, tex); | |
2224 if (res < 0) | |
2225 return res; | |
2226 ++tex; | |
2227 } | |
2228 this->glTexSubImage2D(GL_TEXTURE_2D, 0, 0, toy, | |
2229 thistw, txi->tileh, | |
2230 datasurf->format->Amask ? GL_RGBA : GL_RGB, | |
2231 GL_UNSIGNED_BYTE, | |
2232 (char *) datasurf->pixels + bpp * fromx); | |
2233 #ifdef DEBUG_GLSDL | |
2234 glSDL_print_glerror(this, 2); | |
2235 #endif | |
2236 fromx += txi->tilew; | |
2237 toy += txi->tileh; | |
2238 } | |
2239 return 0; | |
2240 } | |
2241 | |
2242 | |
2243 /* Image tiled vertically (tall surface) */ | |
2244 static int | |
2245 glSDL_UploadVert(_THIS, SDL_Surface * datasurf, private_hwdata * txi) | |
2246 { | |
2247 int res; | |
2248 int tex = 0; | |
2249 int fromy = 0; | |
2250 int tox = txi->texsize; /* To init first texture */ | |
2251 while (1) { | |
2252 int thisth = datasurf->h - fromy; | |
2253 if (thisth > txi->tileh) | |
2254 thisth = txi->tileh; | |
2255 else if (thisth <= 0) | |
2256 break; | |
2257 if (tox + txi->tilew > txi->texsize) { | |
2258 tox = 0; | |
2259 res = glSDL_InitTexture(this, datasurf, txi, tex); | |
2260 if (res < 0) | |
2261 return res; | |
2262 ++tex; | |
2263 } | |
2264 this->glTexSubImage2D(GL_TEXTURE_2D, 0, tox, 0, | |
2265 txi->tilew, thisth, | |
2266 datasurf->format->Amask ? GL_RGBA : GL_RGB, | |
2267 GL_UNSIGNED_BYTE, | |
2268 (char *) datasurf->pixels + | |
2269 datasurf->pitch * fromy); | |
2270 #ifdef DEBUG_GLSDL | |
2271 glSDL_print_glerror(this, 3); | |
2272 #endif | |
2273 fromy += txi->tileh; | |
2274 tox += txi->tilew; | |
2275 } | |
2276 return 0; | |
2277 } | |
2278 | |
2279 | |
2280 /* Image tiled two-way (huge surface) */ | |
2281 static int | |
2282 glSDL_UploadHuge(_THIS, SDL_Surface * datasurf, private_hwdata * txi) | |
2283 { | |
2284 int bpp = datasurf->format->BytesPerPixel; | |
2285 int res; | |
2286 int tex = 0; | |
2287 int y = 0; | |
2288 while (y < datasurf->h) { | |
2289 int x; | |
2290 int thisth = datasurf->h - y; | |
2291 if (thisth > txi->tileh) | |
2292 thisth = txi->tileh; | |
2293 x = 0; | |
2294 while (x < datasurf->w) { | |
2295 int thistw = datasurf->w - x; | |
2296 if (thistw > txi->tilew) | |
2297 thistw = txi->tilew; | |
2298 res = glSDL_InitTexture(this, datasurf, txi, tex++); | |
2299 if (res < 0) | |
2300 return res; | |
2301 this->glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, | |
2302 thistw, thisth, | |
2303 datasurf->format-> | |
2304 Amask ? GL_RGBA : GL_RGB, | |
2305 GL_UNSIGNED_BYTE, | |
2306 (char *) datasurf->pixels + | |
2307 datasurf->pitch * y + bpp * x); | |
2308 #ifdef DEBUG_GLSDL | |
2309 fprintf(stderr, | |
2310 "glTexSubImage(x = %d, y = %d, w = %d, h = %d)\n", x, | |
2311 y, thistw, thisth); | |
2312 glSDL_print_glerror(this, 4); | |
2313 #endif | |
2314 x += txi->tilew; | |
2315 } | |
2316 y += txi->tileh; | |
2317 } | |
2318 return 0; | |
2319 } | |
2320 | |
2321 | |
2322 /* Upload all textures for a surface. */ | |
2323 static int | |
2324 glSDL_UploadTextures(_THIS, SDL_Surface * datasurf, private_hwdata * txi) | |
2325 { | |
2326 switch (txi->tilemode) { | |
2327 case GLSDL_TM_SINGLE: | |
2328 case GLSDL_TM_HORIZONTAL: | |
2329 glSDL_UploadHoriz(this, datasurf, txi); | |
2330 break; | |
2331 case GLSDL_TM_VERTICAL: | |
2332 glSDL_UploadVert(this, datasurf, txi); | |
2333 break; | |
2334 case GLSDL_TM_HUGE: | |
2335 glSDL_UploadHuge(this, datasurf, txi); | |
2336 break; | |
2337 } | |
2338 return 0; | |
2339 } | |
2340 | |
2341 | |
2342 /* | |
2343 * IMPORTANT: | |
2344 * This function will try various ways of giving you | |
2345 * a TexInfo, and will succeed most of the time. | |
2346 * | |
2347 * However, the TexInfo returned may be temporary, | |
2348 * (as opposed to connected to 'surface'). A temporary | |
2349 * TexInfo must be used only once and then thrown away, | |
2350 * since it means that glSDL cannot track changes in | |
2351 * the pixel data of 'texture'. | |
2352 */ | |
2353 static private_hwdata * | |
2354 glSDL_UploadSurface(_THIS, SDL_Surface * surface) | |
2355 { | |
2356 int i; | |
2357 int converted = 0; | |
2358 private_hwdata *txi = glSDL_GetTexInfo(surface); | |
2359 | |
2360 if (IS_GLSDL_SURFACE(surface)) { | |
2361 /* | |
2362 * Ok, this is a glSDL surface, and it *might* be | |
2363 * in texture memory already. If so, it may need | |
2364 * an update. | |
2365 */ | |
2366 if (txi->invalid_area.w) { | |
2367 glSDL_UnloadTexture(this, txi); | |
2368 } else { | |
2369 int missing = 0; | |
2370 if (txi->textures) { | |
2371 for (i = 0; i < txi->textures; ++i) | |
2372 if (GLSDL_NOTEX == txi->texture[i]) { | |
2373 missing = 1; | |
2374 break; | |
2375 } | |
2376 if (!missing) | |
2377 return txi; /* They're already there! */ | |
2378 } | |
2379 } | |
2380 } else { | |
2381 /* | |
2382 * Nope, this isn't (yet) a glSDL surface. Let's | |
2383 * try to either make it one, or set up a temporary | |
2384 * TexInfo for it, valid for only one blit. | |
2385 */ | |
2386 if ((surface->flags & SDL_HWSURFACE) == SDL_HWSURFACE) { | |
2387 txi = glSDL_AddTexInfo(this, surface); | |
2388 if (!txi) { | |
2389 GLERR("UploadSurface(): Could not add TexInfo!"); | |
2390 return NULL; | |
2391 } | |
2392 surface->flags |= SDL_HWSURFACE; | |
2393 surface->flags |= SDL_HWACCEL; | |
2394 } else { | |
2395 /* | |
2396 * FIXME | |
2397 * here if the surface is small enough, it's a good | |
2398 * candidate for a blit using glDrawPixels instead | |
2399 * of a texture blit | |
2400 */ | |
2401 txi = glSDL_CreateTempTexInfo(this, surface); | |
2402 if (!txi) { | |
2403 GLERR("UploadSurface(): Could not create temp TexInfo!"); | |
2404 return NULL; | |
2405 } | |
2406 } | |
2407 } | |
2408 | |
2409 if (txi->texsize > maxtexsize) { | |
2410 /* This surface wasn't tiled properly... */ | |
2411 if (txi->temporary) | |
2412 glSDL_FreeTexInfo(this, txi); | |
2413 GLERR("UploadSurface(): Too large texture!"); | |
2414 return NULL; | |
2415 } | |
2416 | |
2417 /* | |
2418 * Kludge: Convert if not of preferred RGB or RGBA format. | |
2419 * | |
2420 * Conversion should only be done when *really* needed. | |
2421 * That is, it should rarely have to be done with OpenGL | |
2422 * 1.2+. | |
2423 * | |
2424 * Besides, any surface that's been SDL_DisplayFormat()ed | |
2425 * should already be in the best known OpenGL format - | |
2426 * preferably one that makes DMA w/o conversion possible. | |
2427 */ | |
2428 if (!glSDL_FormatIsOk(surface)) { | |
2429 #ifdef DEBUG_GLSDL | |
2430 fprintf(stderr, "glSDL: WARNING: On-the-fly conversion performed!\n"); | |
2431 #endif | |
2432 converted = 1; | |
2433 /* NOTE: We forget about the original surface here. */ | |
2434 if (surface->format->Amask) | |
2435 surface = glSDL_DisplayFormatAlpha(surface); | |
2436 else | |
2437 surface = glSDL_DisplayFormat(surface); | |
2438 if (!surface) { | |
2439 GLERR("UploadSurface(): Could not convert surface!"); | |
2440 if (txi->temporary) | |
2441 glSDL_FreeTexInfo(this, txi); | |
2442 return NULL; | |
2443 } | |
2444 } | |
2445 | |
2446 glSDL_UploadTextures(this, surface, txi); | |
2447 | |
2448 if (converted) | |
2449 SDL_FreeSurface(surface); | |
2450 | |
2451 return txi; | |
2452 } | |
2453 | |
2454 | |
2455 static void | |
2456 glSDL_UnloadTexture(_THIS, private_hwdata * txi) | |
2457 { | |
2458 int i; | |
2459 for (i = 0; i < txi->textures; ++i) | |
2460 if (txi->texture[i] != GLSDL_NOTEX) | |
2461 this->glDeleteTextures(1, &txi->texture[i]); | |
2462 SDL_memset(&txi->invalid_area, 0, sizeof(txi->invalid_area)); | |
2463 } | |
2464 | |
2465 /* vi: set ts=4 sw=4 expandtab: */ |