A first attempt to make a simple and clean way of an on the fly videomode change.
[supertux.git] / src / texture.cpp
1 //
2 // C Implementation: texture
3 //
4 // Description:
5 //
6 //
7 // Author: Tobias Glaesser <tobi.web@gmx.de>, (C) 2004
8 //
9 // Copyright: See COPYING file that comes with this distribution
10 //
11 //
12
13 #include "SDL.h"
14 #include "SDL_image.h"
15 #include "globals.h"
16 #include "screen.h"
17 #include "setup.h"
18 #include "texture.h"
19
20 #define NO_TEXTURE 0
21
22 void (*texture_load)     (texture_type* ptexture, const std::string& file, int use_alpha);
23 void (*texture_load_part)(texture_type* ptexture, const std::string& file, int x, int y, int w, int h, int use_alpha);
24 void (*texture_free)     (texture_type* ptexture);  
25 void (*texture_draw)     (texture_type* ptexture, float x, float y, Uint8 alpha, bool update);  
26 void (*texture_draw_bg)  (texture_type* ptexture, Uint8 alpha,  bool update);  
27 void (*texture_draw_part)(texture_type* ptexture, float sx, float sy, float x, float y, float w, float h, Uint8 alpha, bool update);
28
29
30 void texture_setup(void)
31 {
32 #ifdef NOOPENGL
33   texture_load = texture_load_sdl;
34   texture_load_part = texture_load_part_sdl;
35   texture_free = texture_free_sdl;
36   texture_draw = texture_draw_sdl;
37   texture_draw_bg = texture_draw_bg_sdl;
38   texture_draw_part = texture_draw_part_sdl;
39 #else
40
41   if(use_gl)
42     {
43       texture_load = texture_load_gl;
44       texture_load_part = texture_load_part_gl;
45       texture_free = texture_free_gl;
46       texture_draw = texture_draw_gl;
47       texture_draw_bg = texture_draw_bg_gl;
48       texture_draw_part = texture_draw_part_gl;
49     }
50   else
51     {
52       texture_load = texture_load_sdl;
53       texture_load_part = texture_load_part_sdl;
54       texture_free = texture_free_sdl;
55       texture_draw = texture_draw_sdl;
56       texture_draw_bg = texture_draw_bg_sdl;
57       texture_draw_part = texture_draw_part_sdl;
58     }
59 #endif
60 }
61
62 #ifndef NOOPENGL
63 void texture_load_gl(texture_type* ptexture, const std::string& file, int use_alpha)
64 {
65   texture_load_sdl(ptexture,file,use_alpha);
66   texture_create_gl(ptexture->sdl_surface,&ptexture->gl_texture);
67 }
68
69 void texture_load_part_gl(texture_type* ptexture, const std::string& file, int x, int y, int w, int h, int use_alpha)
70 {
71   texture_load_part_sdl(ptexture,file,x,y,w,h,use_alpha);
72   texture_create_gl(ptexture->sdl_surface,&ptexture->gl_texture);
73 }
74
75 /* Quick utility function for texture creation */
76 static int power_of_two(int input)
77 {
78   int value = 1;
79
80   while ( value < input ) {
81     value <<= 1;
82   }
83   return value;
84 }
85
86 void texture_create_gl(SDL_Surface * surf, GLuint * tex)
87 {
88   Uint32 saved_flags;
89   Uint8  saved_alpha;
90   int w, h;
91   SDL_Surface *conv;
92   
93   w = power_of_two(surf->w);
94   h = power_of_two(surf->h),
95   conv = SDL_CreateRGBSurface(SDL_SWSURFACE, w, h, surf->format->BitsPerPixel,
96 #if SDL_BYTEORDER == SDL_BIG_ENDIAN
97                               0xff000000, 0x00ff0000, 0x0000ff00, 0x000000ff);
98 #else
99
100                               0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000);
101 #endif
102
103   /* Save the alpha blending attributes */
104   saved_flags = surf->flags&(SDL_SRCALPHA|SDL_RLEACCELOK);
105   saved_alpha = surf->format->alpha;
106   if ( (saved_flags & SDL_SRCALPHA)
107        == SDL_SRCALPHA )
108     {
109       SDL_SetAlpha(surf, 0, 0);
110     }
111
112   SDL_BlitSurface(surf, 0, conv, 0);
113
114   /* Restore the alpha blending attributes */
115   if ( (saved_flags & SDL_SRCALPHA)
116        == SDL_SRCALPHA )
117     {
118       SDL_SetAlpha(surf, saved_flags, saved_alpha);
119     }
120
121   glGenTextures(1, &*tex);
122   glBindTexture(GL_TEXTURE_2D , *tex);
123   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
124   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
125   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
126   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
127   glPixelStorei(GL_UNPACK_ROW_LENGTH, conv->pitch / conv->format->BytesPerPixel);
128   glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB10_A2, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, conv->pixels);
129   glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
130       
131   SDL_FreeSurface(conv);
132 }
133
134 void texture_free_gl(texture_type* ptexture)
135 {
136   SDL_FreeSurface(ptexture->sdl_surface);
137   glDeleteTextures(1, &ptexture->gl_texture);
138 }
139
140 void texture_draw_gl(texture_type* ptexture, float x, float y, Uint8 alpha, bool update)
141 {
142 if(ptexture->gl_texture == NO_TEXTURE)
143   texture_create_gl(ptexture->sdl_surface,&ptexture->gl_texture);
144
145 float pw = power_of_two(ptexture->w);
146 float ph = power_of_two(ptexture->h);
147
148   glEnable(GL_TEXTURE_2D);
149   glEnable(GL_BLEND);
150   glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
151
152   glColor4ub(alpha, alpha, alpha, alpha);
153
154   glBindTexture(GL_TEXTURE_2D, ptexture->gl_texture);
155
156   glBegin(GL_QUADS);
157   glTexCoord2f(0, 0);
158   glVertex2f(x, y);
159   glTexCoord2f((float)ptexture->w / pw, 0);
160   glVertex2f((float)ptexture->w+x, y);
161   glTexCoord2f((float)ptexture->w / pw, (float)ptexture->h / ph);  glVertex2f((float)ptexture->w+x, (float)ptexture->h+y);
162   glTexCoord2f(0, (float)ptexture->h / ph);
163   glVertex2f(x, (float)ptexture->h+y);
164   glEnd();
165   
166   glDisable(GL_TEXTURE_2D);
167   glDisable(GL_BLEND);
168   
169 /* Avoid compiler warnings */
170 if(update)
171 {}
172 }
173
174 void texture_draw_bg_gl(texture_type* ptexture, Uint8 alpha, bool update)
175 {
176 if(ptexture->gl_texture == NO_TEXTURE)
177   texture_create_gl(ptexture->sdl_surface,&ptexture->gl_texture);
178
179 float pw = power_of_two(ptexture->w);
180 float ph = power_of_two(ptexture->h);
181
182   glColor3ub(alpha, alpha, alpha);
183
184   glEnable(GL_TEXTURE_2D);
185   glBindTexture(GL_TEXTURE_2D, ptexture->gl_texture);
186
187   glBegin(GL_QUADS);
188   glTexCoord2f(0, 0);
189   glVertex2f(0, 0);
190   glTexCoord2f((float)ptexture->w / pw, 0);
191   glVertex2f(screen->w, 0);
192   glTexCoord2f((float)ptexture->w / pw, (float)ptexture->h / ph);
193   glVertex2f(screen->w, screen->h);
194   glTexCoord2f(0, (float)ptexture->h / ph);
195   glVertex2f(0, screen->h);
196   glEnd();
197   
198   glDisable(GL_TEXTURE_2D);
199
200 /* Avoid compiler warnings */
201 if(update)
202 {}
203 }
204
205 void texture_draw_part_gl(texture_type* ptexture,float sx, float sy, float x, float y, float w, float h, Uint8 alpha, bool update)
206 {
207 if(ptexture->gl_texture == NO_TEXTURE)
208   texture_create_gl(ptexture->sdl_surface,&ptexture->gl_texture);
209
210 float pw = power_of_two(ptexture->w);
211 float ph = power_of_two(ptexture->h);
212
213   glBindTexture(GL_TEXTURE_2D, ptexture->gl_texture);
214
215   glEnable(GL_BLEND);
216   glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
217
218   glColor4ub(alpha, alpha, alpha, alpha);
219
220   glEnable(GL_TEXTURE_2D);
221
222
223   glBegin(GL_QUADS);
224   glTexCoord2f(sx / pw, sy / ph);
225   glVertex2f(x, y);
226   glTexCoord2f((float)(sx + w) / pw, sy / ph);
227   glVertex2f(w+x, y);
228   glTexCoord2f((sx+w) / pw, (sy+h) / ph);
229   glVertex2f(w +x, h+y);
230   glTexCoord2f(sx / pw, (float)(sy+h) / ph);
231   glVertex2f(x, h+y);
232   glEnd();
233
234   glDisable(GL_TEXTURE_2D);
235   glDisable(GL_BLEND);
236
237 /* Avoid compiler warnings */
238 if(update)
239 {}
240 }
241 #endif
242
243 void texture_load_sdl(texture_type* ptexture, const std::string& file, int use_alpha)
244 {
245   SDL_Surface * temp;
246   
247   temp = IMG_Load(file.c_str());
248
249   if (temp == NULL)
250     st_abort("Can't load", file);
251
252   if(use_alpha == IGNORE_ALPHA && !use_gl)
253   ptexture->sdl_surface = SDL_DisplayFormat(temp);
254   else
255   ptexture->sdl_surface = SDL_DisplayFormatAlpha(temp);
256   
257   if (ptexture->sdl_surface == NULL)
258     st_abort("Can't covert to display format", file);
259
260   if (use_alpha == IGNORE_ALPHA && !use_gl)
261     SDL_SetAlpha(ptexture->sdl_surface, 0, 0);
262
263   SDL_FreeSurface(temp);
264
265   ptexture->w = ptexture->sdl_surface->w;
266   ptexture->h = ptexture->sdl_surface->h;
267   
268   ptexture->gl_texture = NO_TEXTURE;
269 }
270
271 void texture_load_part_sdl(texture_type* ptexture, const std::string& file, int x, int y, int w, int h,  int use_alpha)
272 {
273
274   SDL_Rect src;
275   SDL_Surface * temp;
276   SDL_Surface * conv;
277
278   temp = IMG_Load(file.c_str());
279
280   if (temp == NULL)
281     st_abort("Can't load", file);
282
283   /* Set source rectangle for conv: */
284
285   src.x = x;
286   src.y = y;
287   src.w = w;
288   src.h = h;
289
290   conv = SDL_CreateRGBSurface(temp->flags, w, h, temp->format->BitsPerPixel,
291                               temp->format->Rmask,
292                               temp->format->Gmask,
293                               temp->format->Bmask,
294                               temp->format->Amask);
295
296   /* #if SDL_BYTEORDER == SDL_BIG_ENDIAN
297                                0xff000000, 0x00ff0000, 0x0000ff00, 0x000000ff);
298   #else
299
300                                0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000);
301   #endif*/
302
303   SDL_SetAlpha(temp,0,0);
304
305   SDL_BlitSurface(temp, &src, conv, NULL);
306   if(use_alpha == IGNORE_ALPHA && !use_gl)
307   ptexture->sdl_surface = SDL_DisplayFormat(conv);
308   else
309   ptexture->sdl_surface = SDL_DisplayFormatAlpha(conv);
310
311   if (ptexture->sdl_surface == NULL)
312     st_abort("Can't covert to display format", file);
313
314   if (use_alpha == IGNORE_ALPHA && !use_gl)
315     SDL_SetAlpha(ptexture->sdl_surface, 0, 0);
316
317   SDL_FreeSurface(temp);
318   SDL_FreeSurface(conv);
319
320   ptexture->w = ptexture->sdl_surface->w;
321   ptexture->h = ptexture->sdl_surface->h;
322 }
323
324 void texture_from_sdl_surface(texture_type* ptexture, SDL_Surface* sdl_surf, int use_alpha)
325 {
326   Uint32 saved_flags;
327   Uint8  saved_alpha;
328   
329   /* Save the alpha blending attributes */
330   saved_flags = sdl_surf->flags&(SDL_SRCALPHA|SDL_RLEACCELOK);
331   saved_alpha = sdl_surf->format->alpha;
332   if ( (saved_flags & SDL_SRCALPHA)
333        == SDL_SRCALPHA )
334     {
335       SDL_SetAlpha(sdl_surf, 0, 0);
336     }
337    
338   if(use_alpha == IGNORE_ALPHA && !use_gl)
339   ptexture->sdl_surface = SDL_DisplayFormat(sdl_surf);
340   else
341   ptexture->sdl_surface = SDL_DisplayFormatAlpha(sdl_surf);
342
343   /* Restore the alpha blending attributes */
344   if ( (saved_flags & SDL_SRCALPHA)
345        == SDL_SRCALPHA )
346     {
347       SDL_SetAlpha(ptexture->sdl_surface, saved_flags, saved_alpha);
348     }
349   
350   if (ptexture->sdl_surface == NULL)
351     st_abort("Can't covert to display format", "SURFACE");
352
353   if (use_alpha == IGNORE_ALPHA && !use_gl)
354     SDL_SetAlpha(ptexture->sdl_surface, 0, 0);
355
356   ptexture->w = ptexture->sdl_surface->w;
357   ptexture->h = ptexture->sdl_surface->h;
358
359 #ifndef NOOPENGL
360
361   if(use_gl)
362     {
363       texture_create_gl(ptexture->sdl_surface,&ptexture->gl_texture);
364     }
365 #endif
366 }
367
368 void texture_draw_sdl(texture_type* ptexture, float x, float y, Uint8 alpha, bool update)
369 {
370   SDL_Rect dest;
371
372   dest.x = (int)x;
373   dest.y = (int)y;
374   dest.w = ptexture->w;
375   dest.h = ptexture->h;
376   
377   if(alpha != 255) /* SDL isn't capable of this kind of alpha :( therefore we'll leave now. */
378   return;
379   
380   SDL_SetAlpha(ptexture->sdl_surface ,SDL_SRCALPHA,alpha);
381   SDL_BlitSurface(ptexture->sdl_surface, NULL, screen, &dest);
382   
383   if (update == UPDATE)
384     SDL_UpdateRect(screen, dest.x, dest.y, dest.w, dest.h);
385 }
386
387
388 void texture_draw_bg_sdl(texture_type* ptexture, Uint8 alpha, bool update)
389 {
390   SDL_Rect dest;
391   
392   dest.x = 0;
393   dest.y = 0;
394   dest.w = screen->w;
395   dest.h = screen->h;
396
397   if(alpha != 255)
398   SDL_SetAlpha(ptexture->sdl_surface ,SDL_SRCALPHA,alpha);
399   SDL_SoftStretch(ptexture->sdl_surface, NULL, screen, &dest);
400   
401   if (update == UPDATE)
402     SDL_UpdateRect(screen, dest.x, dest.y, dest.w, dest.h);
403 }
404
405 void texture_draw_part_sdl(texture_type* ptexture, float sx, float sy, float x, float y, float w, float h, Uint8 alpha, bool update)
406 {
407   SDL_Rect src, dest;
408
409   src.x = (int)sx;
410   src.y = (int)sy;
411   src.w = (int)w;
412   src.h = (int)h;
413
414   dest.x = (int)x;
415   dest.y = (int)y;
416   dest.w = (int)w;
417   dest.h = (int)h;
418
419   if(alpha != 255)
420   SDL_SetAlpha(ptexture->sdl_surface ,SDL_SRCALPHA,alpha);
421   
422   SDL_BlitSurface(ptexture->sdl_surface, &src, screen, &dest);
423
424   if (update == UPDATE)
425     update_rect(screen, dest.x, dest.y, dest.w, dest.h);
426 }
427
428 void texture_free_sdl(texture_type* ptexture)
429 {
430   SDL_FreeSurface(ptexture->sdl_surface);
431 #ifndef NOOPENGL
432   if(ptexture->gl_texture != NO_TEXTURE)
433     glDeleteTextures(1, &ptexture->gl_texture);
434 #endif
435 }
436