rev |
line source |
nuclear@4
|
1 #include <string.h>
|
nuclear@23
|
2 #include <alloca.h>
|
nuclear@4
|
3 #include "opengl.h"
|
nuclear@4
|
4 #include "image.h"
|
nuclear@4
|
5 #include "imago2.h"
|
nuclear@4
|
6
|
nuclear@4
|
7
|
nuclear@4
|
8 static unsigned int next_pow2(unsigned int x);
|
nuclear@4
|
9
|
nuclear@4
|
10 Image::Image()
|
nuclear@4
|
11 {
|
nuclear@4
|
12 width = height = tex_width = tex_height = 0;
|
nuclear@4
|
13 pixels = 0;
|
nuclear@4
|
14 tex = 0;
|
nuclear@4
|
15 tex_valid = false;
|
nuclear@4
|
16 }
|
nuclear@4
|
17
|
nuclear@4
|
18 Image::~Image()
|
nuclear@4
|
19 {
|
nuclear@4
|
20 destroy();
|
nuclear@4
|
21 }
|
nuclear@4
|
22
|
nuclear@4
|
23 Image::Image(const Image &img)
|
nuclear@4
|
24 {
|
nuclear@4
|
25 pixels = 0;
|
nuclear@4
|
26 create(img.width, img.height, img.pixels);
|
nuclear@4
|
27 }
|
nuclear@4
|
28
|
nuclear@4
|
29 Image &Image::operator =(const Image &img)
|
nuclear@4
|
30 {
|
nuclear@4
|
31 if(&img != this) {
|
nuclear@4
|
32 create(img.width, img.height, img.pixels);
|
nuclear@4
|
33 }
|
nuclear@4
|
34 return *this;
|
nuclear@4
|
35 }
|
nuclear@4
|
36
|
nuclear@4
|
37 bool Image::create(int width, int height, unsigned char *pixels)
|
nuclear@4
|
38 {
|
nuclear@4
|
39 destroy();
|
nuclear@4
|
40
|
nuclear@4
|
41 try {
|
nuclear@22
|
42 unsigned char *tmp = new unsigned char[width * height * 4];
|
nuclear@4
|
43 this->pixels = tmp;
|
nuclear@4
|
44 this->width = width;
|
nuclear@4
|
45 this->height = height;
|
nuclear@4
|
46 }
|
nuclear@4
|
47 catch(...) {
|
nuclear@4
|
48 return false;
|
nuclear@4
|
49 }
|
nuclear@4
|
50
|
nuclear@4
|
51 if(pixels) {
|
nuclear@22
|
52 memcpy(this->pixels, pixels, width * height * 4);
|
nuclear@4
|
53 }
|
nuclear@4
|
54 return true;
|
nuclear@4
|
55 }
|
nuclear@4
|
56
|
nuclear@4
|
57 void Image::destroy()
|
nuclear@4
|
58 {
|
nuclear@4
|
59 delete [] pixels;
|
nuclear@4
|
60 pixels = 0;
|
nuclear@4
|
61 width = height = 0;
|
nuclear@4
|
62
|
nuclear@4
|
63 if(tex) {
|
nuclear@4
|
64 glDeleteTextures(1, &tex);
|
nuclear@4
|
65 tex = 0;
|
nuclear@4
|
66 tex_valid = false;
|
nuclear@4
|
67 }
|
nuclear@4
|
68 }
|
nuclear@4
|
69
|
nuclear@4
|
70 bool Image::load(const char *fname)
|
nuclear@4
|
71 {
|
nuclear@4
|
72 int xsz, ysz;
|
nuclear@22
|
73 unsigned char *pix = (unsigned char*)img_load_pixels(fname, &xsz, &ysz, IMG_FMT_RGBA32);
|
nuclear@4
|
74 if(!pix) {
|
nuclear@4
|
75 return false;
|
nuclear@4
|
76 }
|
nuclear@4
|
77 return create(xsz, ysz, pix);
|
nuclear@4
|
78 }
|
nuclear@4
|
79
|
nuclear@4
|
80 unsigned int Image::texture() const
|
nuclear@4
|
81 {
|
nuclear@4
|
82 if(!pixels) {
|
nuclear@4
|
83 return 0;
|
nuclear@4
|
84 }
|
nuclear@4
|
85 if(!tex) {
|
nuclear@4
|
86 glGenTextures(1, &tex);
|
nuclear@4
|
87 }
|
nuclear@4
|
88
|
nuclear@4
|
89 if(!tex_valid) {
|
nuclear@4
|
90 tex_width = next_pow2(width);
|
nuclear@4
|
91 tex_height = next_pow2(height);
|
nuclear@4
|
92
|
nuclear@4
|
93 glBindTexture(GL_TEXTURE_2D, tex);
|
nuclear@4
|
94 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
|
nuclear@4
|
95 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
nuclear@4
|
96
|
nuclear@4
|
97 if(GLEW_SGIS_generate_mipmap) {
|
nuclear@4
|
98 glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, 1);
|
nuclear@4
|
99
|
nuclear@22
|
100 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tex_width, tex_height, 0, GL_RGBA, GL_UNSIGNED_BYTE,
|
nuclear@4
|
101 width == tex_width && height == tex_height ? pixels : 0);
|
nuclear@4
|
102 if(width != tex_width || height != tex_height) {
|
nuclear@22
|
103 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
|
nuclear@4
|
104 }
|
nuclear@4
|
105 } else {
|
nuclear@22
|
106 gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGBA, tex_width, tex_height, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
|
nuclear@4
|
107 }
|
nuclear@4
|
108
|
nuclear@4
|
109 if(GLEW_EXT_texture_filter_anisotropic) {
|
nuclear@4
|
110 static float max_aniso = -1.0;
|
nuclear@4
|
111
|
nuclear@4
|
112 if(max_aniso < 0.0) {
|
nuclear@4
|
113 glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &max_aniso);
|
nuclear@4
|
114 printf("using anisotropic filtering: x%g\n", max_aniso);
|
nuclear@4
|
115 }
|
nuclear@4
|
116
|
nuclear@4
|
117 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, max_aniso);
|
nuclear@4
|
118 }
|
nuclear@4
|
119 tex_valid = true;
|
nuclear@4
|
120 }
|
nuclear@4
|
121 return tex;
|
nuclear@4
|
122 }
|
nuclear@4
|
123
|
nuclear@4
|
124 int Image::texture_width() const
|
nuclear@4
|
125 {
|
nuclear@4
|
126 return tex_width;
|
nuclear@4
|
127 }
|
nuclear@4
|
128
|
nuclear@4
|
129 int Image::texture_height() const
|
nuclear@4
|
130 {
|
nuclear@4
|
131 return tex_height;
|
nuclear@4
|
132 }
|
nuclear@4
|
133
|
nuclear@4
|
134 void Image::invalidate_texture()
|
nuclear@4
|
135 {
|
nuclear@4
|
136 tex_valid = false;
|
nuclear@4
|
137 }
|
nuclear@4
|
138
|
nuclear@4
|
139
|
nuclear@4
|
140 void clear_image(Image *img)
|
nuclear@4
|
141 {
|
nuclear@22
|
142 clear_image(img, 0, 0, 0, 255);
|
nuclear@4
|
143 }
|
nuclear@4
|
144
|
nuclear@22
|
145 void clear_image(Image *img, float r, float g, float b, float a)
|
nuclear@4
|
146 {
|
nuclear@4
|
147 if(!img->pixels) {
|
nuclear@4
|
148 return;
|
nuclear@4
|
149 }
|
nuclear@4
|
150
|
nuclear@22
|
151 unsigned char col[4];
|
nuclear@4
|
152 unsigned char *ptr = img->pixels;
|
nuclear@4
|
153 int npix = img->width * img->height;
|
nuclear@4
|
154
|
nuclear@4
|
155 col[0] = (int)(r * 255.0);
|
nuclear@4
|
156 col[1] = (int)(g * 255.0);
|
nuclear@4
|
157 col[2] = (int)(b * 255.0);
|
nuclear@22
|
158 col[3] = (int)(a * 255.0);
|
nuclear@4
|
159
|
nuclear@4
|
160 for(int i=0; i<npix; i++) {
|
nuclear@22
|
161 for(int j=0; j<4; j++) {
|
nuclear@4
|
162 ptr[j] = col[j];
|
nuclear@4
|
163 }
|
nuclear@22
|
164 ptr += 4;
|
nuclear@22
|
165 }
|
nuclear@22
|
166 }
|
nuclear@22
|
167
|
nuclear@22
|
168 void clear_image_alpha(Image *img, float a)
|
nuclear@22
|
169 {
|
nuclear@22
|
170 if(!img->pixels) {
|
nuclear@22
|
171 return;
|
nuclear@22
|
172 }
|
nuclear@22
|
173
|
nuclear@22
|
174 unsigned char alpha = (int)(a * 255.0);
|
nuclear@22
|
175 unsigned char *ptr = img->pixels;
|
nuclear@22
|
176 int npix = img->width * img->height;
|
nuclear@22
|
177
|
nuclear@22
|
178 for(int i=0; i<npix; i++) {
|
nuclear@22
|
179 ptr[3] = alpha;
|
nuclear@22
|
180 ptr += 4;
|
nuclear@4
|
181 }
|
nuclear@4
|
182 }
|
nuclear@4
|
183
|
nuclear@4
|
184 bool combine_image(Image *dest, const Image *aimg, const Image *bimg, ImgCombine op, float t)
|
nuclear@4
|
185 {
|
nuclear@4
|
186 int xsz = dest->width;
|
nuclear@4
|
187 int ysz = dest->height;
|
nuclear@4
|
188 int npixels = xsz * ysz;
|
nuclear@22
|
189 int nbytes = npixels * 4;
|
nuclear@4
|
190 int tint = (int)(t * 255);
|
nuclear@4
|
191
|
nuclear@4
|
192 if(aimg->width != xsz || bimg->width != xsz || aimg->height != ysz || bimg->height != ysz) {
|
nuclear@4
|
193 return false;
|
nuclear@4
|
194 }
|
nuclear@4
|
195
|
nuclear@4
|
196 unsigned char *dptr = dest->pixels;
|
nuclear@4
|
197 const unsigned char *aptr = aimg->pixels;
|
nuclear@4
|
198 const unsigned char *bptr = bimg->pixels;
|
nuclear@4
|
199
|
nuclear@4
|
200 switch(op) {
|
nuclear@4
|
201 case IMG_OP_ADD:
|
nuclear@4
|
202 for(int i=0; i<nbytes; i++) {
|
nuclear@4
|
203 unsigned int x = *aptr++ + *bptr++;
|
nuclear@4
|
204 *dptr++ = x > 255 ? 255 : x;
|
nuclear@4
|
205 }
|
nuclear@4
|
206 break;
|
nuclear@4
|
207
|
nuclear@4
|
208 case IMG_OP_SUB:
|
nuclear@4
|
209 for(int i=0; i<nbytes; i++) {
|
nuclear@4
|
210 int x = (int)*aptr++ - (int)*bptr++;
|
nuclear@4
|
211 *dptr++ = x < 0 ? 0 : x;
|
nuclear@4
|
212 }
|
nuclear@4
|
213 break;
|
nuclear@4
|
214
|
nuclear@4
|
215 case IMG_OP_MUL:
|
nuclear@4
|
216 for(int i=0; i<nbytes; i++) {
|
nuclear@4
|
217 unsigned int x = ((unsigned int)*aptr++ * (unsigned int)*bptr++) >> 8;
|
nuclear@4
|
218 *dptr++ = x > 255 ? 255 : x;
|
nuclear@4
|
219 }
|
nuclear@4
|
220 break;
|
nuclear@4
|
221
|
nuclear@4
|
222 case IMG_OP_LERP:
|
nuclear@4
|
223 for(int i=0; i<nbytes; i++) {
|
nuclear@4
|
224 int x = (int)*aptr + ((((int)*bptr - (int)*aptr) * tint) >> 8);
|
nuclear@4
|
225 *dptr++ = x > 255 ? 255 : (x < 0 ? 0 : x);
|
nuclear@4
|
226 }
|
nuclear@4
|
227 break;
|
nuclear@4
|
228
|
nuclear@4
|
229 default:
|
nuclear@4
|
230 break;
|
nuclear@4
|
231 }
|
nuclear@4
|
232
|
nuclear@4
|
233 dest->invalidate_texture();
|
nuclear@4
|
234 return true;
|
nuclear@4
|
235 }
|
nuclear@4
|
236
|
nuclear@23
|
237 void convolve_horiz_image(Image *dest, float *kern, int ksz, float scale)
|
nuclear@23
|
238 {
|
nuclear@23
|
239 if((ksz & 1) == 0) {
|
nuclear@23
|
240 fprintf(stderr, "%s: kernel size (%d) must be odd, skipping last value\n", __FUNCTION__, ksz);
|
nuclear@23
|
241 --ksz;
|
nuclear@23
|
242 }
|
nuclear@23
|
243 if(scale == 0.0) {
|
nuclear@23
|
244 // calculate scale factor
|
nuclear@23
|
245 float sum = 0.0;
|
nuclear@23
|
246 for(int i=0; i<ksz; i++) {
|
nuclear@23
|
247 sum += kern[i];
|
nuclear@23
|
248 }
|
nuclear@23
|
249 scale = 1.0 / sum;
|
nuclear@23
|
250 }
|
nuclear@23
|
251 int krad = ksz / 2;
|
nuclear@23
|
252 float *buf = (float*)alloca(dest->width * 4 * sizeof *buf);
|
nuclear@23
|
253 unsigned char *sptr = dest->pixels;
|
nuclear@23
|
254
|
nuclear@23
|
255 for(int i=0; i<dest->height; i++) {
|
nuclear@23
|
256 float *bptr = buf;
|
nuclear@23
|
257 for(int j=0; j<dest->width * 4; j++) {
|
nuclear@23
|
258 *bptr++ = (float)(sptr[j] / 255.0);
|
nuclear@23
|
259 }
|
nuclear@23
|
260
|
nuclear@23
|
261 for(int j=0; j<dest->width; j++) {
|
nuclear@23
|
262 float col[] = {0, 0, 0, 0};
|
nuclear@23
|
263
|
nuclear@23
|
264 for(int k=0; k<ksz; k++) {
|
nuclear@23
|
265 int idx = j + k - krad;
|
nuclear@23
|
266 if(idx < 0) idx = 0;
|
nuclear@23
|
267 if(idx >= dest->width) idx = dest->width - 1;
|
nuclear@23
|
268
|
nuclear@23
|
269 col[0] += buf[idx * 4] * kern[k];
|
nuclear@23
|
270 col[1] += buf[idx * 4 + 1] * kern[k];
|
nuclear@23
|
271 col[2] += buf[idx * 4 + 2] * kern[k];
|
nuclear@23
|
272 col[3] += buf[idx * 4 + 3] * kern[k];
|
nuclear@23
|
273 }
|
nuclear@23
|
274
|
nuclear@23
|
275 int ri = (int)(col[0] * scale * 255.0);
|
nuclear@23
|
276 int gi = (int)(col[1] * scale * 255.0);
|
nuclear@23
|
277 int bi = (int)(col[2] * scale * 255.0);
|
nuclear@23
|
278 int ai = (int)(col[3] * scale * 255.0);
|
nuclear@23
|
279
|
nuclear@23
|
280 sptr[0] = ri < 0 ? 0 : (ri > 255 ? 255 : ri);
|
nuclear@23
|
281 sptr[1] = gi < 0 ? 0 : (gi > 255 ? 255 : gi);
|
nuclear@23
|
282 sptr[2] = bi < 0 ? 0 : (bi > 255 ? 255 : bi);
|
nuclear@23
|
283 sptr[3] = ai < 0 ? 0 : (ai > 255 ? 255 : ai);
|
nuclear@23
|
284 sptr += 4;
|
nuclear@23
|
285 }
|
nuclear@23
|
286 }
|
nuclear@23
|
287
|
nuclear@23
|
288 dest->invalidate_texture();
|
nuclear@23
|
289 }
|
nuclear@23
|
290
|
nuclear@23
|
291 void convolve_vert_image(Image *dest, float *kern, int ksz, float scale)
|
nuclear@23
|
292 {
|
nuclear@23
|
293 if((ksz & 1) == 0) {
|
nuclear@23
|
294 fprintf(stderr, "%s: kernel size (%d) must be odd, skipping last value\n", __FUNCTION__, ksz);
|
nuclear@23
|
295 --ksz;
|
nuclear@23
|
296 }
|
nuclear@23
|
297 if(scale == 0.0) {
|
nuclear@23
|
298 // calculate scale factor
|
nuclear@23
|
299 float sum = 0.0;
|
nuclear@23
|
300 for(int i=0; i<ksz; i++) {
|
nuclear@23
|
301 sum += kern[i];
|
nuclear@23
|
302 }
|
nuclear@23
|
303 scale = 1.0 / sum;
|
nuclear@23
|
304 }
|
nuclear@23
|
305 int krad = ksz / 2;
|
nuclear@23
|
306 float *buf = (float*)alloca(dest->height * 4 * sizeof *buf);
|
nuclear@23
|
307 unsigned char *sptr = dest->pixels;
|
nuclear@23
|
308
|
nuclear@23
|
309 for(int i=0; i<dest->width; i++) {
|
nuclear@23
|
310 float *bptr = buf;
|
nuclear@23
|
311 sptr = dest->pixels + i * 4;
|
nuclear@23
|
312
|
nuclear@23
|
313 for(int j=0; j<dest->height; j++) {
|
nuclear@23
|
314 for(int k=0; k<4; k++) {
|
nuclear@23
|
315 *bptr++ = (float)(sptr[k] / 255.0);
|
nuclear@23
|
316 }
|
nuclear@23
|
317 sptr += dest->width * 4;
|
nuclear@23
|
318 }
|
nuclear@23
|
319
|
nuclear@23
|
320 sptr = dest->pixels + i * 4;
|
nuclear@23
|
321
|
nuclear@23
|
322 for(int j=0; j<dest->height; j++) {
|
nuclear@23
|
323 float col[] = {0, 0, 0, 0};
|
nuclear@23
|
324
|
nuclear@23
|
325 for(int k=0; k<ksz; k++) {
|
nuclear@23
|
326 int idx = j + k - krad;
|
nuclear@23
|
327 if(idx < 0) idx = 0;
|
nuclear@23
|
328 if(idx >= dest->height) idx = dest->height - 1;
|
nuclear@23
|
329
|
nuclear@23
|
330 col[0] += buf[idx * 4] * kern[k];
|
nuclear@23
|
331 col[1] += buf[idx * 4 + 1] * kern[k];
|
nuclear@23
|
332 col[2] += buf[idx * 4 + 2] * kern[k];
|
nuclear@23
|
333 col[3] += buf[idx * 4 + 3] * kern[k];
|
nuclear@23
|
334 }
|
nuclear@23
|
335
|
nuclear@23
|
336 int ri = (int)(col[0] * scale * 255.0);
|
nuclear@23
|
337 int gi = (int)(col[1] * scale * 255.0);
|
nuclear@23
|
338 int bi = (int)(col[2] * scale * 255.0);
|
nuclear@23
|
339 int ai = (int)(col[3] * scale * 255.0);
|
nuclear@23
|
340
|
nuclear@23
|
341 sptr[0] = ri < 0 ? 0 : (ri > 255 ? 255 : ri);
|
nuclear@23
|
342 sptr[1] = gi < 0 ? 0 : (gi > 255 ? 255 : gi);
|
nuclear@23
|
343 sptr[2] = bi < 0 ? 0 : (bi > 255 ? 255 : bi);
|
nuclear@23
|
344 sptr[3] = ai < 0 ? 0 : (ai > 255 ? 255 : ai);
|
nuclear@23
|
345 sptr += dest->width * 4;
|
nuclear@23
|
346 }
|
nuclear@23
|
347 }
|
nuclear@23
|
348 }
|
nuclear@23
|
349
|
nuclear@4
|
350 static unsigned int next_pow2(unsigned int x)
|
nuclear@4
|
351 {
|
nuclear@4
|
352 x--;
|
nuclear@4
|
353 x = (x >> 1) | x;
|
nuclear@4
|
354 x = (x >> 2) | x;
|
nuclear@4
|
355 x = (x >> 4) | x;
|
nuclear@4
|
356 x = (x >> 8) | x;
|
nuclear@4
|
357 x = (x >> 16) | x;
|
nuclear@4
|
358 return x + 1;
|
nuclear@4
|
359 }
|