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