tavli

view src/image.cc @ 23:3e6430028d54

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