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