comparison src/video/glsdl/SDL_glsdl.c @ 1658:e49147870aac SDL-1.3

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