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>
24 #include "texture.hxx"
27 SGTexture::SGTexture()
34 SGTexture::SGTexture(unsigned int width, unsigned int height)
37 texture_data = new GLubyte[ width * height * 3 ];
40 SGTexture::~SGTexture()
46 if ( texture_id != 0 ) {
57 glGenTextures(1, &texture_id);
59 #elif GL_EXT_texture_object
60 glGenTexturesEXT(1, &texture_id);
66 glBindTexture(GL_TEXTURE_2D, texture_id);
68 #elif GL_EXT_texture_object
69 glBindTextureEXT(GL_TEXTURE_2D, texture_id);
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);
81 * A function to resize the OpenGL window which will be used by
82 * the dynamic texture generating routines.
84 * @param width The width of the new window
85 * @param height The height of the new window
88 SGTexture::resize(unsigned int width, unsigned int height)
92 // Make sure that we don't get a divide by zero exception
96 // Set the viewport for the OpenGL window
97 glViewport(0, 0, width, height);
99 // Calculate the aspect ratio of the window
100 aspect = width/height;
102 // Go to the projection matrix, this gets modified by the perspective
104 glMatrixMode(GL_PROJECTION);
107 // Do the perspective calculations
108 gluPerspective(45.0, aspect, 1.0, 400.0);
110 // Return to the modelview matrix
111 glMatrixMode(GL_MODELVIEW);
115 * A function to prepare the OpenGL state machine for dynamic
116 * texture generation.
118 * @param width The width of the texture
119 * @param height The height of the texture
122 SGTexture::prepare(unsigned int width, unsigned int height) {
124 texture_width = width;
125 texture_height = height;
127 // Resize the OpenGL window to the size of our dynamic texture
128 resize(texture_width, texture_height);
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);
134 // Turn off texturing (don't want the torus to be texture);
135 glDisable(GL_TEXTURE_2D);
139 * A function to generate the dynamic texture.
141 * The actual texture can be accessed by calling get_texture()
143 * @param width The width of the previous OpenGL window
144 * @param height The height of the previous OpenGL window
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.
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);
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);
164 // Set the OpenGL window back to its previous size
165 resize(width, height);
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);
174 SGTexture::read_alpha_texture(const char *name)
177 SGTexture::ImageRec *image;
183 image = ImageOpen(name);
188 texture_width = image->xsize;
189 texture_height = image->ysize;
191 // printf("image->zsize = %d\n", image->zsize);
193 if (image->zsize != 1) {
198 texture_data = new GLubyte[ image->xsize * image->ysize ];
204 for(y=0; y<image->ysize; y++) {
205 ImageGetRow(image,lptr,y,0);
206 lptr += image->xsize;
212 SGTexture::read_rgb_texture(const char *name)
215 GLubyte *rbuf, *gbuf, *bbuf, *abuf;
216 SGTexture::ImageRec *image;
222 image = ImageOpen(name);
226 texture_width = image->xsize;
227 texture_height = image->ysize;
228 if (image->zsize != 3 && image->zsize != 4) {
233 texture_data = new GLubyte[ image->xsize * image->ysize * 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) {
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);
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);
276 SGTexture::read_rgba_texture(const char *name)
279 GLubyte *rbuf, *gbuf, *bbuf, *abuf;
280 SGTexture::ImageRec *image;
286 image = ImageOpen(name);
290 texture_width = image->xsize;
291 texture_height = image->ysize;
292 if (image->zsize != 3 && image->zsize != 4) {
297 texture_data = new GLubyte[ image->xsize * image->ysize * 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) {
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);
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);
339 SGTexture::read_raw_texture(const char *name)
342 SGTexture::ImageRec *image;
348 image = RawImageOpen(name);
354 texture_height = 256;
356 texture_data = new GLubyte[ 256 * 256 * 3 ];
361 for(y=0; y<256; y++) {
362 gzread(image->file, ptr, 256*3);
369 SGTexture::read_r8_texture(const char *name)
373 SGTexture::ImageRec *image;
379 //it wouldn't make sense to write a new function ...
380 image = RawImageOpen(name);
386 texture_height = 256;
388 texture_data = new GLubyte [ 256 * 256 * 3 ];
393 for(xy=0; xy<(256*256); xy++) {
394 gzread(image->file, c, 1);
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];
408 SGTexture::set_pixel(GLuint x, GLuint y, sgVec3 &c)
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);
421 SGTexture::get_pixel(GLuint x, GLuint y)
425 sgSetVec3(c, 0, 0, 0);
429 unsigned int pos = (x + y*texture_width)*3;
431 sgSetVec3(c, texture_data[pos], texture_data[pos+1], texture_data[pos+2]);
436 SGTexture::ImageRec *
437 SGTexture::ImageOpen(const char *fileName)
444 SGTexture::ImageRec *image;
448 endianTest.testWord = 1;
449 if (endianTest.testByte[0] == 1) {
455 image = new SGTexture::ImageRec;
457 // fprintf(stderr, "Out of memory!\n");
460 if ((image->file = gzopen(fileName, "rb")) == 0) {
464 gzread(image->file, image, 12);
467 ConvertShort(&image->imagic, 6);
470 image->tmp = new GLubyte[ image->xsize * 256 ];
471 if (image->tmp == 0) {
472 // fprintf(stderr, "\nOut of memory!\n");
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");
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);
489 ConvertUint(image->rowStart, x/(int) sizeof(unsigned));
490 ConvertUint((unsigned *)image->rowSize, x/(int) sizeof(int));
498 SGTexture::ImageClose(SGTexture::ImageRec *image) {
499 gzclose(image->file);
505 SGTexture::ImageRec *
506 SGTexture::RawImageOpen(const char *fileName)
513 SGTexture::ImageRec *image;
516 endianTest.testWord = 1;
517 if (endianTest.testByte[0] == 1) {
523 image = new SGTexture::ImageRec;
525 // fprintf(stderr, "Out of memory!\n");
528 if ((image->file = gzopen(fileName, "rb")) == 0) {
532 gzread(image->file, image, 12);
535 ConvertShort(&image->imagic, 6);
539 //just allocate a pseudo value as I'm too lazy to change ImageClose()...
540 image->tmp = new GLubyte;
542 if (image->tmp == 0) {
543 // fprintf(stderr, "\nOut of memory!\n");
551 SGTexture::ImageGetRow(SGTexture::ImageRec *image, GLubyte *buf, int y, int z) {
552 GLubyte *iPtr, *oPtr, pixel;
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]);
564 count = (int)(pixel & 0x7F);
580 gzseek(image->file, 512+(y*image->xsize)+(z*image->xsize*image->ysize),
582 gzread(image->file, buf, image->xsize);
587 SGTexture::rgbtorgb(GLubyte *r, GLubyte *g, GLubyte *b, GLubyte *l, int n) {
592 l += 3; r++; g++; b++;
597 SGTexture::rgbatorgba(GLubyte *r, GLubyte *g, GLubyte *b, GLubyte *a,
604 l += 4; r++; g++; b++; a++;
610 SGTexture::ConvertShort(unsigned short *array, unsigned int length) {
611 unsigned short b1, b2;
614 ptr = (unsigned char *)array;
618 *array++ = (b1 << 8) | (b2);
624 SGTexture::ConvertUint(unsigned *array, unsigned int length) {
625 unsigned int b1, b2, b3, b4;
628 ptr = (unsigned char *)array;
634 *array++ = (b1 << 24) | (b2 << 16) | (b3 << 8) | (b4);