Mercurial > sdl-ios-xcode
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 } |