goat3dgfx

view src/texture.cc @ 29:9d581abd0bfb

merged
author John Tsiombikas <nuclear@member.fsf.org>
date Sun, 02 Mar 2014 02:18:15 +0200
parents 7d6b667821cf
children 253542d715f4
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 using namespace goatgfx;
11 static int glifmt_from_ifmt(unsigned int ifmt);
12 static int glfmt_from_ifmt(unsigned int ifmt);
13 static int gltype_from_ifmt(unsigned int ifmt);
15 static int glifmt_from_imgfmt(Image::Format fmt);
17 static unsigned int type_to_target(TextureType type);
18 static TextureType target_to_type(unsigned int targ);
20 static unsigned int cur_target[8] = {
21 GL_TEXTURE_2D, GL_TEXTURE_2D, GL_TEXTURE_2D, GL_TEXTURE_2D,
22 GL_TEXTURE_2D, GL_TEXTURE_2D, GL_TEXTURE_2D, GL_TEXTURE_2D
23 };
25 static unsigned int cube_faces[] = {
26 GL_TEXTURE_CUBE_MAP_POSITIVE_X,
27 GL_TEXTURE_CUBE_MAP_NEGATIVE_X,
28 GL_TEXTURE_CUBE_MAP_POSITIVE_Y,
29 GL_TEXTURE_CUBE_MAP_NEGATIVE_Y,
30 GL_TEXTURE_CUBE_MAP_POSITIVE_Z,
31 GL_TEXTURE_CUBE_MAP_NEGATIVE_Z
32 };
35 void goatgfx::bind_texture(Texture *tex, int tunit)
36 {
37 if(tex) {
38 tex->bind(tunit);
39 } else {
40 glActiveTexture(GL_TEXTURE0 + tunit);
41 glBindTexture(cur_target[tunit], 0);
42 glActiveTexture(GL_TEXTURE0);
43 }
44 }
46 Texture::Texture()
47 {
48 target = 0;
49 sz[0] = sz[1] = sz[2] = 0;
50 texfmt = 0;
52 img = 0;
53 glGenTextures(1, &id);
54 }
56 Texture::~Texture()
57 {
58 if(id) {
59 glDeleteTextures(1, &id);
60 }
61 if(img) {
62 delete img;
63 }
64 }
66 void Texture::set_wrapping(unsigned int wrap)
67 {
68 if(!target) {
69 return;
70 }
72 glBindTexture(target, id);
73 glTexParameteri(target, GL_TEXTURE_WRAP_S, wrap);
74 glTexParameteri(target, GL_TEXTURE_WRAP_T, wrap);
75 glTexParameteri(target, GL_TEXTURE_WRAP_R, wrap);
76 }
78 void Texture::set_filtering(unsigned int filt)
79 {
80 unsigned int mag_filter;
82 if(!target) {
83 return;
84 }
86 switch(filt) {
87 case GL_LINEAR_MIPMAP_NEAREST:
88 case GL_LINEAR_MIPMAP_LINEAR:
89 mag_filter = GL_LINEAR;
90 break;
92 case GL_NEAREST_MIPMAP_NEAREST:
93 case GL_NEAREST_MIPMAP_LINEAR:
94 mag_filter = GL_NEAREST;
95 break;
97 default:
98 mag_filter = filt;
99 }
101 set_filtering(filt, mag_filter);
102 }
104 void Texture::set_filtering(unsigned int min_filt, unsigned int mag_filt)
105 {
106 glBindTexture(target, id);
107 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, min_filt);
108 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, mag_filt);
109 }
111 unsigned int Texture::get_format() const
112 {
113 return texfmt;
114 }
116 int Texture::get_size(int dim) const
117 {
118 if(dim < 0 || dim >= 3) {
119 return 0;
120 }
121 return sz[dim];
122 }
124 unsigned int Texture::get_id() const
125 {
126 return id;
127 }
129 TextureType Texture::get_type() const
130 {
131 return target_to_type(target);
132 }
134 void Texture::bind(int tex_unit) const
135 {
136 glActiveTexture(GL_TEXTURE0 + tex_unit);
137 glBindTexture(target, id);
138 glActiveTexture(GL_TEXTURE0);
140 cur_target[tex_unit] = target;
141 }
144 void Texture::create(int xsz, int ysz, TextureType textype, unsigned int ifmt)
145 {
146 if(textype == TEX_CUBE && xsz != ysz) {
147 error_log("trying to create cubemap with different width and height (%dx%d)\n", xsz, ysz);
148 return;
149 }
151 int fmt = glfmt_from_ifmt(ifmt);
152 int type = gltype_from_ifmt(ifmt);
154 target = type_to_target(textype);
156 glBindTexture(target, id);
157 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
158 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
160 switch(type) {
161 case TEX_2D:
162 glTexImage2D(GL_TEXTURE_2D, 0, glifmt_from_ifmt(ifmt), xsz, ysz, 0, fmt, type, 0);
163 break;
165 case TEX_CUBE:
166 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
167 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
168 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
169 for(int i=0; i<6; i++) {
170 glTexImage2D(cube_faces[i], 0, ifmt, xsz, ysz, 0, GL_RGB, GL_UNSIGNED_BYTE, 0);
171 }
172 break;
173 }
175 CHECKGLERR;
176 sz[0] = xsz;
177 sz[1] = ysz;
178 texfmt = ifmt;
179 }
181 void Texture::set_image(const Image &img, int idx)
182 {
183 if(idx >= 0 && idx < 6) {
184 set_image_cube(img, idx);
185 } else {
186 if(!set_image_cube(img)) {
187 set_image_2d(img);
188 }
189 }
190 }
192 void Texture::set_image_2d(const Image &img)
193 {
194 texfmt = glifmt_from_imgfmt(img.get_format());
195 unsigned int fmt = glfmt_from_ifmt(texfmt);
196 unsigned int type = gltype_from_ifmt(texfmt);
198 sz[0] = img.get_width();
199 sz[1] = img.get_height();
201 glBindTexture(GL_TEXTURE_2D, id);
202 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
203 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
204 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
205 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
207 #ifdef __GLEW_H__
208 if(GLEW_SGIS_generate_mipmap) {
209 glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP_SGIS, GL_TRUE);
210 #endif
211 glTexImage2D(GL_TEXTURE_2D, 0, texfmt, sz[0], sz[1], 0, fmt, type, img.get_pixels());
212 #ifdef __GLEW_H__
213 } else {
214 gluBuild2DMipmaps(GL_TEXTURE_2D, texfmt, sz[0], sz[1], fmt, type, img.get_pixels());
215 }
216 #endif
218 #ifdef GL_ES_VERSION_2_0
219 glGenerateMipmap(GL_TEXTURE_2D);
220 #endif
221 }
223 bool Texture::set_image_cube(const Image &img, int idx)
224 {
225 if(idx < 0 || idx >= 6) {
226 return false;
227 }
229 texfmt = glifmt_from_imgfmt(img.get_format());
230 unsigned int fmt = glfmt_from_ifmt(texfmt);
231 unsigned int type = gltype_from_ifmt(texfmt);
233 sz[0] = img.get_width();
234 sz[1] = img.get_height();
236 glBindTexture(GL_TEXTURE_CUBE_MAP, id);
237 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
238 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
239 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
240 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
241 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
243 glTexImage2D(cube_faces[idx], 0, texfmt, sz[0], sz[1], 0, fmt, type, img.get_pixels());
244 return true;
245 }
247 bool Texture::set_image_cube(const Image &img)
248 {
249 static const float one_third = 1.0 / 3.0;
250 static const float two_thirds = 2.0 / 3.0;
251 static const float hcross[2][6] = {
252 {0.5, 0.0, 0.25, 0.25, 0.25, 0.75}, {one_third, one_third, 0.0, two_thirds, one_third, one_third} };
253 static const float vcross[2][6] = {
254 {two_thirds, 0.0, one_third, one_third, one_third, one_third}, {0.25, 0.25, 0.0, 0.5, 0.25, 0.75} };
255 static const float hsix[2][6] = {
256 {0.0, 0.0, one_third, one_third, two_thirds, two_thirds}, {0.0, 0.5, 0.0, 0.5, 0.0, 0.5} };
258 int xsz = img.get_width();
259 int ysz = img.get_height();
261 if(xsz / 4 == ysz / 3) {
262 // horizontal cross, assume the vertical bit is center-left
263 return set_cube_multi(img, hcross[0], hcross[1], xsz / 4);
264 }
265 if(xsz / 3 == ysz / 4) {
266 // vertical cross, assume the horizontal bit is center-top (180-rotated image 5)
267 return set_cube_multi(img, vcross[0], vcross[1], ysz / 4, (1 << 5));
268 }
269 if(xsz / 3 == ysz / 2) {
270 // horizontal sixpack
271 return set_cube_multi(img, hsix[0], hsix[1], ysz / 2);
272 }
274 return false;
275 }
278 bool Texture::load(const char *fname)
279 {
280 Image img;
281 if(!img.load(fname)) {
282 error_log("failed to load 2D texture: %s\n", fname);
283 return false;
284 }
285 set_image(img);
287 info_log("loaded 2D texture: %s\n", fname);
288 return true;
289 }
291 bool Texture::load_cube(const char *fname)
292 {
293 Image img;
294 if(!img.load(fname)) {
295 return false;
296 }
297 return set_image_cube(img);
298 }
300 bool Texture::set_cube_multi(const Image &img, const float *xoffsets, const float *yoffsets, float sz,
301 unsigned int rotmask)
302 {
303 for(int i=0; i<6; i++) {
304 Image face;
306 int xoffs = xoffsets[i] * img.get_width();
307 int yoffs = yoffsets[i] * img.get_height();
309 if(!face.set_pixels(sz, sz, img.get_pixels(), xoffs, yoffs, img.get_width(), img.get_format())) {
310 return false;
311 }
313 if(rotmask & (1 << i)) {
314 face.rotate_180();
315 }
316 set_image_cube(face, i);
317 }
318 return true;
319 }
321 static int glifmt_from_ifmt(unsigned int ifmt)
322 {
323 #ifdef GL_ES_VERSION_2_0
324 switch(ifmt) {
325 case GL_LUMINANCE16F:
326 case GL_LUMINANCE32F:
327 ifmt = GL_LUMINANCE;
328 break;
330 case GL_RGB16F:
331 case GL_RGB32F:
332 ifmt = GL_RGB;
333 break;
335 case GL_RGBA16F:
336 case GL_RGBA32F:
337 ifmt = GL_RGBA;
338 break;
340 default:
341 break;
342 }
343 #endif
344 return ifmt; // by default just pass it through...
345 }
347 static int glfmt_from_ifmt(unsigned int ifmt)
348 {
349 switch(ifmt) {
350 case GL_LUMINANCE16F:
351 case GL_LUMINANCE32F:
352 return GL_LUMINANCE;
354 case GL_RGB16F:
355 case GL_RGB32F:
356 return GL_RGB;
358 case GL_RGBA16F:
359 case GL_RGBA32F:
360 return GL_RGBA;
362 default:
363 break;
364 }
365 return ifmt;
366 }
368 static int gltype_from_ifmt(unsigned int ifmt)
369 {
370 switch(ifmt) {
371 case GL_RGB16F:
372 case GL_RGBA16F:
373 case GL_LUMINANCE16F:
374 #ifdef GL_ES_VERSION_2_0
375 return GL_HALF_FLOAT_OES;
376 #endif
377 case GL_RGB32F:
378 case GL_RGBA32F:
379 case GL_LUMINANCE32F:
380 return GL_FLOAT;
382 default:
383 break;
384 }
385 return GL_UNSIGNED_BYTE;
386 }
388 static int glifmt_from_imgfmt(Image::Format fmt)
389 {
390 switch(fmt) {
391 case Image::FMT_GREY:
392 return GL_LUMINANCE;
393 case Image::FMT_GREY_FLOAT:
394 return GL_LUMINANCE16F;
395 case Image::FMT_RGB:
396 return GL_RGB;
397 case Image::FMT_RGB_FLOAT:
398 return GL_RGB16F;
399 case Image::FMT_RGBA:
400 return GL_RGBA;
401 case Image::FMT_RGBA_FLOAT:
402 return GL_RGBA16F;
403 default:
404 break;
405 }
406 return 0;
407 }
409 static unsigned int type_to_target(TextureType type)
410 {
411 return type == TEX_CUBE ? GL_TEXTURE_CUBE_MAP : GL_TEXTURE_2D;
412 }
414 static TextureType target_to_type(unsigned int targ)
415 {
416 return targ == GL_TEXTURE_CUBE_MAP ? TEX_CUBE : TEX_2D;
417 }
419 // ---- TextureSet ----
420 TextureSet::TextureSet()
421 : DataSet<Texture*>(create_tex, load_tex, done_tex, free_tex)
422 {
423 }
425 // static callbacks
427 Texture *TextureSet::create_tex()
428 {
429 return new Texture;
430 }
432 bool TextureSet::load_tex(Texture *tex, const char *fname)
433 {
434 Image *img = new Image;
435 if(!img->load(fname)) {
436 delete img;
437 return false;
438 }
440 delete tex->img;
441 tex->img = img;
443 return true;
444 }
446 bool TextureSet::done_tex(Texture *tex)
447 {
448 if(!tex->img) {
449 return false;
450 }
452 tex->set_image(*tex->img);
453 return true;
454 }
456 void TextureSet::free_tex(Texture *tex)
457 {
458 delete tex;
459 }