tavli

view src/image.cc @ 22:c2a2069a49ec

slot highlighting, TODO blur
author John Tsiombikas <nuclear@member.fsf.org>
date Tue, 07 Jul 2015 21:56:37 +0300
parents b41ceead1708
children 3e6430028d54
line source
1 #include <string.h>
2 #include "opengl.h"
3 #include "image.h"
4 #include "imago2.h"
7 static unsigned int next_pow2(unsigned int x);
9 Image::Image()
10 {
11 width = height = tex_width = tex_height = 0;
12 pixels = 0;
13 tex = 0;
14 tex_valid = false;
15 }
17 Image::~Image()
18 {
19 destroy();
20 }
22 Image::Image(const Image &img)
23 {
24 pixels = 0;
25 create(img.width, img.height, img.pixels);
26 }
28 Image &Image::operator =(const Image &img)
29 {
30 if(&img != this) {
31 create(img.width, img.height, img.pixels);
32 }
33 return *this;
34 }
36 bool Image::create(int width, int height, unsigned char *pixels)
37 {
38 destroy();
40 try {
41 unsigned char *tmp = new unsigned char[width * height * 4];
42 this->pixels = tmp;
43 this->width = width;
44 this->height = height;
45 }
46 catch(...) {
47 return false;
48 }
50 if(pixels) {
51 memcpy(this->pixels, pixels, width * height * 4);
52 }
53 return true;
54 }
56 void Image::destroy()
57 {
58 delete [] pixels;
59 pixels = 0;
60 width = height = 0;
62 if(tex) {
63 glDeleteTextures(1, &tex);
64 tex = 0;
65 tex_valid = false;
66 }
67 }
69 bool Image::load(const char *fname)
70 {
71 int xsz, ysz;
72 unsigned char *pix = (unsigned char*)img_load_pixels(fname, &xsz, &ysz, IMG_FMT_RGBA32);
73 if(!pix) {
74 return false;
75 }
76 return create(xsz, ysz, pix);
77 }
79 unsigned int Image::texture() const
80 {
81 if(!pixels) {
82 return 0;
83 }
84 if(!tex) {
85 glGenTextures(1, &tex);
86 }
88 if(!tex_valid) {
89 tex_width = next_pow2(width);
90 tex_height = next_pow2(height);
92 glBindTexture(GL_TEXTURE_2D, tex);
93 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
94 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
96 if(GLEW_SGIS_generate_mipmap) {
97 glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, 1);
99 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tex_width, tex_height, 0, GL_RGBA, GL_UNSIGNED_BYTE,
100 width == tex_width && height == tex_height ? pixels : 0);
101 if(width != tex_width || height != tex_height) {
102 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
103 }
104 } else {
105 gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGBA, tex_width, tex_height, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
106 }
108 if(GLEW_EXT_texture_filter_anisotropic) {
109 static float max_aniso = -1.0;
111 if(max_aniso < 0.0) {
112 glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &max_aniso);
113 printf("using anisotropic filtering: x%g\n", max_aniso);
114 }
116 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, max_aniso);
117 }
118 tex_valid = true;
119 }
120 return tex;
121 }
123 int Image::texture_width() const
124 {
125 return tex_width;
126 }
128 int Image::texture_height() const
129 {
130 return tex_height;
131 }
133 void Image::invalidate_texture()
134 {
135 tex_valid = false;
136 }
139 void clear_image(Image *img)
140 {
141 clear_image(img, 0, 0, 0, 255);
142 }
144 void clear_image(Image *img, float r, float g, float b, float a)
145 {
146 if(!img->pixels) {
147 return;
148 }
150 unsigned char col[4];
151 unsigned char *ptr = img->pixels;
152 int npix = img->width * img->height;
154 col[0] = (int)(r * 255.0);
155 col[1] = (int)(g * 255.0);
156 col[2] = (int)(b * 255.0);
157 col[3] = (int)(a * 255.0);
159 for(int i=0; i<npix; i++) {
160 for(int j=0; j<4; j++) {
161 ptr[j] = col[j];
162 }
163 ptr += 4;
164 }
165 }
167 void clear_image_alpha(Image *img, float a)
168 {
169 if(!img->pixels) {
170 return;
171 }
173 unsigned char alpha = (int)(a * 255.0);
174 unsigned char *ptr = img->pixels;
175 int npix = img->width * img->height;
177 for(int i=0; i<npix; i++) {
178 ptr[3] = alpha;
179 ptr += 4;
180 }
181 }
183 bool combine_image(Image *dest, const Image *aimg, const Image *bimg, ImgCombine op, float t)
184 {
185 int xsz = dest->width;
186 int ysz = dest->height;
187 int npixels = xsz * ysz;
188 int nbytes = npixels * 4;
189 int tint = (int)(t * 255);
191 if(aimg->width != xsz || bimg->width != xsz || aimg->height != ysz || bimg->height != ysz) {
192 return false;
193 }
195 unsigned char *dptr = dest->pixels;
196 const unsigned char *aptr = aimg->pixels;
197 const unsigned char *bptr = bimg->pixels;
199 switch(op) {
200 case IMG_OP_ADD:
201 for(int i=0; i<nbytes; i++) {
202 unsigned int x = *aptr++ + *bptr++;
203 *dptr++ = x > 255 ? 255 : x;
204 }
205 break;
207 case IMG_OP_SUB:
208 for(int i=0; i<nbytes; i++) {
209 int x = (int)*aptr++ - (int)*bptr++;
210 *dptr++ = x < 0 ? 0 : x;
211 }
212 break;
214 case IMG_OP_MUL:
215 for(int i=0; i<nbytes; i++) {
216 unsigned int x = ((unsigned int)*aptr++ * (unsigned int)*bptr++) >> 8;
217 *dptr++ = x > 255 ? 255 : x;
218 }
219 break;
221 case IMG_OP_LERP:
222 for(int i=0; i<nbytes; i++) {
223 int x = (int)*aptr + ((((int)*bptr - (int)*aptr) * tint) >> 8);
224 *dptr++ = x > 255 ? 255 : (x < 0 ? 0 : x);
225 }
226 break;
228 default:
229 break;
230 }
232 dest->invalidate_texture();
233 return true;
234 }
236 static unsigned int next_pow2(unsigned int x)
237 {
238 x--;
239 x = (x >> 1) | x;
240 x = (x >> 2) | x;
241 x = (x >> 4) | x;
242 x = (x >> 8) | x;
243 x = (x >> 16) | x;
244 return x + 1;
245 }