Add invisible switch (set an 'invisible' tag to '1' in switch (ie info_camp) entity...
[neverball] / share / image.c
1 /*   
2  * Copyright (C) 2003 Robert Kooima
3  *
4  * NEVERBALL is  free software; you can redistribute  it and/or modify
5  * it under the  terms of the GNU General  Public License as published
6  * by the Free  Software Foundation; either version 2  of the License,
7  * or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT  ANY  WARRANTY;  without   even  the  implied  warranty  of
11  * MERCHANTABILITY or  FITNESS FOR A PARTICULAR PURPOSE.   See the GNU
12  * General Public License for more details.
13  */
14
15 #include <SDL.h>
16 #include <SDL_ttf.h>
17 #include <SDL_image.h>
18 #include <string.h>
19 #include <math.h>
20
21 #include "glext.h"
22 #include "image.h"
23 #include "base_config.h"
24
25 /*---------------------------------------------------------------------------*/
26
27 void image_snap(char *filename, int w, int h)
28 {
29     int i;
30
31     SDL_Surface *buf = SDL_CreateRGBSurface(SDL_SWSURFACE, w, h, 24,
32                                             RMASK, GMASK, BMASK, 0);
33     SDL_Surface *img = SDL_CreateRGBSurface(SDL_SWSURFACE, w, h, 24,
34                                             RMASK, GMASK, BMASK, 0);
35
36     glReadPixels(0, 0, w, h, GL_RGB, GL_UNSIGNED_BYTE, buf->pixels);
37
38     for (i = 0; i < h; i++)
39         memcpy((GLubyte *) img->pixels + 3 * w * i,
40                (GLubyte *) buf->pixels + 3 * w * (h - i), 3 * w);
41
42     SDL_SaveBMP(img, filename);
43
44     SDL_FreeSurface(img);
45     SDL_FreeSurface(buf);
46 }
47
48 void image_size(int *W, int *H, int w, int h)
49 {
50     *W = 1;
51     *H = 1;
52
53     while (*W < w) *W *= 2;
54     while (*H < h) *H *= 2;
55 }
56
57 /*---------------------------------------------------------------------------*/
58
59 void image_swab(SDL_Surface *src)
60 {
61     int i, j, b = (src->format->BitsPerPixel == 32) ? 4 : 3;
62     
63     SDL_LockSurface(src);
64     {
65         unsigned char *s = (unsigned char *) src->pixels;
66         unsigned char  t;
67
68         /* Iterate over each pixel of the image. */
69
70         for (i = 0; i < src->h; i++)
71             for (j = 0; j < src->w; j++)
72             {
73                 int k = (i * src->w + j) * b;
74
75                 /* Swap the red and blue channels of each. */
76
77                 t        = s[k + 2];
78                 s[k + 2] = s[k + 0];
79                 s[k + 0] =        t;
80             }
81     }
82     SDL_UnlockSurface(src);
83 }
84
85 void image_white(SDL_Surface *src)
86 {
87     int i, j, b = (src->format->BitsPerPixel == 32) ? 4 : 3;
88     
89     SDL_LockSurface(src);
90     {
91         unsigned char *s = (unsigned char *) src->pixels;
92
93         /* Iterate over each pixel of the image. */
94
95         for (i = 0; i < src->h; i++)
96             for (j = 0; j < src->w; j++)
97             {
98                 int k = (i * src->w + j) * b;
99
100                 /* Whiten the RGB channels without touching any Alpha. */
101
102                 s[k + 0] = 0xFF;
103                 s[k + 1] = 0xFF;
104                 s[k + 2] = 0xFF;
105             }
106     }
107     SDL_UnlockSurface(src);
108 }
109
110 SDL_Surface *image_scale(SDL_Surface *src, int n)
111 {
112     int si, di;
113     int sj, dj;
114     int k, b = (src->format->BitsPerPixel == 32) ? 4 : 3;
115
116     SDL_Surface *dst = SDL_CreateRGBSurface(SDL_SWSURFACE,
117                                             src->w / n,
118                                             src->h / n,
119                                             src->format->BitsPerPixel,
120                                             src->format->Rmask,
121                                             src->format->Gmask,
122                                             src->format->Bmask,
123                                             src->format->Amask);
124     if (dst)
125     {
126         SDL_LockSurface(src);
127         SDL_LockSurface(dst);
128         {
129             unsigned char *s = (unsigned char *) src->pixels;
130             unsigned char *d = (unsigned char *) dst->pixels;
131
132             /* Iterate each component of each distination pixel. */
133
134             for (di = 0; di < src->h / n; di++)
135                 for (dj = 0; dj < src->w / n; dj++)
136                     for (k = 0; k < b; k++)
137                     {
138                         int c = 0;
139
140                         /* Average the NxN source pixel block for each. */
141
142                         for (si = di * n; si < (di + 1) * n; si++)
143                             for (sj = dj * n; sj < (dj + 1) * n; sj++)
144                                 c += s[(si * src->w + sj) * b + k];
145
146                         d[(di * dst->w + dj) * b + k] =
147                             (unsigned char) (c / (n * n));
148                     }
149         }
150         SDL_UnlockSurface(dst);
151         SDL_UnlockSurface(src);
152     }
153
154     return dst;
155 }
156
157 /*---------------------------------------------------------------------------*/
158
159 /*
160  * Create on  OpenGL texture  object using the  given SDL  surface and
161  * format,  scaled  using the  current  scale  factor.  When  scaling,
162  * assume dimensions are used only for layout and lie about the size.
163  */
164 GLuint make_image_from_surf(int *w, int *h, SDL_Surface *s)
165 {
166     /*int    t = config_get_d(CONFIG_TEXTURES);*/
167     int    t = 0; /* TODO: Fint a way to revert CONFIG_TEXTURES */
168     GLuint o = 0;
169
170     glGenTextures(1, &o);
171     glBindTexture(GL_TEXTURE_2D, o);
172
173     if (t > 1)
174     {
175         SDL_Surface *d = image_scale(s, t);
176
177         /* Load the scaled image. */
178
179         if (d->format->BitsPerPixel == 32)
180             glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, d->w, d->h, 0,
181                          GL_RGBA, GL_UNSIGNED_BYTE, d->pixels);
182         else
183             glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB,  d->w, d->h, 0,
184                          GL_RGB,  GL_UNSIGNED_BYTE, d->pixels);
185
186         SDL_FreeSurface(d);
187     }
188     else
189     {
190         /* Load the unscaled image. */
191
192         if (s->format->BitsPerPixel == 32)
193             glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, s->w, s->h, 0,
194                          GL_RGBA, GL_UNSIGNED_BYTE, s->pixels);
195         else
196             glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB,  s->w, s->h, 0,
197                          GL_RGB,  GL_UNSIGNED_BYTE, s->pixels);
198     }
199
200     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
201     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
202
203     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
204     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
205
206     if (w) *w = s->w;
207     if (h) *h = s->h;
208
209     return o;
210 }
211
212 /*---------------------------------------------------------------------------*/
213
214 /*
215  * Load  an image  from the  named file.   If the  image is  not RGBA,
216  * convert it to RGBA.  Return an OpenGL texture object.
217  */
218 GLuint make_image_from_file(int *W, int *H,
219                             int *w, int *h, const char *name)
220 {
221     SDL_Surface *src;
222     SDL_Surface *dst;
223     SDL_Rect rect;
224
225     GLuint o = 0;
226
227     /* Load the file. */
228
229     if ((src = IMG_Load(config_data(name))))
230     {
231         int w2;
232         int h2;
233
234         image_size(&w2, &h2, src->w, src->h);
235
236         if (w) *w = src->w;
237         if (h) *h = src->h;
238
239         /* Create a new destination surface. */
240         
241         if ((dst = SDL_CreateRGBSurface(SDL_SWSURFACE, w2, h2, 32,
242                                         RMASK, GMASK, BMASK, AMASK)))
243         {
244             /* Copy source pixels to the center of the destination. */
245
246             rect.x = (Sint16) (w2 - src->w) / 2;
247             rect.y = (Sint16) (h2 - src->h) / 2;
248
249             SDL_SetAlpha(src, 0, 0);
250             SDL_BlitSurface(src, NULL, dst, &rect);
251
252             o = make_image_from_surf(W, H, dst);
253
254             SDL_FreeSurface(dst);
255         }
256         SDL_FreeSurface(src);
257     }
258     return o;
259 }
260
261 /*---------------------------------------------------------------------------*/
262
263 /*
264  * Render the given  string using the given font.   Transfer the image
265  * to a  surface of  power-of-2 size large  enough to fit  the string.
266  * Return an OpenGL texture object.
267  */
268 GLuint make_image_from_font(int *W, int *H,
269                             int *w, int *h, const char *text, TTF_Font *font, int k)
270 {
271     SDL_Color fg = { 0xFF, 0xFF, 0xFF, 0xFF };
272
273     SDL_Surface *src;
274     SDL_Surface *dst;
275     SDL_Rect rect;
276
277     GLuint o = 0;
278
279     /* Render the text. */
280
281     if (text && strlen(text) > 0)
282     {
283         if ((src = TTF_RenderUTF8_Blended(font, text, fg)))
284         {
285             int w2;
286             int h2;
287
288             image_size(&w2, &h2, src->w, src->h);
289
290             if (w) *w = src->w;
291             if (h) *h = src->h;
292
293             /* Create a new destination surface. */
294             
295             if ((dst = SDL_CreateRGBSurface(SDL_SWSURFACE, w2, h2, 32,
296                                             RMASK, GMASK, BMASK, AMASK)))
297             {
298                 /* Copy source pixels to the center of the destination. */
299
300                 rect.x = (Sint16) (w2 - src->w) / 2;
301                 rect.y = (Sint16) (h2 - src->h) / 2;
302
303                 SDL_SetAlpha(src, 0, 0);
304                 SDL_BlitSurface(src, NULL, dst, &rect);
305
306                 image_white(dst);
307
308                 o = make_image_from_surf(W, H, dst);
309
310                 SDL_FreeSurface(dst);
311             }
312             SDL_FreeSurface(src);
313         }
314
315         if (W) *W *= k;
316         if (H) *H *= k;
317         if (w) *w *= k;
318         if (h) *h *= k;
319     }
320     else
321     {
322         if (W) *W = 0;
323         if (H) *H = 0;
324         if (w) *w = 0;
325         if (h) *h = 0;
326     }
327
328     return o;
329 }
330
331 /*---------------------------------------------------------------------------*/