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 }
|