]> git.mxchange.org Git - simgear.git/blob - simgear/screen/texture.cxx
Tweaks in preparation for the 0.3.6-pre1 release.
[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     num_colors = 1;
197     if (!texture_data)
198         return;
199
200     lptr = texture_data;
201     for(y=0; y<image->ysize; y++) {
202         ImageGetRow(image,lptr,y,0);
203         lptr += image->xsize;
204     }
205     ImageClose(image);
206 }
207
208 void
209 SGTexture::read_rgb_texture(const char *name)
210 {
211     GLubyte *ptr;
212     GLubyte *rbuf, *gbuf, *bbuf, *abuf;
213     SGTexture::ImageRec *image;
214     int y;
215
216     if (texture_data)
217         delete texture_data;
218
219     image = ImageOpen(name);
220     if(!image)
221         return;
222
223     texture_width = image->xsize;
224     texture_height = image->ysize;
225     if (image->zsize != 3 && image->zsize != 4) {
226       ImageClose(image);
227       return;
228     }
229
230     texture_data = new GLubyte[ image->xsize * image->ysize * 3 ];
231     num_colors = 3;
232     rbuf = new GLubyte[ image->xsize ];
233     gbuf = new GLubyte[ image->xsize ];
234     bbuf = new GLubyte[ image->xsize ];
235     abuf = new GLubyte[ image->xsize ];
236     if(!texture_data || !rbuf || !gbuf || !bbuf || !abuf) {
237       delete texture_data;
238       delete rbuf;
239       delete gbuf;
240       delete bbuf;
241       delete abuf;
242       return;
243     }
244
245     ptr = texture_data;
246     for(y=0; y<image->ysize; y++) {
247         if(image->zsize == 4) {
248             ImageGetRow(image,rbuf,y,0);
249             ImageGetRow(image,gbuf,y,1);
250             ImageGetRow(image,bbuf,y,2);
251             ImageGetRow(image,abuf,y,3); // discard
252             rgbtorgb(rbuf,gbuf,bbuf,ptr,image->xsize);
253             ptr += (image->xsize * 3);
254         } else {
255             ImageGetRow(image,rbuf,y,0);
256             ImageGetRow(image,gbuf,y,1);
257             ImageGetRow(image,bbuf,y,2);
258             rgbtorgb(rbuf,gbuf,bbuf,ptr,image->xsize);
259             ptr += (image->xsize * 3);
260         }
261     }
262
263     ImageClose(image);
264     delete rbuf;
265     delete gbuf;
266     delete bbuf;
267     delete abuf;
268 }
269
270
271
272 void
273 SGTexture::read_rgba_texture(const char *name)
274 {
275     GLubyte *ptr;
276     GLubyte *rbuf, *gbuf, *bbuf, *abuf;
277     SGTexture::ImageRec *image;
278     int y;
279
280     if (texture_data)
281         delete texture_data;
282
283     image = ImageOpen(name);
284     if(!image)
285         return;
286
287     texture_width = image->xsize;
288     texture_height = image->ysize;
289     if (image->zsize != 3 && image->zsize != 4) {
290       ImageClose(image);
291       return;
292     }
293
294     texture_data = new GLubyte[ image->xsize * image->ysize * 4 ];
295     num_colors = 4;
296     rbuf = new GLubyte[ image->xsize ];
297     gbuf = new GLubyte[ image->xsize ];
298     bbuf = new GLubyte[ image->xsize ];
299     abuf = new GLubyte[ image->xsize ];
300     if(!texture_data || !rbuf || !gbuf || !bbuf || !abuf) {
301       delete texture_data;
302       delete rbuf;
303       delete gbuf;
304       delete bbuf;
305       delete abuf;
306       return;
307     }
308
309     ptr = texture_data;
310     memset(abuf, 255, image->xsize);
311     for(y=0; y<image->ysize; y++) {
312         if(image->zsize == 4) {
313             ImageGetRow(image,rbuf,y,0);
314             ImageGetRow(image,gbuf,y,1);
315             ImageGetRow(image,bbuf,y,2);
316             ImageGetRow(image,abuf,y,3);
317             rgbatorgba(rbuf,gbuf,bbuf,abuf,ptr,image->xsize);
318             ptr += (image->xsize * 4);
319         } else {
320             ImageGetRow(image,rbuf,y,0);
321             ImageGetRow(image,gbuf,y,1);
322             ImageGetRow(image,bbuf,y,2);
323             rgbatorgba(rbuf,gbuf,bbuf,abuf,ptr,image->xsize);
324             ptr += (image->xsize * 3);
325         }
326     }
327
328     ImageClose(image);
329     delete rbuf;
330     delete gbuf;
331     delete bbuf;
332     delete abuf;
333 }
334
335 void
336 SGTexture::read_raw_texture(const char *name)
337 {
338     GLubyte *ptr;
339     SGTexture::ImageRec *image;
340     int y;
341
342     if (texture_data)
343         delete texture_data;
344
345     image = RawImageOpen(name);
346
347     if(!image)
348         return;
349
350     texture_width = 256;
351     texture_height = 256;
352
353     texture_data = new GLubyte[ 256 * 256 * 3 ];
354     if(!texture_data)
355       return;
356
357     ptr = texture_data;
358     for(y=0; y<256; y++) {
359         gzread(image->file, ptr, 256*3);
360         ptr+=256*3;
361     }
362     ImageClose(image);
363 }
364
365 void
366 SGTexture::read_r8_texture(const char *name)
367 {
368     unsigned char c[1];
369     GLubyte *ptr;
370     SGTexture::ImageRec *image;
371     int xy;
372
373     if (texture_data)
374         delete texture_data;
375
376     //it wouldn't make sense to write a new function ...
377     image = RawImageOpen(name);
378
379     if(!image)
380         return;
381
382     texture_width = 256;
383     texture_height = 256;
384
385     texture_data = new GLubyte [ 256 * 256 * 3 ];
386     if(!texture_data)
387         return;
388
389     ptr = texture_data;
390     for(xy=0; xy<(256*256); xy++) {
391         gzread(image->file, c, 1);
392
393         //look in the table for the right colours
394         ptr[0]=msfs_colour[c[0]][0];
395         ptr[1]=msfs_colour[c[0]][1];
396         ptr[2]=msfs_colour[c[0]][2];
397
398         ptr+=3;
399     }
400     ImageClose(image);
401 }
402
403
404 void
405 SGTexture::set_pixel(GLuint x, GLuint y, sgVec3 &c)
406 {
407     if (!texture_data)
408         return;
409
410     unsigned int pos = (x + y*texture_width)*3;
411     texture_data[pos]   = (unsigned char)(c[0] * 256);
412     texture_data[pos+1] = (unsigned char)(c[1] * 256);
413     texture_data[pos+2] = (unsigned char)(c[2] * 256);
414 }
415
416
417 float *
418 SGTexture::get_pixel(GLuint x, GLuint y)
419 {
420     static sgVec3 c;
421
422     sgSetVec3(c, 0, 0, 0);
423     if (!texture_data)
424         return c;
425
426     unsigned int pos = (x + y*texture_width)*3;
427
428     sgSetVec3(c, texture_data[pos], texture_data[pos+1], texture_data[pos+2]);
429
430     return c;
431 }
432
433 SGTexture::ImageRec *
434 SGTexture::ImageOpen(const char *fileName)
435 {
436      union {
437        int testWord;
438        char testByte[4];
439      } endianTest;
440
441     SGTexture::ImageRec *image;
442     int swapFlag;
443     int x;
444
445     endianTest.testWord = 1;
446     if (endianTest.testByte[0] == 1) {
447         swapFlag = 1;
448     } else {
449         swapFlag = 0;
450     }
451
452     image = new SGTexture::ImageRec;
453     if (image == 0) {
454         // fprintf(stderr, "Out of memory!\n");
455         return 0;
456     }
457     if ((image->file = gzopen(fileName, "rb")) == 0) {
458       return 0;
459     }
460
461     gzread(image->file, image, 12);
462
463     if (swapFlag) {
464         ConvertShort(&image->imagic, 6);
465     }
466
467     image->tmp = new GLubyte[ image->xsize * 256 ];
468     if (image->tmp == 0) {
469         // fprintf(stderr, "\nOut of memory!\n");
470         return 0;
471     }
472
473     if ((image->type & 0xFF00) == 0x0100) {
474         x = image->ysize * image->zsize * (int) sizeof(unsigned);
475         image->rowStart = new unsigned[x];
476         image->rowSize = new int[x];
477         if (image->rowStart == 0 || image->rowSize == 0) {
478             // fprintf(stderr, "\nOut of memory!\n");
479             return 0;
480         }
481         image->rleEnd = 512 + (2 * x);
482         gzseek(image->file, 512, SEEK_SET);
483         gzread(image->file, image->rowStart, x);
484         gzread(image->file, image->rowSize, x);
485         if (swapFlag) {
486             ConvertUint(image->rowStart, x/(int) sizeof(unsigned));
487             ConvertUint((unsigned *)image->rowSize, x/(int) sizeof(int));
488         }
489     }
490     return image;
491 }
492
493
494 void
495 SGTexture::ImageClose(SGTexture::ImageRec *image) {
496     gzclose(image->file);
497     delete image->tmp;
498     delete image;
499 }
500
501
502 SGTexture::ImageRec *
503 SGTexture::RawImageOpen(const char *fileName)
504 {
505      union {
506        int testWord;
507        char testByte[4];
508      } endianTest;
509
510     SGTexture::ImageRec *image;
511     int swapFlag;
512
513     endianTest.testWord = 1;
514     if (endianTest.testByte[0] == 1) {
515         swapFlag = 1;
516     } else {
517         swapFlag = 0;
518     }
519
520     image = new SGTexture::ImageRec;
521     if (image == 0) {
522         // fprintf(stderr, "Out of memory!\n");
523         return 0;
524     }
525     if ((image->file = gzopen(fileName, "rb")) == 0) {
526       return 0;
527     }
528
529     gzread(image->file, image, 12);
530
531     if (swapFlag) {
532         ConvertShort(&image->imagic, 6);
533     }
534
535
536     //just allocate a pseudo value as I'm too lazy to change ImageClose()...
537     image->tmp = new GLubyte;
538
539     if (image->tmp == 0) {
540         // fprintf(stderr, "\nOut of memory!\n");
541         return 0;
542     }
543
544     return image;
545 }
546
547 void
548 SGTexture::ImageGetRow(SGTexture::ImageRec *image, GLubyte *buf, int y, int z) {
549     GLubyte *iPtr, *oPtr, pixel;
550     int count;
551
552     if ((image->type & 0xFF00) == 0x0100) {
553         gzseek(image->file, (long) image->rowStart[y+z*image->ysize], SEEK_SET);
554         gzread(image->file, image->tmp,
555                (unsigned int)image->rowSize[y+z*image->ysize]);
556
557         iPtr = image->tmp;
558         oPtr = buf;
559         for (;;) {
560             pixel = *iPtr++;
561             count = (int)(pixel & 0x7F);
562             if (!count) {
563                 return;
564             }
565             if (pixel & 0x80) {
566                 while (count--) {
567                     *oPtr++ = *iPtr++;
568                 }
569             } else {
570                 pixel = *iPtr++;
571                 while (count--) {
572                     *oPtr++ = pixel;
573                 }
574             }
575         }
576     } else {
577         gzseek(image->file, 512+(y*image->xsize)+(z*image->xsize*image->ysize),
578               SEEK_SET);
579         gzread(image->file, buf, image->xsize);
580     }
581 }
582
583 void
584 SGTexture::rgbtorgb(GLubyte *r, GLubyte *g, GLubyte *b, GLubyte *l, int n) {
585     while(n--) {
586         l[0] = r[0];
587         l[1] = g[0];
588         l[2] = b[0];
589         l += 3; r++; g++; b++;
590     }
591 }
592
593 void
594 SGTexture::rgbatorgba(GLubyte *r, GLubyte *g, GLubyte *b, GLubyte *a,
595                       GLubyte *l, int n) {
596     while(n--) {
597         l[0] = r[0];
598         l[1] = g[0];
599         l[2] = b[0];
600         l[3] = a[0];
601         l += 4; r++; g++; b++; a++;
602     }
603 }
604
605
606 void
607 SGTexture::ConvertShort(unsigned short *array, unsigned int length) {
608     unsigned short b1, b2;
609     unsigned char *ptr;
610
611     ptr = (unsigned char *)array;
612     while (length--) {
613         b1 = *ptr++;
614         b2 = *ptr++;
615         *array++ = (b1 << 8) | (b2);
616     }
617 }
618
619
620 void
621 SGTexture::ConvertUint(unsigned *array, unsigned int length) {
622     unsigned int b1, b2, b3, b4;
623     unsigned char *ptr;
624
625     ptr = (unsigned char *)array;
626     while (length--) {
627         b1 = *ptr++;
628         b2 = *ptr++;
629         b3 = *ptr++;
630         b4 = *ptr++;
631         *array++ = (b1 << 24) | (b2 << 16) | (b3 << 8) | (b4);
632     }
633 }
634