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