This repository has been archived by the owner on Feb 11, 2021. It is now read-only.
/
SDL_glsdl.c
2465 lines (2161 loc) · 68.4 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997-2006 Sam Lantinga
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Sam Lantinga
slouken@libsdl.org
*/
#include "SDL_config.h"
/*
* glSDL "SDL-over-OpenGL" video driver implemented by
* David Olofson <david@olofson.net> and
* Stephane Marchesin <stephane.marchesin@wanadoo.fr>
*/
#include <math.h>
#include "SDL.h"
#include "SDL_error.h"
#include "SDL_video.h"
#include "SDL_mouse.h"
#include "../SDL_sysvideo.h"
#include "../SDL_pixels_c.h"
#include "SDL_glsdl.h"
#undef DEBUG_GLSDL
#undef DEBUG_GLSDL_CHOP
#define FAKE_MAXTEXSIZE 256
#undef GLSDL_GRAPHICAL_DEBUG
/* Initialization/Query functions */
/* Hardware surface functions */
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
static int glSDL_SetColors(_THIS, int firstcolor, int ncolors,
SDL_Color * colors);
static int glSDL_AllocHWSurface(_THIS, SDL_Surface * surface);
static int glSDL_LockHWSurface(_THIS, SDL_Surface * surface);
static int glSDL_FlipHWSurface(_THIS, SDL_Surface * surface);
static void glSDL_UnlockHWSurface(_THIS, SDL_Surface * surface);
static void glSDL_FreeHWSurface(_THIS, SDL_Surface * surface);
static int glSDL_FillHWRect(_THIS, SDL_Surface * dst, SDL_Rect * rect,
Uint32 color);
static int glSDL_CheckHWBlit(_THIS, SDL_Surface * src, SDL_Surface * dst);
static int glSDL_SetHWColorKey(_THIS, SDL_Surface * surface, Uint32 key);
static int glSDL_SetHWAlpha(_THIS, SDL_Surface * surface, Uint8 alpha);
static int glSDL_VideoInit(_THIS, SDL_PixelFormat * vformat);
static SDL_Rect **glSDL_ListModes(_THIS, SDL_PixelFormat * format,
Uint32 flags);
static void glSDL_VideoQuit(_THIS);
static void glSDL_UpdateRects(_THIS, int numrects, SDL_Rect * rects);
static SDL_Surface *glSDL_SetVideoMode(_THIS, SDL_Surface * current,
int width, int height, int bpp,
Uint32 flags);
68
69
70
71
72
73
74
75
76
77
78
79
80
#define IS_GLSDL_SURFACE(s) ((s) && glSDL_GetTexInfo(s))
#define LOGIC_W(s) ( IS_GLSDL_SURFACE(this,s) ? TEXINFO(s)->lw : (s)->w )
#define LOGIC_H(s) ( IS_GLSDL_SURFACE(this,s) ? TEXINFO(s)->lh : (s)->h )
#define GLSDL_NOTEX (~0)
/*
* Special version for glSDL, which ignores the fake SDL_HWSURFACE
* flags, so we don't have SDL calling us back whenever we want to
* do some internal blitting...
*/
81
static void
82
83
glSDL_SoftBlit(SDL_Surface * src, SDL_Rect * srcrect,
SDL_Surface * dst, SDL_Rect * dstrect)
84
{
85
86
87
88
89
90
91
92
93
SDL_BlitInfo info;
if (srcrect)
if (!srcrect->w || !srcrect->h)
return;
/* Check to make sure the blit mapping is valid */
if ((src->map->dst != dst) ||
(src->map->dst->format_version != src->map->format_version))
94
if (SDL_MapSurface(src, dst) < 0)
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
return;
/* Set up the blit information */
if (srcrect) {
info.s_pixels = (Uint8 *) src->pixels +
(Uint16) srcrect->y * src->pitch +
(Uint16) srcrect->x * src->format->BytesPerPixel;
info.s_width = srcrect->w;
info.s_height = srcrect->h;
} else {
info.s_pixels = (Uint8 *) src->pixels;
info.s_width = src->w;
info.s_height = src->h;
}
info.s_skip = src->pitch - info.s_width * src->format->BytesPerPixel;
if (dstrect) {
info.d_pixels = (Uint8 *) dst->pixels +
(Uint16) dstrect->y * dst->pitch +
(Uint16) dstrect->x * dst->format->BytesPerPixel;
/*
* NOTE: SDL_SoftBlit() uses the 'dstrect' for this!
* This version is more like SDL_BlitSurface().
*/
info.d_width = srcrect->w;
info.d_height = srcrect->h;
} else {
info.d_pixels = (Uint8 *) dst->pixels;
info.d_width = dst->w;
info.d_height = dst->h;
}
info.d_skip = dst->pitch - info.d_width * dst->format->BytesPerPixel;
info.aux_data = src->map->sw_data->aux_data;
info.src = src->format;
info.table = src->map->table;
info.dst = dst->format;
131
src->map->sw_data->blit(&info);
132
133
134
135
136
137
138
139
}
/*
* Another special version. Doesn't lock/unlock, and doesn't mess
* with flags and stuff. It just converts the surface, period.
* Does not convert into palletized formats.
*/
140
static SDL_Surface *
141
142
glSDL_ConvertSurface(SDL_Surface * surface,
SDL_PixelFormat * format, Uint32 flags)
143
{
144
145
146
147
148
149
150
SDL_Surface *convert;
Uint32 colorkey = 0;
Uint8 alpha = 0;
Uint32 surface_flags;
SDL_Rect bounds;
/* Create a new surface with the desired format */
151
152
153
154
155
convert = SDL_CreateRGBSurface(flags,
surface->w, surface->h,
format->BitsPerPixel, format->Rmask,
format->Gmask, format->Bmask,
format->Amask);
156
157
158
159
160
161
162
163
164
165
166
167
if (convert == NULL) {
return (NULL);
}
/* Save the original surface color key and alpha */
surface_flags = surface->flags;
if ((surface_flags & SDL_SRCCOLORKEY) == SDL_SRCCOLORKEY) {
/* Convert colourkeyed surfaces to RGBA if requested */
if ((flags & SDL_SRCCOLORKEY) != SDL_SRCCOLORKEY && format->Amask) {
surface_flags &= ~SDL_SRCCOLORKEY;
} else {
colorkey = surface->format->colorkey;
168
SDL_SetColorKey(surface, 0, 0);
169
170
171
172
173
174
175
176
}
}
if ((surface_flags & SDL_SRCALPHA) == SDL_SRCALPHA) {
/* Copy over the alpha channel to RGBA if requested */
if (format->Amask) {
surface->flags &= ~SDL_SRCALPHA;
} else {
alpha = surface->format->alpha;
177
SDL_SetAlpha(surface, 0, 0);
178
179
180
181
182
183
184
185
}
}
/* Copy over the image data */
bounds.x = 0;
bounds.y = 0;
bounds.w = surface->w;
bounds.h = surface->h;
186
glSDL_SoftBlit(surface, &bounds, convert, &bounds);
187
188
189
/* Clean up the original surface, and update converted surface */
if (convert != NULL) {
190
SDL_SetClipRect(convert, &surface->clip_rect);
191
192
193
194
195
196
}
if ((surface_flags & SDL_SRCCOLORKEY) == SDL_SRCCOLORKEY) {
Uint32 cflags = surface_flags & (SDL_SRCCOLORKEY | SDL_RLEACCELOK);
if (convert != NULL) {
Uint8 keyR, keyG, keyB;
197
198
199
SDL_GetRGB(colorkey, surface->format, &keyR, &keyG, &keyB);
SDL_SetColorKey(convert, cflags | (flags & SDL_RLEACCELOK),
SDL_MapRGB(convert->format, keyR, keyG, keyB));
200
}
201
SDL_SetColorKey(surface, cflags, colorkey);
202
203
204
205
}
if ((surface_flags & SDL_SRCALPHA) == SDL_SRCALPHA) {
Uint32 aflags = surface_flags & (SDL_SRCALPHA | SDL_RLEACCELOK);
if (convert != NULL) {
206
SDL_SetAlpha(convert, aflags | (flags & SDL_RLEACCELOK), alpha);
207
208
209
210
}
if (format->Amask) {
surface->flags |= SDL_SRCALPHA;
} else {
211
SDL_SetAlpha(surface, aflags, alpha);
212
213
214
215
216
}
}
/* We're ready to go! */
return (convert);
217
218
219
220
221
222
223
224
225
}
/*----------------------------------------------------------
Some OpenGL function wrappers
----------------------------------------------------------*/
static struct
{
226
227
228
229
int do_blend;
int do_texture;
GLuint texture;
GLenum sfactor, dfactor;
230
231
} glstate;
232
static void
233
glSDL_reset(void)
234
{
235
236
237
238
239
glstate.do_blend = -1;
glstate.do_blend = -1;
glstate.texture = GLSDL_NOTEX;
glstate.sfactor = 0xffffffff;
glstate.dfactor = 0xffffffff;
240
241
}
242
static __inline__ void
243
glSDL_do_blend(_THIS, int on)
244
{
245
246
247
248
if (glstate.do_blend == on)
return;
if (on)
249
this->glEnable(GL_BLEND);
250
else
251
this->glDisable(GL_BLEND);
252
glstate.do_blend = on;
253
254
}
255
static __inline__ void
256
glSDL_do_texture(_THIS, int on)
257
{
258
259
260
261
if (glstate.do_texture == on)
return;
if (on)
262
this->glEnable(GL_TEXTURE_2D);
263
else
264
this->glDisable(GL_TEXTURE_2D);
265
glstate.do_texture = on;
266
267
}
268
static __inline__ void
269
glSDL_blendfunc(_THIS, GLenum sfactor, GLenum dfactor)
270
{
271
272
if ((sfactor == glstate.sfactor) && (dfactor == glstate.dfactor))
return;
273
274
this->glBlendFunc(sfactor, dfactor);
275
276
277
glstate.sfactor = sfactor;
glstate.dfactor = dfactor;
278
279
}
280
static __inline__ void
281
glSDL_texture(_THIS, GLuint tx)
282
{
283
284
if (tx == glstate.texture)
return;
285
286
this->glBindTexture(GL_TEXTURE_2D, tx);
287
glstate.texture = tx;
288
289
290
291
292
293
294
295
296
297
298
}
/*----------------------------------------------------------
glSDL specific data types
----------------------------------------------------------*/
typedef enum
{
299
300
301
302
GLSDL_TM_SINGLE,
GLSDL_TM_HORIZONTAL,
GLSDL_TM_VERTICAL,
GLSDL_TM_HUGE
303
304
305
306
307
} GLSDL_TileModes;
typedef struct private_hwdata
{
308
309
/* Size of surface in logic screen pixels */
int lw, lh;
310
311
312
313
314
315
316
317
int textures;
GLuint *texture;
int texsize; /* width/height of OpenGL texture */
GLSDL_TileModes tilemode;
int tilew, tileh; /* At least one must equal texsize! */
int tilespertex;
SDL_Rect virt; /* Total size of assembled surface */
318
319
320
/* Area of surface to upload when/after unlocking */
SDL_Rect invalid_area;
321
322
int temporary; /* Throw away after one use. */
323
324
325
SDL_Surface *next; /* The next Surface in our linked list of hardware surfaces ; == NULL if first surface */
SDL_Surface *prev; /* The prev Surface in our linked list of hardware surfaces ; == NULL if last surface */
326
327
328
} private_hwdata;
/* some function prototypes */
329
330
331
332
333
334
335
336
337
338
static void glSDL_Invalidate(SDL_Surface * surface, SDL_Rect * area);
static void glSDL_SetLogicSize(_THIS, SDL_Surface * surface, int w, int h);
static private_hwdata *glSDL_UploadSurface(_THIS, SDL_Surface * surface);
static private_hwdata *glSDL_GetTexInfo(SDL_Surface * surface);
static void glSDL_init_formats(_THIS);
static private_hwdata *glSDL_AddTexInfo(_THIS, SDL_Surface * surface);
static void glSDL_RemoveTexInfo(_THIS, SDL_Surface * surface);
static void glSDL_UnloadTexture(_THIS, private_hwdata * txi);
static int glSDL_BlitGL(_THIS, SDL_Surface * src,
SDL_Rect * srcrect, SDL_Rect * dstrect);
339
340
341
342
343
344
345
/* some variables */
static GLint maxtexsize = -1;
static SDL_PixelFormat *RGBfmt = NULL;
static SDL_PixelFormat *RGBAfmt = NULL;
static void *mirrorbuf = NULL;
/* the raw 888 opengl surface, hidden from the application */
346
SDL_Surface *OpenGL_Surface;
347
348
/* pointer to the beggining of the list used for memory allocation */
349
SDL_Surface *first = NULL;
350
351
#ifdef DEBUG_GLSDL
352
static __inline__ int
353
GLERET(const char *txt)
354
{
355
fprintf(stderr, "glSDL ERROR: '%s'\n", txt);
356
return -1;
357
}
358
static __inline__ void
359
GLERR(const char *txt)
360
{
361
fprintf(stderr, "glSDL ERROR: '%s'\n", txt);
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
}
#else
#define GLERET(x) (-1)
#define GLERR(x)
#endif
static SDL_VideoDevice underlying_device;
static int old_screen_flags;
/*
* List of video drivers known to support OpenGL
* The purpose of this is to make glSDL "portable" across
* all video backends that support OpenGL
*/
static VideoBootStrap *opengl_bootstrap =
#if SDL_VIDEO_DRIVER_QUARTZ
378
&QZ_bootstrap;
379
#elif SDL_VIDEO_DRIVER_X11
380
&X11_bootstrap;
381
#elif SDL_VIDEO_DRIVER_WINDIB
382
&WINDIB_bootstrap;
383
#elif SDL_VIDEO_DRIVER_BWINDOW
384
&BWINDOW_bootstrap;
385
#elif SDL_VIDEO_DRIVER_TOOLBOX
386
&TOOLBOX_bootstrap;
387
#elif SDL_VIDEO_DRIVER_CYBERGRAPHICS
388
&CGX_bootstrap;
389
#elif SDL_VIDEO_DRIVER_PHOTON
390
&ph_bootstrap;
391
#elif SDL_VIDEO_DRIVER_DC
392
&DC_bootstrap;
393
#else
394
NULL;
395
396
#endif
397
static int
398
glSDL_Available(void)
399
400
{
#ifdef DEBUG_GLSDL
401
fprintf(stderr, "available\n");
402
#endif
403
404
if (opengl_bootstrap == NULL)
return 0;
405
return (opengl_bootstrap->available());
406
407
}
408
static void
409
glSDL_DeleteDevice(SDL_VideoDevice * device)
410
{
411
412
SDL_free(device->hidden);
SDL_free(device);
413
414
415
}
/* Create a glSDL device */
416
static SDL_VideoDevice *
417
glSDL_CreateDevice(int devindex)
418
{
419
SDL_VideoDevice *device;
420
#ifdef DEBUG_GLSDL
421
fprintf(stderr, "entering createdevice\n");
422
423
#endif
424
/* Create the device with the underlying driver */
425
device = opengl_bootstrap->create(devindex);
426
427
/* Save the video device contents for future use */
428
SDL_memcpy(&underlying_device, device, sizeof(SDL_VideoDevice));
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
/* Hook glSDL on the video device */
device->VideoInit = glSDL_VideoInit;
device->ListModes = glSDL_ListModes;
device->VideoQuit = glSDL_VideoQuit;
device->UpdateRects = glSDL_UpdateRects;
device->FillHWRect = glSDL_FillHWRect;
device->SetHWColorKey = glSDL_SetHWColorKey;
device->SetHWAlpha = glSDL_SetHWAlpha;
device->AllocHWSurface = glSDL_AllocHWSurface;
device->LockHWSurface = glSDL_LockHWSurface;
device->UnlockHWSurface = glSDL_UnlockHWSurface;
device->FlipHWSurface = glSDL_FlipHWSurface;
device->FreeHWSurface = glSDL_FreeHWSurface;
device->CheckHWBlit = glSDL_CheckHWBlit;
device->SetColors = glSDL_SetColors;
device->SetVideoMode = glSDL_SetVideoMode;
device->info.hw_available = 1;
device->info.blit_hw = 1;
device->info.blit_hw_CC = 1;
device->info.blit_hw_A = 1;
device->info.blit_sw = 1;
device->info.blit_sw_CC = 1;
device->info.blit_sw_A = 1;
device->info.blit_fill = 1;
/* These functions are not supported by glSDL, so we NULLify them */
device->SetGamma = NULL;
device->GetGamma = NULL;
device->SetGammaRamp = NULL;
device->GetGammaRamp = NULL;
device->ToggleFullScreen = NULL;
device->free = glSDL_DeleteDevice;
463
464
#ifdef DEBUG_GLSDL
465
fprintf(stderr, "leaving createdevice\n");
466
467
#endif
468
return device;
469
470
471
472
}
/* Our bootstraping structure */
VideoBootStrap glSDL_bootstrap = {
473
474
"glSDL", "glSDL - SDL over OpenGL",
glSDL_Available, glSDL_CreateDevice
475
476
};
477
static int
478
glSDL_VideoInit(_THIS, SDL_PixelFormat * vformat)
479
{
480
int r;
481
printf("glSDL videoinit\n");
482
#ifdef DEBUG_GLSDL
483
fprintf(stderr, "videoinit\n");
484
#endif
485
r = underlying_device.VideoInit(this, vformat);
486
487
488
489
490
491
492
493
494
495
this->info.hw_available = 1;
this->info.blit_hw = 1;
this->info.blit_hw_CC = 1;
this->info.blit_hw_A = 1;
this->info.blit_sw = 1;
this->info.blit_sw_CC = 1;
this->info.blit_sw_A = 1;
this->info.blit_fill = 1;
return r;
496
497
}
498
SDL_Rect **
499
glSDL_ListModes(_THIS, SDL_PixelFormat * format, Uint32 flags)
500
{
501
return ((SDL_Rect **) - 1);
502
503
}
504
static void
505
glSDL_VideoQuit(_THIS)
506
{
507
508
509
510
SDL_Surface *scr;
/* free all hwdata structures */
while (first != NULL)
511
glSDL_RemoveTexInfo(this, first);
512
513
SDL_free(mirrorbuf);
514
515
mirrorbuf = NULL;
516
517
SDL_FreeFormat(RGBfmt);
SDL_FreeFormat(RGBAfmt);
518
519
RGBfmt = RGBAfmt = NULL;
520
SDL_FreeFormat(this->displayformatalphapixel);
521
522
this->displayformatalphapixel = NULL;
523
SDL_FreeSurface(OpenGL_Surface);
524
525
526
527
528
529
530
531
532
OpenGL_Surface = NULL;
/* restore the flags to gracefully exit from fullscreen */
this->screen->flags = old_screen_flags;
/* keep the screen */
scr = this->screen;
/* we cleaned up our stuff, now restore the underlying video driver */
533
SDL_memcpy(this, &underlying_device, sizeof(SDL_VideoDevice));
534
535
536
537
this->screen = scr;
/* call the underlying video driver's VideoQuit function */
538
this->VideoQuit(this);
539
540
}
541
static SDL_Surface *
542
543
glSDL_SetVideoMode(_THIS, SDL_Surface * current, int width, int height,
int bpp, Uint32 flags)
544
{
545
546
547
548
549
SDL_Surface *hooked_screen;
int i;
int flag_doublebuf = 0;
if (opengl_bootstrap == NULL) {
550
GLERR("No bootstrap for glSDL compiled in !\n");
551
552
553
554
555
return NULL;
}
/* we don't have OpenGL */
if ((flags & SDL_INTERNALOPENGL) == SDL_INTERNALOPENGL) {
556
GLERR("OpenGL video modes are not supported by glSDL !\n");
557
558
559
560
561
562
563
564
565
566
567
568
return (NULL);
}
/*
* Adjust the flags
*/
flags &= ~SDL_HWPALETTE;
flags |= SDL_INTERNALOPENGL;
/* remember whether the user requested DOUBLEBUF */
if (flags & SDL_DOUBLEBUF) {
569
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
570
571
flag_doublebuf = 1;
} else {
572
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 0);
573
574
575
576
flag_doublebuf = 0;
}
hooked_screen =
577
578
underlying_device.SetVideoMode(this, current, width, height, 0,
flags);
579
580
if (!hooked_screen) {
581
GLERR("Unable to open an OpenGL window !\n");
582
583
584
585
586
return (NULL);
}
/* save the screen flags for restore time */
old_screen_flags = hooked_screen->flags;
587
588
#ifdef DEBUG_GLSDL
589
fprintf(stderr, "got %d bpp\n", bpp);
590
591
#endif
592
593
594
595
596
597
/* setup the public surface format
* glSDL always returns the bpp its asked
*/
switch (bpp) {
case 32:
this->is_32bit = 1;
598
this->screen = SDL_CreateRGBSurface(flags, width, height, bpp,
599
#if SDL_BYTEORDER == SDL_LIL_ENDIAN
600
601
0x00FF0000,
0x0000FF00, 0x000000FF, 0x00000000
602
#else
603
604
0x0000FF00,
0x00FF0000, 0xFF000000, 0x00000000
605
#endif
606
607
608
609
);
break;
case 24:
this->is_32bit = 0;
610
this->screen = SDL_CreateRGBSurface(flags, width, height, bpp,
611
#if SDL_BYTEORDER == SDL_LIL_ENDIAN
612
613
0x00FF0000,
0x0000FF00, 0x000000FF, 0x00000000
614
#else
615
616
0x0000FF00,
0x00FF0000, 0xFF000000, 0x00000000
617
#endif
618
619
620
621
);
break;
case 16:
this->is_32bit = 0;
622
this->screen = SDL_CreateRGBSurface(flags, width, height, bpp,
623
#if SDL_BYTEORDER == SDL_LIL_ENDIAN
624
625
0x0000F800,
0x000007E0, 0x0000001F, 0x00000000
626
#else
627
628
0x0000001F,
0x000007E0, 0x0000F800, 0x00000000
629
#endif
630
631
632
633
);
break;
case 15:
this->is_32bit = 0;
634
this->screen = SDL_CreateRGBSurface(flags, width, height, bpp,
635
#if SDL_BYTEORDER == SDL_LIL_ENDIAN
636
637
0x00007C00,
0x000003E0, 0x0000001F, 0x00000000
638
#else
639
640
0x0000001F,
0x000003E0, 0x00007C00, 0x00000000
641
#endif
642
643
644
645
646
647
);
break;
case 8:
default:
this->is_32bit = 0;
this->screen =
648
SDL_CreateRGBSurface(flags, width, height, bpp, 0, 0, 0, 0);
649
650
651
/* give it a default palette if 8 bpp
* note : SDL already takes care of the palette for 4 bits & 1 bit surfaces
*/
652
653
654
655
656
/* if (bpp==8)
{
this->screen->format->palette->ncolors=255;
SDL_DitherColors(this->screen->format->palette->colors,bpp);
}*/
657
658
659
660
661
662
663
664
665
666
667
break;
}
/* also, we add SDL_HWSURFACE all the time, and let SDL create a shadow surface accordingly */
this->screen->flags =
hooked_screen->flags | SDL_HWSURFACE | SDL_INTERNALOPENGL;
/* add SDL_DOUBLEBUF if it was requested */
if (flag_doublebuf)
this->screen->flags |= SDL_DOUBLEBUF;
/* Tell SDL the alpha pixel format we'd like to have */
668
this->displayformatalphapixel = SDL_AllocFormat(32,
669
#if SDL_BYTEORDER == SDL_BIG_ENDIAN
670
671
672
0xFF000000,
0x00FF0000,
0x0000FF00, 0x000000FF
673
#else
674
675
676
0x000000FF,
0x0000FF00,
0x00FF0000, 0xFF000000
677
#endif
678
);
679
680
/* Now create the raw OpenGL surface */
681
OpenGL_Surface = SDL_CreateRGBSurface(flags, width, height, 24,
682
#if SDL_BYTEORDER == SDL_LIL_ENDIAN
683
684
0x000000FF,
0x0000FF00, 0x00FF0000, 0x00000000
685
#else
686
687
0xFF000000,
0x00FF0000, 0x0000FF00, 0x00000000
688
#endif
689
);
690
691
/* Here we have to setup OpenGL funcs ourselves */
692
693
694
695
696
697
698
699
700
701
702
703
704
#ifndef __QNXNTO__
#define SDL_PROC(ret,func,params) \
do { \
this->func = SDL_GL_GetProcAddress(#func); \
if ( ! this->func ) { \
SDL_SetError("Couldn't load GL function: %s\n", #func); \
return(NULL); \
} \
} while ( 0 );
#else
#define SDL_PROC(ret,func,params) this->func=func;
#endif /* __QNXNTO__ */
#include "../SDL_glfuncs.h"
705
#undef SDL_PROC
706
707
if (this->GL_MakeCurrent(this) < 0)
708
return (NULL);
709
710
711
712
713
714
715
716
717
#define SDL_PROC(ret,func,params) \
do { \
this->func = SDL_GL_GetProcAddress(#func); \
if ( ! this->func ) { \
SDL_SetError("Couldn't load GL function: %s\n", #func); \
return(NULL); \
} \
} while ( 0 );
#include "../SDL_glfuncs.h"
718
#undef SDL_PROC
719
720
721
#ifdef FAKE_MAXTEXSIZE
722
maxtexsize = FAKE_MAXTEXSIZE;
723
#else
724
this->glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxtexsize);
725
726
#endif
#ifdef DEBUG_GLSDL
727
fprintf(stderr, "glSDL: Max texture size: %d\n", maxtexsize);
728
729
#endif
730
glSDL_init_formats(this);
731
732
if (flag_doublebuf)
733
this->glDrawBuffer(GL_BACK);
734
else
735
this->glDrawBuffer(GL_FRONT);
736
737
this->glDisable(GL_DITHER);
738
739
740
if (glSDL_AddTexInfo(this, this->screen) < 0) {
GLERR("HookDevice() failed to add info to screen surface!");
741
742
743
return NULL;
}
744
glSDL_SetLogicSize(this, this->screen, this->screen->w, this->screen->h);
745
746
747
glSDL_do_texture(this, 0);
glSDL_do_blend(this, 0);
748
749
for (i = 0; i < 1 + flag_doublebuf; ++i) {
750
751
752
753
754
755
756
this->glBegin(GL_TRIANGLE_FAN);
this->glColor3ub(0, 0, 0);
this->glVertex2i(0, 0);
this->glVertex2i(this->screen->w, 0);
this->glVertex2i(this->screen->w, this->screen->h);
this->glVertex2i(0, this->screen->h);
this->glEnd();
757
if (!i)
758
this->GL_SwapBuffers(this);
759
760
}
761
mirrorbuf = SDL_malloc(this->screen->h * this->screen->pitch);
762
if (!mirrorbuf) {
763
GLERR("HookDevice() failed to allocate temp buffer for mirroring!");
764
765
766
767
return NULL;
}
return this->screen;
768
769
}
770
static int
771
glSDL_SetColors(_THIS, int firstcolor, int ncolors, SDL_Color * colors)
772
{
773
774
/* We don't need to fill this one */
return 0;
775
776
777
778
}
#ifdef DEBUG_GLSDL
779
static void
780
glSDL_print_glerror(_THIS, int point)
781
{
782
const char *err = "<unknown>";
783
switch (this->glGetError()) {
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
case GL_NO_ERROR:
return;
case GL_INVALID_ENUM:
err = "GL_INVALID_ENUM";
break;
case GL_INVALID_VALUE:
err = "GL_INVALID_VALUE";
break;
case GL_INVALID_OPERATION:
err = "GL_INVALID_OPERATION";
break;
case GL_STACK_OVERFLOW:
err = "GL_STACK_OVERFLOW";
break;
case GL_STACK_UNDERFLOW:
err = "GL_STACK_UNDERFLOW";
break;
case GL_OUT_OF_MEMORY:
err = "GL_OUT_OF_MEMORY";
default:
break;
}
806
fprintf(stderr, "OpenGL error \"%s\" at point %d.\n", err, point);
807
808
809
810
}
#endif
/* Get texinfo for a surface. */
811
static __inline__ private_hwdata *
812
glSDL_GetTexInfo(SDL_Surface * surface)
813
{
814
815
816
if (!surface)
return NULL;
return surface->hwdata;
817
818
819
820
}
/* Allocate a "blank" texinfo for a suface. */
821
static private_hwdata *
822
glSDL_AllocTexInfo(SDL_Surface * surface)
823
{
824
825
826
827
private_hwdata *txi;
if (!surface)
return NULL;
828
txi = glSDL_GetTexInfo(surface);
829
830
831
832
if (txi)
return txi; /* There already is one! --> */
/* ...and hook a new texinfo struct up to it. */
833
txi = (private_hwdata *) SDL_calloc(1, sizeof(private_hwdata));
834
if (!txi) {
835
GLERR("AllocTexInfo(): Failed allocating TexInfo struct!");
836
837
838
839
return NULL;
}
txi->temporary = 1;
#ifdef DEBUG_GLSDL
840
fprintf(stderr, "glSDL: Allocated TexInfo %p.\n", txi);
841
#endif
842
return txi;
843
844
845
}
846
static void
847
glSDL_FreeTexInfo(_THIS, private_hwdata * txi)
848
{
849
850
if (!txi)
return;
851
852
853
854
glSDL_UnloadTexture(this, txi);
SDL_free(txi->texture);
SDL_free(txi);
855
#ifdef DEBUG_GLSDL
856
fprintf(stderr, "glSDL: Freed TexInfo %p.\n", txi);
857
858
859
860
861
#endif
}
/* Detach and free the texinfo of a surface. */
862
static void
863
glSDL_RemoveTexInfo(_THIS, SDL_Surface * surface)
864
{
865
SDL_Surface *next, *prev;
866
if (!glSDL_GetTexInfo(surface))
867
868
869
870
871
872
873
874
875
876
877
878
879
880
return;
/* maintain our doubly linked list */
next = surface->hwdata->next;
prev = surface->hwdata->prev;
if (prev != NULL) {
prev->hwdata->next = next;
} else {
first = next;
}
if (next != NULL) {
next->hwdata->prev = prev;
}
881
glSDL_FreeTexInfo(this, surface->hwdata);
882
surface->hwdata = NULL;
883
884
885
886
887
888
889
890
}
/*
* Calculate chopping/tiling of a surface to
* fit it into the smallest possible OpenGL
* texture.
*/
891
static int
892
glSDL_CalcChop(private_hwdata * txi)
893
{
894
895
896
897
int rows, vw, vh;
int vertical = 0;
int texsize;
int lastw, lasth, minsize;
898
899
900
vw = txi->virt.w;
vh = txi->virt.h;
901
902
#ifdef DEBUG_GLSDL_CHOP
903
fprintf(stderr, "w=%d, h=%d ", vw, vh);
904
#endif
905
906
907
908
909
if (vh > vw) {
int t = vw;
vw = vh;
vh = t;
vertical = 1;
910
#ifdef DEBUG_GLSDL_CHOP
911
fprintf(stderr, "(vertical) \t");
912
#endif
913
}
914
915
916
917
918
919
/*
* Check whether this is a "huge" surface - at least one dimension
* must be <= than the maximum texture size, or we'll have to chop
* in both directions.
*/
920
#ifdef DEBUG_GLSDL
921
if (maxtexsize < 0)
922
return GLERET("glSDL_CalcChop() called before OpenGL init!");
923
#endif
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
if (vh > maxtexsize) {
/*
* Very simple hack for now; we just tile
* both ways with maximum size textures.
*/
texsize = maxtexsize;
txi->tilemode = GLSDL_TM_HUGE;
txi->texsize = texsize;
txi->tilew = texsize;
txi->tileh = texsize;
txi->tilespertex = 1;
/* Calculate number of textures needed */
txi->textures = (vw + texsize - 1) / texsize;
txi->textures *= (vh + texsize - 1) / texsize;
940
941
txi->texture = SDL_malloc(txi->textures * sizeof(int));
SDL_memset(txi->texture, -1, txi->textures * sizeof(int));
942
#ifdef DEBUG_GLSDL
943
fprintf(stderr, "two-way tiling; textures=%d\n", txi->textures);
944
#endif
945
if (!txi->texture) {
946
947
fprintf(stderr, "glSDL: INTERNAL ERROR: Failed to allocate"
" texture name table!\n");
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
return -3;
}
return 0;
}
/* Calculate minimum size */
rows = 1;
lastw = vw;
lasth = vh;
minsize = lastw > lasth ? lastw : lasth;
while (1) {
int w, h, size;
++rows;
w = vw / rows;
h = rows * vh;
size = w > h ? w : h;
if (size >= minsize) {
--rows;
break;
}
lastw = w;
lasth = h;
minsize = size;
}
if (minsize > maxtexsize) {
/* Handle multiple textures for very wide/tall surfaces. */
minsize = maxtexsize;
rows = (vw + minsize - 1) / minsize;
}
977
#ifdef DEBUG_GLSDL_CHOP
978
979
fprintf(stderr, "==> minsize=%d ", minsize);
fprintf(stderr, "(rows=%d) \t", rows);
980
981
#endif
982
983
984
985
/* Recalculate with nearest higher power-of-2 width. */
for (texsize = 1; texsize < minsize; texsize <<= 1);
txi->texsize = texsize;
rows = (vw + texsize - 1) / texsize;
986
#ifdef DEBUG_GLSDL_CHOP
987
fprintf(stderr, "==> texsize=%d (rows=%d) \t", texsize, rows);
988
989
#endif
990
991
/* Calculate number of tiles per texture */
txi->tilespertex = txi->texsize / vh;
992
#ifdef DEBUG_GLSDL_CHOP
993
fprintf(stderr, "tilespertex=%d \t", txi->tilespertex);
994
995
#endif
996
997
/* Calculate number of textures needed */
txi->textures = (rows + txi->tilespertex - 1) / txi->tilespertex;
998
999
txi->texture = (GLuint *) SDL_malloc(txi->textures * sizeof(GLuint));
SDL_memset(txi->texture, GLSDL_NOTEX, txi->textures * sizeof(GLuint));
1000
#ifdef DEBUG_GLSDL_CHOP