- moved loadshared() to the right point
[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, Uint8 alpha, bool update);  
24 void (*texture_draw_bg)  (texture_type* ptexture, Uint8 alpha,  bool update);  
25 void (*texture_draw_part)(texture_type* ptexture, float sx, float sy, float x, float y, float w, float h, Uint8 alpha, 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, Uint8 alpha, 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(alpha, alpha, alpha, alpha);
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 /* Avoid compiler warnings */
165 if(update)
166 {}
167 }
168
169 void texture_draw_bg_gl(texture_type* ptexture, Uint8 alpha, bool update)
170 {
171 float pw = power_of_two(ptexture->w);
172 float ph = power_of_two(ptexture->h);
173
174   glColor3ub(alpha, alpha, alpha);
175
176   glEnable(GL_TEXTURE_2D);
177   glBindTexture(GL_TEXTURE_2D, ptexture->gl_texture);
178
179   glBegin(GL_QUADS);
180   glTexCoord2f(0, 0);
181   glVertex2f(0, 0);
182   glTexCoord2f((float)ptexture->w / pw, 0);
183   glVertex2f(screen->w, 0);
184   glTexCoord2f((float)ptexture->w / pw, (float)ptexture->h / ph);
185   glVertex2f(screen->w, screen->h);
186   glTexCoord2f(0, (float)ptexture->h / ph);
187   glVertex2f(0, screen->h);
188   glEnd();
189   
190   glDisable(GL_TEXTURE_2D);
191
192 /* Avoid compiler warnings */
193 if(update)
194 {}
195 }
196
197 void texture_draw_part_gl(texture_type* ptexture,float sx, float sy, float x, float y, float w, float h, Uint8 alpha, bool update)
198 {
199 float pw = power_of_two(ptexture->w);
200 float ph = power_of_two(ptexture->h);
201
202   glBindTexture(GL_TEXTURE_2D, ptexture->gl_texture);
203
204   glEnable(GL_BLEND);
205   glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
206
207   glColor4ub(alpha, alpha, alpha, alpha);
208
209   glEnable(GL_TEXTURE_2D);
210
211
212   glBegin(GL_QUADS);
213   glTexCoord2f(sx / pw, sy / ph);
214   glVertex2f(x, y);
215   glTexCoord2f((float)(sx + w) / pw, sy / ph);
216   glVertex2f(w+x, y);
217   glTexCoord2f((sx+w) / pw, (sy+h) / ph);
218   glVertex2f(w +x, h+y);
219   glTexCoord2f(sx / pw, (float)(sy+h) / ph);
220   glVertex2f(x, h+y);
221   glEnd();
222
223   glDisable(GL_TEXTURE_2D);
224   glDisable(GL_BLEND);
225
226 /* Avoid compiler warnings */
227 if(update)
228 {}
229 }
230 #endif
231
232 void texture_load_sdl(texture_type* ptexture, const std::string& file, int use_alpha)
233 {
234   SDL_Surface * temp;
235   
236   temp = IMG_Load(file.c_str());
237
238   if (temp == NULL)
239     st_abort("Can't load", file);
240
241   if(use_alpha == IGNORE_ALPHA && !use_gl)
242   ptexture->sdl_surface = SDL_DisplayFormat(temp);
243   else
244   ptexture->sdl_surface = SDL_DisplayFormatAlpha(temp);
245   
246   if (ptexture->sdl_surface == NULL)
247     st_abort("Can't covert to display format", file);
248
249   if (use_alpha == IGNORE_ALPHA && !use_gl)
250     SDL_SetAlpha(ptexture->sdl_surface, 0, 0);
251
252   SDL_FreeSurface(temp);
253
254   ptexture->w = ptexture->sdl_surface->w;
255   ptexture->h = ptexture->sdl_surface->h;
256   
257 }
258
259 void texture_load_part_sdl(texture_type* ptexture, const std::string& file, int x, int y, int w, int h,  int use_alpha)
260 {
261
262   SDL_Rect src;
263   SDL_Surface * temp;
264   SDL_Surface * conv;
265
266   temp = IMG_Load(file.c_str());
267
268   if (temp == NULL)
269     st_abort("Can't load", file);
270
271   /* Set source rectangle for conv: */
272
273   src.x = x;
274   src.y = y;
275   src.w = w;
276   src.h = h;
277
278   conv = SDL_CreateRGBSurface(temp->flags, w, h, temp->format->BitsPerPixel,
279                               temp->format->Rmask,
280                               temp->format->Gmask,
281                               temp->format->Bmask,
282                               temp->format->Amask);
283
284   /* #if SDL_BYTEORDER == SDL_BIG_ENDIAN
285                                0xff000000, 0x00ff0000, 0x0000ff00, 0x000000ff);
286   #else
287
288                                0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000);
289   #endif*/
290
291   SDL_SetAlpha(temp,0,0);
292
293   SDL_BlitSurface(temp, &src, conv, NULL);
294   if(use_alpha == IGNORE_ALPHA && !use_gl)
295   ptexture->sdl_surface = SDL_DisplayFormat(conv);
296   else
297   ptexture->sdl_surface = SDL_DisplayFormatAlpha(conv);
298
299   if (ptexture->sdl_surface == NULL)
300     st_abort("Can't covert to display format", file);
301
302   if (use_alpha == IGNORE_ALPHA && !use_gl)
303     SDL_SetAlpha(ptexture->sdl_surface, 0, 0);
304
305   SDL_FreeSurface(temp);
306   SDL_FreeSurface(conv);
307
308   ptexture->w = ptexture->sdl_surface->w;
309   ptexture->h = ptexture->sdl_surface->h;
310 }
311
312 void texture_from_sdl_surface(texture_type* ptexture, SDL_Surface* sdl_surf, int use_alpha)
313 {
314   Uint32 saved_flags;
315   Uint8  saved_alpha;
316   
317   /* Save the alpha blending attributes */
318   saved_flags = sdl_surf->flags&(SDL_SRCALPHA|SDL_RLEACCELOK);
319   saved_alpha = sdl_surf->format->alpha;
320   if ( (saved_flags & SDL_SRCALPHA)
321        == SDL_SRCALPHA )
322     {
323       SDL_SetAlpha(sdl_surf, 0, 0);
324     }
325    
326   if(use_alpha == IGNORE_ALPHA && !use_gl)
327   ptexture->sdl_surface = SDL_DisplayFormat(sdl_surf);
328   else
329   ptexture->sdl_surface = SDL_DisplayFormatAlpha(sdl_surf);
330
331   /* Restore the alpha blending attributes */
332   if ( (saved_flags & SDL_SRCALPHA)
333        == SDL_SRCALPHA )
334     {
335       SDL_SetAlpha(ptexture->sdl_surface, saved_flags, saved_alpha);
336     }
337   
338   if (ptexture->sdl_surface == NULL)
339     st_abort("Can't covert to display format", "SURFACE");
340
341   if (use_alpha == IGNORE_ALPHA && !use_gl)
342     SDL_SetAlpha(ptexture->sdl_surface, 0, 0);
343
344   ptexture->w = ptexture->sdl_surface->w;
345   ptexture->h = ptexture->sdl_surface->h;
346
347 #ifndef NOOPENGL
348
349   if(use_gl)
350     {
351       texture_create_gl(ptexture->sdl_surface,&ptexture->gl_texture);
352     }
353 #endif
354 }
355
356 void texture_draw_sdl(texture_type* ptexture, float x, float y, Uint8 alpha, bool update)
357 {
358   SDL_Rect dest;
359
360   dest.x = (int)x;
361   dest.y = (int)y;
362   dest.w = ptexture->w;
363   dest.h = ptexture->h;
364   
365   if(alpha != 255) /* SDL isn't capable of this kind of alpha :( therefore we'll leave now. */
366   return;
367   
368   SDL_SetAlpha(ptexture->sdl_surface ,SDL_SRCALPHA,alpha);
369   SDL_BlitSurface(ptexture->sdl_surface, NULL, screen, &dest);
370   
371   if (update == UPDATE)
372     SDL_UpdateRect(screen, dest.x, dest.y, dest.w, dest.h);
373 }
374
375
376 void texture_draw_bg_sdl(texture_type* ptexture, Uint8 alpha, bool update)
377 {
378   SDL_Rect dest;
379   
380   dest.x = 0;
381   dest.y = 0;
382   dest.w = screen->w;
383   dest.h = screen->h;
384
385   if(alpha != 255)
386   SDL_SetAlpha(ptexture->sdl_surface ,SDL_SRCALPHA,alpha);
387   SDL_SoftStretch(ptexture->sdl_surface, NULL, screen, &dest);
388   
389   if (update == UPDATE)
390     SDL_UpdateRect(screen, dest.x, dest.y, dest.w, dest.h);
391 }
392
393 void texture_draw_part_sdl(texture_type* ptexture, float sx, float sy, float x, float y, float w, float h, Uint8 alpha, bool update)
394 {
395   SDL_Rect src, dest;
396
397   src.x = (int)sx;
398   src.y = (int)sy;
399   src.w = (int)w;
400   src.h = (int)h;
401
402   dest.x = (int)x;
403   dest.y = (int)y;
404   dest.w = (int)w;
405   dest.h = (int)h;
406
407   if(alpha != 255)
408   SDL_SetAlpha(ptexture->sdl_surface ,SDL_SRCALPHA,alpha);
409   
410   SDL_BlitSurface(ptexture->sdl_surface, &src, screen, &dest);
411
412   if (update == UPDATE)
413     update_rect(screen, dest.x, dest.y, dest.w, dest.h);
414 }
415
416 void texture_free_sdl(texture_type* ptexture)
417 {
418   SDL_FreeSurface(ptexture->sdl_surface);
419 }
420