3 * Texture manipulation routines
5 * Copyright (c) Mark J. Kilgard, 1997.
6 * Code added in april 2003 by Erik Hofman
8 * This program is freely distributable without licensing fees
9 * and is provided without guarantee or warrantee expressed or
10 * implied. This program is -not- in the public domain.
15 #include <simgear/compiler.h>
22 #include "texture.hxx"
25 SGTexture::SGTexture()
30 SGTexture::SGTexture(unsigned int width, unsigned int height)
32 texture_data = new GLubyte[ width * height * 3 ];
35 SGTexture::~SGTexture()
45 glGenTextures(1, &texture_id);
47 #elif GL_EXT_texture_object
48 glGenTexturesEXT(1, &texture_id);
53 glBindTexture(GL_TEXTURE_2D, texture_id);
55 #elif GL_EXT_texture_object
56 glBindTextureEXT(GL_TEXTURE_2D, texture_id);
60 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
61 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
62 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
63 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
68 * A function to resize the OpenGL window which will be used by
69 * the dynamic texture generating routines.
71 * @param width The width of the new window
72 * @param height The height of the new window
75 SGTexture::resize(unsigned int width, unsigned int height)
79 // Make sure that we don't get a divide by zero exception
83 // Set the viewport for the OpenGL window
84 glViewport(0, 0, width, height);
86 // Calculate the aspect ratio of the window
87 aspect = width/height;
89 // Go to the projection matrix, this gets modified by the perspective
91 glMatrixMode(GL_PROJECTION);
94 // Do the perspective calculations
95 gluPerspective(45.0, aspect, 1.0, 400.0);
97 // Return to the modelview matrix
98 glMatrixMode(GL_MODELVIEW);
102 * A function to prepare the OpenGL state machine for dynamic
103 * texture generation.
105 * @param width The width of the texture
106 * @param height The height of the texture
109 SGTexture::prepare(unsigned int width, unsigned int height) {
111 texture_width = width;
112 texture_height = height;
114 // Resize the OpenGL window to the size of our dynamic texture
115 resize(texture_width, texture_height);
117 // Clear the contents of the screen buffer to blue
118 glClearColor(0.0, 0.0, 1.0, 1.0);
119 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
121 // Turn off texturing (don't want the torus to be texture);
122 glDisable(GL_TEXTURE_2D);
126 * A function to generate the dynamic texture.
128 * The actual texture can be accessed by calling get_texture()
130 * @param width The width of the previous OpenGL window
131 * @param height The height of the previous OpenGL window
134 SGTexture::finish(unsigned int width, unsigned int height) {
135 // If a texture hasn't been created then it gets created, and the contents
136 // of the frame buffer gets copied into it. If the texture has already been
137 // created then its contents just get updated.
141 // Copies the contents of the frame buffer into the texture
142 glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 0, 0,
143 texture_width, texture_height, 0);
146 // Copies the contents of the frame buffer into the texture
147 glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0,
148 texture_width, texture_height);
151 // Set the OpenGL window back to its previous size
152 resize(width, height);
154 // Clear the window back to black
155 glClearColor(0.0, 0.0, 0.0, 1.0);
156 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
161 SGTexture::read_alpha_texture(const char *name)
164 SGTexture::ImageRec *image;
170 image = ImageOpen(name);
175 texture_width = image->xsize;
176 texture_height = image->ysize;
178 // printf("image->zsize = %d\n", image->zsize);
180 if (image->zsize != 1) {
185 texture_data = new GLubyte[ image->xsize * image->ysize ];
190 for(y=0; y<image->ysize; y++) {
191 ImageGetRow(image,lptr,y,0);
192 lptr += image->xsize;
198 SGTexture::read_rgb_texture(const char *name)
201 GLubyte *rbuf, *gbuf, *bbuf, *abuf;
202 SGTexture::ImageRec *image;
208 image = ImageOpen(name);
212 texture_width = image->xsize;
213 texture_height = image->ysize;
214 if (image->zsize != 3 && image->zsize != 4) {
219 texture_data = new GLubyte[ image->xsize * image->ysize * 3];
220 rbuf = new GLubyte[ image->xsize ];
221 gbuf = new GLubyte[ image->xsize ];
222 bbuf = new GLubyte[ image->xsize ];
223 abuf = new GLubyte[ image->xsize ];
224 if(!texture_data || !rbuf || !gbuf || !bbuf || !abuf) {
234 for(y=0; y<image->ysize; y++) {
235 if(image->zsize == 4) {
236 ImageGetRow(image,rbuf,y,0);
237 ImageGetRow(image,gbuf,y,1);
238 ImageGetRow(image,bbuf,y,2);
239 ImageGetRow(image,abuf,y,3); /* Discard. */
240 rgbtorgb(rbuf,gbuf,bbuf,ptr,image->xsize);
241 ptr += (image->xsize * 3);
243 ImageGetRow(image,rbuf,y,0);
244 ImageGetRow(image,gbuf,y,1);
245 ImageGetRow(image,bbuf,y,2);
246 rgbtorgb(rbuf,gbuf,bbuf,ptr,image->xsize);
247 ptr += (image->xsize * 3);
259 SGTexture::read_raw_texture(const char *name)
262 SGTexture::ImageRec *image;
268 image = RawImageOpen(name);
274 texture_height = 256;
276 texture_data = new GLubyte[ 256 * 256 * 3 ];
281 for(y=0; y<256; y++) {
282 gzread(image->file, ptr, 256*3);
289 SGTexture::read_r8_texture(const char *name)
293 SGTexture::ImageRec *image;
299 //it wouldn't make sense to write a new function ...
300 image = RawImageOpen(name);
306 texture_height = 256;
308 texture_data = new GLubyte [ 256 * 256 * 3 ];
313 for(xy=0; xy<(256*256); xy++) {
314 gzread(image->file, c, 1);
316 //look in the table for the right colours
317 ptr[0]=msfs_colour[c[0]][0];
318 ptr[1]=msfs_colour[c[0]][1];
319 ptr[2]=msfs_colour[c[0]][2];
328 SGTexture::set_pixel(GLuint x, GLuint y, sgVec3 &c)
330 unsigned int pos = (x + y*texture_width)*3;
331 texture_data[pos] = c[0];
332 texture_data[pos+1] = c[1];
333 texture_data[pos+2] = c[2];
338 SGTexture::get_pixel(GLuint x, GLuint y)
341 unsigned int pos = (x + y*texture_width)*3;
343 sgSetVec3(c, texture_data[pos], texture_data[pos+1], texture_data[pos+2]);
349 SGTexture::ImageRec *
350 SGTexture::ImageOpen(const char *fileName)
357 SGTexture::ImageRec *image;
361 endianTest.testWord = 1;
362 if (endianTest.testByte[0] == 1) {
368 image = new SGTexture::ImageRec;
370 // fprintf(stderr, "Out of memory!\n");
373 if ((image->file = gzopen(fileName, "rb")) == 0) {
377 gzread(image->file, image, 12);
380 ConvertShort(&image->imagic, 6);
383 image->tmp = new GLubyte[ image->xsize * 256 ];
384 if (image->tmp == 0) {
385 // fprintf(stderr, "\nOut of memory!\n");
389 if ((image->type & 0xFF00) == 0x0100) {
390 x = image->ysize * image->zsize * (int) sizeof(unsigned);
391 image->rowStart = new unsigned[x];
392 image->rowSize = new int[x];
393 if (image->rowStart == 0 || image->rowSize == 0) {
394 // fprintf(stderr, "\nOut of memory!\n");
397 image->rleEnd = 512 + (2 * x);
398 gzseek(image->file, 512, SEEK_SET);
399 gzread(image->file, image->rowStart, x);
400 gzread(image->file, image->rowSize, x);
402 ConvertUint(image->rowStart, x/(int) sizeof(unsigned));
403 ConvertUint((unsigned *)image->rowSize, x/(int) sizeof(int));
411 SGTexture::ImageClose(SGTexture::ImageRec *image) {
412 gzclose(image->file);
418 SGTexture::ImageRec *
419 SGTexture::RawImageOpen(const char *fileName)
426 SGTexture::ImageRec *image;
429 endianTest.testWord = 1;
430 if (endianTest.testByte[0] == 1) {
436 image = new SGTexture::ImageRec;
438 // fprintf(stderr, "Out of memory!\n");
441 if ((image->file = gzopen(fileName, "rb")) == 0) {
445 gzread(image->file, image, 12);
448 ConvertShort(&image->imagic, 6);
452 //just allocate a pseudo value as I'm too lazy to change ImageClose()...
453 image->tmp = new GLubyte;
455 if (image->tmp == 0) {
456 // fprintf(stderr, "\nOut of memory!\n");
464 SGTexture::ImageGetRow(SGTexture::ImageRec *image, GLubyte *buf, int y, int z) {
465 GLubyte *iPtr, *oPtr, pixel;
468 if ((image->type & 0xFF00) == 0x0100) {
469 gzseek(image->file, (long) image->rowStart[y+z*image->ysize], SEEK_SET);
470 gzread(image->file, image->tmp,
471 (unsigned int)image->rowSize[y+z*image->ysize]);
477 count = (int)(pixel & 0x7F);
493 gzseek(image->file, 512+(y*image->xsize)+(z*image->xsize*image->ysize),
495 gzread(image->file, buf, image->xsize);
500 SGTexture::rgbtorgb(GLubyte *r, GLubyte *g, GLubyte *b, GLubyte *l, int n) {
505 l += 3; r++; g++; b++;
510 SGTexture::ConvertShort(unsigned short *array, unsigned int length) {
511 unsigned short b1, b2;
514 ptr = (unsigned char *)array;
518 *array++ = (b1 << 8) | (b2);
524 SGTexture::ConvertUint(unsigned *array, unsigned int length) {
525 unsigned int b1, b2, b3, b4;
528 ptr = (unsigned char *)array;
534 *array++ = (b1 << 24) | (b2 << 16) | (b3 << 8) | (b4);