nasty bug in Texture::create
[laserbrain_demo] / src / texture.cc
index a787abd..3af8116 100644 (file)
@@ -1,8 +1,11 @@
 #include <math.h>
+#include <assert.h>
 #include "texture.h"
+#include "datamap.h"
 #include "image.h"
 #include "opengl.h"
 #include "imago2.h"
+#include "logger.h"
 
 static int glifmt_from_ifmt(unsigned int ifmt);
 static int glfmt_from_ifmt(unsigned int ifmt);
@@ -35,10 +38,22 @@ void bind_texture(Texture *tex, int tunit)
        } else {
                glActiveTexture(GL_TEXTURE0 + tunit);
                glBindTexture(cur_target[tunit], 0);
+               assert(glGetError() == GL_NO_ERROR);
                glActiveTexture(GL_TEXTURE0);
        }
 }
 
+int next_pow2(int x)
+{
+       x--;
+       x = (x >> 1) | x;
+       x = (x >> 2) | x;
+       x = (x >> 4) | x;
+       x = (x >> 8) | x;
+       x = (x >> 16) | x;
+       return x + 1;
+}
+
 
 Image *Texture::default_img;
 
@@ -69,6 +84,7 @@ void Texture::set_wrapping(unsigned int wrap)
        }
 
        glBindTexture(target, id);
+       assert(glGetError() == GL_NO_ERROR);
        glTexParameteri(target, GL_TEXTURE_WRAP_S, wrap);
        glTexParameteri(target, GL_TEXTURE_WRAP_T, wrap);
        glTexParameteri(target, GL_TEXTURE_WRAP_R, wrap);
@@ -103,6 +119,7 @@ void Texture::set_filtering(unsigned int filt)
 void Texture::set_filtering(unsigned int min_filt, unsigned int mag_filt)
 {
        glBindTexture(target, id);
+       assert(glGetError() == GL_NO_ERROR);
        glTexParameteri(target, GL_TEXTURE_MIN_FILTER, min_filt);
        glTexParameteri(target, GL_TEXTURE_MAG_FILTER, mag_filt);
 }
@@ -120,6 +137,16 @@ int Texture::get_size(int dim) const
        return sz[dim];
 }
 
+int Texture::get_width() const
+{
+       return sz[0];
+}
+
+int Texture::get_height() const
+{
+       return sz[1];
+}
+
 unsigned int Texture::get_id() const
 {
        return id;
@@ -134,6 +161,7 @@ void Texture::bind(int tex_unit) const
 {
        glActiveTexture(GL_TEXTURE0 + tex_unit);
        glBindTexture(target, id);
+       assert(glGetError() == GL_NO_ERROR);
        glActiveTexture(GL_TEXTURE0);
 
        cur_target[tex_unit] = target;
@@ -143,7 +171,7 @@ void Texture::bind(int tex_unit) const
 void Texture::create(int xsz, int ysz, TextureType textype, unsigned int ifmt)
 {
        if(textype == TEX_CUBE && xsz != ysz) {
-               fprintf(stderr, "trying to create cubemap with different width and height (%dx%d)\n", xsz, ysz);
+               error_log("trying to create cubemap with different width and height (%dx%d)\n", xsz, ysz);
                return;
        }
 
@@ -153,10 +181,11 @@ void Texture::create(int xsz, int ysz, TextureType textype, unsigned int ifmt)
        target = type_to_target(textype);
 
        glBindTexture(target, id);
+       assert(glGetError() == GL_NO_ERROR);
        glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
        glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
 
-       switch(type) {
+       switch(textype) {
        case TEX_2D:
                glTexImage2D(GL_TEXTURE_2D, 0, glifmt_from_ifmt(ifmt), xsz, ysz, 0, fmt, type, 0);
                break;
@@ -191,6 +220,7 @@ void Texture::create_default(TextureType type)
                                pixels[1] = 64;
                                pixels[2] = chess ? 32 : 255;
                                pixels[3] = 255;
+                               pixels += 4;
                        }
                }
        }
@@ -230,11 +260,14 @@ void Texture::set_image_2d(const Image &img)
 
        target = GL_TEXTURE_2D;
        glBindTexture(target, id);
+       assert(glGetError() == GL_NO_ERROR);
        glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
        glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
        glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_REPEAT);
        glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_REPEAT);
 
