2 * Texture manipulation routines
4 * Copyright (c) Mark J. Kilgard, 1997.
5 * Code added in april 2003 by Erik Hofman
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.
14 #include <simgear/compiler.h>
21 #include "texture.hxx"
24 SGTexture::SGTexture()
31 SGTexture::SGTexture(unsigned int width, unsigned int height)
34 texture_data = new GLubyte[ width * height * 3 ];
37 SGTexture::~SGTexture()
43 if ( texture_id != 0 ) {
54 glGenTextures(1, &texture_id);
56 #elif GL_EXT_texture_object
57 glGenTexturesEXT(1, &texture_id);
63 glBindTexture(GL_TEXTURE_2D, texture_id);
65 #elif GL_EXT_texture_object
66 glBindTextureEXT(GL_TEXTURE_2D, texture_id);
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);
78 * A function to resize the OpenGL window which will be used by
79 * the dynamic texture generating routines.
81 * @param width The width of the new window
82 * @param height The height of the new window
85 SGTexture::resize(unsigned int width, unsigned int height)
89 // Make sure that we don't get a divide by zero exception
93 // Set the viewport for the OpenGL window
94 glViewport(0, 0, width, height);
96 // Calculate the aspect ratio of the window
97 aspect = width/height;
99 // Go to the projection matrix, this gets modified by the perspective
101 glMatrixMode(GL_PROJECTION);
104 // Do the perspective calculations
105 gluPerspective(45.0, aspect, 1.0, 400.0);
107 // Return to the modelview matrix
108 glMatrixMode(GL_MODELVIEW);
112 * A function to prepare the OpenGL state machine for dynamic
113 * texture generation.
115 * @param width The width of the texture
116 * @param height The height of the texture
119 SGTexture::prepare(unsigned int width, unsigned int height) {
121 texture_width = width;
122 texture_height = height;
124 // Resize the OpenGL window to the size of our dynamic texture
125 resize(texture_width, texture_height);
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);
131 // Turn off texturing (don't want the torus to be texture);
132 glDisable(GL_TEXTURE_2D);
136 * A function to generate the dynamic texture.
138 * The actual texture can be accessed by calling get_texture()
140 * @param width The width of the previous OpenGL window
141 * @param height The height of the previous OpenGL window
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.
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);
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);
161 // Set the OpenGL window back to its previous size
162 resize(width, height);
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);
171 SGTexture::read_alpha_texture(const char *name)
174 SGTexture::ImageRec *image;
180 image = ImageOpen(name);
185 texture_width = image->xsize;
186 texture_height = image->ysize;
188 // printf("image->zsize = %d\n", image->zsize);
190 if (image->zsize != 1) {
195 texture_data = new GLubyte[ image->xsize * image->ysize ];
201 for(y=0; y<image->ysize; y++) {
202 ImageGetRow(image,lptr,y,0);
203 lptr += image->xsize;
209 SGTexture::read_rgb_texture(const char *name)
212 GLubyte *rbuf, *gbuf, *bbuf, *abuf;
213 SGTexture::ImageRec *image;
219 image = ImageOpen(name);
223 texture_width = image->xsize;
224 texture_height = image->ysize;
225 if (image->zsize != 3 && image->zsize != 4) {
230 texture_data = new GLubyte[ image->xsize * image->ysize * 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) {
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);
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);
273 SGTexture::read_rgba_texture(const char *name)
276 GLubyte *rbuf, *gbuf, *bbuf, *abuf;
277 SGTexture::ImageRec *image;
283 image = ImageOpen(name);
287 texture_width = image->xsize;
288 texture_height = image->ysize;
289 if (image->zsize != 3 && image->zsize != 4) {
294 texture_data = new GLubyte[ image->xsize * image->ysize * 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) {
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);
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);
336 SGTexture::read_raw_texture(const char *name)
339 SGTexture::ImageRec *image;
345 image = RawImageOpen(name);
351 texture_height = 256;
353 texture_data = new GLubyte[ 256 * 256 * 3 ];
358 for(y=0; y<256; y++) {
359 gzread(image->file, ptr, 256*3);
366 SGTexture::read_r8_texture(const char *name)
370 SGTexture::ImageRec *image;
376 //it wouldn't make sense to write a new function ...
377 image = RawImageOpen(name);
383 texture_height = 256;
385 texture_data = new GLubyte [ 256 * 256 * 3 ];
390 for(xy=0; xy<(256*256); xy++) {
391 gzread(image->file, c, 1);
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];
405 SGTexture::set_pixel(GLuint x, GLuint y, sgVec3 &c)
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);
418 SGTexture::get_pixel(GLuint x, GLuint y)
422 sgSetVec3(c, 0, 0, 0);
426 unsigned int pos = (x + y*texture_width)*3;
428 sgSetVec3(c, texture_data[pos], texture_data[pos+1], texture_data[pos+2]);
433 SGTexture::ImageRec *
434 SGTexture::ImageOpen(const char *fileName)
441 SGTexture::ImageRec *image;
445 endianTest.testWord = 1;
446 if (endianTest.testByte[0] == 1) {
452 image = new SGTexture::ImageRec;
454 // fprintf(stderr, "Out of memory!\n");
457 if ((image->file = gzopen(fileName, "rb")) == 0) {
461 gzread(image->file, image, 12);
464 ConvertShort(&image->imagic, 6);
467 image->tmp = new GLubyte[ image->xsize * 256 ];
468 if (image->tmp == 0) {
469 // fprintf(stderr, "\nOut of memory!\n");
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");
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);
486 ConvertUint(image->rowStart, x/(int) sizeof(unsigned));
487 ConvertUint((unsigned *)image->rowSize, x/(int) sizeof(int));
495 SGTexture::ImageClose(SGTexture::ImageRec *image) {
496 gzclose(image->file);
502 SGTexture::ImageRec *
503 SGTexture::RawImageOpen(const char *fileName)
510 SGTexture::ImageRec *image;
513 endianTest.testWord = 1;
514 if (endianTest.testByte[0] == 1) {
520 image = new SGTexture::ImageRec;
522 // fprintf(stderr, "Out of memory!\n");
525 if ((image->file = gzopen(fileName, "rb")) == 0) {
529 gzread(image->file, image, 12);
532 ConvertShort(&image->imagic, 6);
536 //just allocate a pseudo value as I'm too lazy to change ImageClose()...
537 image->tmp = new GLubyte;
539 if (image->tmp == 0) {
540 // fprintf(stderr, "\nOut of memory!\n");
548 SGTexture::ImageGetRow(SGTexture::ImageRec *image, GLubyte *buf, int y, int z) {
549 GLubyte *iPtr, *oPtr, pixel;
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]);
561 count = (int)(pixel & 0x7F);
577 gzseek(image->file, 512+(y*image->xsize)+(z*image->xsize*image->ysize),
579 gzread(image->file, buf, image->xsize);
584 SGTexture::rgbtorgb(GLubyte *r, GLubyte *g, GLubyte *b, GLubyte *l, int n) {
589 l += 3; r++; g++; b++;
594 SGTexture::rgbatorgba(GLubyte *r, GLubyte *g, GLubyte *b, GLubyte *a,
601 l += 4; r++; g++; b++; a++;
607 SGTexture::ConvertShort(unsigned short *array, unsigned int length) {
608 unsigned short b1, b2;
611 ptr = (unsigned char *)array;
615 *array++ = (b1 << 8) | (b2);
621 SGTexture::ConvertUint(unsigned *array, unsigned int length) {
622 unsigned int b1, b2, b3, b4;
625 ptr = (unsigned char *)array;
631 *array++ = (b1 << 24) | (b2 << 16) | (b3 << 8) | (b4);