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