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( &param_old );
236             v_old = &param_old;
237         }
238         else
239         {
240             memcpy( &param_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