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