]> git.mxchange.org Git - simgear.git/blob - simgear/screen/texture.cxx
Add a function which might return whether a texture is in video memory, delete the...
[simgear.git] / simgear / screen / texture.cxx
1 /*
2  * Texture manipulation routines
3  *
4  * Copyright (c) Mark J. Kilgard, 1997.
5  * Code added in april 2003 by Erik Hofman
6  *
7  * This program is freely distributable without licensing fees 
8  * and is provided without guarantee or warrantee expressed or 
9  * implied. This program is -not- in the public domain.
10  *
11  * $Id$
12  */
13
14 #include <simgear/compiler.h>
15 #ifdef WIN32
16 # include <windows.h>
17 #endif
18 #include <GL/glu.h>
19 #include <zlib.h>
20
21 #include "texture.hxx"
22 #include "colours.h"
23
24 SGTexture::SGTexture()
25    : texture_id(0),
26      texture_data(0)
27 {
28 }
29
30 SGTexture::SGTexture(unsigned int width, unsigned int height)
31    : texture_id(0)
32 {
33     texture_data = new GLubyte[ width * height * 3 ];
34 }
35
36 SGTexture::~SGTexture()
37 {
38     if (texture_data)
39         delete texture_data;
40
41     if (texture_id)
42         free_id();
43 }
44
45 void
46 SGTexture::bind()
47 {
48     if (!texture_data) {
49 #ifdef GL_VERSION_1_1
50         glGenTextures(1, &texture_id);
51
52 #elif GL_EXT_texture_object
53         glGenTexturesEXT(1, &texture_id);
54 #endif
55     }
56
57 #ifdef GL_VERSION_1_1
58     glBindTexture(GL_TEXTURE_2D, texture_id);
59
60 #elif GL_EXT_texture_object
61     glBindTextureEXT(GL_TEXTURE_2D, texture_id);
62 #endif
63
64     if (!texture_data) {
65         glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
66         glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
67         glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
68         glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
69     }
70 }
71
72 /**
73  * A function to resize the OpenGL window which will be used by
74  * the dynamic texture generating routines.
75  *
76  * @param width The width of the new window
77  * @param height The height of the new window
78  */
79 void
80 SGTexture::resize(unsigned int width, unsigned int height)
81 {
82     GLfloat aspect;
83
84     // Make sure that we don't get a divide by zero exception
85     if (height == 0)
86         height = 1;
87
88     // Set the viewport for the OpenGL window
89     glViewport(0, 0, width, height);
90
91     // Calculate the aspect ratio of the window
92     aspect = width/height;
93
94     // Go to the projection matrix, this gets modified by the perspective
95     // calulations
96     glMatrixMode(GL_PROJECTION);
97     glLoadIdentity();
98
99     // Do the perspective calculations
100     gluPerspective(45.0, aspect, 1.0, 400.0);
101
102     // Return to the modelview matrix
103     glMatrixMode(GL_MODELVIEW);
104 }
105
106 /**
107  * A function to prepare the OpenGL state machine for dynamic
108  * texture generation.
109  *
110  * @param width The width of the texture
111  * @param height The height of the texture
112  */
113 void
114 SGTexture::prepare(unsigned int width, unsigned int height) {
115
116     texture_width = width;
117     texture_height = height;
118
119     // Resize the OpenGL window to the size of our dynamic texture
120     resize(texture_width, texture_height);
121
122     // Clear the contents of the screen buffer to blue
123     glClearColor(0.0, 0.0, 1.0, 1.0);
124     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
125
126     // Turn off texturing (don't want the torus to be texture);
127     glDisable(GL_TEXTURE_2D);
128 }
129
130 /**
131  * A function to generate the dynamic texture.
132  *
133  * The actual texture can be accessed by calling get_texture()
134  *
135  * @param width The width of the previous OpenGL window
136  * @param height The height of the previous OpenGL window
137  */
138 void
139 SGTexture::finish(unsigned int width, unsigned int height) {
140     // If a texture hasn't been created then it gets created, and the contents
141     // of the frame buffer gets copied into it. If the texture has already been
142     // created then its contents just get updated.
143     bind();
144     if (!texture_data)
145     {
146       // Copies the contents of the frame buffer into the texture
147       glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 0, 0,
148                                       texture_width, texture_height, 0);
149
150     } else {
151       // Copies the contents of the frame buffer into the texture
152       glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0,
153                                          texture_width, texture_height);
154     }
155
156     // Set the OpenGL window back to its previous size
157     resize(width, height);
158
159     // Clear the window back to black
160     glClearColor(0.0, 0.0, 0.0, 1.0);
161     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
162 }
163
164
165 void
166 SGTexture::read_alpha_texture(const char *name)
167 {
168     GLubyte *lptr;
169     SGTexture::ImageRec *image;
170     int y;
171
172     if (texture_data)
173         delete texture_data;
174
175     image = ImageOpen(name);
176     if(!image) {
177         return;
178     }
179
180     texture_width = image->xsize;
181     texture_height = image->ysize;
182
183     // printf("image->zsize = %d\n", image->zsize);
184
185     if (image->zsize != 1) {
186       ImageClose(image);
187       return;
188     }
189
190     texture_data = new GLubyte[ image->xsize * image->ysize ];
191     if (!texture_data)
192         return;
193
194     lptr = texture_data;
195     for(y=0; y<image->ysize; y++) {
196         ImageGetRow(image,lptr,y,0);
197         lptr += image->xsize;
198     }
199     ImageClose(image);
200 }
201
202 void
203 SGTexture::read_rgb_texture(const char *name)
204 {
205     GLubyte *ptr;
206     GLubyte *rbuf, *gbuf, *bbuf, *abuf;
207     SGTexture::ImageRec *image;
208     int y;
209
210     if (texture_data)
211         delete texture_data;
212
213     image = ImageOpen(name);
214     if(!image)
215         return;
216
217     texture_width = image->xsize;
218     texture_height = image->ysize;
219     if (image->zsize != 3 && image->zsize != 4) {
220       ImageClose(image);
221       return;
222     }
223
224     texture_data = new GLubyte[ image->xsize * image->ysize * 3];
225     rbuf = new GLubyte[ image->xsize ];
226     gbuf = new GLubyte[ image->xsize ];
227     bbuf = new GLubyte[ image->xsize ];
228     abuf = new GLubyte[ image->xsize ];
229     if(!texture_data || !rbuf || !gbuf || !bbuf || !abuf) {
230       delete texture_data;
231       delete rbuf;
232       delete gbuf;
233       delete bbuf;
234       delete abuf;
235       return;
236     }
237
238     ptr = texture_data;
239     for(y=0; y<image->ysize; y++) {
240         if(image->zsize == 4) {
241             ImageGetRow(image,rbuf,y,0);
242             ImageGetRow(image,gbuf,y,1);
243             ImageGetRow(image,bbuf,y,2);
244             ImageGetRow(image,abuf,y,3);  /* Discard. */
245             rgbtorgb(rbuf,gbuf,bbuf,ptr,image->xsize);
246             ptr += (image->xsize * 3);
247         } else {
248             ImageGetRow(image,rbuf,y,0);
249             ImageGetRow(image,gbuf,y,1);
250             ImageGetRow(image,bbuf,y,2);
251             rgbtorgb(rbuf,gbuf,bbuf,ptr,image->xsize);
252             ptr += (image->xsize * 3);
253         }
254     }
255
256     ImageClose(image);
257     delete rbuf;
258     delete gbuf;
259     delete bbuf;
260     delete abuf;
261 }
262
263 void
264 SGTexture::read_raw_texture(const char *name)
265 {
266     GLubyte *ptr;
267     SGTexture::ImageRec *image;
268     int y;
269
270     if (texture_data)
271         delete texture_data;
272
273     image = RawImageOpen(name);
274
275     if(!image)
276         return;
277
278     texture_width = 256;
279     texture_height = 256;
280
281     texture_data = new GLubyte[ 256 * 256 * 3 ];
282     if(!texture_data)
283       return;
284
285     ptr = texture_data;
286     for(y=0; y<256; y++) {
287         gzread(image->file, ptr, 256*3);
288         ptr+=256*3;
289     }
290     ImageClose(image);
291 }
292
293 void
294 SGTexture::read_r8_texture(const char *name)
295 {
296     unsigned char c[1];
297     GLubyte *ptr;
298     SGTexture::ImageRec *image;
299     int xy;
300
301     if (texture_data)
302         delete texture_data;
303
304     //it wouldn't make sense to write a new function ...
305     image = RawImageOpen(name);
306
307     if(!image)
308         return;
309
310     texture_width = 256;
311     texture_height = 256;
312
313     texture_data = new GLubyte [ 256 * 256 * 3 ];
314     if(!texture_data)
315         return;
316
317     ptr = texture_data;
318     for(xy=0; xy<(256*256); xy++) {
319         gzread(image->file, c, 1);
320
321         //look in the table for the right colours
322         ptr[0]=msfs_colour[c[0]][0];
323         ptr[1]=msfs_colour[c[0]][1];
324         ptr[2]=msfs_colour[c[0]][2];
325
326         ptr+=3;
327     }
328     ImageClose(image);
329 }
330
331
332 #if 0
333 void
334 SGTexture::set_pixel(GLuint x, GLuint y, sgVec3 &c)
335 {
336     unsigned int pos = (x + y*texture_width)*3;
337     texture_data[pos]   = c[0];
338     texture_data[pos+1] = c[1];
339     texture_data[pos+2] = c[2];
340 }
341
342
343 sgVec3 *
344 SGTexture::get_pixel(GLuint x, GLuint y)
345 {
346     static sgVec3 c;
347     unsigned int pos = (x + y*texture_width)*3;
348
349     sgSetVec3(c, texture_data[pos], texture_data[pos+1], texture_data[pos+2]);
350
351     return &c;
352 }
353 #endif
354
355
356 SGTexture::ImageRec *
357 SGTexture::ImageOpen(const char *fileName)
358 {
359      union {
360        int testWord;
361        char testByte[4];
362      } endianTest;
363
364     SGTexture::ImageRec *image;
365     int swapFlag;
366     int x;
367
368     endianTest.testWord = 1;
369     if (endianTest.testByte[0] == 1) {
370         swapFlag = 1;
371     } else {
372         swapFlag = 0;
373     }
374
375     image = new SGTexture::ImageRec;
376     if (image == 0) {
377         // fprintf(stderr, "Out of memory!\n");
378         return 0;
379     }
380     if ((image->file = gzopen(fileName, "rb")) == 0) {
381       return 0;
382     }
383
384     gzread(image->file, image, 12);
385
386     if (swapFlag) {
387         ConvertShort(&image->imagic, 6);
388     }
389
390     image->tmp = new GLubyte[ image->xsize * 256 ];
391     if (image->tmp == 0) {
392         // fprintf(stderr, "\nOut of memory!\n");
393         return 0;
394     }
395
396     if ((image->type & 0xFF00) == 0x0100) {
397         x = image->ysize * image->zsize * (int) sizeof(unsigned);
398         image->rowStart = new unsigned[x];
399         image->rowSize = new int[x];
400         if (image->rowStart == 0 || image->rowSize == 0) {
401             // fprintf(stderr, "\nOut of memory!\n");
402             return 0;
403         }
404         image->rleEnd = 512 + (2 * x);
405         gzseek(image->file, 512, SEEK_SET);
406         gzread(image->file, image->rowStart, x);
407         gzread(image->file, image->rowSize, x);
408         if (swapFlag) {
409             ConvertUint(image->rowStart, x/(int) sizeof(unsigned));
410             ConvertUint((unsigned *)image->rowSize, x/(int) sizeof(int));
411         }
412     }
413     return image;
414 }
415
416
417 void
418 SGTexture::ImageClose(SGTexture::ImageRec *image) {
419     gzclose(image->file);
420     delete image->tmp;
421     delete image;
422 }
423
424
425 SGTexture::ImageRec *
426 SGTexture::RawImageOpen(const char *fileName)
427 {
428      union {
429        int testWord;
430        char testByte[4];
431      } endianTest;
432
433     SGTexture::ImageRec *image;
434     int swapFlag;
435
436     endianTest.testWord = 1;
437     if (endianTest.testByte[0] == 1) {
438         swapFlag = 1;
439     } else {
440         swapFlag = 0;
441     }
442
443     image = new SGTexture::ImageRec;
444     if (image == 0) {
445         // fprintf(stderr, "Out of memory!\n");
446         return 0;
447     }
448     if ((image->file = gzopen(fileName, "rb")) == 0) {
449       return 0;
450     }
451
452     gzread(image->file, image, 12);
453
454     if (swapFlag) {
455         ConvertShort(&image->imagic, 6);
456     }
457
458
459     //just allocate a pseudo value as I'm too lazy to change ImageClose()...
460     image->tmp = new GLubyte;
461
462     if (image->tmp == 0) {
463         // fprintf(stderr, "\nOut of memory!\n");
464         return 0;
465     }
466
467     return image;
468 }
469
470 void
471 SGTexture::ImageGetRow(SGTexture::ImageRec *image, GLubyte *buf, int y, int z) {
472     GLubyte *iPtr, *oPtr, pixel;
473     int count;
474
475     if ((image->type & 0xFF00) == 0x0100) {
476         gzseek(image->file, (long) image->rowStart[y+z*image->ysize], SEEK_SET);
477         gzread(image->file, image->tmp,
478                (unsigned int)image->rowSize[y+z*image->ysize]);
479
480         iPtr = image->tmp;
481         oPtr = buf;
482         for (;;) {
483             pixel = *iPtr++;
484             count = (int)(pixel & 0x7F);
485             if (!count) {
486                 return;
487             }
488             if (pixel & 0x80) {
489                 while (count--) {
490                     *oPtr++ = *iPtr++;
491                 }
492             } else {
493                 pixel = *iPtr++;
494                 while (count--) {
495                     *oPtr++ = pixel;
496                 }
497             }
498         }
499     } else {
500         gzseek(image->file, 512+(y*image->xsize)+(z*image->xsize*image->ysize),
501               SEEK_SET);
502         gzread(image->file, buf, image->xsize);
503     }
504 }
505
506 void
507 SGTexture::rgbtorgb(GLubyte *r, GLubyte *g, GLubyte *b, GLubyte *l, int n) {
508     while(n--) {
509         l[0] = r[0];
510         l[1] = g[0];
511         l[2] = b[0];
512         l += 3; r++; g++; b++;
513     }
514 }
515
516 void
517 SGTexture::ConvertShort(unsigned short *array, unsigned int length) {
518     unsigned short b1, b2;
519     unsigned char *ptr;
520
521     ptr = (unsigned char *)array;
522     while (length--) {
523         b1 = *ptr++;
524         b2 = *ptr++;
525         *array++ = (b1 << 8) | (b2);
526     }
527 }
528
529
530 void
531 SGTexture::ConvertUint(unsigned *array, unsigned int length) {
532     unsigned int b1, b2, b3, b4;
533     unsigned char *ptr;
534
535     ptr = (unsigned char *)array;
536     while (length--) {
537         b1 = *ptr++;
538         b2 = *ptr++;
539         b3 = *ptr++;
540         b4 = *ptr++;
541         *array++ = (b1 << 24) | (b2 << 16) | (b3 << 8) | (b4);
542     }
543 }
544