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