X-Git-Url: http://git.mutantstargoat.com/user/nuclear/?a=blobdiff_plain;f=src%2Ftexture.cc;fp=src%2Ftexture.cc;h=95d34e317845e83f4d616f0c61c91f877aff24bd;hb=84320a4b92c1922cd40bd7ce3d942d19cc704bd2;hp=0000000000000000000000000000000000000000;hpb=dd39621d642e417f1e343cbf813205a658272639;p=vrfileman diff --git a/src/texture.cc b/src/texture.cc new file mode 100644 index 0000000..95d34e3 --- /dev/null +++ b/src/texture.cc @@ -0,0 +1,429 @@ +#include +#include "texture.h" +#include "image.h" +#include "opengl.h" +#include "imago2.h" + +#if defined(GL_ES_VERSION_2_0) || defined(GL_VERSION_3_0) +#define USE_GL_GENERATE_MIPMAP +#elif defined(__GLEW_H__) +#define USE_SGIS_GENERATE_MIPMAP +#endif + +static int glifmt_from_ifmt(unsigned int ifmt); +static int glfmt_from_ifmt(unsigned int ifmt); +static int gltype_from_ifmt(unsigned int ifmt); + +static int glifmt_from_imgfmt(Image::Format fmt); +static Image::Format imgfmt_from_glifmt(unsigned int ifmt); + +static unsigned int cur_target[8] = { + GL_TEXTURE_2D, GL_TEXTURE_2D, GL_TEXTURE_2D, GL_TEXTURE_2D, + GL_TEXTURE_2D, GL_TEXTURE_2D, GL_TEXTURE_2D, GL_TEXTURE_2D +}; + +void bind_texture(Texture *tex, int tunit) +{ + if(tex) { + tex->bind(tunit); + } else { + glActiveTexture(GL_TEXTURE0 + tunit); + glBindTexture(cur_target[tunit], 0); + glActiveTexture(GL_TEXTURE0); + } +} + +Texture *load_texture(const char *fname) +{ + TextureCube *texcube = new TextureCube; + if(texcube->load(fname)) { + return texcube; + } + delete texcube; + + Texture2D *tex = new Texture2D; + if(tex->load(fname)) { + return tex; + } + delete tex; + return 0; +} + + +Texture::Texture() +{ + target = 0; + sz[0] = sz[1] = sz[2] = 0; + texfmt = 0; + + glGenTextures(1, &id); +} + +Texture::~Texture() +{ + if(id) { + glDeleteTextures(1, &id); + } +} + +void Texture::set_wrapping(unsigned int wrap) +{ + if(!target) { + return; + } + + glBindTexture(target, id); + glTexParameteri(target, GL_TEXTURE_WRAP_S, wrap); + glTexParameteri(target, GL_TEXTURE_WRAP_T, wrap); +} + +void Texture::set_filtering(unsigned int filt) +{ + unsigned int mag_filter; + + if(!target) { + return; + } + + switch(filt) { + case GL_LINEAR_MIPMAP_NEAREST: + case GL_LINEAR_MIPMAP_LINEAR: + mag_filter = GL_LINEAR; + break; + + case GL_NEAREST_MIPMAP_NEAREST: + case GL_NEAREST_MIPMAP_LINEAR: + mag_filter = GL_NEAREST; + break; + + default: + mag_filter = filt; + } + + set_filtering(filt, mag_filter); +} + +void Texture::set_filtering(unsigned int min_filt, unsigned int mag_filt) +{ + glBindTexture(target, id); + glTexParameteri(target, GL_TEXTURE_MIN_FILTER, min_filt); + glTexParameteri(target, GL_TEXTURE_MAG_FILTER, mag_filt); +} + +unsigned int Texture::get_format() const +{ + return texfmt; +} + +int Texture::get_size(int dim) const +{ + if(dim < 0 || dim >= 3) { + return 0; + } + return sz[dim]; +} + +unsigned int Texture::get_id() const +{ + return id; +} + +void Texture::bind(int tex_unit) const +{ + glActiveTexture(GL_TEXTURE0 + tex_unit); + glBindTexture(target, id); + glActiveTexture(GL_TEXTURE0); + + cur_target[tex_unit] = target; +} + + +// ---- Texture2D ---- + +Texture2D::Texture2D() +{ + target = GL_TEXTURE_2D; +} + +TextureType Texture2D::get_type() const +{ + return TEXTURE_2D; +} + +void Texture2D::create(int xsz, int ysz, unsigned int ifmt) +{ + int fmt = glfmt_from_ifmt(ifmt); + int type = gltype_from_ifmt(ifmt); + + glBindTexture(GL_TEXTURE_2D, id); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexImage2D(GL_TEXTURE_2D, 0, glifmt_from_ifmt(ifmt), xsz, ysz, 0, fmt, type, 0); + sz[0] = xsz; + sz[1] = ysz; + texfmt = ifmt; +} + +void Texture2D::set_image(const Image &img, int idx) +{ + texfmt = glifmt_from_imgfmt(img.get_format()); + unsigned int fmt = glfmt_from_ifmt(texfmt); + unsigned int type = gltype_from_ifmt(texfmt); + + sz[0] = img.get_width(); + sz[1] = img.get_height(); + + glBindTexture(GL_TEXTURE_2D, id); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + +#ifdef USE_SGIS_GENERATE_MIPMAP + if(GLEW_SGIS_generate_mipmap) { + glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP_SGIS, GL_TRUE); +#endif + glTexImage2D(GL_TEXTURE_2D, 0, texfmt, sz[0], sz[1], 0, fmt, type, img.get_pixels()); +#ifdef USE_SGIS_GENERATE_MIPMAP + } else { + gluBuild2DMipmaps(GL_TEXTURE_2D, texfmt, sz[0], sz[1], fmt, type, img.get_pixels()); + } +#endif + +#ifdef USE_GL_GENERATE_MIPMAP + glGenerateMipmap(GL_TEXTURE_2D); +#endif +} + +void Texture2D::get_image(Image *img, int idx) const +{ +#ifndef GL_ES_VERSION_2_0 + glBindTexture(GL_TEXTURE_2D, id); + + Image::Format img_fmt = imgfmt_from_glifmt(texfmt); + img->create(sz[0], sz[1], img_fmt); + + unsigned int fmt = glfmt_from_ifmt(texfmt); + unsigned int type = gltype_from_ifmt(texfmt); + glGetTexImage(GL_TEXTURE_2D, 0, fmt, type, img->get_pixels()); +#endif // GL_ES_VERSION_2_0 +} + +void Texture2D::set_subimage(const Image &img, int xoffs, int yoffs) +{ + unsigned int ifmt = glifmt_from_imgfmt(img.get_format()); + + glBindTexture(GL_TEXTURE_2D, id); + glTexSubImage2D(GL_TEXTURE_2D, 0, xoffs, yoffs, img.get_width(), img.get_height(), + glfmt_from_ifmt(ifmt), gltype_from_ifmt(ifmt), img.get_pixels()); +} + +bool Texture2D::load(const char *fname) +{ + Image img; + if(!img.load(fname)) { + fprintf(stderr, "failed to load 2D texture: %s\n", fname); + return false; + } + set_image(img); + + printf("loaded 2D texture: %s\n", fname); + return true; +} + +bool Texture2D::save(const char *fname) const +{ +#ifndef GL_ES_VERSION_2_0 + unsigned char *pixels = new unsigned char[sz[0] * sz[1] * 4]; + + glBindTexture(GL_TEXTURE_2D, id); + glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels); + + if(img_save_pixels(fname, pixels, sz[0], sz[1]) == -1) { + fprintf(stderr, "failed to save 2D texture: %s\n", fname); + delete [] pixels; + return false; + } + + printf("saved 2D texture: %s\n", fname); + delete [] pixels; + return true; +#else + return false; // TODO +#endif +} + +// ---- TextureCube ---- +static unsigned int cube_faces[] = { + GL_TEXTURE_CUBE_MAP_POSITIVE_X, + GL_TEXTURE_CUBE_MAP_NEGATIVE_X, + GL_TEXTURE_CUBE_MAP_POSITIVE_Y, + GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, + GL_TEXTURE_CUBE_MAP_POSITIVE_Z, + GL_TEXTURE_CUBE_MAP_NEGATIVE_Z +}; + +TextureCube::TextureCube() +{ + target = GL_TEXTURE_CUBE_MAP; +} + +TextureType TextureCube::get_type() const +{ + return TEXTURE_CUBE; +} + + +void TextureCube::create(int xsz, int ysz, unsigned int ifmt) +{ + if(xsz != ysz) { + fprintf(stderr, "trying to create cubemap with different width and height (%dx%d)\n", xsz, ysz); + return; + } + + texfmt = ifmt; + + glBindTexture(GL_TEXTURE_CUBE_MAP, id); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + + for(int i=0; i<6; i++) { + glTexImage2D(cube_faces[i], 0, ifmt, xsz, ysz, 0, GL_RGB, GL_UNSIGNED_BYTE, 0); + } +} + +void TextureCube::set_image(const Image &img, int idx) +{ + // TODO +} + +void TextureCube::get_image(Image *img, int idx) const +{ + // TODO +} + +bool TextureCube::load(const char *fname) +{ + return false; // TODO +} + +bool TextureCube::save(const char *fname) const +{ + return false; // TODO +} + +static int glifmt_from_ifmt(unsigned int ifmt) +{ +#ifdef GL_ES_VERSION_2_0 + switch(ifmt) { + case GL_LUMINANCE16F: + case GL_LUMINANCE32F: + ifmt = GL_LUMINANCE; + break; + + case GL_RGB16F: + case GL_RGB32F: + ifmt = GL_RGB; + break; + + case GL_RGBA16F: + case GL_RGBA32F: + ifmt = GL_RGBA; + break; + + default: + break; + } +#endif + return ifmt; // by default just pass it through... +} + +static int glfmt_from_ifmt(unsigned int ifmt) +{ + switch(ifmt) { + case GL_LUMINANCE16F: + case GL_LUMINANCE32F: + return GL_LUMINANCE; + + case GL_RGB16F: + case GL_RGB32F: + return GL_RGB; + + case GL_RGBA16F: + case GL_RGBA32F: + return GL_RGBA; + + default: + break; + } + return ifmt; +} + +static int gltype_from_ifmt(unsigned int ifmt) +{ + switch(ifmt) { + case GL_RGB16F: + case GL_RGBA16F: + case GL_LUMINANCE16F: +#ifdef GL_ES_VERSION_2_0 + return GL_HALF_FLOAT_OES; +#endif + case GL_RGB32F: + case GL_RGBA32F: + case GL_LUMINANCE32F: + return GL_FLOAT; + + default: + break; + } + return GL_UNSIGNED_BYTE; +} + +static int glifmt_from_imgfmt(Image::Format fmt) +{ + switch(fmt) { + case Image::FMT_GREY: + return GL_LUMINANCE; + case Image::FMT_GREY_FLOAT: + return GL_LUMINANCE16F; + case Image::FMT_RGB: + return GL_RGB; + case Image::FMT_RGB_FLOAT: + return GL_RGB16F; + case Image::FMT_RGBA: + return GL_RGBA; + case Image::FMT_RGBA_FLOAT: + return GL_RGBA16F; + default: + break; + } + return 0; +} + +static Image::Format imgfmt_from_glifmt(unsigned int ifmt) +{ + switch(ifmt) { + case GL_LUMINANCE: + return Image::FMT_GREY; + case GL_LUMINANCE16F: + return Image::FMT_GREY_FLOAT; + case GL_RGB: + return Image::FMT_RGB; + case GL_RGB16F: + return Image::FMT_RGB_FLOAT; + case GL_RGBA: + return Image::FMT_RGBA; + case GL_RGBA16F: + return Image::FMT_RGBA_FLOAT; + default: + break; + } + + fprintf(stderr, "imgfmt_from_glifmt: unknown internal format: %x\n", ifmt); +#ifndef NDEBUG + abort(); +#endif + return Image::FMT_RGBA; // ... whatever +}