goat3dgfx
diff src/texture.cc @ 0:1873dfd13f2d
initial commit
author | John Tsiombikas <nuclear@member.fsf.org> |
---|---|
date | Thu, 14 Nov 2013 05:27:09 +0200 |
parents | |
children | 7bd5ebec3b6f |
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/src/texture.cc Thu Nov 14 05:27:09 2013 +0200 1.3 @@ -0,0 +1,370 @@ 1.4 +#include "texture.h" 1.5 +#include "image.h" 1.6 +#include "opengl.h" 1.7 +#include "imago2.h" 1.8 +#include "logger.h" 1.9 +#include "datapath.h" 1.10 + 1.11 +static int glifmt_from_ifmt(unsigned int ifmt); 1.12 +static int glfmt_from_ifmt(unsigned int ifmt); 1.13 +static int gltype_from_ifmt(unsigned int ifmt); 1.14 + 1.15 +static int glifmt_from_imgfmt(Image::Format fmt); 1.16 + 1.17 +static unsigned int cur_target[8] = { 1.18 + GL_TEXTURE_2D, GL_TEXTURE_2D, GL_TEXTURE_2D, GL_TEXTURE_2D, 1.19 + GL_TEXTURE_2D, GL_TEXTURE_2D, GL_TEXTURE_2D, GL_TEXTURE_2D 1.20 +}; 1.21 + 1.22 +void set_texture(Texture *tex, int tunit) 1.23 +{ 1.24 + if(tex) { 1.25 + tex->bind(tunit); 1.26 + } else { 1.27 + glActiveTexture(GL_TEXTURE0 + tunit); 1.28 + glBindTexture(cur_target[tunit], 0); 1.29 + glActiveTexture(GL_TEXTURE0); 1.30 + } 1.31 +} 1.32 + 1.33 +Texture *load_texture(const char *fname) 1.34 +{ 1.35 + TextureCube *texcube = new TextureCube; 1.36 + if(texcube->load(fname)) { 1.37 + return texcube; 1.38 + } 1.39 + delete texcube; 1.40 + 1.41 + Texture2D *tex = new Texture2D; 1.42 + if(tex->load(fname)) { 1.43 + return tex; 1.44 + } 1.45 + delete tex; 1.46 + return 0; 1.47 +} 1.48 + 1.49 + 1.50 +Texture::Texture() 1.51 +{ 1.52 + target = 0; 1.53 + sz[0] = sz[1] = sz[2] = 0; 1.54 + texfmt = 0; 1.55 + 1.56 + glGenTextures(1, &id); 1.57 +} 1.58 + 1.59 +Texture::~Texture() 1.60 +{ 1.61 + if(id) { 1.62 + glDeleteTextures(1, &id); 1.63 + } 1.64 +} 1.65 + 1.66 +void Texture::set_wrapping(unsigned int wrap) 1.67 +{ 1.68 + if(!target) { 1.69 + return; 1.70 + } 1.71 + 1.72 + glBindTexture(target, id); 1.73 + glTexParameteri(target, GL_TEXTURE_WRAP_S, wrap); 1.74 + glTexParameteri(target, GL_TEXTURE_WRAP_T, wrap); 1.75 +} 1.76 + 1.77 +void Texture::set_filtering(unsigned int filt) 1.78 +{ 1.79 + unsigned int mag_filter; 1.80 + 1.81 + if(!target) { 1.82 + return; 1.83 + } 1.84 + 1.85 + switch(filt) { 1.86 + case GL_LINEAR_MIPMAP_NEAREST: 1.87 + case GL_LINEAR_MIPMAP_LINEAR: 1.88 + mag_filter = GL_LINEAR; 1.89 + break; 1.90 + 1.91 + case GL_NEAREST_MIPMAP_NEAREST: 1.92 + case GL_NEAREST_MIPMAP_LINEAR: 1.93 + mag_filter = GL_NEAREST; 1.94 + break; 1.95 + 1.96 + default: 1.97 + mag_filter = filt; 1.98 + } 1.99 + 1.100 + set_filtering(filt, mag_filter); 1.101 +} 1.102 + 1.103 +void Texture::set_filtering(unsigned int min_filt, unsigned int mag_filt) 1.104 +{ 1.105 + glBindTexture(target, id); 1.106 + glTexParameteri(target, GL_TEXTURE_MIN_FILTER, min_filt); 1.107 + glTexParameteri(target, GL_TEXTURE_MAG_FILTER, mag_filt); 1.108 +} 1.109 + 1.110 +unsigned int Texture::get_format() const 1.111 +{ 1.112 + return texfmt; 1.113 +} 1.114 + 1.115 +int Texture::get_size(int dim) const 1.116 +{ 1.117 + if(dim < 0 || dim >= 3) { 1.118 + return 0; 1.119 + } 1.120 + return sz[dim]; 1.121 +} 1.122 + 1.123 +unsigned int Texture::get_id() const 1.124 +{ 1.125 + return id; 1.126 +} 1.127 + 1.128 +void Texture::bind(int tex_unit) const 1.129 +{ 1.130 + glActiveTexture(GL_TEXTURE0 + tex_unit); 1.131 + glBindTexture(target, id); 1.132 + glActiveTexture(GL_TEXTURE0); 1.133 + 1.134 + cur_target[tex_unit] = target; 1.135 +} 1.136 + 1.137 + 1.138 +// ---- Texture2D ---- 1.139 + 1.140 +Texture2D::Texture2D() 1.141 +{ 1.142 + target = GL_TEXTURE_2D; 1.143 +} 1.144 + 1.145 +void Texture2D::create(int xsz, int ysz, unsigned int ifmt) 1.146 +{ 1.147 + int fmt = glfmt_from_ifmt(ifmt); 1.148 + int type = gltype_from_ifmt(ifmt); 1.149 + 1.150 + glBindTexture(GL_TEXTURE_2D, id); 1.151 + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 1.152 + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 1.153 + glTexImage2D(GL_TEXTURE_2D, 0, glifmt_from_ifmt(ifmt), xsz, ysz, 0, fmt, type, 0); 1.154 + CHECKGLERR; 1.155 + sz[0] = xsz; 1.156 + sz[1] = ysz; 1.157 + texfmt = ifmt; 1.158 +} 1.159 + 1.160 +void Texture2D::set_image(const Image &img, int idx) 1.161 +{ 1.162 + texfmt = glifmt_from_imgfmt(img.get_format()); 1.163 + unsigned int fmt = glfmt_from_ifmt(texfmt); 1.164 + unsigned int type = gltype_from_ifmt(texfmt); 1.165 + 1.166 + sz[0] = img.get_width(); 1.167 + sz[1] = img.get_height(); 1.168 + 1.169 + glBindTexture(GL_TEXTURE_2D, id); 1.170 + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); 1.171 + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 1.172 + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); 1.173 + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); 1.174 + 1.175 +#ifdef __GLEW_H__ 1.176 + if(GLEW_SGIS_generate_mipmap) { 1.177 + glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP_SGIS, GL_TRUE); 1.178 +#endif 1.179 + glTexImage2D(GL_TEXTURE_2D, 0, texfmt, sz[0], sz[1], 0, fmt, type, img.get_pixels()); 1.180 +#ifdef __GLEW_H__ 1.181 + } else { 1.182 + gluBuild2DMipmaps(GL_TEXTURE_2D, texfmt, sz[0], sz[1], fmt, type, img.get_pixels()); 1.183 + } 1.184 +#endif 1.185 + 1.186 +#ifdef GL_ES_VERSION_2_0 1.187 + glGenerateMipmap(GL_TEXTURE_2D); 1.188 +#endif 1.189 +} 1.190 + 1.191 +bool Texture2D::load(const char *fname) 1.192 +{ 1.193 + Image img; 1.194 + if(!img.load(fname) == -1) { 1.195 + error_log("failed to load 2D texture: %s\n", fname); 1.196 + return false; 1.197 + } 1.198 + set_image(img); 1.199 + 1.200 + info_log("loaded 2D texture: %s\n", fname); 1.201 + return true; 1.202 +} 1.203 + 1.204 +bool Texture2D::save(const char *fname) const 1.205 +{ 1.206 +#ifndef GL_ES_VERSION_2_0 1.207 + unsigned char *pixels = new unsigned char[sz[0] * sz[1] * 4]; 1.208 + 1.209 + glBindTexture(GL_TEXTURE_2D, id); 1.210 + glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels); 1.211 + 1.212 + if(img_save_pixels(fname, pixels, sz[0], sz[1]) == -1) { 1.213 + error_log("failed to save 2D texture: %s\n", fname); 1.214 + delete [] pixels; 1.215 + return false; 1.216 + } 1.217 + 1.218 + info_log("saved 2D texture: %s\n", fname); 1.219 + delete [] pixels; 1.220 + return true; 1.221 +#else 1.222 + return false; // TODO 1.223 +#endif 1.224 +} 1.225 + 1.226 +// ---- TextureCube ---- 1.227 +static unsigned int cube_faces[] = { 1.228 + GL_TEXTURE_CUBE_MAP_POSITIVE_X, 1.229 + GL_TEXTURE_CUBE_MAP_NEGATIVE_X, 1.230 + GL_TEXTURE_CUBE_MAP_POSITIVE_Y, 1.231 + GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, 1.232 + GL_TEXTURE_CUBE_MAP_POSITIVE_Z, 1.233 + GL_TEXTURE_CUBE_MAP_NEGATIVE_Z 1.234 +}; 1.235 + 1.236 +TextureCube::TextureCube() 1.237 +{ 1.238 + target = GL_TEXTURE_CUBE_MAP; 1.239 +} 1.240 + 1.241 +void TextureCube::create(int xsz, int ysz, unsigned int ifmt) 1.242 +{ 1.243 + if(xsz != ysz) { 1.244 + error_log("trying to create cubemap with different width and height (%dx%d)\n", xsz, ysz); 1.245 + return; 1.246 + } 1.247 + 1.248 + texfmt = ifmt; 1.249 + 1.250 + glBindTexture(GL_TEXTURE_CUBE_MAP, id); 1.251 + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); 1.252 + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 1.253 + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 1.254 + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 1.255 + 1.256 + for(int i=0; i<6; i++) { 1.257 + glTexImage2D(cube_faces[i], 0, ifmt, xsz, ysz, 0, GL_RGB, GL_UNSIGNED_BYTE, 0); 1.258 + } 1.259 +} 1.260 + 1.261 +void TextureCube::set_image(const Image &img, int idx) 1.262 +{ 1.263 + // TODO 1.264 +} 1.265 + 1.266 +bool TextureCube::load(const char *fname) 1.267 +{ 1.268 + return false; // TODO 1.269 +} 1.270 + 1.271 +bool TextureCube::save(const char *fname) const 1.272 +{ 1.273 + return false; // TODO 1.274 +} 1.275 + 1.276 +static int glifmt_from_ifmt(unsigned int ifmt) 1.277 +{ 1.278 +#ifdef GL_ES_VERSION_2_0 1.279 + switch(ifmt) { 1.280 + case GL_LUMINANCE16F: 1.281 + case GL_LUMINANCE32F: 1.282 + ifmt = GL_LUMINANCE; 1.283 + break; 1.284 + 1.285 + case GL_RGB16F: 1.286 + case GL_RGB32F: 1.287 + ifmt = GL_RGB; 1.288 + break; 1.289 + 1.290 + case GL_RGBA16F: 1.291 + case GL_RGBA32F: 1.292 + ifmt = GL_RGBA; 1.293 + break; 1.294 + 1.295 + default: 1.296 + break; 1.297 + } 1.298 +#endif 1.299 + return ifmt; // by default just pass it through... 1.300 +} 1.301 + 1.302 +static int glfmt_from_ifmt(unsigned int ifmt) 1.303 +{ 1.304 + switch(ifmt) { 1.305 + case GL_LUMINANCE16F: 1.306 + case GL_LUMINANCE32F: 1.307 + return GL_LUMINANCE; 1.308 + 1.309 + case GL_RGB16F: 1.310 + case GL_RGB32F: 1.311 + return GL_RGB; 1.312 + 1.313 + case GL_RGBA16F: 1.314 + case GL_RGBA32F: 1.315 + return GL_RGBA; 1.316 + 1.317 + default: 1.318 + break; 1.319 + } 1.320 + return ifmt; 1.321 +} 1.322 + 1.323 +static int gltype_from_ifmt(unsigned int ifmt) 1.324 +{ 1.325 + switch(ifmt) { 1.326 + case GL_RGB16F: 1.327 + case GL_RGBA16F: 1.328 + case GL_LUMINANCE16F: 1.329 +#ifdef GL_ES_VERSION_2_0 1.330 + return GL_HALF_FLOAT_OES; 1.331 +#endif 1.332 + case GL_RGB32F: 1.333 + case GL_RGBA32F: 1.334 + case GL_LUMINANCE32F: 1.335 + return GL_FLOAT; 1.336 + 1.337 + default: 1.338 + break; 1.339 + } 1.340 + return GL_UNSIGNED_BYTE; 1.341 +} 1.342 + 1.343 +static int glifmt_from_imgfmt(Image::Format fmt) 1.344 +{ 1.345 + switch(fmt) { 1.346 + case Image::FMT_GREY: 1.347 + return GL_LUMINANCE; 1.348 + case Image::FMT_GREY_FLOAT: 1.349 + return GL_LUMINANCE16F; 1.350 + case Image::FMT_RGB: 1.351 + return GL_RGB; 1.352 + case Image::FMT_RGB_FLOAT: 1.353 + return GL_RGB16F; 1.354 + case Image::FMT_RGBA: 1.355 + return GL_RGBA; 1.356 + case Image::FMT_RGBA_FLOAT: 1.357 + return GL_RGBA16F; 1.358 + default: 1.359 + break; 1.360 + } 1.361 + return 0; 1.362 +} 1.363 + 1.364 +// ---- TextureSet ---- 1.365 +static void destroy_texture(Texture *tex) 1.366 +{ 1.367 + delete tex; 1.368 +} 1.369 + 1.370 +TextureSet::TextureSet() 1.371 + : DataSet<Texture*>(load_texture, destroy_texture) 1.372 +{ 1.373 +}