1 //********************************************************************************************
2 //*
3 //* This file is part of the SDL extensions library.
4 //*
5 //* Egoboo is free software: you can redistribute it and/or modify it
6 //* under the terms of the GNU General Public License as published by
7 //* the Free Software Foundation, either version 3 of the License, or
8 //* (at your option) any later version.
9 //*
10 //* Egoboo is distributed in the hope that it will be useful, but
11 //* WITHOUT ANY WARRANTY; without even the implied warranty of
12 //* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 //* General Public License for more details.
14 //*
15 //* You should have received a copy of the GNU General Public License
16 //* along with Egoboo. If not, see <http://www.gnu.org/licenses/>.
17 //*
18 //********************************************************************************************
19
20 /// @file extensions/SDL_GL_extensions.c
21 /// @ingroup _sdl_extensions_
22 /// @brief Implementation of the OpenGL extensions to SDL
23 /// @details
24
25 #include "SDL_GL_extensions.h"
26
27 #include "ogl_debug.h"
28 #include "ogl_texture.h"
29
30 //--------------------------------------------------------------------------------------------
31 //--------------------------------------------------------------------------------------------
32 #define LOCAL_STDOUT ((NULL == _SDL_GL_stdout) ? stdout : _SDL_GL_stdout)
33
34 //--------------------------------------------------------------------------------------------
35 //--------------------------------------------------------------------------------------------
36 static FILE * _SDL_GL_stdout = NULL;
37
38 //--------------------------------------------------------------------------------------------
39 //--------------------------------------------------------------------------------------------
40 // create the mask
41 // this will work if both endian systems think they have "RGBA" graphics
42 // if you need a different pixel format (ARGB or BGRA or whatever) this section
43 // will have to be changed to reflect that
44 #if (SDL_BYTEORDER == SDL_LIL_ENDIAN)
45
46 const Uint32 sdl_a_shift = 24;
47 const Uint32 sdl_b_shift = 16;
48 const Uint32 sdl_g_shift = 8;
49 const Uint32 sdl_r_shift = 0;
50
51 const Uint32 sdl_a_mask = ( Uint32 )( 0xFF << 24 );
52 const Uint32 sdl_b_mask = ( Uint32 )( 0xFF << 16 );
53 const Uint32 sdl_g_mask = ( Uint32 )( 0xFF << 8 );
54 const Uint32 sdl_r_mask = ( Uint32 )( 0xFF << 0 );
55
56 #else
57
58 const Uint32 sdl_a_shift = 0;
59 const Uint32 sdl_b_shift = 8;
60 const Uint32 sdl_g_shift = 16;
61 const Uint32 sdl_r_shift = 24;
62
63 const Uint32 sdl_a_mask = ( Uint32 )( 0xFF << 0 );
64 const Uint32 sdl_b_mask = ( Uint32 )( 0xFF << 8 );
65 const Uint32 sdl_g_mask = ( Uint32 )( 0xFF << 16 );
66 const Uint32 sdl_r_mask = ( Uint32 )( 0xFF << 24 );
67
68 #endif
69
70 //--------------------------------------------------------------------------------------------
71 // - Global function stolen from Jonathan Fisher
72 // - who stole it from gl_font.c test program from SDL_ttf ;)
73 //--------------------------------------------------------------------------------------------
powerOfTwo(int input)74 int powerOfTwo( int input )
75 {
76 int value = 1;
77
78 while ( value < input )
79 {
80 value <<= 1;
81 }
82 return value;
83 }
84
85 //--------------------------------------------------------------------------------------------
86 // - Global function stolen from Jonathan Fisher
87 // - who stole it from gl_font.c test program from SDL_ttf ;)
88 //--------------------------------------------------------------------------------------------
SDL_GL_uploadSurface(SDL_Surface * surface,GLuint tx_id,GLfloat * texCoords)89 SDL_bool SDL_GL_uploadSurface( SDL_Surface *surface, GLuint tx_id, GLfloat *texCoords )
90 {
91 int tx_w, tx_h;
92
93 GLfloat local_texCoords[4];
94
95 if ( NULL == surface ) return SDL_FALSE;
96
97 // handle the optional parameters
98 if ( NULL == texCoords ) texCoords = local_texCoords;
99
100 // Use the surface width & height expanded to the next powers of two
101 tx_w = powerOfTwo( surface->w );
102 tx_h = powerOfTwo( surface->h );
103
104 texCoords[0] = 0.0f;
105 texCoords[1] = 0.0f;
106 texCoords[2] = ( GLfloat )surface->w / ( GLfloat )tx_w;
107 texCoords[3] = ( GLfloat )surface->h / ( GLfloat )tx_h;
108
109 // use the default wrap parameters
110 SDL_GL_convert_surface( tx_id, surface, -1, -1 );
111
112 return SDL_TRUE;
113 }
114
115 //--------------------------------------------------------------------------------------------
SDL_GL_set_gl_mode(struct s_oglx_video_parameters * v)116 SDL_bool SDL_GL_set_gl_mode( struct s_oglx_video_parameters * v )
117 {
118 /// @details BB@> this function applies OpenGL settings. Must have a valid SDL_Surface to do any good.
119
120 if ( NULL == v || !SDL_WasInit( SDL_INIT_VIDEO ) ) return SDL_FALSE;
121
122 oglx_Get_Screen_Info( &ogl_caps );
123
124 if ( v->multisample_arb )
125 {
126 GL_DEBUG( glDisable )( GL_MULTISAMPLE );
127 GL_DEBUG( glEnable )( GL_MULTISAMPLE_ARB );
128 }
129 else if ( v->multisample )
130 {
131 GL_DEBUG( glEnable )( GL_MULTISAMPLE );
132 }
133 else
134 {
135 GL_DEBUG( glDisable )( GL_MULTISAMPLE );
136 GL_DEBUG( glDisable )( GL_MULTISAMPLE_ARB );
137 }
138
139 // Enable perspective correction?
140 GL_DEBUG( glHint )( GL_PERSPECTIVE_CORRECTION_HINT, v->perspective );
141
142 // Enable dithering?
143 if ( v->dither ) GL_DEBUG( glEnable )( GL_DITHER );
144 else GL_DEBUG( glDisable )( GL_DITHER );
145
146 // Enable Gouraud shading? (Important!)
147 GL_DEBUG( glShadeModel )( v->shading );
148
149 // Enable antialiasing?
150 if ( v->antialiasing )
151 {
152 GL_DEBUG( glEnable )( GL_LINE_SMOOTH );
153 GL_DEBUG( glHint )( GL_LINE_SMOOTH_HINT, GL_NICEST );
154
155 GL_DEBUG( glEnable )( GL_POINT_SMOOTH );
156 GL_DEBUG( glHint )( GL_POINT_SMOOTH_HINT, GL_NICEST );
157
158 GL_DEBUG( glDisable )( GL_POLYGON_SMOOTH );
159 GL_DEBUG( glHint )( GL_POLYGON_SMOOTH_HINT, GL_FASTEST );
160
161 // PLEASE do not turn this on unless you use
162 // GL_DEBUG(glEnable)(GL_BLEND);
163 // GL_DEBUG(glBlendFunc)(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
164 // before every single draw command
165 //
166 // GL_DEBUG(glEnable)(GL_POLYGON_SMOOTH);
167 // GL_DEBUG(glHint)(GL_POLYGON_SMOOTH_HINT, GL_NICEST);
168 }
169 else
170 {
171 GL_DEBUG( glDisable )( GL_POINT_SMOOTH );
172 GL_DEBUG( glDisable )( GL_LINE_SMOOTH );
173 GL_DEBUG( glDisable )( GL_POLYGON_SMOOTH );
174 }
175
176 // anisotropic filtering
177 if ( v->userAnisotropy > 1.0f )
178 {
179 // limit the userAnisotropy top be in a valid range
180 if ( v->userAnisotropy > ogl_caps.maxAnisotropy )
181 {
182 v->userAnisotropy = ogl_caps.maxAnisotropy;
183 }
184
185 GL_DEBUG( glTexParameterf )( GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, v->userAnisotropy );
186 };
187
188 // fill mode
189 GL_DEBUG( glPolygonMode )( GL_FRONT, GL_FILL );
190 GL_DEBUG( glPolygonMode )( GL_BACK, GL_FILL );
191
192 /* Disable OpenGL lighting */
193 GL_DEBUG( glDisable )( GL_LIGHTING );
194
195 /* Backface culling */
196 // The glEnable() seems implied - DDOI
197
198 // cull backward facing polygons
199 GL_DEBUG( glEnable )( GL_CULL_FACE ); // GL_ENABLE_BIT
200 GL_DEBUG( glCullFace )( GL_BACK ); // GL_POLYGON_BIT
201
202 return SDL_TRUE;
203 }
204
205 //--------------------------------------------------------------------------------------------
SDL_GL_report_mode(SDLX_video_parameters_t * retval)206 void SDL_GL_report_mode( SDLX_video_parameters_t * retval )
207 {
208 SDL_Surface * surface = ( NULL == retval ) ? NULL : retval->surface;
209
210 SDLX_set_stdout( LOCAL_STDOUT );
211 SDLX_report_mode( surface, retval );
212
213 if ( NULL != retval && retval->flags.opengl )
214 {
215 oglx_set_stdout( LOCAL_STDOUT );
216 oglx_report_caps();
217 }
218
219 fflush( LOCAL_STDOUT );
220 }
221
222 //--------------------------------------------------------------------------------------------
SDL_GL_set_mode(SDLX_video_parameters_t * v_old,SDLX_video_parameters_t * v_new,oglx_video_parameters_t * gl_new,SDL_bool has_valid_mode)223 SDLX_video_parameters_t * SDL_GL_set_mode( SDLX_video_parameters_t * v_old, SDLX_video_parameters_t * v_new, oglx_video_parameters_t * gl_new, SDL_bool has_valid_mode )
224 {
225 /// @details BB@> let SDL_GL try to set a new video mode.
226
227 SDLX_video_parameters_t param_old;
228 SDLX_video_parameters_t * retval = NULL;
229
230 // initialize v_old and param_old
231 if ( has_valid_mode )
232 {
233 if ( NULL == v_old )
234 {
235 SDLX_video_parameters_default( ¶m_old );
236 v_old = ¶m_old;
237 }
238 else
239 {
240 memcpy( ¶m_old, v_old, sizeof( SDLX_video_parameters_t ) );
241 }
242 }
243 else
244 {
245 v_old = NULL;
246 }
247
248 // use the sdl extensions to set the SDL video mode
249 retval = SDLX_set_mode( v_old, v_new, has_valid_mode, SDL_FALSE );
250
251 if ( NULL != retval )
252 {
253 // report on the success or failure to set the mode
254 SDL_GL_report_mode( retval );
255
256 // set the opengl parameters
257 gl_new->multisample = GL_FALSE;
258 gl_new->multisample_arb = GL_FALSE;
259 if ( NULL != retval->surface && retval->flags.opengl )
260 {
261 // correct the multisampling
262 gl_new->multisample_arb = retval->gl_att.multi_samples > 1;
263
264 SDL_GL_set_gl_mode( gl_new );
265 }
266 }
267
268 return retval;
269 }
270
271 //--------------------------------------------------------------------------------------------
272 //--------------------------------------------------------------------------------------------
SDL_GL_set_stdout(FILE * pfile)273 FILE * SDL_GL_set_stdout( FILE * pfile )
274 {
275 FILE * pfile_old = _SDL_GL_stdout;
276
277 if ( NULL == pfile )
278 {
279 _SDL_GL_stdout = stdout;
280 }
281 else
282 {
283 _SDL_GL_stdout = pfile;
284 }
285
286 return pfile_old;
287 }
288
289 //--------------------------------------------------------------------------------------------
SDL_GL_convert_surface(GLenum binding,SDL_Surface * surface,GLint wrap_s,GLint wrap_t)290 GLuint SDL_GL_convert_surface( GLenum binding, SDL_Surface * surface, GLint wrap_s, GLint wrap_t )
291 {
292 int srf_w, srf_h, tx_w, tx_h;
293 SDL_Surface * screen, * local_surface;
294 SDL_PixelFormat * pformat;
295 SDL_PixelFormat tmpformat;
296 bool_t use_alpha;
297 GLenum target;
298
299 SDLX_screen_info_t sdl_scr;
300
301 // Bind the error texture instead of the old texture
302 ErrorImage_bind( GL_TEXTURE_2D, binding );
303
304 if ( NULL == surface ) return INVALID_GL_ID;
305 local_surface = surface;
306
307 // handle default parameters
308 if ( wrap_s < 0 ) wrap_s = GL_REPEAT;
309 if ( wrap_t < 0 ) wrap_t = GL_REPEAT;
310
311 // grab the screen information
312 SDLX_Get_Screen_Info( &sdl_scr, SDL_FALSE );
313
314 /* Set the original local_surface's size (incase it's not an exact square of a power of two) */
315 srf_h = local_surface->h;
316 srf_w = local_surface->w;
317
318 // adjust the texture target
319 target = (( 1 == local_surface->h ) && ( local_surface->w > 1 ) ) ? GL_TEXTURE_1D : GL_TEXTURE_2D;
320
321 /* Determine the correct power of two greater than or equal to the original local_surface's size */
322 tx_h = powerOfTwo( local_surface->h );
323 tx_w = powerOfTwo( local_surface->w );
324
325 screen = SDL_GetVideoSurface();
326 pformat = screen->format;
327 memcpy( &tmpformat, screen->format, sizeof( SDL_PixelFormat ) ); // make a copy of the format
328
329 // if( ogl_caps.alpha_bits > 0 )
330 {
331 // convert the local_surface to a 32-bit pixel format
332 tmpformat.Amask = sdl_a_mask;
333 tmpformat.Ashift = sdl_a_shift;
334 tmpformat.Aloss = 0;
335
336 tmpformat.Bmask = sdl_b_mask;
337 tmpformat.Bshift = sdl_a_shift;
338 tmpformat.Bloss = 0;
339
340 tmpformat.Gmask = sdl_g_mask;
341 tmpformat.Gshift = sdl_g_shift;
342 tmpformat.Gloss = 0;
343
344 tmpformat.Rmask = sdl_r_mask;
345 tmpformat.Rshift = sdl_r_shift;
346 tmpformat.Rloss = 0;
347
348 // make the pixel size match the screen format
349 tmpformat.BitsPerPixel = 32;
350 tmpformat.BytesPerPixel = 4;
351 }
352 // else
353 // {
354 // // convert the local_surface to a 24-bit pixel format without alpha
355 // // convert the local_surface to a 32-bit pixel format
356 // tmpformat.Amask = 0;
357 // tmpformat.Ashift = sdl_a_shift;
358 // tmpformat.Aloss = 8;
359
360 // tmpformat.Bmask = sdl_b_mask;
361 // tmpformat.Bshift = sdl_a_shift;
362 // tmpformat.Bloss = 0;
363
364 // tmpformat.Gmask = sdl_g_mask;
365 // tmpformat.Gshift = sdl_g_shift;
366 // tmpformat.Gloss = 0;
367
368 // tmpformat.Rmask = sdl_r_mask;
369 // tmpformat.Rshift = sdl_r_shift;
370 // tmpformat.Rloss = 0;
371
372 // // make the pixel size match the screen format
373 // tmpformat.BitsPerPixel = 24;
374 // tmpformat.BytesPerPixel = 3;
375 // }
376
377 {
378 SDL_Surface * tmp;
379 Uint32 convert_flags;
380
381 // convert the local_surface format to the correct format
382 convert_flags = SDL_SWSURFACE;
383 tmp = SDL_ConvertSurface( local_surface, &tmpformat, convert_flags );
384 if ( local_surface != surface ) SDL_FreeSurface( local_surface );
385 local_surface = tmp;
386
387 // fix the alpha channel on the new SDL_Surface. For some reason, SDL wants to create
388 // local_surface with local_surface->format->alpha==0x00 which causes a problem if we have to
389 // use the SDL_BlitSurface() function below. With the local_surface alpha set to zero, the
390 // local_surface will be converted to BLACK!
391 //
392 // The following statement tells SDL
393 // 1) to set the local_surface to opaque
394 // 2) not to alpha blend the local_surface on blit
395 SDL_SetAlpha( local_surface, 0, SDL_ALPHA_OPAQUE );
396 SDL_SetColorKey( local_surface, 0, 0 );
397 }
398
399 // create a ptex that is acceptable to OpenGL (height and width are powers of 2)
400 if ( srf_h != tx_h || srf_w != tx_w )
401 {
402 SDL_Surface * tmp = SDL_CreateRGBSurface( SDL_SWSURFACE, tx_w, tx_h, tmpformat.BitsPerPixel, tmpformat.Rmask, tmpformat.Gmask, tmpformat.Bmask, tmpformat.Amask );
403
404 SDL_BlitSurface( local_surface, &local_surface->clip_rect, tmp, &local_surface->clip_rect );
405 if ( local_surface != surface )
406 SDL_FreeSurface( local_surface );
407 local_surface = tmp;
408 };
409
410 /* Generate an OpenGL texture ID */
411 if ( !VALID_BINDING( binding ) || ERROR_IMAGE_BINDING( binding ) )
412 {
413 GL_DEBUG( glGenTextures )( 1, &binding );
414 }
415
416 /* Set up some parameters for the format of the oglx_texture_t */
417 binding = oglx_bind_to_tex_params( binding, target, wrap_s, wrap_t );
418
419 /* actually create the OpenGL textures */
420 use_alpha = !( 8 == local_surface->format->Aloss );
421 if ( target == GL_TEXTURE_2D )
422 {
423 if ( tex_params.texturefilter >= TX_MIPMAP )
424 {
425 oglx_upload_2d_mipmap( use_alpha, local_surface->w, local_surface->h, local_surface->pixels );
426 }
427 else
428 {
429 oglx_upload_2d( use_alpha, local_surface->w, local_surface->h, local_surface->pixels );
430 }
431 }
432 else if ( target == GL_TEXTURE_1D )
433 {
434 oglx_upload_1d( use_alpha, local_surface->w, local_surface->pixels );
435 }
436 else
437 {
438 EGOBOO_ASSERT( 0 );
439 }
440
441 if ( local_surface != surface ) SDL_FreeSurface( local_surface );
442
443 return binding;
444 }
445
446