added 3dengfx into the repo, probably not the correct version for this
[summerhack] / src / 3dengfx / src / 3dengfx / textures.cpp
1 /*
2 This file is part of the 3dengfx, realtime visualization system.
3
4 Copyright (c) 2004, 2005 John Tsiombikas <nuclear@siggraph.org>
5
6 3dengfx is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 3dengfx is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with 3dengfx; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19 */
20
21 #include "3dengfx_config.h"
22
23 #include <string.h>
24 #include <cassert>
25 #include "opengl.h"
26 #include "textures.hpp"
27
28 static void invert_image(Pixel *img, int x, int y) {
29         Pixel *s2 = img + (y - 1) * x;
30         Pixel *tmp = new Pixel[x];
31         
32         int swaps = y / 2;
33         int sl_bytes = x * sizeof(Pixel);
34         for(int i=0; i<swaps; i++) {
35                 memcpy(tmp, img, sl_bytes);
36                 memcpy(img, s2, sl_bytes);
37                 memcpy(s2, tmp, sl_bytes);
38                 img += x;
39                 s2 -= x;
40         }
41
42         delete [] tmp;
43 }
44
45 static PixelBuffer undef_pbuf;
46
47 static void gen_undef_image(int x, int y) {
48         if((int)undef_pbuf.width != x || (int)undef_pbuf.height != y) {
49                 if(undef_pbuf.buffer) {
50                         delete [] undef_pbuf.buffer;
51                 }
52                 undef_pbuf.width = x;
53                 undef_pbuf.height = y;
54                 undef_pbuf.pitch = x * sizeof(Pixel);
55                 undef_pbuf.buffer = new Pixel[x * y];
56
57                 for(int i=0; i<y; i++) {
58                         memset(&undef_pbuf.buffer[i * x], (i/(y >= 8 ? y/8 : 1))%2 ? 0x00ff0000 : 0, x * sizeof(Pixel));
59                 }
60         }
61 }
62
63
64 Texture::Texture(int x, int y, TextureDim type) {
65         width = x;
66         height = type == TEX_1D ? 1 : y;
67         this->type = type;
68
69         if(x != -1 && y != -1) {
70                 gen_undef_image(width, height);
71                 add_frame(undef_pbuf);
72         }
73 }
74
75 Texture::Texture(int x, TextureDim type) {
76         width = x;
77         height = type == TEX_1D ? 1 : x;
78         this->type = type;
79
80         gen_undef_image(width, height);
81         add_frame(undef_pbuf);
82 }
83                 
84 Texture::~Texture() {
85         // TODO: check if it's destroyed between a lock/unlock and free image data
86 }
87
88 void Texture::add_frame() {
89         glGenTextures(1, &tex_id);
90         glBindTexture(type, tex_id);
91         
92         glTexParameteri(type, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
93         glTexParameteri(type, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
94
95         if(type == TEX_CUBE) {
96                 glTexParameteri(type, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
97                 glTexParameteri(type, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
98         } else {
99                 glTexParameteri(type, GL_TEXTURE_WRAP_S, GL_REPEAT);
100                 glTexParameteri(type, GL_TEXTURE_WRAP_T, GL_REPEAT);
101         }
102         
103         frame_tex_id.push_back(tex_id);
104 }
105
106 void Texture::add_frame(const PixelBuffer &pbuf) {
107         add_frame();
108
109         if(type == TEX_CUBE) {
110                 set_pixel_data(pbuf, CUBE_MAP_PX);
111                 set_pixel_data(pbuf, CUBE_MAP_NX);
112                 set_pixel_data(pbuf, CUBE_MAP_PY);
113                 set_pixel_data(pbuf, CUBE_MAP_NY);
114                 set_pixel_data(pbuf, CUBE_MAP_PZ);
115                 set_pixel_data(pbuf, CUBE_MAP_NZ);
116         } else {
117                 set_pixel_data(pbuf);
118         }
119 }
120
121 void Texture::set_active_frame(unsigned int frame) {
122         assert(frame < frame_tex_id.size());
123         
124         active_frame = frame;
125         tex_id = frame_tex_id[active_frame];
126 }
127
128 unsigned int Texture::get_active_frame() const {
129         return active_frame;
130 }
131
132 void Texture::lock(CubeMapFace cube_map_face) {
133         buffer = new Pixel[width * height];
134         
135         glBindTexture(type, tex_id);
136         
137         if(type == TEX_CUBE) {
138                 glGetTexImage(cube_map_face, 0, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
139         } else {
140                 glGetTexImage(type, 0, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
141         }
142
143         invert_image(buffer, width, height);
144 }
145
146 void Texture::unlock(CubeMapFace cube_map_face) {
147         glBindTexture(type, tex_id);
148
149         invert_image(buffer, width, height);
150
151         switch(type) {
152         case TEX_1D:
153                 glTexImage1D(type, 0, 4, width, 0, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
154                 break;
155
156         case TEX_2D:
157                 glTexImage2D(type, 0, 4, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
158                 break;
159
160         case TEX_CUBE:
161                 glTexImage2D(cube_map_face, 0, 4, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
162                 break;
163
164         default:
165                 break;
166         }
167         
168         delete [] buffer;
169         buffer = 0;
170 }
171
172 void Texture::set_pixel_data(const PixelBuffer &pbuf, CubeMapFace cube_map_face) {
173         
174         if(!frame_tex_id.size()) {
175                 add_frame();
176         }
177                 
178         width = pbuf.width;
179         height = pbuf.height;
180         
181         glBindTexture(type, tex_id);
182
183         buffer = new Pixel[width * height];
184         memcpy(buffer, pbuf.buffer, width * height * sizeof(Pixel));
185         invert_image(buffer, width, height);
186
187         switch(type) {
188         case TEX_1D:
189                 glTexImage1D(type, 0, 4, width, 0, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
190                 break;
191
192         case TEX_2D:
193                 glTexImage2D(type, 0, 4, width, height, 0, GL_BGRA, GL_UNSIGNED_BYTE, buffer);
194                 break;
195
196         case TEX_CUBE:
197                 invert_image(buffer, width, height);
198                 glTexImage2D(cube_map_face, 0, 4, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
199                 break;
200
201         default:
202                 break;
203         }
204
205         delete [] buffer;
206         buffer = 0;
207 }
208
209 TextureDim Texture::get_type() const {
210         return type;
211 }