00001
00002
00003
00004
00005
00006
00007
00008
00009
00010 #ifndef MACOSX
00011 #define JPEG_SUPPORT
00012 #define PNG_SUPPORT
00013 #endif
00014
00015 #ifdef MACOSX
00016 #include <unistd.h>
00017 #include "CGBuffer.h"
00018 #ifndef PNG_SUPPORT
00019 #include <Quicktime/ImageCompression.h>
00020 #include <QuickTime/QuickTimeComponents.h>
00021 #endif
00022 #endif
00023
00024 #include <cmath>
00025 #include <algorithm>
00026 #include <iostream>
00027 #include <fstream>
00028 #include <cstdlib>
00029 #include <cstdio>
00030 #include <cassert>
00031
00032 #ifndef _WIN32
00033 #ifndef MACOSX
00034 #include <config.h>
00035 #endif
00036 #endif
00037
00038 #include <celmath/vecmath.h>
00039 #include <celutil/filetype.h>
00040 #include <celutil/debug.h>
00041
00042 #include "gl.h"
00043 #include "glext.h"
00044 #include "celestia.h"
00045
00046
00047
00048 #ifndef GL_TEXTURE_MAX_LEVEL
00049 #define GL_TEXTURE_MAX_LEVEL 0x813D
00050 #endif
00051
00052 #ifdef JPEG_SUPPORT
00053
00054 #ifndef PNG_SUPPORT
00055 #include "setjmp.h"
00056 #endif // PNG_SUPPORT
00057
00058 extern "C" {
00059 #ifdef _WIN32
00060 #include "jpeglib.h"
00061 #else
00062 #include <jpeglib.h>
00063 #endif
00064 }
00065
00066 #endif // JPEG_SUPPORT
00067
00068 #ifdef PNG_SUPPORT // PNG_SUPPORT
00069 #ifdef MACOSX
00070 #include "../../macosx/png.h"
00071 #else
00072 #include "png.h"
00073 #endif // MACOSX
00074
00075
00076 #ifndef png_jmpbuf
00077 #define png_jmpbuf(png_ptr) png_ptr->jmpbuf
00078 #endif // PNG_SUPPORT
00079
00080
00081 #if PNG_LIBPNG_VER < 10004
00082 #define png_set_palette_to_rgb(p) png_set_expand(p)
00083 #define png_set_gray_1_2_4_to_8(p) png_set_expand(p)
00084 #define png_set_tRNS_to_alpha(p) png_set_expand(p)
00085 #endif // PNG_LIBPNG_VER < 10004
00086
00087 #endif // PNG_SUPPORT
00088
00089 #include "texture.h"
00090 #include "virtualtex.h"
00091
00092 using namespace std;
00093
00094 static bool texCapsInitialized = false;
00095
00096 struct TextureCaps
00097 {
00098 bool compressionSupported;
00099 bool clampToEdgeSupported;
00100 bool clampToBorderSupported;
00101 bool autoMipMapSupported;
00102 bool maxLevelSupported;
00103 GLint maxTextureSize;
00104 };
00105
00106 static TextureCaps texCaps;
00107
00108
00109 static bool testMaxLevel()
00110 {
00111 unsigned char texels[64];
00112
00113 glEnable(GL_TEXTURE_2D);
00114
00115 glTexImage2D(GL_TEXTURE_2D,
00116 0,
00117 GL_LUMINANCE,
00118 8, 8,
00119 0,
00120 GL_LUMINANCE,
00121 GL_UNSIGNED_BYTE,
00122 texels);
00123 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 2);
00124 float maxLev = -1.0f;
00125 glGetTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, &maxLev);
00126 glDisable(GL_TEXTURE_2D);
00127
00128 return maxLev == 2;
00129 }
00130
00131
00132 static const TextureCaps& GetTextureCaps()
00133 {
00134 if (!texCapsInitialized)
00135 {
00136 texCapsInitialized = true;
00137 texCaps.compressionSupported = ExtensionSupported("GL_ARB_texture_compression");
00138 if (texCaps.compressionSupported)
00139 InitExtension("GL_ARB_texture_compression");
00140
00141 #ifdef GL_VERSION_1_2
00142 texCaps.clampToEdgeSupported = true;
00143 #else
00144 texCaps.clampToEdgeSupported = ExtensionSupported("GL_EXT_texture_edge_clamp");
00145 #endif // GL_VERSION_1_2
00146 texCaps.clampToBorderSupported = ExtensionSupported("GL_ARB_texture_border_clamp");
00147 texCaps.autoMipMapSupported = ExtensionSupported("GL_SGIS_generate_mipmap");
00148 texCaps.maxLevelSupported = testMaxLevel();
00149 glGetIntegerv(GL_MAX_TEXTURE_SIZE, &texCaps.maxTextureSize);
00150 }
00151
00152 return texCaps;
00153 }
00154
00155
00156
00157 static int getInternalFormat(int format)
00158 {
00159 switch (format)
00160 {
00161 case GL_RGBA:
00162 case GL_BGRA_EXT:
00163 return 4;
00164 case GL_RGB:
00165 case GL_BGR_EXT:
00166 return 3;
00167 case GL_LUMINANCE_ALPHA:
00168 return 2;
00169 case GL_ALPHA:
00170 case GL_INTENSITY:
00171 case GL_LUMINANCE:
00172 return 1;
00173 case GL_DSDT_NV:
00174 return format;
00175 case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
00176 case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
00177 case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
00178 return format;
00179 default:
00180 return 0;
00181 }
00182 }
00183
00184
00185 #if 0
00186
00187
00188 static int getCompressedInternalFormat(int format)
00189 {
00190 switch (format)
00191 {
00192 case GL_RGB:
00193 case GL_BGR_EXT:
00194 return GL_COMPRESSED_RGB_ARB;
00195 case GL_RGBA:
00196 case GL_BGRA_EXT:
00197 return GL_COMPRESSED_RGBA_ARB;
00198 case GL_ALPHA:
00199 return GL_COMPRESSED_ALPHA_ARB;
00200 case GL_LUMINANCE:
00201 return GL_COMPRESSED_LUMINANCE_ARB;
00202 case GL_LUMINANCE_ALPHA:
00203 return GL_COMPRESSED_LUMINANCE_ALPHA_ARB;
00204 case GL_INTENSITY:
00205 return GL_COMPRESSED_INTENSITY_ARB;
00206 case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
00207 case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
00208 case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
00209 return format;
00210 default:
00211 return 0;
00212 }
00213 }
00214 #endif
00215
00216
00217 static int getCompressedBlockSize(int format)
00218 {
00219 if (format == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT)
00220 return 8;
00221 else
00222 return 16;
00223 }
00224
00225
00226 static GLenum GetGLTexAddressMode(Texture::AddressMode addressMode)
00227 {
00228 const TextureCaps& caps = GetTextureCaps();
00229
00230 switch (addressMode)
00231 {
00232 case Texture::Wrap:
00233 return GL_REPEAT;
00234
00235 case Texture::EdgeClamp:
00236 return caps.clampToEdgeSupported ? GL_CLAMP_TO_EDGE : GL_CLAMP;
00237
00238 case Texture::BorderClamp:
00239 if (caps.clampToBorderSupported)
00240 return GL_CLAMP_TO_BORDER_ARB;
00241 else
00242 return caps.clampToEdgeSupported ? GL_CLAMP_TO_EDGE : GL_CLAMP;
00243 }
00244
00245 return 0;
00246 }
00247
00248
00249 static void SetBorderColor(Color borderColor, GLenum target)
00250 {
00251 float bc[4] = { borderColor.red(), borderColor.green(),
00252 borderColor.blue(), borderColor.alpha() };
00253 glTexParameterfv(target, GL_TEXTURE_BORDER_COLOR, bc);
00254 }
00255
00256
00257
00258
00259 static void LoadMipmapSet(Image& img, GLenum target)
00260 {
00261 int internalFormat = getInternalFormat(img.getFormat());
00262
00263 for (int mip = 0; mip < img.getMipLevelCount(); mip++)
00264 {
00265 uint mipWidth = max((uint) img.getWidth() >> mip, 1u);
00266 uint mipHeight = max((uint) img.getHeight() >> mip, 1u);
00267
00268 if (img.isCompressed())
00269 {
00270 glx::glCompressedTexImage2DARB(target,
00271 mip,
00272 internalFormat,
00273 mipWidth, mipHeight,
00274 0,
00275 img.getMipLevelSize(mip),
00276 img.getMipLevel(mip));
00277 }
00278 else
00279 {
00280 glTexImage2D(target,
00281 mip,
00282 internalFormat,
00283 mipWidth, mipHeight,
00284 0,
00285 (GLenum) img.getFormat(),
00286 GL_UNSIGNED_BYTE,
00287 img.getMipLevel(mip));
00288 }
00289 }
00290 }
00291
00292
00293
00294 static void LoadMiplessTexture(Image& img, GLenum target)
00295 {
00296 int internalFormat = getInternalFormat(img.getFormat());
00297
00298 if (img.isCompressed())
00299 {
00300 glx::glCompressedTexImage2DARB(target,
00301 0,
00302 internalFormat,
00303 img.getWidth(), img.getHeight(),
00304 0,
00305 img.getMipLevelSize(0),
00306 img.getMipLevel(0));
00307 }
00308 else
00309 {
00310 glTexImage2D(target,
00311 0,
00312 internalFormat,
00313 img.getWidth(), img.getHeight(),
00314 0,
00315 (GLenum) img.getFormat(),
00316 GL_UNSIGNED_BYTE,
00317 img.getMipLevel(0));
00318 }
00319 }
00320
00321
00322 static int ilog2(unsigned int x)
00323 {
00324 int n = -1;
00325
00326 while (x != 0)
00327 {
00328 x >>= 1;
00329 n++;
00330 }
00331
00332 return n;
00333 }
00334
00335
00336 static int CalcMipLevelCount(int w, int h)
00337 {
00338 return max(ilog2(w), ilog2(h)) + 1;
00339 }
00340
00341
00342 Texture::Texture(int w, int h, int d) :
00343 width(w), height(h), depth(d), alpha(false)
00344 {
00345 }
00346
00347
00348 Texture::~Texture()
00349 {
00350 }
00351
00352
00353 int Texture::getLODCount() const
00354 {
00355 return 1;
00356 }
00357
00358
00359 int Texture::getUTileCount(int) const
00360 {
00361 return 1;
00362 }
00363
00364
00365 int Texture::getVTileCount(int) const
00366 {
00367 return 1;
00368 }
00369
00370
00371 int Texture::getWTileCount(int) const
00372 {
00373 return 1;
00374 }
00375
00376
00377 void Texture::setBorderColor(Color)
00378 {
00379 }
00380
00381
00382 int Texture::getWidth() const
00383 {
00384 return width;
00385 }
00386
00387
00388 int Texture::getHeight() const
00389 {
00390 return height;
00391 }
00392
00393
00394 int Texture::getDepth() const
00395 {
00396 return depth;
00397 }
00398
00399
00400
00401 ImageTexture::ImageTexture(Image& img,
00402 AddressMode addressMode,
00403 MipMapMode mipMapMode) :
00404 Texture(img.getWidth(), img.getHeight()),
00405 glName(0)
00406 {
00407 glGenTextures(1, (GLuint*)&glName);
00408 glBindTexture(GL_TEXTURE_2D, glName);
00409
00410 bool mipmap = mipMapMode == DefaultMipMaps;
00411 bool precomputedMipMaps = false;
00412
00413
00414 int mipLevelCount = img.getMipLevelCount();
00415 if (mipmap &&
00416 mipLevelCount == CalcMipLevelCount(img.getWidth(), img.getHeight()))
00417 precomputedMipMaps = true;
00418
00419
00420
00421 if (!precomputedMipMaps && img.isCompressed())
00422 mipmap = false;
00423
00424 GLenum texAddress = GetGLTexAddressMode(addressMode);
00425 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, texAddress);
00426 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, texAddress);
00427 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
00428 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
00429 mipmap ? GL_LINEAR_MIPMAP_LINEAR : GL_LINEAR);
00430
00431 if (mipMapMode == AutoMipMaps)
00432 glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP_SGIS, GL_TRUE);
00433
00434 int internalFormat = getInternalFormat(img.getFormat());
00435
00436 if (mipmap)
00437 {
00438 #if 0
00439 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL,
00440 maxMipMapLevel);
00441 #endif
00442 if (precomputedMipMaps)
00443 {
00444 LoadMipmapSet(img, GL_TEXTURE_2D);
00445 }
00446 else
00447 {
00448 gluBuild2DMipmaps(GL_TEXTURE_2D,
00449 internalFormat,
00450 getWidth(), getHeight(),
00451 (GLenum) img.getFormat(),
00452 GL_UNSIGNED_BYTE,
00453 img.getPixels());
00454 }
00455 }
00456 else
00457 {
00458 LoadMiplessTexture(img, GL_TEXTURE_2D);
00459 }
00460
00461 alpha = img.hasAlpha();
00462 }
00463
00464
00465 ImageTexture::~ImageTexture()
00466 {
00467 if (glName != 0)
00468 glDeleteTextures(1, (const GLuint*) &glName);
00469 }
00470
00471
00472 void ImageTexture::bind()
00473 {
00474 glBindTexture(GL_TEXTURE_2D, glName);
00475 }
00476
00477
00478 const TextureTile ImageTexture::getTile(int lod, int u, int v)
00479 {
00480 if (lod != 0 || u != 0 || v != 0)
00481 return TextureTile(0);
00482 else
00483 return TextureTile(glName);
00484 }
00485
00486
00487 unsigned int ImageTexture::getName() const
00488 {
00489 return glName;
00490 }
00491
00492
00493 void ImageTexture::setBorderColor(Color borderColor)
00494 {
00495 bind();
00496 SetBorderColor(borderColor, GL_TEXTURE_2D);
00497 }
00498
00499
00500 TiledTexture::TiledTexture(Image& img,
00501 int _uSplit, int _vSplit,
00502 MipMapMode mipMapMode) :
00503 Texture(img.getWidth(), img.getHeight()),
00504 uSplit(_uSplit),
00505 vSplit(_vSplit),
00506 glNames(NULL)
00507 {
00508 glNames = new uint[uSplit * vSplit];
00509 {
00510 for (int i = 0; i < uSplit * vSplit; i++)
00511 glNames[i] = 0;
00512 }
00513
00514 alpha = img.hasAlpha();
00515
00516 bool mipmap = mipMapMode == DefaultMipMaps;
00517 bool precomputedMipMaps = false;
00518
00519
00520 int mipLevelCount = img.getMipLevelCount();
00521 int completeMipCount = CalcMipLevelCount(img.getWidth(), img.getHeight());
00522
00523
00524
00525 if (mipmap && mipLevelCount >= completeMipCount - 1)
00526 precomputedMipMaps = true;
00527
00528
00529
00530 if (!precomputedMipMaps && img.isCompressed())
00531 mipmap = false;
00532
00533 GLenum texAddress = GetGLTexAddressMode(EdgeClamp);
00534 int internalFormat = getInternalFormat(img.getFormat());
00535 int components = img.getComponents();
00536
00537
00538 int tileWidth = img.getWidth() / uSplit;
00539 int tileHeight = img.getHeight() / vSplit;
00540 int tileMipLevelCount = CalcMipLevelCount(tileWidth, tileHeight);
00541 Image* tile = new Image(img.getFormat(),
00542 tileWidth, tileHeight,
00543 tileMipLevelCount);
00544 if (tile == NULL)
00545 return;
00546
00547 for (int v = 0; v < vSplit; v++)
00548 {
00549 for (int u = 0; u < uSplit; u++)
00550 {
00551
00552 glGenTextures(1, (GLuint*)&glNames[v * uSplit + u]);
00553 glBindTexture(GL_TEXTURE_2D, glNames[v * uSplit + u]);
00554
00555 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, texAddress);
00556 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, texAddress);
00557 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
00558 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
00559 mipmap ? GL_LINEAR_MIPMAP_LINEAR : GL_LINEAR);
00560
00561
00562
00563
00564 if (precomputedMipMaps)
00565 {
00566 if (img.isCompressed())
00567 {
00568 for (int mip = 0; mip < tileMipLevelCount; mip++)
00569 {
00570 int blockSize = getCompressedBlockSize(img.getFormat());
00571 unsigned char* imgMip =
00572 img.getMipLevel(min(mip, mipLevelCount));
00573 uint mipWidth = max((uint) img.getWidth() >> mip, 1u);
00574 unsigned char* tileMip = tile->getMipLevel(mip);
00575 uint tileMipWidth = max((uint) tile->getWidth() >> mip, 1u);
00576 uint tileMipHeight = max((uint) tile->getHeight() >> mip, 1u);
00577 int uBlocks = max(tileMipWidth / 4, 1u);
00578 int vBlocks = max(tileMipHeight / 4, 1u);
00579 int destBytesPerRow = uBlocks * blockSize;
00580 int srcBytesPerRow = max(mipWidth / 4, 1u) * blockSize;
00581 int srcU = u * tileMipWidth / 4;
00582 int srcV = v * tileMipHeight / 4;
00583 int tileOffset = srcV * srcBytesPerRow +
00584 srcU * blockSize;
00585
00586 for (int y = 0; y < vBlocks; y++)
00587 {
00588 memcpy(tileMip + y * destBytesPerRow,
00589 imgMip + tileOffset + y * srcBytesPerRow,
00590 destBytesPerRow);
00591 }
00592 }
00593 }
00594 else
00595 {
00596
00597 }
00598
00599 LoadMipmapSet(*tile, GL_TEXTURE_2D);
00600 }
00601 else
00602 {
00603 if (img.isCompressed())
00604 {
00605 int blockSize = getCompressedBlockSize(img.getFormat());
00606 int uBlocks = max(tileWidth / 4, 1);
00607 int vBlocks = max(tileHeight / 4, 1);
00608 int destBytesPerRow = uBlocks * blockSize;
00609 int srcBytesPerRow = max(img.getWidth() / 4, 1) * blockSize;
00610 int srcU = u * tileWidth / 4;
00611 int srcV = v * tileHeight / 4;
00612 int tileOffset = srcV * srcBytesPerRow +
00613 srcU * blockSize;
00614
00615 for (int y = 0; y < vBlocks; y++)
00616 {
00617 memcpy(tile->getPixels() + y * destBytesPerRow,
00618 img.getPixels() + tileOffset + y * srcBytesPerRow,
00619 destBytesPerRow);
00620 }
00621 }
00622 else
00623 {
00624 unsigned char* tilePixels = img.getPixels() +
00625 (v * tileHeight * img.getWidth() + u * tileWidth) * components;
00626 for (int y = 0; y < tileHeight; y++)
00627 {
00628 memcpy(tile->getPixels() + y * tileWidth * components,
00629 tilePixels + y * img.getWidth() * components,
00630 tileWidth * components);
00631 }
00632 }
00633
00634 if (mipmap)
00635 {
00636 gluBuild2DMipmaps(GL_TEXTURE_2D,
00637 internalFormat,
00638 tileWidth, tileHeight,
00639 (GLenum) tile->getFormat(),
00640 GL_UNSIGNED_BYTE,
00641 tile->getPixels());
00642 }
00643 else
00644 {
00645 LoadMiplessTexture(*tile, GL_TEXTURE_2D);
00646 }
00647 }
00648 }
00649 }
00650
00651 delete tile;
00652 }
00653
00654
00655 TiledTexture::~TiledTexture()
00656 {
00657 if (glNames != NULL)
00658 {
00659 for (int i = 0; i < uSplit * vSplit; i++)
00660 {
00661 if (glNames[i] != 0)
00662 glDeleteTextures(1, (const GLuint*) &glNames[i]);
00663 }
00664 delete[] glNames;
00665 }
00666 }
00667
00668
00669 void TiledTexture::bind()
00670 {
00671 }
00672
00673
00674 void TiledTexture::setBorderColor(Color borderColor)
00675 {
00676 for (int i = 0; i < vSplit; i++)
00677 {
00678 for (int j = 0; j < uSplit; j++)
00679 {
00680 glBindTexture(GL_TEXTURE_2D, glNames[i * uSplit + j]);
00681 SetBorderColor(borderColor, GL_TEXTURE_2D);
00682 }
00683 }
00684 }
00685
00686
00687 int TiledTexture::getUTileCount(int) const
00688 {
00689 return uSplit;
00690 }
00691
00692
00693 int TiledTexture::getVTileCount(int) const
00694 {
00695 return vSplit;
00696 }
00697
00698
00699 const TextureTile TiledTexture::getTile(int lod, int u, int v)
00700 {
00701 if (lod != 0 || u >= uSplit || u < 0 || v >= vSplit || v < 0)
00702 return TextureTile(0);
00703 else
00704 {
00705 return TextureTile(glNames[v * uSplit + u]);
00706 }
00707 }
00708
00709
00710
00711 CubeMap::CubeMap(Image* faces[]) :
00712 Texture(faces[0]->getWidth(), faces[0]->getHeight()),
00713 glName(0)
00714 {
00715
00716 int width = faces[0]->getWidth();
00717 int format = faces[0]->getFormat();
00718 int i = 0;
00719 for (i = 0; i < 6; i++)
00720 {
00721 if (faces[i]->getWidth() != width ||
00722 faces[i]->getHeight() != width ||
00723 faces[i]->getFormat() != format)
00724 return;
00725 }
00726
00727
00728
00729 bool mipmap = true;
00730 bool precomputedMipMaps = false;
00731
00732
00733 int mipLevelCount = faces[0]->getMipLevelCount();
00734 if (mipmap && mipLevelCount == CalcMipLevelCount(width, width))
00735 precomputedMipMaps = true;
00736
00737
00738
00739 if (!precomputedMipMaps && faces[0]->isCompressed())
00740 mipmap = false;
00741
00742 glGenTextures(1, (GLuint*)&glName);
00743 glBindTexture(GL_TEXTURE_CUBE_MAP_EXT, glName);
00744
00745 glTexParameteri(GL_TEXTURE_CUBE_MAP_EXT, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
00746 glTexParameteri(GL_TEXTURE_CUBE_MAP_EXT, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
00747 glTexParameteri(GL_TEXTURE_CUBE_MAP_EXT, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
00748 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
00749 mipmap ? GL_LINEAR_MIPMAP_LINEAR : GL_LINEAR);
00750
00751 int internalFormat = getInternalFormat(format);
00752
00753 for (i = 0; i < 6; i++)
00754 {
00755 GLenum targetFace = (GLenum) ((int) GL_TEXTURE_CUBE_MAP_POSITIVE_X_EXT + i);
00756 Image* face = faces[i];
00757
00758 if (mipmap)
00759 {
00760 if (precomputedMipMaps)
00761 {
00762 LoadMipmapSet(*face, targetFace);
00763 }
00764 else
00765 {
00766 gluBuild2DMipmaps(targetFace,
00767 internalFormat,
00768 getWidth(), getHeight(),
00769 (GLenum) face->getFormat(),
00770 GL_UNSIGNED_BYTE,
00771 face->getPixels());
00772 }
00773 }
00774 else
00775 {
00776 LoadMiplessTexture(*face, targetFace);
00777 }
00778 }
00779 }
00780
00781
00782 CubeMap::~CubeMap()
00783 {
00784 if (glName != 0)
00785 glDeleteTextures(1, (const GLuint*) &glName);
00786 }
00787
00788
00789 void CubeMap::bind()
00790 {
00791 glBindTexture(GL_TEXTURE_CUBE_MAP_EXT, glName);
00792 }
00793
00794
00795 const TextureTile CubeMap::getTile(int lod, int u, int v)
00796 {
00797 if (lod != 0 || u != 0 || v != 0)
00798 return TextureTile(0);
00799 else
00800 return TextureTile(glName);
00801 }
00802
00803
00804 void CubeMap::setBorderColor(Color borderColor)
00805 {
00806 bind();
00807 SetBorderColor(borderColor, GL_TEXTURE_CUBE_MAP_EXT);
00808 }
00809
00810
00811
00812 Texture* CreateProceduralTexture(int width, int height,
00813 int format,
00814 ProceduralTexEval func,
00815 Texture::AddressMode addressMode,
00816 Texture::MipMapMode mipMode)
00817 {
00818 Image* img = new Image(format, width, height);
00819 if (img == NULL)
00820 return NULL;
00821
00822 for (int y = 0; y < height; y++)
00823 {
00824 for (int x = 0; x < width; x++)
00825 {
00826 float u = (float) x / (float) width * 2 - 1;
00827 float v = (float) y / (float) height * 2 - 1;
00828 func(u, v, 0, img->getPixelRow(y) + x * img->getComponents());
00829 }
00830 }
00831
00832 Texture* tex = new ImageTexture(*img, addressMode, mipMode);
00833 delete img;
00834
00835 return tex;
00836 }
00837
00838
00839 Texture* CreateProceduralTexture(int width, int height,
00840 int format,
00841 TexelFunctionObject& func,
00842 Texture::AddressMode addressMode,
00843 Texture::MipMapMode mipMode)
00844 {
00845 Image* img = new Image(format, width, height);
00846 if (img == NULL)
00847 return NULL;
00848
00849 for (int y = 0; y < height; y++)
00850 {
00851 for (int x = 0; x < width; x++)
00852 {
00853 float u = (float) x / (float) width * 2 - 1;
00854 float v = (float) y / (float) height * 2 - 1;
00855 func(u, v, 0, img->getPixelRow(y) + x * img->getComponents());
00856 }
00857 }
00858
00859 Texture* tex = new ImageTexture(*img, addressMode, mipMode);
00860 delete img;
00861
00862 return tex;
00863 }
00864
00865
00866
00867 static Vec3f cubeVector(int face, float s, float t)
00868 {
00869 Vec3f v;
00870 switch (face)
00871 {
00872 case 0:
00873 v = Vec3f(1.0f, -t, -s);
00874 break;
00875 case 1:
00876 v = Vec3f(-1.0f, -t, s);
00877 break;
00878 case 2:
00879 v = Vec3f(s, 1.0f, t);
00880 break;
00881 case 3:
00882 v = Vec3f(s, -1.0f, -t);
00883 break;
00884 case 4:
00885 v = Vec3f(s, -t, 1.0f);
00886 break;
00887 case 5:
00888 v = Vec3f(-s, -t, -1.0f);
00889 break;
00890 default:
00891
00892 break;
00893 }
00894
00895 v.normalize();
00896
00897 return v;
00898 }
00899
00900
00901 extern Texture* CreateProceduralCubeMap(int size, int format,
00902 ProceduralTexEval func)
00903 {
00904 Image* faces[6];
00905 bool failed = false;
00906
00907 int i = 0;
00908 for (i = 0; i < 6; i++)
00909 {
00910 faces[i] = NULL;
00911 faces[i] = new Image(format, size, size);
00912 if (faces == NULL)
00913 failed = true;
00914 }
00915
00916 if (!failed)
00917 {
00918 for (int i = 0; i < 6; i++)
00919 {
00920 Image* face = faces[i];
00921 for (int y = 0; y < size; y++)
00922 {
00923 for (int x = 0; x < size; x++)
00924 {
00925 float s = ((float) x + 0.5f) / (float) size * 2 - 1;
00926 float t = ((float) y + 0.5f) / (float) size * 2 - 1;
00927 Vec3f v = cubeVector(i, s, t);
00928 func(v.x, v.y, v.z,
00929 face->getPixelRow(y) + x * face->getComponents());
00930 }
00931 }
00932 }
00933 }
00934
00935 Texture* tex = new CubeMap(faces);
00936
00937
00938 for (i = 0; i < 6; i++)
00939 {
00940 if (faces[i] != NULL)
00941 delete faces[i];
00942 }
00943
00944 return tex;
00945 }
00946
00947
00948 static bool isPow2(int x)
00949 {
00950 return ((x & (x - 1)) == 0);
00951 }
00952
00953
00954 static Texture* CreateTextureFromImage(Image& img,
00955 Texture::AddressMode addressMode,
00956 Texture::MipMapMode mipMode)
00957 {
00958
00959
00960
00961
00962
00963
00964 if (!isPow2(img.getWidth()) || !isPow2(img.getHeight()))
00965 {
00966 clog << "Texture has non-power of two dimensions.\n";
00967 return NULL;
00968 }
00969
00970 bool splittingAllowed = true;
00971 Texture* tex = NULL;
00972
00973 int maxDim = GetTextureCaps().maxTextureSize;
00974
00975 if ((img.getWidth() > maxDim || img.getHeight() > maxDim) &&
00976 splittingAllowed)
00977 {
00978
00979 int uSplit = max(1, img.getWidth() / maxDim);
00980 int vSplit = max(1, img.getHeight() / maxDim);
00981
00982 tex = new TiledTexture(img, uSplit, vSplit, mipMode);
00983 }
00984 else
00985 {
00986
00987
00988
00989 tex = new ImageTexture(img, addressMode, mipMode);
00990 }
00991
00992 return tex;
00993 }
00994
00995
00996 Texture* LoadTextureFromFile(const string& filename,
00997 Texture::AddressMode addressMode,
00998 Texture::MipMapMode mipMode)
00999 {
01000
01001 if (DetermineFileType(filename) == Content_CelestiaTexture)
01002 return LoadVirtualTexture(filename);
01003
01004
01005
01006 Image* img = LoadImageFromFile(filename);
01007 if (img == NULL)
01008 return NULL;
01009
01010 Texture* tex = CreateTextureFromImage(*img, addressMode, mipMode);
01011 delete img;
01012
01013 return tex;
01014 }
01015
01016
01017
01018 Texture* LoadHeightMapFromFile(const string& filename,
01019 float height,
01020 Texture::AddressMode addressMode)
01021 {
01022 Image* img = LoadImageFromFile(filename);
01023 if (img == NULL)
01024 return NULL;
01025 Image* normalMap = img->computeNormalMap(height,
01026 addressMode == Texture::Wrap);
01027 delete img;
01028 if (normalMap == NULL)
01029 return NULL;
01030
01031 Texture* tex = CreateTextureFromImage(*normalMap, addressMode,
01032 Texture::DefaultMipMaps);
01033 delete normalMap;
01034
01035 return tex;
01036 }