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: */