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