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