1 /*
2 Copyright (C) 2007, 2010 - Bit-Blot
3
4 This file is part of Aquaria.
5
6 Aquaria is free software; you can redistribute it and/or
7 modify it under the terms of the GNU General Public License
8 as published by the Free Software Foundation; either version 2
9 of the License, or (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14
15 See the GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 */
21 #include "Texture.h"
22 #include "Core.h"
23 #include "../ExternalLibs/glpng.h"
24 #include "ByteBuffer.h"
25
26 #include <assert.h>
27
28 #if defined(BBGE_BUILD_UNIX)
29 #include <stdint.h>
30 #endif
31
32 //#include "pngLoad.h"
33 //#include "jpeg/jpeglib.h"
34 /*
35 #include <il/il.h>
36 #include <il/ilu.h>
37 #include <il/ilut.h>
38 */
39 #ifdef Z2D_J2K
40 //..\j2k-codec\j2k-codec.lib
41 #include "..\j2k-codec\j2k-codec.h"
42 #endif
43
44 #ifdef BBGE_BUILD_OPENGL
45 GLint Texture::filter = GL_LINEAR;
46
47 GLint Texture::format = 0;
48 #endif
49 bool Texture::useMipMaps = true;
50
51 /*
52 #ifdef BBGE_BUILD_OPENGL
53 #include "glext/glext.h"
54 #endif
55 */
56
57
Texture()58 Texture::Texture()
59 {
60 #ifdef BBGE_BUILD_OPENGL
61 textures[0] = 0;
62 #endif
63 #ifdef BBGE_BUILD_DIRECTX
64 d3dTexture = 0;
65 #endif
66 width = height = 0;
67
68 repeat = false;
69 repeating = false;
70 pngSetStandardOrientation(0);
71 ow = oh = -1;
72 }
73
~Texture()74 Texture::~Texture()
75 {
76 destroy();
77 }
78
read(int tx,int ty,int w,int h,unsigned char * pixels)79 void Texture::read(int tx, int ty, int w, int h, unsigned char *pixels)
80 {
81 #ifdef BBGE_BUILD_OPENGL
82 if (tx == 0 && ty == 0 && w == this->width && h == this->height)
83 {
84 glBindTexture(GL_TEXTURE_2D, textures[0]);
85 glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
86 glBindTexture(GL_TEXTURE_2D, 0);
87 }
88 else
89 {
90 std::ostringstream os;
91 os << "Unable to read a texture subimage (size = "
92 << this->width << "x" << this->height << ", requested = "
93 << tx << "," << ty << "+" << w << "x" << h << ")";
94 debugLog(os.str());
95 }
96 #endif
97 }
98
write(int tx,int ty,int w,int h,const unsigned char * pixels)99 void Texture::write(int tx, int ty, int w, int h, const unsigned char *pixels)
100 {
101 #ifdef BBGE_BUILD_OPENGL
102 glBindTexture(GL_TEXTURE_2D, textures[0]);
103
104 glTexSubImage2D(GL_TEXTURE_2D, 0,
105 tx,
106 ty,
107 w,
108 h,
109 GL_RGBA,
110 GL_UNSIGNED_BYTE,
111 pixels
112 );
113
114 glBindTexture(GL_TEXTURE_2D, 0);
115 /*
116 target Specifies the target texture. Must be
117 GL_TEXTURE_2D.
118
119 level Specifies the level-of-detail number. Level 0 is
120 the base image level. Level n is the nth mipmap
121 reduction image.
122
123 xoffset Specifies a texel offset in the x direction within
124 the texture array.
125
126 yoffset Specifies a texel offset in the y direction within
127 the texture array.
128
129 width Specifies the width of the texture subimage.
130
131 height Specifies the height of the texture subimage.
132
133 format Specifies the format of the pixel data. The
134 following symbolic values are accepted:
135 GL_COLOR_INDEX, GL_RED, GL_GREEN, GL_BLUE,
136 GL_ALPHA, GL_RGB, GL_RGBA, GL_LUMINANCE, and
137 GL_LUMINANCE_ALPHA.
138
139 type Specifies the data type of the pixel data. The
140 following symbolic values are accepted:
141 GL_UNSIGNED_BYTE, GL_BYTE, GL_BITMAP,
142 GL_UNSIGNED_SHORT, GL_SHORT, GL_UNSIGNED_INT,
143 GL_INT, and GL_FLOAT.
144
145 pixels Specifies a pointer to the image data in memory.
146 */
147 #endif
148 }
149
unload()150 void Texture::unload()
151 {
152 #ifdef BBGE_BUILD_OPENGL
153 if (textures[0])
154 {
155 ow = width;
156 oh = height;
157
158 if (core->debugLogTextures)
159 {
160 debugLog("UNLOADING TEXTURE: " + name);
161 }
162
163
164 glDeleteTextures(1, &textures[0]);
165 textures[0] = 0;
166 }
167 #endif
168 }
169
destroy()170 void Texture::destroy()
171 {
172 #ifdef BBGE_BUILD_OPENGL
173 unload();
174 #endif
175 #ifdef BBGE_BUILD_DIRECTX
176 if (d3dTexture)
177 {
178 d3dTexture->Release();
179 d3dTexture = 0;
180 }
181 #endif
182
183 core->removeTexture(this);
184 }
185
getPixelWidth()186 int Texture::getPixelWidth()
187 {
188 #ifdef BBGE_BUILD_OPENGL
189 int w = 0, h = 0;
190 unsigned int size = 0;
191 unsigned char *data = getBufferAndSize(&w, &h, &size);
192 if (!data)
193 return 0;
194
195 int smallestx = -1, largestx = -1;
196 for (unsigned int x = 0; x < unsigned(w); x++)
197 {
198 for (unsigned int y = 0; y < unsigned(h); y++)
199 {
200 unsigned int p = (y*unsigned(w)*4) + (x*4) + 3;
201 if (p < size && data[p] >= 254)
202 {
203 if (smallestx == -1 || x < smallestx)
204 smallestx = x;
205 if (largestx == -1 || x > largestx)
206 largestx = x;
207 }
208 }
209 }
210 free(data);
211 return largestx - smallestx;
212 #elif defined(BBGE_BUILD_DIRECTX)
213 return 0;
214 #endif
215 }
216
getPixelHeight()217 int Texture::getPixelHeight()
218 {
219 #ifdef BBGE_BUILD_OPENGL
220 int w = 0, h = 0;
221 unsigned int size = 0;
222 unsigned char *data = getBufferAndSize(&w, &h, &size);
223 if (!data)
224 return 0;
225
226 int smallesty = -1, largesty = -1;
227 for (unsigned int x = 0; x < unsigned(w); x++)
228 {
229 for (unsigned int y = 0; y < unsigned(h); y++)
230 {
231 int p = (y*unsigned(w)*4) + (x*4) + 3;
232 if (p < size && data[p] >= 254)
233 {
234 if (smallesty == -1 || y < smallesty)
235 smallesty = y;
236 if (largesty == -1 || y > largesty)
237 largesty = y;
238 }
239 }
240 }
241 free(data);
242 return largesty - smallesty;
243 #elif defined(BBGE_BUILD_DIRECTX)
244 return 0;
245 #endif
246 }
247
reload()248 void Texture::reload()
249 {
250 debugLog("RELOADING TEXTURE: " + name + " with loadName " + loadName + "...");
251
252 unload();
253 load(loadName);
254
255 /*if (ow != -1 && oh != -1)
256 {
257 width = ow;
258 height = oh;
259 }*/
260 debugLog("DONE");
261 }
262
load(std::string file)263 bool Texture::load(std::string file)
264 {
265 if (file.size()<4)
266 {
267 errorLog("Texture Name is Empty or Too Short");
268 return false;
269 }
270
271 stringToLowerUserData(file);
272 file = core->adjustFilenameCase(file);
273
274 loadName = file;
275 repeating = false;
276
277 size_t pos = file.find_last_of('.');
278
279 if ((pos != std::string::npos) && (pos >= 0))
280 {
281 // make sure this didn't catch the '.' in /home/username/.Aquaria/* --ryan.
282 const std::string userdata = core->getUserDataFolder();
283 const size_t len = userdata.length();
284 if (pos < len)
285 pos = std::string::npos;
286 }
287
288 /*if (core->debugLogTextures)
289 {
290 std::ostringstream os;
291 os << "pos [" << pos << "], file :" << file;
292 debugLog(os.str());
293 }*/
294
295 bool found = exists(file);
296
297 if(!found && exists(file + ".png"))
298 {
299 found = true;
300 file += ".png";
301 }
302
303 // .tga/.zga are never used as game graphics anywhere except save slot thumbnails.
304 // if so, their file names are passed exact, not with a missing extension
305
306 if (found)
307 {
308 file = localisePathInternalModpath(file);
309 file = core->adjustFilenameCase(file);
310
311 /*
312 std::ostringstream os;
313 os << "Loading texture [" << file << "]";
314 debugLog(os.str());
315 */
316 std::string post = file.substr(file.size()-3, 3);
317 stringToLower(post);
318 if (post == "png")
319 {
320
321 #ifdef BBGE_BUILD_OPENGL
322 return loadPNG(file);
323 #endif
324
325 #ifdef BBGE_BUILD_DIRECTX
326 D3DXCreateTextureFromFile(core->getD3DDevice(), file.c_str(), &this->d3dTexture);
327 if (!d3dTexture)
328 {
329 errorLog ("failed to load texture");
330 }
331 else
332 {
333 D3DSURFACE_DESC desc;
334 this->d3dTexture->GetLevelDesc(0,&desc);
335
336 width = desc.Width;
337 height = desc.Height;
338 }
339 #endif
340 }
341 else if (post == "zga")
342 {
343 return loadZGA(file);
344 }
345 else if (post == "tga")
346 {
347 return loadTGA(file);
348 }
349 else
350 {
351 debugLog("unknown image file type: " + file);
352 }
353 }
354 else
355 {
356 // load default image / leave white
357 if (core->debugLogTextures)
358 debugLog("***Could not find texture: " + file);
359 }
360 return false;
361 }
362
apply(bool repeatOverride)363 void Texture::apply(bool repeatOverride)
364 {
365 #ifdef BBGE_BUILD_OPENGL
366 glBindTexture(GL_TEXTURE_2D, textures[0]);
367 if (repeat || repeatOverride)
368 {
369 if (!repeating)
370 {
371 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
372 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
373 repeating = true;
374 }
375 }
376 else
377 {
378 if (repeating)
379 {
380 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
381 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
382 repeating = false;
383 }
384 }
385 #endif
386 #ifdef BBGE_BUILD_DIRECTX
387 core->getD3DDevice()->SetTexture(0, d3dTexture);
388
389 #endif
390 }
391
unbind()392 void Texture::unbind()
393 {
394 }
395
loadPNG(const std::string & file)396 bool Texture::loadPNG(const std::string &file)
397 {
398 if (file.empty()) return false;
399 bool good = false;
400
401 #ifdef BBGE_BUILD_OPENGL
402
403
404 pngInfo info;
405
406 int pngType = PNG_ALPHA;
407
408 if (format != 0)
409 {
410 if (format == GL_LUMINANCE_ALPHA)
411 pngType = PNG_LUMINANCEALPHA;
412 }
413
414 unsigned long memsize = 0;
415 const char *memptr = readFile(file, &memsize);
416 if(!memptr || !memsize)
417 goto fail;
418
419 if (filter == GL_NEAREST)
420 {
421 textures[0] = pngBindMem(memptr, memsize, PNG_NOMIPMAPS, pngType, &info, GL_CLAMP_TO_EDGE, filter, filter);
422 }
423 else
424 {
425 textures[0] = pngBindMem(memptr, memsize, PNG_BUILDMIPMAPS, pngType, &info, GL_CLAMP_TO_EDGE, GL_LINEAR_MIPMAP_LINEAR, filter);
426 }
427
428 if (textures[0] != 0)
429 {
430 width = info.Width;
431 height = info.Height;
432 good = true;
433 }
434 else
435 {
436 fail:
437
438 debugLog("Can't load PNG file: " + file);
439 }
440
441 if(memptr)
442 delete [] memptr;
443
444 #endif
445 return good;
446 }
447
448 // internal load functions
loadTGA(const std::string & file)449 bool Texture::loadTGA(const std::string &file)
450 {
451 return loadTGA(TGAload(file.c_str()));
452 }
453
loadZGA(const std::string & file)454 bool Texture::loadZGA(const std::string &file)
455 {
456 unsigned long size = 0;
457 char *buf = readCompressedFile(file, &size);
458 ImageTGA *tga = TGAloadMem(buf, size);
459 if (!tga)
460 {
461 debugLog("Can't load ZGA File: " + file);
462 return false;
463 }
464 return loadTGA(tga);
465 }
466
loadTGA(ImageTGA * imageTGA)467 bool Texture::loadTGA(ImageTGA *imageTGA)
468 {
469 if (!imageTGA)
470 return false;
471
472 glGenTextures(1, &textures[0]);
473 glBindTexture(GL_TEXTURE_2D, textures[0]);
474 glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,filter); // Linear Filtering
475 glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,filter); // Linear Filtering
476
477 if (imageTGA->channels==3)
478 glTexImage2D(GL_TEXTURE_2D, 0, 3, imageTGA->sizeX, imageTGA->sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, imageTGA->data);
479 else if (imageTGA->channels==4)
480 glTexImage2D(GL_TEXTURE_2D, 0, 4,imageTGA->sizeX, imageTGA->sizeY, 0, GL_RGBA, GL_UNSIGNED_BYTE, imageTGA->data);
481
482 width = imageTGA->sizeX;
483 height = imageTGA->sizeY;
484
485 if (imageTGA->data)
486 delete[] (imageTGA->data);
487 free (imageTGA);
488
489 return true;
490 }
491
492
493 #define TGA_RGB 2 // This tells us it's a normal RGB (really BGR) file
494 #define TGA_A 3 // This tells us it's a ALPHA file
495 #define TGA_RLE 10 // This tells us that the targa is Run-Length Encoded (RLE)
496
497 #if defined(BBGE_BUILD_UNIX)
498 typedef uint8_t byte;
499 typedef uint16_t WORD;
500 #endif
501
502
503 #ifdef BBGE_BUILD_WINDOWS
504 #define byte char
505 #endif
506
TGAload(const char * filename)507 ImageTGA *Texture::TGAload(const char *filename)
508 {
509 unsigned long size = 0;
510 char *rawbuf = readFile(filename, &size);
511 ImageTGA *tga = TGAloadMem(rawbuf, size);
512 if (rawbuf)
513 delete [] rawbuf;
514 if (!tga)
515 {
516 debugLog("Can't load TGA File!");
517 return NULL;
518 }
519 return tga;
520 }
521
TGAloadMem(void * mem,int size)522 ImageTGA *Texture::TGAloadMem(void *mem, int size)
523 {
524 if (!mem || size < 20)
525 return NULL;
526
527 ByteBuffer bb(mem, size, ByteBuffer::REUSE);
528
529 ImageTGA *pImageData = NULL; // This stores our important image data
530 WORD width = 0, height = 0; // The dimensions of the image
531 byte length = 0; // The length in bytes to the pixels
532 byte imageType = 0; // The image type (RLE, RGB, Alpha...)
533 byte bits = 0; // The bits per pixel for the image (16, 24, 32)
534 int channels = 0; // The channels of the image (3 = RGA : 4 = RGBA)
535 int stride = 0; // The stride (channels * width)
536 int i = 0; // A counter
537
538 // This function loads in a TARGA (.TGA) file and returns its data to be
539 // used as a texture or what have you. This currently loads in a 16, 24
540 // and 32-bit targa file, along with RLE compressed files. Eventually you
541 // will want to do more error checking to make it more robust. This is
542 // also a perfect start to go into a modular class for an engine.
543 // Basically, how it works is, you read in the header information, then
544 // move your file pointer to the pixel data. Before reading in the pixel
545 // data, we check to see the if it's an RLE compressed image. This is because
546 // we will handle it different. If it isn't compressed, then we need another
547 // check to see if we need to convert it from 16-bit to 24 bit. 24-bit and
548 // 32-bit textures are very similar, so there's no need to do anything special.
549 // We do, however, read in an extra bit for each color.
550
551
552 // Allocate the structure that will hold our eventual image data (must free it!)
553 pImageData = (ImageTGA*)malloc(sizeof(ImageTGA));
554
555 // Read in the length in bytes from the header to the pixel data
556 bb >> length;
557
558 // Jump over one byte
559 bb.skipRead(1);
560
561 // Read in the imageType (RLE, RGB, etc...)
562 //fread(&imageType, sizeof(byte), 1, pFile);
563 bb >> imageType;
564
565 // Skip past general information we don't care about
566 bb.skipRead(9);
567
568 // Read the width, height and bits per pixel (16, 24 or 32)
569 bb >> width >> height >> bits;
570
571 /*
572 std::ostringstream os;
573 os << "TGALoad: width: " << width << " height: " << height << " bits: " << bits;
574 debugLog(os.str());
575 */
576
577 // Now we move the file pointer to the pixel data
578 bb.skipRead(length + 1);
579
580 // Check if the image is RLE compressed or not
581 if(imageType != TGA_RLE)
582 {
583 // Check if the image is a 24 or 32-bit image
584 if(bits == 24 || bits == 32)
585 {
586 // Calculate the channels (3 or 4) - (use bits >> 3 for more speed).
587 // Next, we calculate the stride and allocate enough memory for the pixels.
588 channels = bits / 8;
589 stride = channels * width;
590 pImageData->data = new unsigned char[stride * height];
591
592 // Load in all the pixel data line by line
593 for(int y = 0; y < height; y++)
594 {
595 // Store a pointer to the current line of pixels
596 unsigned char *pLine = &(pImageData->data[stride * y]);
597
598 // Read in the current line of pixels
599 if (bb.readable() < stride)
600 break;
601 bb.read(pLine, stride);
602
603 // Go through all of the pixels and swap the B and R values since TGA
604 // files are stored as BGR instead of RGB (or use GL_BGR_EXT verses GL_RGB)
605 for(i = 0; i < stride; i += channels)
606 {
607 int temp = pLine[i];
608 pLine[i] = pLine[i + 2];
609 pLine[i + 2] = temp;
610 }
611 }
612 }
613 // Check if the image is a 16 bit image (RGB stored in 1 unsigned short)
614 else if(bits == 16)
615 {
616 unsigned short pixels = 0;
617 int r=0, g=0, b=0;
618
619 // Since we convert 16-bit images to 24 bit, we hardcode the channels to 3.
620 // We then calculate the stride and allocate memory for the pixels.
621 channels = 3;
622 stride = channels * width;
623 pImageData->data = new unsigned char[stride * height];
624
625 // Load in all the pixel data pixel by pixel
626 for(int i = 0; i < width*height; i++)
627 {
628 // Read in the current pixel
629 if (bb.readable() < sizeof(unsigned char))
630 break;
631 bb >> pixels;
632
633 // To convert a 16-bit pixel into an R, G, B, we need to
634 // do some masking and such to isolate each color value.
635 // 0x1f = 11111 in binary, so since 5 bits are reserved in
636 // each unsigned short for the R, G and B, we bit shift and mask
637 // to find each value. We then bit shift up by 3 to get the full color.
638 b = (pixels & 0x1f) << 3;
639 g = ((pixels >> 5) & 0x1f) << 3;
640 r = ((pixels >> 10) & 0x1f) << 3;
641
642 // This essentially assigns the color to our array and swaps the
643 // B and R values at the same time.
644 pImageData->data[i * 3 + 0] = r;
645 pImageData->data[i * 3 + 1] = g;
646 pImageData->data[i * 3 + 2] = b;
647 }
648 }
649 // Else return a NULL for a bad or unsupported pixel format
650 else
651 return NULL;
652 }
653 // Else, it must be Run-Length Encoded (RLE)
654 else
655 {
656 // First, let me explain real quickly what RLE is.
657 // For further information, check out Paul Bourke's intro article at:
658 // http://astronomy.swin.edu.au/~pbourke/dataformats/rle/
659 //
660 // Anyway, we know that RLE is a basic type compression. It takes
661 // colors that are next to each other and then shrinks that info down
662 // into the color and a integer that tells how much of that color is used.
663 // For instance:
664 // aaaaabbcccccccc would turn into a5b2c8
665 // Well, that's fine and dandy and all, but how is it down with RGB colors?
666 // Simple, you read in an color count (rleID), and if that number is less than 128,
667 // it does NOT have any optimization for those colors, so we just read the next
668 // pixels normally. Say, the color count was 28, we read in 28 colors like normal.
669 // If the color count is over 128, that means that the next color is optimized and
670 // we want to read in the same pixel color for a count of (colorCount - 127).
671 // It's 127 because we add 1 to the color count, as you'll notice in the code.
672
673 // Create some variables to hold the rleID, current colors read, channels, & stride.
674 byte rleID = 0;
675 int colorsRead = 0;
676 channels = bits / 8;
677 stride = channels * width;
678
679 // Next we want to allocate the memory for the pixels and create an array,
680 // depending on the channel count, to read in for each pixel.
681 pImageData->data = new unsigned char[stride * height];
682 byte *pColors = new byte [channels];
683
684 // Load in all the pixel data
685 while(i < width*height)
686 {
687 // Read in the current color count + 1
688 bb >> rleID;
689
690 // Check if we don't have an encoded string of colors
691 if(rleID < 128)
692 {
693 // Increase the count by 1
694 rleID++;
695
696 // Go through and read all the unique colors found
697 while(rleID)
698 {
699 // Read in the current color
700 if (bb.readable() < channels)
701 break;
702 bb.read(pColors, channels);
703
704 // Store the current pixel in our image array
705 pImageData->data[colorsRead + 0] = pColors[2];
706 pImageData->data[colorsRead + 1] = pColors[1];
707 pImageData->data[colorsRead + 2] = pColors[0];
708
709 // If we have a 4 channel 32-bit image, assign one more for the alpha
710 if(bits == 32)
711 pImageData->data[colorsRead + 3] = pColors[3];
712
713 // Increase the current pixels read, decrease the amount
714 // of pixels left, and increase the starting index for the next pixel.
715 i++;
716 rleID--;
717 colorsRead += channels;
718 }
719 }
720 // Else, let's read in a string of the same character
721 else
722 {
723 // Minus the 128 ID + 1 (127) to get the color count that needs to be read
724 rleID -= 127;
725
726 // Read in the current color, which is the same for a while
727 if (bb.readable() < channels)
728 break;
729 bb.read(pColors, channels);
730
731 // Go and read as many pixels as are the same
732 while(rleID)
733 {
734 // Assign the current pixel to the current index in our pixel array
735 pImageData->data[colorsRead + 0] = pColors[2];
736 pImageData->data[colorsRead + 1] = pColors[1];
737 pImageData->data[colorsRead + 2] = pColors[0];
738
739 // If we have a 4 channel 32-bit image, assign one more for the alpha
740 if(bits == 32)
741 pImageData->data[colorsRead + 3] = pColors[3];
742
743 // Increase the current pixels read, decrease the amount
744 // of pixels left, and increase the starting index for the next pixel.
745 i++;
746 rleID--;
747 colorsRead += channels;
748 }
749
750 }
751
752 }
753
754 // Free up pColors
755 delete[] pColors;
756 }
757
758 // Fill in our tImageTGA structure to pass back
759 pImageData->channels = channels;
760 pImageData->sizeX = width;
761 pImageData->sizeY = height;
762
763 // Return the TGA data (remember, you must free this data after you are done)
764 return pImageData;
765 }
766
767 // ceil to next power of 2
clp2(unsigned int x)768 static unsigned int clp2(unsigned int x)
769 {
770 --x;
771 x |= (x >> 1);
772 x |= (x >> 2);
773 x |= (x >> 4);
774 x |= (x >> 8);
775 x |= (x >> 16);
776 return x + 1;
777 }
778
getBufferAndSize(int * wparam,int * hparam,unsigned int * sizeparam)779 unsigned char * Texture::getBufferAndSize(int *wparam, int *hparam, unsigned int *sizeparam)
780 {
781 unsigned char *data = NULL;
782 unsigned int size = 0;
783 int tw = 0, th = 0;
784 int w = 0, h = 0;
785
786 // This can't happen. If it does we're doomed.
787 if(width <= 0 || height <= 0)
788 goto fail;
789
790 glBindTexture(GL_TEXTURE_2D, textures[0]);
791
792 // As returned by graphics driver
793
794 glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &w);
795 glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &h);
796
797 // As we know it - but round to nearest power of 2 - OpenGL does this internally anyways.
798 tw = clp2(width); // known to be > 0.
799 th = clp2(height);
800
801 if (w != tw || h != th)
802 {
803 std::ostringstream os;
804 os << "Texture::getBufferAndSize() WARNING: width/height disagree: ";
805 os << "Driver says (" << w << ", " << h << "); ";
806 os << "Texture says (" << width << ", " << height << "); ";
807 os << "Rounded to (" << tw << ", " << th << ")";
808 debugLog(os.str());
809 // choose max. for size calculation
810 w = w > tw ? w : tw;
811 h = h > th ? h : th;
812 }
813
814 size = w * h * 4;
815 if (!size)
816 goto fail;
817
818 data = (unsigned char*)malloc(size + 32);
819 if (!data)
820 {
821 std::ostringstream os;
822 os << "Game::fillGridFromQuad allocation failure, size = " << size;
823 errorLog(os.str());
824 goto fail;
825 }
826 memcpy(data + size, "SAFE", 5);
827 glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
828 glBindTexture(GL_TEXTURE_2D, 0);
829
830 // Not sure but this might be the case with nouveau drivers on linux... still investigating. -- fg
831 if(memcmp(data + size, "SAFE", 5))
832 {
833 errorLog("Texture::getBufferAndSize(): Broken graphics driver! Wrote past end of buffer!");
834 free(data); // in case we are here, this will most likely cause a crash.
835 goto fail;
836 }
837
838 *wparam = w;
839 *hparam = h;
840 *sizeparam = size;
841 return data;
842
843
844 fail:
845 *wparam = 0;
846 *hparam = 0;
847 *sizeparam = 0;
848 return NULL;
849 }
850