added 3dengfx into the repo, probably not the correct version for this
[summerhack] / src / 3dengfx / src / 3dengfx / textures.cpp
diff --git a/src/3dengfx/src/3dengfx/textures.cpp b/src/3dengfx/src/3dengfx/textures.cpp
new file mode 100644 (file)
index 0000000..e651375
--- /dev/null
@@ -0,0 +1,211 @@
+/*
+This file is part of the 3dengfx, realtime visualization system.
+
+Copyright (c) 2004, 2005 John Tsiombikas <nuclear@siggraph.org>
+
+3dengfx is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+3dengfx is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with 3dengfx; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+#include "3dengfx_config.h"
+
+#include <string.h>
+#include <cassert>
+#include "opengl.h"
+#include "textures.hpp"
+
+static void invert_image(Pixel *img, int x, int y) {
+       Pixel *s2 = img + (y - 1) * x;
+       Pixel *tmp = new Pixel[x];
+       
+       int swaps = y / 2;
+       int sl_bytes = x * sizeof(Pixel);
+       for(int i=0; i<swaps; i++) {
+               memcpy(tmp, img, sl_bytes);
+               memcpy(img, s2, sl_bytes);
+               memcpy(s2, tmp, sl_bytes);
+               img += x;
+               s2 -= x;
+       }
+
+       delete [] tmp;
+}
+
+static PixelBuffer undef_pbuf;
+
+static void gen_undef_image(int x, int y) {
+       if((int)undef_pbuf.width != x || (int)undef_pbuf.height != y) {
+               if(undef_pbuf.buffer) {
+                       delete [] undef_pbuf.buffer;
+               }
+               undef_pbuf.width = x;
+               undef_pbuf.height = y;
+               undef_pbuf.pitch = x * sizeof(Pixel);
+               undef_pbuf.buffer = new Pixel[x * y];
+
+               for(int i=0; i<y; i++) {
+                       memset(&undef_pbuf.buffer[i * x], (i/(y >= 8 ? y/8 : 1))%2 ? 0x00ff0000 : 0, x * sizeof(Pixel));
+               }
+       }
+}
+
+
+Texture::Texture(int x, int y, TextureDim type) {
+       width = x;
+       height = type == TEX_1D ? 1 : y;
+       this->type = type;
+
+       if(x != -1 && y != -1) {
+               gen_undef_image(width, height);
+               add_frame(undef_pbuf);
+       }
+}
+
+Texture::Texture(int x, TextureDim type) {
+       width = x;
+       height = type == TEX_1D ? 1 : x;
+       this->type = type;
+
+       gen_undef_image(width, height);
+       add_frame(undef_pbuf);
+}
+               
+Texture::~Texture() {
+       // TODO: check if it's destroyed between a lock/unlock and free image data
+}
+
+void Texture::add_frame() {
+       glGenTextures(1, &tex_id);
+       glBindTexture(type, tex_id);
+       
+       glTexParameteri(type, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+       glTexParameteri(type, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+
+       if(type == TEX_CUBE) {
+               glTexParameteri(type, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+               glTexParameteri(type, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+       } else {
+               glTexParameteri(type, GL_TEXTURE_WRAP_S, GL_REPEAT);
+               glTexParameteri(type, GL_TEXTURE_WRAP_T, GL_REPEAT);
+       }
+       
+       frame_tex_id.push_back(tex_id);
+}
+
+void Texture::add_frame(const PixelBuffer &pbuf) {
+       add_frame();
+
+       if(type == TEX_CUBE) {
+               set_pixel_data(pbuf, CUBE_MAP_PX);
+               set_pixel_data(pbuf, CUBE_MAP_NX);
+               set_pixel_data(pbuf, CUBE_MAP_PY);
+               set_pixel_data(pbuf, CUBE_MAP_NY);
+               set_pixel_data(pbuf, CUBE_MAP_PZ);
+               set_pixel_data(pbuf, CUBE_MAP_NZ);
+       } else {
+               set_pixel_data(pbuf);
+       }
+}
+
+void Texture::set_active_frame(unsigned int frame) {
+       assert(frame < frame_tex_id.size());
+       
+       active_frame = frame;
+       tex_id = frame_tex_id[active_frame];
+}
+
+unsigned int Texture::get_active_frame() const {
+       return active_frame;
+}
+
+void Texture::lock(CubeMapFace cube_map_face) {
+       buffer = new Pixel[width * height];
+       
+       glBindTexture(type, tex_id);
+       
+       if(type == TEX_CUBE) {
+               glGetTexImage(cube_map_face, 0, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
+       } else {
+               glGetTexImage(type, 0, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
+       }
+
+       invert_image(buffer, width, height);
+}
+
+void Texture::unlock(CubeMapFace cube_map_face) {
+       glBindTexture(type, tex_id);
+
+       invert_image(buffer, width, height);
+
+       switch(type) {
+       case TEX_1D:
+               glTexImage1D(type, 0, 4, width, 0, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
+               break;
+
+       case TEX_2D:
+               glTexImage2D(type, 0, 4, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
+               break;
+
+       case TEX_CUBE:
+               glTexImage2D(cube_map_face, 0, 4, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
+               break;
+
+       default:
+               break;
+       }
+       
+       delete [] buffer;
+       buffer = 0;
+}
+
+void Texture::set_pixel_data(const PixelBuffer &pbuf, CubeMapFace cube_map_face) {
+       
+       if(!frame_tex_id.size()) {
+               add_frame();
+       }
+               
+       width = pbuf.width;
+       height = pbuf.height;
+       
+       glBindTexture(type, tex_id);
+
+       buffer = new Pixel[width * height];
+       memcpy(buffer, pbuf.buffer, width * height * sizeof(Pixel));
+       invert_image(buffer, width, height);
+
+       switch(type) {
+       case TEX_1D:
+               glTexImage1D(type, 0, 4, width, 0, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
+               break;
+
+       case TEX_2D:
+               glTexImage2D(type, 0, 4, width, height, 0, GL_BGRA, GL_UNSIGNED_BYTE, buffer);
+               break;
+
+       case TEX_CUBE:
+               invert_image(buffer, width, height);
+               glTexImage2D(cube_map_face, 0, 4, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
+               break;
+
+       default:
+               break;
+       }
+
+       delete [] buffer;
+       buffer = 0;
+}
+
+TextureDim Texture::get_type() const {
+       return type;
+}