10 static int glifmt_from_ifmt(unsigned int ifmt);
11 static int glfmt_from_ifmt(unsigned int ifmt);
12 static int gltype_from_ifmt(unsigned int ifmt);
14 static int glifmt_from_imgfmt(Image::Format fmt);
16 static unsigned int type_to_target(TextureType type);
17 static TextureType target_to_type(unsigned int targ);
19 static unsigned int cur_target[8] = {
20 GL_TEXTURE_2D, GL_TEXTURE_2D, GL_TEXTURE_2D, GL_TEXTURE_2D,
21 GL_TEXTURE_2D, GL_TEXTURE_2D, GL_TEXTURE_2D, GL_TEXTURE_2D
24 static unsigned int cube_faces[] = {
25 GL_TEXTURE_CUBE_MAP_POSITIVE_X,
26 GL_TEXTURE_CUBE_MAP_NEGATIVE_X,
27 GL_TEXTURE_CUBE_MAP_POSITIVE_Y,
28 GL_TEXTURE_CUBE_MAP_NEGATIVE_Y,
29 GL_TEXTURE_CUBE_MAP_POSITIVE_Z,
30 GL_TEXTURE_CUBE_MAP_NEGATIVE_Z
34 void bind_texture(Texture *tex, int tunit)
39 glActiveTexture(GL_TEXTURE0 + tunit);
40 glBindTexture(cur_target[tunit], 0);
41 assert(glGetError() == GL_NO_ERROR);
42 glActiveTexture(GL_TEXTURE0);
58 Image *Texture::default_img;
63 sz[0] = sz[1] = sz[2] = 0;
67 glGenTextures(1, &id);
73 glDeleteTextures(1, &id);
80 void Texture::set_wrapping(unsigned int wrap)
86 glBindTexture(target, id);
87 assert(glGetError() == GL_NO_ERROR);
88 glTexParameteri(target, GL_TEXTURE_WRAP_S, wrap);
89 glTexParameteri(target, GL_TEXTURE_WRAP_T, wrap);
90 glTexParameteri(target, GL_TEXTURE_WRAP_R, wrap);
93 void Texture::set_filtering(unsigned int filt)
95 unsigned int mag_filter;
102 case GL_LINEAR_MIPMAP_NEAREST:
103 case GL_LINEAR_MIPMAP_LINEAR:
104 mag_filter = GL_LINEAR;
107 case GL_NEAREST_MIPMAP_NEAREST:
108 case GL_NEAREST_MIPMAP_LINEAR:
109 mag_filter = GL_NEAREST;
116 set_filtering(filt, mag_filter);
119 void Texture::set_filtering(unsigned int min_filt, unsigned int mag_filt)
121 glBindTexture(target, id);
122 assert(glGetError() == GL_NO_ERROR);
123 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, min_filt);
124 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, mag_filt);
127 unsigned int Texture::get_format() const
132 int Texture::get_size(int dim) const
134 if(dim < 0 || dim >= 3) {
140 int Texture::get_width() const
145 int Texture::get_height() const
150 unsigned int Texture::get_id() const
155 TextureType Texture::get_type() const
157 return target_to_type(target);
160 void Texture::bind(int tex_unit) const
162 glActiveTexture(GL_TEXTURE0 + tex_unit);
163 glBindTexture(target, id);
164 assert(glGetError() == GL_NO_ERROR);
165 glActiveTexture(GL_TEXTURE0);
167 cur_target[tex_unit] = target;
171 void Texture::create(int xsz, int ysz, TextureType textype, unsigned int ifmt)
173 if(textype == TEX_CUBE && xsz != ysz) {
174 error_log("trying to create cubemap with different width and height (%dx%d)\n", xsz, ysz);
178 int fmt = glfmt_from_ifmt(ifmt);
179 int type = gltype_from_ifmt(ifmt);
181 target = type_to_target(textype);
183 glBindTexture(target, id);
184 assert(glGetError() == GL_NO_ERROR);
185 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
186 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
190 glTexImage2D(GL_TEXTURE_2D, 0, glifmt_from_ifmt(ifmt), xsz, ysz, 0, fmt, type, 0);
194 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
195 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
196 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
197 for(int i=0; i<6; i++) {
198 glTexImage2D(cube_faces[i], 0, ifmt, xsz, ysz, 0, GL_RGB, GL_UNSIGNED_BYTE, 0);
208 #define DEF_IMAGE_SIZE 64
209 void Texture::create_default(TextureType type)
212 default_img = new Image;
213 default_img->create(DEF_IMAGE_SIZE, DEF_IMAGE_SIZE, Image::FMT_RGBA);
215 unsigned char *pixels = (unsigned char*)default_img->get_pixels();
216 for(int i=0; i<DEF_IMAGE_SIZE; i++) {
217 for(int j=0; j<DEF_IMAGE_SIZE; j++) {
218 bool chess = ((i >> 3) & 1) == ((j >> 3) & 1);
219 pixels[0] = chess ? 255 : 32;
221 pixels[2] = chess ? 32 : 255;
230 set_image(*default_img);
234 for(int i=0; i<6; i++) {
235 set_image(*default_img, i);
241 void Texture::set_image(const Image &img, int idx)
243 if(idx >= 0 && idx < 6) {
244 set_image_cube(img, idx);
246 if(!set_image_cube(img)) {
252 void Texture::set_image_2d(const Image &img)
254 texfmt = glifmt_from_imgfmt(img.get_format());
255 unsigned int fmt = glfmt_from_ifmt(texfmt);
256 unsigned int type = gltype_from_ifmt(texfmt);
258 sz[0] = img.get_width();
259 sz[1] = img.get_height();
261 target = GL_TEXTURE_2D;
262 glBindTexture(target, id);
263 assert(glGetError() == GL_NO_ERROR);
264 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
265 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
266 glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_REPEAT);
267 glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_REPEAT);
269 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
272 if(GLEW_SGIS_generate_mipmap) {
273 glTexParameteri(target, GL_GENERATE_MIPMAP_SGIS, GL_TRUE);
275 glTexImage2D(target, 0, texfmt, sz[0], sz[1], 0, fmt, type, img.get_pixels());
278 gluBuild2DMipmaps(target, texfmt, sz[0], sz[1], fmt, type, img.get_pixels());
282 #ifdef GL_ES_VERSION_2_0
283 glGenerateMipmap(target);
287 bool Texture::set_image_cube(const Image &img, int idx)
290 if(idx < 0 || idx >= 6) {
294 texfmt = glifmt_from_imgfmt(img.get_format());
295 unsigned int fmt = glfmt_from_ifmt(texfmt);
296 unsigned int type = gltype_from_ifmt(texfmt);
298 sz[0] = img.get_width();
299 sz[1] = img.get_height();
301 target = GL_TEXTURE_CUBE_MAP;
302 glBindTexture(target, id);
303 if((err = glGetError()) == GL_INVALID_OPERATION) {
304 return false; // probably not a cubemap
306 assert(err == GL_NO_ERROR);
307 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
308 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
309 glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
310 glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
311 glTexParameteri(target, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
313 glTexImage2D(cube_faces[idx], 0, texfmt, sz[0], sz[1], 0, fmt, type, img.get_pixels());
317 bool Texture::set_image_cube(const Image &img)
319 static const float one_third = 1.0 / 3.0;
320 static const float two_thirds = 2.0 / 3.0;
321 static const float hcross[2][6] = {
322 {0.5, 0.0, 0.25, 0.25, 0.25, 0.75}, {one_third, one_third, 0.0, two_thirds, one_third, one_third} };
323 static const float vcross[2][6] = {
324 {two_thirds, 0.0, one_third, one_third, one_third, one_third}, {0.25, 0.25, 0.0, 0.5, 0.25, 0.75} };
325 static const float hsix[2][6] = {
326 {0.0, 0.0, one_third, one_third, two_thirds, two_thirds}, {0.0, 0.5, 0.0, 0.5, 0.0, 0.5} };
328 int xsz = img.get_width();
329 int ysz = img.get_height();
331 if((xsz << 8) / 4 == (ysz << 8) / 3) {
332 // horizontal cross, assume the vertical bit is center-left
333 return set_cube_multi(img, hcross[0], hcross[1], xsz / 4);
335 if((xsz << 8) / 3 == (ysz << 8) / 4) {
336 // vertical cross, assume the horizontal bit is center-top (180-rotated image 5)
337 return set_cube_multi(img, vcross[0], vcross[1], ysz / 4, (1 << 5));
339 if((xsz << 8) / 3 == (ysz << 8) / 2) {
340 // horizontal sixpack
341 return set_cube_multi(img, hsix[0], hsix[1], ysz / 2);
348 bool Texture::load(const char *fname)
351 if(!img.load(fname)) {
352 error_log("failed to load 2D texture: %s\n", fname);
357 info_log("loaded 2D texture: %s\n", fname);
361 bool Texture::load_cube(const char *fname)
364 if(!img.load(fname)) {
367 return set_image_cube(img);
370 bool Texture::set_cube_multi(const Image &img, const float *xoffsets, const float *yoffsets, float sz,
371 unsigned int rotmask)
373 for(int i=0; i<6; i++) {
376 int xoffs = xoffsets[i] * img.get_width();
377 int yoffs = yoffsets[i] * img.get_height();
379 if(!face.set_pixels(sz, sz, img.get_pixels(), xoffs, yoffs, img.get_width(), img.get_format())) {
383 if(rotmask & (1 << i)) {
386 set_image_cube(face, i);
391 static int glifmt_from_ifmt(unsigned int ifmt)
393 #ifdef GL_ES_VERSION_2_0
395 case GL_LUMINANCE16F_ARB:
396 case GL_LUMINANCE32F_ARB:
414 return ifmt; // by default just pass it through...
417 static int glfmt_from_ifmt(unsigned int ifmt)
420 case GL_LUMINANCE16F_ARB:
421 case GL_LUMINANCE32F_ARB:
441 static int gltype_from_ifmt(unsigned int ifmt)
446 case GL_LUMINANCE16F_ARB:
447 #ifdef GL_ES_VERSION_2_0
448 return GL_HALF_FLOAT_OES;
452 case GL_LUMINANCE32F_ARB:
458 return GL_UNSIGNED_BYTE;
461 static int glifmt_from_imgfmt(Image::Format fmt)
464 case Image::FMT_GREY:
465 return GL_SLUMINANCE;
466 case Image::FMT_GREY_FLOAT:
467 return GL_LUMINANCE16F_ARB;
470 case Image::FMT_RGB_FLOAT:
472 case Image::FMT_RGBA:
473 return GL_SRGB_ALPHA;
474 case Image::FMT_RGBA_FLOAT:
482 static unsigned int type_to_target(TextureType type)
484 return type == TEX_CUBE ? GL_TEXTURE_CUBE_MAP : GL_TEXTURE_2D;
487 static TextureType target_to_type(unsigned int targ)
489 return targ == GL_TEXTURE_CUBE_MAP ? TEX_CUBE : TEX_2D;
492 // ---- TextureSet ----
493 TextureSet::TextureSet()
494 : DataSet<Texture*>(create_tex, load_tex, done_tex, free_tex)
498 Texture *TextureSet::get_texture(const char *name, TextureType type, const DataMap *dmap) const
501 int nsize = dmap ? dmap->path_size(name) : 0;
503 fname = (char*)alloca(nsize);
504 dmap->lookup(name, fname, nsize);
505 //debug_log("texture lookup: %s -> %s\n", name, fname);
508 //debug_log("texture lookup failed, using: %s\n", fname);
511 std::map<std::string, Texture*>::const_iterator iter = data.find(fname);
512 if(iter != data.end()) {
516 Texture *res = create();
518 res->create_default(type);
519 resman_add(rman, fname, res);
525 Texture *TextureSet::create_tex()
530 bool TextureSet::load_tex(Texture *tex, const char *fname)
532 Image *img = new Image;
534 if(!img->load(fname)) {
545 bool TextureSet::done_tex(Texture *tex)
547 //debug_log("TextureSet::done_tex [%s]\n", tex->img->name.c_str());
552 tex->set_image(*tex->img);
556 void TextureSet::free_tex(Texture *tex)