1658
|
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 }
|