goat3dgfx

annotate 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
rev   line source
nuclear@0 1 #include "texture.h"
nuclear@0 2 #include "image.h"
nuclear@0 3 #include "opengl.h"
nuclear@0 4 #include "imago2.h"
nuclear@0 5 #include "logger.h"
nuclear@0 6 #include "datapath.h"
nuclear@0 7
nuclear@0 8 static int glifmt_from_ifmt(unsigned int ifmt);
nuclear@0 9 static int glfmt_from_ifmt(unsigned int ifmt);
nuclear@0 10 static int gltype_from_ifmt(unsigned int ifmt);
nuclear@0 11
nuclear@0 12 static int glifmt_from_imgfmt(Image::Format fmt);
nuclear@0 13
nuclear@0 14 static unsigned int cur_target[8] = {
nuclear@0 15 GL_TEXTURE_2D, GL_TEXTURE_2D, GL_TEXTURE_2D, GL_TEXTURE_2D,
nuclear@0 16 GL_TEXTURE_2D, GL_TEXTURE_2D, GL_TEXTURE_2D, GL_TEXTURE_2D
nuclear@0 17 };
nuclear@0 18
nuclear@0 19 void set_texture(Texture *tex, int tunit)
nuclear@0 20 {
nuclear@0 21 if(tex) {
nuclear@0 22 tex->bind(tunit);
nuclear@0 23 } else {
nuclear@0 24 glActiveTexture(GL_TEXTURE0 + tunit);
nuclear@0 25 glBindTexture(cur_target[tunit], 0);
nuclear@0 26 glActiveTexture(GL_TEXTURE0);
nuclear@0 27 }
nuclear@0 28 }
nuclear@0 29
nuclear@0 30 Texture *load_texture(const char *fname)
nuclear@0 31 {
nuclear@0 32 TextureCube *texcube = new TextureCube;
nuclear@0 33 if(texcube->load(fname)) {
nuclear@0 34 return texcube;
nuclear@0 35 }
nuclear@0 36 delete texcube;
nuclear@0 37
nuclear@0 38 Texture2D *tex = new Texture2D;
nuclear@0 39 if(tex->load(fname)) {
nuclear@0 40 return tex;
nuclear@0 41 }
nuclear@0 42 delete tex;
nuclear@0 43 return 0;
nuclear@0 44 }
nuclear@0 45
nuclear@0 46
nuclear@0 47 Texture::Texture()
nuclear@0 48 {
nuclear@0 49 target = 0;
nuclear@0 50 sz[0] = sz[1] = sz[2] = 0;
nuclear@0 51 texfmt = 0;
nuclear@0 52
nuclear@0 53 glGenTextures(1, &id);
nuclear@0 54 }
nuclear@0 55
nuclear@0 56 Texture::~Texture()
nuclear@0 57 {
nuclear@0 58 if(id) {
nuclear@0 59 glDeleteTextures(1, &id);
nuclear@0 60 }
nuclear@0 61 }
nuclear@0 62
nuclear@0 63 void Texture::set_wrapping(unsigned int wrap)
nuclear@0 64 {
nuclear@0 65 if(!target) {
nuclear@0 66 return;
nuclear@0 67 }
nuclear@0 68
nuclear@0 69 glBindTexture(target, id);
nuclear@0 70 glTexParameteri(target, GL_TEXTURE_WRAP_S, wrap);
nuclear@0 71 glTexParameteri(target, GL_TEXTURE_WRAP_T, wrap);
nuclear@0 72 }
nuclear@0 73
nuclear@0 74 void Texture::set_filtering(unsigned int filt)
nuclear@0 75 {
nuclear@0 76 unsigned int mag_filter;
nuclear@0 77
nuclear@0 78 if(!target) {
nuclear@0 79 return;
nuclear@0 80 }
nuclear@0 81
nuclear@0 82 switch(filt) {
nuclear@0 83 case GL_LINEAR_MIPMAP_NEAREST:
nuclear@0 84 case GL_LINEAR_MIPMAP_LINEAR:
nuclear@0 85 mag_filter = GL_LINEAR;
nuclear@0 86 break;
nuclear@0 87
nuclear@0 88 case GL_NEAREST_MIPMAP_NEAREST:
nuclear@0 89 case GL_NEAREST_MIPMAP_LINEAR:
nuclear@0 90 mag_filter = GL_NEAREST;
nuclear@0 91 break;
nuclear@0 92
nuclear@0 93 default:
nuclear@0 94 mag_filter = filt;
nuclear@0 95 }
nuclear@0 96
nuclear@0 97 set_filtering(filt, mag_filter);
nuclear@0 98 }
nuclear@0 99
nuclear@0 100 void Texture::set_filtering(unsigned int min_filt, unsigned int mag_filt)
nuclear@0 101 {
nuclear@0 102 glBindTexture(target, id);
nuclear@0 103 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, min_filt);
nuclear@0 104 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, mag_filt);
nuclear@0 105 }
nuclear@0 106
nuclear@0 107 unsigned int Texture::get_format() const
nuclear@0 108 {
nuclear@0 109 return texfmt;
nuclear@0 110 }
nuclear@0 111
nuclear@0 112 int Texture::get_size(int dim) const
nuclear@0 113 {
nuclear@0 114 if(dim < 0 || dim >= 3) {
nuclear@0 115 return 0;
nuclear@0 116 }
nuclear@0 117 return sz[dim];
nuclear@0 118 }
nuclear@0 119
nuclear@0 120 unsigned int Texture::get_id() const
nuclear@0 121 {
nuclear@0 122 return id;
nuclear@0 123 }
nuclear@0 124
nuclear@0 125 void Texture::bind(int tex_unit) const
nuclear@0 126 {
nuclear@0 127 glActiveTexture(GL_TEXTURE0 + tex_unit);
nuclear@0 128 glBindTexture(target, id);
nuclear@0 129 glActiveTexture(GL_TEXTURE0);
nuclear@0 130
nuclear@0 131 cur_target[tex_unit] = target;
nuclear@0 132 }
nuclear@0 133
nuclear@0 134
nuclear@0 135 // ---- Texture2D ----
nuclear@0 136
nuclear@0 137 Texture2D::Texture2D()
nuclear@0 138 {
nuclear@0 139 target = GL_TEXTURE_2D;
nuclear@0 140 }
nuclear@0 141
nuclear@0 142 void Texture2D::create(int xsz, int ysz, unsigned int ifmt)
nuclear@0 143 {
nuclear@0 144 int fmt = glfmt_from_ifmt(ifmt);
nuclear@0 145 int type = gltype_from_ifmt(ifmt);
nuclear@0 146
nuclear@0 147 glBindTexture(GL_TEXTURE_2D, id);
nuclear@0 148 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
nuclear@0 149 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
nuclear@0 150 glTexImage2D(GL_TEXTURE_2D, 0, glifmt_from_ifmt(ifmt), xsz, ysz, 0, fmt, type, 0);
nuclear@0 151 CHECKGLERR;
nuclear@0 152 sz[0] = xsz;
nuclear@0 153 sz[1] = ysz;
nuclear@0 154 texfmt = ifmt;
nuclear@0 155 }
nuclear@0 156
nuclear@0 157 void Texture2D::set_image(const Image &img, int idx)
nuclear@0 158 {
nuclear@0 159 texfmt = glifmt_from_imgfmt(img.get_format());
nuclear@0 160 unsigned int fmt = glfmt_from_ifmt(texfmt);
nuclear@0 161 unsigned int type = gltype_from_ifmt(texfmt);
nuclear@0 162
nuclear@0 163 sz[0] = img.get_width();
nuclear@0 164 sz[1] = img.get_height();
nuclear@0 165
nuclear@0 166 glBindTexture(GL_TEXTURE_2D, id);
nuclear@0 167 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
nuclear@0 168 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
nuclear@0 169 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
nuclear@0 170 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
nuclear@0 171
nuclear@0 172 #ifdef __GLEW_H__
nuclear@0 173 if(GLEW_SGIS_generate_mipmap) {
nuclear@0 174 glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP_SGIS, GL_TRUE);
nuclear@0 175 #endif
nuclear@0 176 glTexImage2D(GL_TEXTURE_2D, 0, texfmt, sz[0], sz[1], 0, fmt, type, img.get_pixels());
nuclear@0 177 #ifdef __GLEW_H__
nuclear@0 178 } else {
nuclear@0 179 gluBuild2DMipmaps(GL_TEXTURE_2D, texfmt, sz[0], sz[1], fmt, type, img.get_pixels());
nuclear@0 180 }
nuclear@0 181 #endif
nuclear@0 182
nuclear@0 183 #ifdef GL_ES_VERSION_2_0
nuclear@0 184 glGenerateMipmap(GL_TEXTURE_2D);
nuclear@0 185 #endif
nuclear@0 186 }
nuclear@0 187
nuclear@0 188 bool Texture2D::load(const char *fname)
nuclear@0 189 {
nuclear@0 190 Image img;
nuclear@0 191 if(!img.load(fname) == -1) {
nuclear@0 192 error_log("failed to load 2D texture: %s\n", fname);
nuclear@0 193 return false;
nuclear@0 194 }
nuclear@0 195 set_image(img);
nuclear@0 196
nuclear@0 197 info_log("loaded 2D texture: %s\n", fname);
nuclear@0 198 return true;
nuclear@0 199 }
nuclear@0 200
nuclear@0 201 bool Texture2D::save(const char *fname) const
nuclear@0 202 {
nuclear@0 203 #ifndef GL_ES_VERSION_2_0
nuclear@0 204 unsigned char *pixels = new unsigned char[sz[0] * sz[1] * 4];
nuclear@0 205
nuclear@0 206 glBindTexture(GL_TEXTURE_2D, id);
nuclear@0 207 glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
nuclear@0 208
nuclear@0 209 if(img_save_pixels(fname, pixels, sz[0], sz[1]) == -1) {
nuclear@0 210 error_log("failed to save 2D texture: %s\n", fname);
nuclear@0 211 delete [] pixels;
nuclear@0 212 return false;
nuclear@0 213 }
nuclear@0 214
nuclear@0 215 info_log("saved 2D texture: %s\n", fname);
nuclear@0 216 delete [] pixels;
nuclear@0 217 return true;
nuclear@0 218 #else
nuclear@0 219 return false; // TODO
nuclear@0 220 #endif
nuclear@0 221 }
nuclear@0 222
nuclear@0 223 // ---- TextureCube ----
nuclear@0 224 static unsigned int cube_faces[] = {
nuclear@0 225 GL_TEXTURE_CUBE_MAP_POSITIVE_X,
nuclear@0 226 GL_TEXTURE_CUBE_MAP_NEGATIVE_X,
nuclear@0 227 GL_TEXTURE_CUBE_MAP_POSITIVE_Y,
nuclear@0 228 GL_TEXTURE_CUBE_MAP_NEGATIVE_Y,
nuclear@0 229 GL_TEXTURE_CUBE_MAP_POSITIVE_Z,
nuclear@0 230 GL_TEXTURE_CUBE_MAP_NEGATIVE_Z
nuclear@0 231 };
nuclear@0 232
nuclear@0 233 TextureCube::TextureCube()
nuclear@0 234 {
nuclear@0 235 target = GL_TEXTURE_CUBE_MAP;
nuclear@0 236 }
nuclear@0 237
nuclear@0 238 void TextureCube::create(int xsz, int ysz, unsigned int ifmt)
nuclear@0 239 {
nuclear@0 240 if(xsz != ysz) {
nuclear@0 241 error_log("trying to create cubemap with different width and height (%dx%d)\n", xsz, ysz);
nuclear@0 242 return;
nuclear@0 243 }
nuclear@0 244
nuclear@0 245 texfmt = ifmt;
nuclear@0 246
nuclear@0 247 glBindTexture(GL_TEXTURE_CUBE_MAP, id);
nuclear@0 248 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
nuclear@0 249 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
nuclear@0 250 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
nuclear@0 251 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
nuclear@0 252
nuclear@0 253 for(int i=0; i<6; i++) {
nuclear@0 254 glTexImage2D(cube_faces[i], 0, ifmt, xsz, ysz, 0, GL_RGB, GL_UNSIGNED_BYTE, 0);
nuclear@0 255 }
nuclear@0 256 }
nuclear@0 257
nuclear@0 258 void TextureCube::set_image(const Image &img, int idx)
nuclear@0 259 {
nuclear@0 260 // TODO
nuclear@0 261 }
nuclear@0 262
nuclear@0 263 bool TextureCube::load(const char *fname)
nuclear@0 264 {
nuclear@0 265 return false; // TODO
nuclear@0 266 }
nuclear@0 267
nuclear@0 268 bool TextureCube::save(const char *fname) const
nuclear@0 269 {
nuclear@0 270 return false; // TODO
nuclear@0 271 }
nuclear@0 272
nuclear@0 273 static int glifmt_from_ifmt(unsigned int ifmt)
nuclear@0 274 {
nuclear@0 275 #ifdef GL_ES_VERSION_2_0
nuclear@0 276 switch(ifmt) {
nuclear@0 277 case GL_LUMINANCE16F:
nuclear@0 278 case GL_LUMINANCE32F:
nuclear@0 279 ifmt = GL_LUMINANCE;
nuclear@0 280 break;
nuclear@0 281
nuclear@0 282 case GL_RGB16F:
nuclear@0 283 case GL_RGB32F:
nuclear@0 284 ifmt = GL_RGB;
nuclear@0 285 break;
nuclear@0 286
nuclear@0 287 case GL_RGBA16F:
nuclear@0 288 case GL_RGBA32F:
nuclear@0 289 ifmt = GL_RGBA;
nuclear@0 290 break;
nuclear@0 291
nuclear@0 292 default:
nuclear@0 293 break;
nuclear@0 294 }
nuclear@0 295 #endif
nuclear@0 296 return ifmt; // by default just pass it through...
nuclear@0 297 }
nuclear@0 298
nuclear@0 299 static int glfmt_from_ifmt(unsigned int ifmt)
nuclear@0 300 {
nuclear@0 301 switch(ifmt) {
nuclear@0 302 case GL_LUMINANCE16F:
nuclear@0 303 case GL_LUMINANCE32F:
nuclear@0 304 return GL_LUMINANCE;
nuclear@0 305
nuclear@0 306 case GL_RGB16F:
nuclear@0 307 case GL_RGB32F:
nuclear@0 308 return GL_RGB;
nuclear@0 309
nuclear@0 310 case GL_RGBA16F:
nuclear@0 311 case GL_RGBA32F:
nuclear@0 312 return GL_RGBA;
nuclear@0 313
nuclear@0 314 default:
nuclear@0 315 break;
nuclear@0 316 }
nuclear@0 317 return ifmt;
nuclear@0 318 }
nuclear@0 319
nuclear@0 320 static int gltype_from_ifmt(unsigned int ifmt)
nuclear@0 321 {
nuclear@0 322 switch(ifmt) {
nuclear@0 323 case GL_RGB16F:
nuclear@0 324 case GL_RGBA16F:
nuclear@0 325 case GL_LUMINANCE16F:
nuclear@0 326 #ifdef GL_ES_VERSION_2_0
nuclear@0 327 return GL_HALF_FLOAT_OES;
nuclear@0 328 #endif
nuclear@0 329 case GL_RGB32F:
nuclear@0 330 case GL_RGBA32F:
nuclear@0 331 case GL_LUMINANCE32F:
nuclear@0 332 return GL_FLOAT;
nuclear@0 333
nuclear@0 334 default:
nuclear@0 335 break;
nuclear@0 336 }
nuclear@0 337 return GL_UNSIGNED_BYTE;
nuclear@0 338 }
nuclear@0 339
nuclear@0 340 static int glifmt_from_imgfmt(Image::Format fmt)
nuclear@0 341 {
nuclear@0 342 switch(fmt) {
nuclear@0 343 case Image::FMT_GREY:
nuclear@0 344 return GL_LUMINANCE;
nuclear@0 345 case Image::FMT_GREY_FLOAT:
nuclear@0 346 return GL_LUMINANCE16F;
nuclear@0 347 case Image::FMT_RGB:
nuclear@0 348 return GL_RGB;
nuclear@0 349 case Image::FMT_RGB_FLOAT:
nuclear@0 350 return GL_RGB16F;
nuclear@0 351 case Image::FMT_RGBA:
nuclear@0 352 return GL_RGBA;
nuclear@0 353 case Image::FMT_RGBA_FLOAT:
nuclear@0 354 return GL_RGBA16F;
nuclear@0 355 default:
nuclear@0 356 break;
nuclear@0 357 }
nuclear@0 358 return 0;
nuclear@0 359 }
nuclear@0 360
nuclear@0 361 // ---- TextureSet ----
nuclear@0 362 static void destroy_texture(Texture *tex)
nuclear@0 363 {
nuclear@0 364 delete tex;
nuclear@0 365 }
nuclear@0 366
nuclear@0 367 TextureSet::TextureSet()
nuclear@0 368 : DataSet<Texture*>(load_texture, destroy_texture)
nuclear@0 369 {
nuclear@0 370 }