+       glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+
 #ifdef __GLEW_H__
        if(GLEW_SGIS_generate_mipmap) {
                glTexParameteri(target, GL_GENERATE_MIPMAP_SGIS, GL_TRUE);
@@ -253,6 +286,7 @@ void Texture::set_image_2d(const Image &img)
 
 bool Texture::set_image_cube(const Image &img, int idx)
 {
+       unsigned int err;
        if(idx < 0 || idx >= 6) {
                return false;
        }
@@ -266,6 +300,10 @@ bool Texture::set_image_cube(const Image &img, int idx)
 
        target = GL_TEXTURE_CUBE_MAP;
        glBindTexture(target, id);
+       if((err = glGetError()) == GL_INVALID_OPERATION) {
+               return false;   // probably not a cubemap
+       }
+       assert(err == GL_NO_ERROR);
        glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
        glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
        glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
@@ -290,15 +328,15 @@ bool Texture::set_image_cube(const Image &img)
        int xsz = img.get_width();
        int ysz = img.get_height();
 
-       if(xsz / 4 == ysz / 3) {
+       if((xsz << 8) / 4 == (ysz << 8) / 3) {
                // horizontal cross, assume the vertical bit is center-left
                return set_cube_multi(img, hcross[0], hcross[1], xsz / 4);
        }
-       if(xsz / 3 == ysz / 4) {
+       if((xsz << 8) / 3 == (ysz << 8) / 4) {
                // vertical cross, assume the horizontal bit is center-top (180-rotated image 5)
                return set_cube_multi(img, vcross[0], vcross[1], ysz / 4, (1 << 5));
        }
-       if(xsz / 3 == ysz / 2) {
+       if((xsz << 8) / 3 == (ysz << 8) / 2) {
                // horizontal sixpack
                return set_cube_multi(img, hsix[0], hsix[1], ysz / 2);
        }
@@ -311,12 +349,12 @@ bool Texture::load(const char *fname)
 {
        Image img;
        if(!img.load(fname)) {
-               fprintf(stderr, "failed to load 2D texture: %s\n", fname);
+               error_log("failed to load 2D texture: %s\n", fname);
                return false;
        }
        set_image(img);
 
-       printf("loaded 2D texture: %s\n", fname);
+       info_log("loaded 2D texture: %s\n", fname);
        return true;
 }
 
@@ -381,14 +419,17 @@ static int glfmt_from_ifmt(unsigned int ifmt)
        switch(ifmt) {
        case GL_LUMINANCE16F_ARB:
        case GL_LUMINANCE32F_ARB:
+       case GL_SLUMINANCE:
                return GL_LUMINANCE;
 
        case GL_RGB16F:
        case GL_RGB32F:
+       case GL_SRGB:
                return GL_RGB;
 
        case GL_RGBA16F:
        case GL_RGBA32F:
+       case GL_SRGB_ALPHA:
                return GL_RGBA;
 
        default:
@@ -421,15 +462,15 @@ static int glifmt_from_imgfmt(Image::Format fmt)
 {
        switch(fmt) {
        case Image::FMT_GREY:
-               return GL_LUMINANCE;
+               return GL_SLUMINANCE;
        case Image::FMT_GREY_FLOAT:
                return GL_LUMINANCE16F_ARB;
        case Image::FMT_RGB:
-               return GL_RGB;
+               return GL_SRGB;
        case Image::FMT_RGB_FLOAT:
                return GL_RGB16F;
        case Image::FMT_RGBA:
-               return GL_RGBA;
+               return GL_SRGB_ALPHA;
        case Image::FMT_RGBA_FLOAT:
                return GL_RGBA16F;
        default:
@@ -454,16 +495,28 @@ TextureSet::TextureSet()
 {
 }
 
-Texture *TextureSet::get_texture(const char *name, TextureType type) const
+Texture *TextureSet::get_texture(const char *name, TextureType type, const DataMap *dmap) const
 {
-       typename std::map<std::string, Texture*>::const_iterator iter = data.find(name);
+       char *fname;
+       int nsize = dmap ? dmap->path_size(name) : 0;
+       if(nsize) {
+               fname = (char*)alloca(nsize);
+               dmap->lookup(name, fname, nsize);
+               //debug_log("texture lookup: %s -> %s\n", name, fname);
+       } else {
+               fname = (char*)name;
+               //debug_log("texture lookup failed, using: %s\n", fname);
+       }
+
+       std::map<std::string, Texture*>::const_iterator iter = data.find(fname);
        if(iter != data.end()) {
                return iter->second;
        }
 
        Texture *res = create();
+       data[fname] = res;
        res->create_default(type);
-       resman_lookup(rman, name, res);
+       resman_lookup(rman, fname, res);
        return res;
 }
 
@@ -477,6 +530,7 @@ Texture *TextureSet::create_tex()
 bool TextureSet::load_tex(Texture *tex, const char *fname)
 {
        Image *img = new Image;
+       img->name = fname;
        if(!img->load(fname)) {
                delete img;
                return false;
@@ -490,6 +544,7 @@ bool TextureSet::load_tex(Texture *tex, const char *fname)
 
 bool TextureSet::done_tex(Texture *tex)
 {
+       //debug_log("TextureSet::done_tex [%s]\n", tex->img->name.c_str());
        if(!tex->img) {
                return false;
        }