goat3dgfx
view src/texture.cc @ 13:25bf39105c82
lalal
author | John Tsiombikas <nuclear@member.fsf.org> |
---|---|
date | Wed, 27 Nov 2013 08:08:59 +0200 |
parents | 3d96734fd477 |
children | 7d6b667821cf |
line source
1 #include <math.h>
2 #include "texture.h"
3 #include "image.h"
4 #include "opengl.h"
5 #include "imago2.h"
6 #include "logger.h"
7 #include "datapath.h"
9 static int glifmt_from_ifmt(unsigned int ifmt);
10 static int glfmt_from_ifmt(unsigned int ifmt);
11 static int gltype_from_ifmt(unsigned int ifmt);
13 static int glifmt_from_imgfmt(Image::Format fmt);
15 static unsigned int cur_target[8] = {
16 GL_TEXTURE_2D, GL_TEXTURE_2D, GL_TEXTURE_2D, GL_TEXTURE_2D,
17 GL_TEXTURE_2D, GL_TEXTURE_2D, GL_TEXTURE_2D, GL_TEXTURE_2D
18 };
20 void set_texture(Texture *tex, int tunit)
21 {
22 if(tex) {
23 tex->bind(tunit);
24 } else {
25 glActiveTexture(GL_TEXTURE0 + tunit);
26 glBindTexture(cur_target[tunit], 0);
27 glActiveTexture(GL_TEXTURE0);
28 }
29 }
31 Texture *load_texture(const char *fname)
32 {
33 TextureCube *texcube = new TextureCube;
34 if(texcube->load(fname)) {
35 return texcube;
36 }
37 delete texcube;
39 Texture2D *tex = new Texture2D;
40 if(tex->load(fname)) {
41 return tex;
42 }
43 delete tex;
44 return 0;
45 }
48 Texture::Texture()
49 {
50 target = 0;
51 sz[0] = sz[1] = sz[2] = 0;
52 texfmt = 0;
54 glGenTextures(1, &id);
55 }
57 Texture::~Texture()
58 {
59 if(id) {
60 glDeleteTextures(1, &id);
61 }
62 }
64 void Texture::set_wrapping(unsigned int wrap)
65 {
66 if(!target) {
67 return;
68 }
70 glBindTexture(target, id);
71 glTexParameteri(target, GL_TEXTURE_WRAP_S, wrap);
72 glTexParameteri(target, GL_TEXTURE_WRAP_T, wrap);
73 }
75 void Texture::set_filtering(unsigned int filt)
76 {
77 unsigned int mag_filter;
79 if(!target) {
80 return;
81 }
83 switch(filt) {
84 case GL_LINEAR_MIPMAP_NEAREST:
85 case GL_LINEAR_MIPMAP_LINEAR:
86 mag_filter = GL_LINEAR;
87 break;
89 case GL_NEAREST_MIPMAP_NEAREST:
90 case GL_NEAREST_MIPMAP_LINEAR:
91 mag_filter = GL_NEAREST;
92 break;
94 default:
95 mag_filter = filt;
96 }
98 set_filtering(filt, mag_filter);
99 }
101 void Texture::set_filtering(unsigned int min_filt, unsigned int mag_filt)
102 {
103 glBindTexture(target, id);
104 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, min_filt);
105 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, mag_filt);
106 }
108 unsigned int Texture::get_format() const
109 {
110 return texfmt;
111 }
113 int Texture::get_size(int dim) const
114 {
115 if(dim < 0 || dim >= 3) {
116 return 0;
117 }
118 return sz[dim];
119 }
121 unsigned int Texture::get_id() const
122 {
123 return id;
124 }
126 void Texture::bind(int tex_unit) const
127 {
128 glActiveTexture(GL_TEXTURE0 + tex_unit);
129 glBindTexture(target, id);
130 glActiveTexture(GL_TEXTURE0);
132 cur_target[tex_unit] = target;
133 }
136 // ---- Texture2D ----
138 Texture2D::Texture2D()
139 {
140 target = GL_TEXTURE_2D;
141 }
143 void Texture2D::create(int xsz, int ysz, unsigned int ifmt)
144 {
145 int fmt = glfmt_from_ifmt(ifmt);
146 int type = gltype_from_ifmt(ifmt);
148 glBindTexture(GL_TEXTURE_2D, id);
149 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
150 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
151 glTexImage2D(GL_TEXTURE_2D, 0, glifmt_from_ifmt(ifmt), xsz, ysz, 0, fmt, type, 0);
152 CHECKGLERR;
153 sz[0] = xsz;
154 sz[1] = ysz;
155 texfmt = ifmt;
156 }
158 void Texture2D::set_image(const Image &img, int idx)
159 {
160 texfmt = glifmt_from_imgfmt(img.get_format());
161 unsigned int fmt = glfmt_from_ifmt(texfmt);
162 unsigned int type = gltype_from_ifmt(texfmt);
164 sz[0] = img.get_width();
165 sz[1] = img.get_height();
167 glBindTexture(GL_TEXTURE_2D, id);
168 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
169 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
170 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
171 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
173 #ifdef __GLEW_H__
174 if(GLEW_SGIS_generate_mipmap) {
175 glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP_SGIS, GL_TRUE);
176 #endif
177 glTexImage2D(GL_TEXTURE_2D, 0, texfmt, sz[0], sz[1], 0, fmt, type, img.get_pixels());
178 #ifdef __GLEW_H__
179 } else {
180 gluBuild2DMipmaps(GL_TEXTURE_2D, texfmt, sz[0], sz[1], fmt, type, img.get_pixels());
181 }
182 #endif
184 #ifdef GL_ES_VERSION_2_0
185 glGenerateMipmap(GL_TEXTURE_2D);
186 #endif
187 }
189 bool Texture2D::load(const char *fname)
190 {
191 Image img;
192 if(!img.load(fname)) {
193 error_log("failed to load 2D texture: %s\n", fname);
194 return false;
195 }
196 set_image(img);
198 info_log("loaded 2D texture: %s\n", fname);
199 return true;
200 }
202 bool Texture2D::save(const char *fname) const
203 {
204 #ifndef GL_ES_VERSION_2_0
205 unsigned char *pixels = new unsigned char[sz[0] * sz[1] * 4];
207 glBindTexture(GL_TEXTURE_2D, id);
208 glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
210 if(img_save_pixels(fname, pixels, sz[0], sz[1]) == -1) {
211 error_log("failed to save 2D texture: %s\n", fname);
212 delete [] pixels;
213 return false;
214 }
216 info_log("saved 2D texture: %s\n", fname);
217 delete [] pixels;
218 return true;
219 #else
220 return false; // TODO
221 #endif
222 }
224 // ---- TextureCube ----
225 static unsigned int cube_faces[] = {
226 GL_TEXTURE_CUBE_MAP_POSITIVE_X,
227 GL_TEXTURE_CUBE_MAP_NEGATIVE_X,
228 GL_TEXTURE_CUBE_MAP_POSITIVE_Y,
229 GL_TEXTURE_CUBE_MAP_NEGATIVE_Y,
230 GL_TEXTURE_CUBE_MAP_POSITIVE_Z,
231 GL_TEXTURE_CUBE_MAP_NEGATIVE_Z
232 };
234 TextureCube::TextureCube()
235 {
236 target = GL_TEXTURE_CUBE_MAP;
237 }
239 void TextureCube::create(int xsz, int ysz, unsigned int ifmt)
240 {
241 if(xsz != ysz) {
242 error_log("trying to create cubemap with different width and height (%dx%d)\n", xsz, ysz);
243 return;
244 }
246 texfmt = ifmt;
248 glBindTexture(GL_TEXTURE_CUBE_MAP, id);
249 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
250 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
251 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
252 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
253 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
255 for(int i=0; i<6; i++) {
256 glTexImage2D(cube_faces[i], 0, ifmt, xsz, ysz, 0, GL_RGB, GL_UNSIGNED_BYTE, 0);
257 }
258 }
260 void TextureCube::set_image(const Image &img, int idx)
261 {
262 texfmt = glifmt_from_imgfmt(img.get_format());
263 unsigned int fmt = glfmt_from_ifmt(texfmt);
264 unsigned int type = gltype_from_ifmt(texfmt);
266 sz[0] = img.get_width();
267 sz[1] = img.get_height();
269 glBindTexture(GL_TEXTURE_CUBE_MAP, id);
270 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
271 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
272 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
273 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
274 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
276 glTexImage2D(cube_faces[idx], 0, texfmt, sz[0], sz[1], 0, fmt, type, img.get_pixels());
277 }
279 bool TextureCube::load(const char *fname)
280 {
281 static const float one_third = 1.0 / 3.0;
282 static const float two_thirds = 2.0 / 3.0;
283 static const float hcross[2][6] = {
284 {0.5, 0.0, 0.25, 0.25, 0.25, 0.75}, {one_third, one_third, 0.0, two_thirds, one_third, one_third} };
285 static const float vcross[2][6] = {
286 {two_thirds, 0.0, one_third, one_third, one_third, one_third}, {0.25, 0.25, 0.0, 0.5, 0.25, 0.75} };
287 static const float hsix[2][6] = {
288 {0.0, 0.0, one_third, one_third, two_thirds, two_thirds}, {0.0, 0.5, 0.0, 0.5, 0.0, 0.5} };
290 Image img;
291 if(!img.load(fname)) {
292 return false;
293 }
295 int xsz = img.get_width();
296 int ysz = img.get_height();
298 if(xsz / 4 == ysz / 3) {
299 // horizontal cross, assume the vertical bit is center-left
300 return load_multi(img, hcross[0], hcross[1], xsz / 4);
301 }
302 if(xsz / 3 == ysz / 4) {
303 // vertical cross, assume the horizontal bit is center-top (180-rotated image 5)
304 return load_multi(img, vcross[0], vcross[1], ysz / 4, (1 << 5));
305 }
306 if(xsz / 3 == ysz / 2) {
307 // horizontal sixpack
308 return load_multi(img, hsix[0], hsix[1], ysz / 2);
309 }
311 error_log("failed to load %s: unknown cubemap configuration\n", fname);
312 return false;
313 }
315 bool TextureCube::save(const char *fname) const
316 {
317 return false; // TODO
318 }
320 bool TextureCube::load_multi(const Image &img, const float *xoffsets, const float *yoffsets, float sz,
321 unsigned int rotmask)
322 {
323 for(int i=0; i<6; i++) {
324 Image face;
326 int xoffs = xoffsets[i] * img.get_width();
327 int yoffs = yoffsets[i] * img.get_height();
329 if(!face.set_pixels(sz, sz, img.get_pixels(), xoffs, yoffs, img.get_width(), img.get_format())) {
330 return false;
331 }
333 if(rotmask & (1 << i)) {
334 face.rotate_180();
335 }
336 set_image(face, i);
337 }
338 return true;
339 }
341 static int glifmt_from_ifmt(unsigned int ifmt)
342 {
343 #ifdef GL_ES_VERSION_2_0
344 switch(ifmt) {
345 case GL_LUMINANCE16F:
346 case GL_LUMINANCE32F:
347 ifmt = GL_LUMINANCE;
348 break;
350 case GL_RGB16F:
351 case GL_RGB32F:
352 ifmt = GL_RGB;
353 break;
355 case GL_RGBA16F:
356 case GL_RGBA32F:
357 ifmt = GL_RGBA;
358 break;
360 default:
361 break;
362 }
363 #endif
364 return ifmt; // by default just pass it through...
365 }
367 static int glfmt_from_ifmt(unsigned int ifmt)
368 {
369 switch(ifmt) {
370 case GL_LUMINANCE16F:
371 case GL_LUMINANCE32F:
372 return GL_LUMINANCE;
374 case GL_RGB16F:
375 case GL_RGB32F:
376 return GL_RGB;
378 case GL_RGBA16F:
379 case GL_RGBA32F:
380 return GL_RGBA;
382 default:
383 break;
384 }
385 return ifmt;
386 }
388 static int gltype_from_ifmt(unsigned int ifmt)
389 {
390 switch(ifmt) {
391 case GL_RGB16F:
392 case GL_RGBA16F:
393 case GL_LUMINANCE16F:
394 #ifdef GL_ES_VERSION_2_0
395 return GL_HALF_FLOAT_OES;
396 #endif
397 case GL_RGB32F:
398 case GL_RGBA32F:
399 case GL_LUMINANCE32F:
400 return GL_FLOAT;
402 default:
403 break;
404 }
405 return GL_UNSIGNED_BYTE;
406 }
408 static int glifmt_from_imgfmt(Image::Format fmt)
409 {
410 switch(fmt) {
411 case Image::FMT_GREY:
412 return GL_LUMINANCE;
413 case Image::FMT_GREY_FLOAT:
414 return GL_LUMINANCE16F;
415 case Image::FMT_RGB:
416 return GL_RGB;
417 case Image::FMT_RGB_FLOAT:
418 return GL_RGB16F;
419 case Image::FMT_RGBA:
420 return GL_RGBA;
421 case Image::FMT_RGBA_FLOAT:
422 return GL_RGBA16F;
423 default:
424 break;
425 }
426 return 0;
427 }
429 // ---- TextureSet ----
430 static void destroy_texture(Texture *tex)
431 {
432 delete tex;
433 }
435 TextureSet::TextureSet()
436 : DataSet<Texture*>(load_texture, destroy_texture)
437 {
438 }