texture.cpp
上传用户:center1979
上传日期:2022-07-26
资源大小:50633k
文件大小:29k
源码类别:

OpenGL

开发平台:

Visual C++

  1. // texture.cpp
  2. //
  3. // Copyright (C) 2001-2003, Chris Laurel
  4. //
  5. // This program is free software; you can redistribute it and/or
  6. // modify it under the terms of the GNU General Public License
  7. // as published by the Free Software Foundation; either version 2
  8. // of the License, or (at your option) any later version.
  9. #ifndef TARGET_OS_MAC
  10. #define JPEG_SUPPORT
  11. #define PNG_SUPPORT
  12. #endif
  13. #ifdef TARGET_OS_MAC
  14. #include <unistd.h>
  15. #include "CGBuffer.h"
  16. #ifndef PNG_SUPPORT
  17. #include <Quicktime/ImageCompression.h>
  18. #include <QuickTime/QuickTimeComponents.h>
  19. #endif
  20. #endif
  21. #include <cmath>
  22. #include <algorithm>
  23. #include <iostream>
  24. #include <fstream>
  25. #include <cstdlib>
  26. #include <cstdio>
  27. #include <cassert>
  28. #ifndef _WIN32
  29. #ifndef TARGET_OS_MAC
  30. #include <config.h>
  31. #endif /* ! TARGET_OS_MAC */
  32. #endif /* ! _WIN32 */
  33. #include <celmath/vecmath.h>
  34. #include <celutil/filetype.h>
  35. #include <celutil/debug.h>
  36. #include <celutil/util.h>
  37. #include "gl.h"
  38. #include "glext.h"
  39. #include "celestia.h"
  40. // OpenGL 1.2 stuff missing from Windows headers . . . probably should be
  41. // moved into glext.h
  42. #ifndef GL_TEXTURE_MAX_LEVEL
  43. #define GL_TEXTURE_MAX_LEVEL 0x813D
  44. #endif
  45. #ifdef JPEG_SUPPORT
  46. #ifndef PNG_SUPPORT
  47. #include "setjmp.h"
  48. #endif // PNG_SUPPORT
  49. extern "C" {
  50. #ifdef _WIN32
  51. #include "jpeglib.h"
  52. #else
  53. #include <jpeglib.h>
  54. #endif
  55. }
  56. #endif // JPEG_SUPPORT
  57. #ifdef PNG_SUPPORT // PNG_SUPPORT
  58. #ifdef TARGET_OS_MAC
  59. #include "../../macosx/png.h"
  60. #else
  61. #include "png.h"
  62. #endif // TARGET_OS_MAC
  63. // Define png_jmpbuf() in case we are using a pre-1.0.6 version of libpng
  64. #ifndef png_jmpbuf
  65. #define png_jmpbuf(png_ptr) png_ptr->jmpbuf
  66. #endif // PNG_SUPPORT
  67. // Define various expansion transformations for old versions of libpng
  68. #if PNG_LIBPNG_VER < 10004
  69. #define png_set_palette_to_rgb(p)  png_set_expand(p)
  70. #define png_set_gray_1_2_4_to_8(p) png_set_expand(p)
  71. #define png_set_tRNS_to_alpha(p)   png_set_expand(p)
  72. #endif // PNG_LIBPNG_VER < 10004
  73. #endif // PNG_SUPPORT
  74. #include "texture.h"
  75. #include "virtualtex.h"
  76. using namespace std;
  77. static bool texCapsInitialized = false;
  78. struct TextureCaps
  79. {
  80.     bool compressionSupported;
  81.     bool clampToEdgeSupported;
  82.     bool clampToBorderSupported;
  83.     bool autoMipMapSupported;
  84.     bool maxLevelSupported;
  85.     GLint maxTextureSize;
  86.     bool nonPow2Supported;
  87. };
  88. static TextureCaps texCaps;
  89. static bool testMaxLevel()
  90. {
  91.     unsigned char texels[64];
  92.     glEnable(GL_TEXTURE_2D);
  93.     // Test whether GL_TEXTURE_MAX_LEVEL is supported . . .
  94.     glTexImage2D(GL_TEXTURE_2D,
  95.                  0,
  96.                  GL_LUMINANCE,
  97.                  8, 8,
  98.                  0,
  99.                  GL_LUMINANCE,
  100.                  GL_UNSIGNED_BYTE,
  101.                  texels);
  102.     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 2);
  103.     float maxLev = -1.0f;
  104.     glGetTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, &maxLev);
  105.     glDisable(GL_TEXTURE_2D);
  106.     return maxLev == 2;
  107. }
  108. static const TextureCaps& GetTextureCaps()
  109. {
  110.     if (!texCapsInitialized)
  111.     {
  112.         texCapsInitialized = true;
  113.         texCaps.compressionSupported = ExtensionSupported("GL_ARB_texture_compression");
  114.         if (texCaps.compressionSupported)
  115.             InitExtension("GL_ARB_texture_compression");
  116. #ifdef GL_VERSION_1_2
  117.         texCaps.clampToEdgeSupported = true;
  118. #else
  119.         texCaps.clampToEdgeSupported = ExtensionSupported("GL_EXT_texture_edge_clamp");
  120. #endif // GL_VERSION_1_2
  121.         texCaps.clampToBorderSupported = ExtensionSupported("GL_ARB_texture_border_clamp");
  122.         texCaps.autoMipMapSupported = ExtensionSupported("GL_SGIS_generate_mipmap");
  123.         texCaps.maxLevelSupported = testMaxLevel();
  124.         glGetIntegerv(GL_MAX_TEXTURE_SIZE, &texCaps.maxTextureSize);
  125.         texCaps.nonPow2Supported = ExtensionSupported("GL_ARB_texture_non_power_of_two");
  126.     }
  127.     return texCaps;
  128. }
  129. static int getInternalFormat(int format)
  130. {
  131.     switch (format)
  132.     {
  133.     case GL_RGBA:
  134.     case GL_BGRA_EXT:
  135.         return 4;
  136.     case GL_RGB:
  137.     case GL_BGR_EXT:
  138.         return 3;
  139.     case GL_LUMINANCE_ALPHA:
  140.         return 2;
  141.     case GL_ALPHA:
  142.     case GL_INTENSITY:
  143.     case GL_LUMINANCE:
  144.         return 1;
  145.     case GL_DSDT_NV:
  146.         return format;
  147.     case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
  148.     case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
  149.     case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
  150.         return format;
  151.     default:
  152.         return 0;
  153.     }
  154. }
  155. #if 0
  156. // Required in order to support on-the-fly compression; currently, this
  157. // feature is disabled.
  158. static int getCompressedInternalFormat(int format)
  159. {
  160.     switch (format)
  161.     {
  162.     case GL_RGB:
  163.     case GL_BGR_EXT:
  164.         return GL_COMPRESSED_RGB_ARB;
  165.     case GL_RGBA:
  166.     case GL_BGRA_EXT:
  167.         return GL_COMPRESSED_RGBA_ARB;
  168.     case GL_ALPHA:
  169.         return GL_COMPRESSED_ALPHA_ARB;
  170.     case GL_LUMINANCE:
  171.         return GL_COMPRESSED_LUMINANCE_ARB;
  172.     case GL_LUMINANCE_ALPHA:
  173.         return GL_COMPRESSED_LUMINANCE_ALPHA_ARB;
  174.     case GL_INTENSITY:
  175.         return GL_COMPRESSED_INTENSITY_ARB;
  176.     case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
  177.     case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
  178.     case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
  179.         return format;
  180.     default:
  181.         return 0;
  182.     }
  183. }
  184. #endif
  185. static int getCompressedBlockSize(int format)
  186. {
  187.     if (format == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT)
  188.         return 8;
  189.     else
  190.         return 16;
  191. }
  192. static GLenum GetGLTexAddressMode(Texture::AddressMode addressMode)
  193. {
  194.     const TextureCaps& caps = GetTextureCaps();
  195.     switch (addressMode)
  196.     {
  197.     case Texture::Wrap:
  198.         return GL_REPEAT;
  199.     case Texture::EdgeClamp:
  200.         return caps.clampToEdgeSupported ? GL_CLAMP_TO_EDGE : GL_CLAMP;
  201.     case Texture::BorderClamp:
  202.         if (caps.clampToBorderSupported)
  203.             return GL_CLAMP_TO_BORDER_ARB;
  204.         else
  205.             return caps.clampToEdgeSupported ? GL_CLAMP_TO_EDGE : GL_CLAMP;
  206.     }
  207.     return 0;
  208. }
  209. static void SetBorderColor(Color borderColor, GLenum target)
  210. {
  211.     float bc[4] = { borderColor.red(), borderColor.green(),
  212.                     borderColor.blue(), borderColor.alpha() };
  213.     glTexParameterfv(target, GL_TEXTURE_BORDER_COLOR, bc);
  214. }
  215. // Load a prebuilt set of mipmaps; assumes that the image contains
  216. // a complete set of mipmap levels.
  217. static void LoadMipmapSet(Image& img, GLenum target)
  218. {
  219.     int internalFormat = getInternalFormat(img.getFormat());
  220.     for (int mip = 0; mip < img.getMipLevelCount(); mip++)
  221.     {
  222.         uint mipWidth  = max((uint) img.getWidth() >> mip, 1u);
  223.         uint mipHeight = max((uint) img.getHeight() >> mip, 1u);
  224.         if (img.isCompressed())
  225.         {
  226.             glx::glCompressedTexImage2DARB(target,
  227.                                            mip,
  228.                                            internalFormat,
  229.                                            mipWidth, mipHeight,
  230.                                            0,
  231.                                            img.getMipLevelSize(mip),
  232.                                            img.getMipLevel(mip));
  233.         }
  234.         else
  235.         {
  236.             glTexImage2D(target,
  237.                          mip,
  238.                          internalFormat,
  239.                          mipWidth, mipHeight,
  240.                          0,
  241.                          (GLenum) img.getFormat(),
  242.                          GL_UNSIGNED_BYTE,
  243.                          img.getMipLevel(mip));
  244.         }
  245.     }
  246. }
  247. // Load a texture without any mipmaps
  248. static void LoadMiplessTexture(Image& img, GLenum target)
  249. {
  250.     int internalFormat = getInternalFormat(img.getFormat());
  251.     if (img.isCompressed())
  252.     {
  253.         glx::glCompressedTexImage2DARB(target,
  254.                                        0,
  255.                                        internalFormat,
  256.                                        img.getWidth(), img.getHeight(),
  257.                                        0,
  258.                                        img.getMipLevelSize(0),
  259.                                        img.getMipLevel(0));
  260.     }
  261.     else
  262.     {
  263.         glTexImage2D(target,
  264.                      0,
  265.                      internalFormat,
  266.                      img.getWidth(), img.getHeight(),
  267.                      0,
  268.                      (GLenum) img.getFormat(),
  269.                      GL_UNSIGNED_BYTE,
  270.                      img.getMipLevel(0));
  271.     }
  272. }
  273. static int ilog2(unsigned int x)
  274. {
  275.     int n = -1;
  276.     while (x != 0)
  277.     {
  278.         x >>= 1;
  279.         n++;
  280.     }
  281.     return n;
  282. }
  283. static int CalcMipLevelCount(int w, int h)
  284. {
  285.     return max(ilog2(w), ilog2(h)) + 1;
  286. }
  287. Texture::Texture(int w, int h, int d) :
  288.     alpha(false),
  289.     compressed(false),
  290.     width(w),
  291.     height(h),
  292.     depth(d),
  293.     formatOptions(0)
  294. {
  295. }
  296. Texture::~Texture()
  297. {
  298. }
  299. int Texture::getLODCount() const
  300. {
  301.     return 1;
  302. }
  303. int Texture::getUTileCount(int) const
  304. {
  305.     return 1;
  306. }
  307. int Texture::getVTileCount(int) const
  308. {
  309.     return 1;
  310. }
  311. int Texture::getWTileCount(int) const
  312. {
  313.     return 1;
  314. }
  315. void Texture::setBorderColor(Color)
  316. {
  317. }
  318. int Texture::getWidth() const
  319. {
  320.     return width;
  321. }
  322. int Texture::getHeight() const
  323. {
  324.     return height;
  325. }
  326. int Texture::getDepth() const
  327. {
  328.     return depth;
  329. }
  330. unsigned int Texture::getFormatOptions() const
  331. {
  332.     return formatOptions;
  333. }
  334. void Texture::setFormatOptions(unsigned int opts)
  335. {
  336.     formatOptions = opts;
  337. }
  338. ImageTexture::ImageTexture(Image& img,
  339.                            AddressMode addressMode,
  340.                            MipMapMode mipMapMode) :
  341.     Texture(img.getWidth(), img.getHeight()),
  342.     glName(0)
  343. {
  344.     glGenTextures(1, (GLuint*) &glName);
  345.     glBindTexture(GL_TEXTURE_2D, glName);
  346.     bool mipmap = mipMapMode != NoMipMaps;
  347.     bool precomputedMipMaps = false;
  348.     // Use precomputed mipmaps only if a complete set is supplied
  349.     int mipLevelCount = img.getMipLevelCount();
  350.     if (mipmap && mipLevelCount == CalcMipLevelCount(img.getWidth(), img.getHeight()))
  351.     {
  352.         precomputedMipMaps = true;
  353.     }
  354.     // We can't automatically generate mipmaps for compressed textures.
  355.     // If a precomputed mipmap set isn't provided, turn off mipmapping entirely.
  356.     if (!precomputedMipMaps && img.isCompressed())
  357.     {
  358.         mipmap = false;
  359.     }
  360.     GLenum texAddress = GetGLTexAddressMode(addressMode);
  361.     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, texAddress);
  362.     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, texAddress);
  363.     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  364.     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
  365.                     mipmap ? GL_LINEAR_MIPMAP_LINEAR : GL_LINEAR);
  366.     if (mipMapMode == AutoMipMaps)
  367.         glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP_SGIS, GL_TRUE);
  368.     int internalFormat = getInternalFormat(img.getFormat());
  369.     if (mipmap)
  370.     {
  371.         if (precomputedMipMaps)
  372.         {
  373.             LoadMipmapSet(img, GL_TEXTURE_2D);
  374.         }
  375.         else if (mipMapMode == DefaultMipMaps)
  376.         {
  377.             gluBuild2DMipmaps(GL_TEXTURE_2D,
  378.                               internalFormat,
  379.                               getWidth(), getHeight(),
  380.                               (GLenum) img.getFormat(),
  381.                               GL_UNSIGNED_BYTE,
  382.                               img.getPixels());
  383.         }
  384.         else
  385.         {
  386.             assert(mipMapMode == AutoMipMaps);
  387.             LoadMiplessTexture(img, GL_TEXTURE_2D);
  388.         }
  389.     }
  390.     else
  391.     {
  392.         LoadMiplessTexture(img, GL_TEXTURE_2D);
  393.     }
  394.     alpha = img.hasAlpha();
  395.     compressed = img.isCompressed();
  396. }
  397. ImageTexture::~ImageTexture()
  398. {
  399.     if (glName != 0)
  400.         glDeleteTextures(1, (const GLuint*) &glName);
  401. }
  402. void ImageTexture::bind()
  403. {
  404.     glBindTexture(GL_TEXTURE_2D, glName);
  405. }
  406. const TextureTile ImageTexture::getTile(int lod, int u, int v)
  407. {
  408.     if (lod != 0 || u != 0 || v != 0)
  409.         return TextureTile(0);
  410.     else
  411.         return TextureTile(glName);
  412. }
  413. unsigned int ImageTexture::getName() const
  414. {
  415.     return glName;
  416. }
  417. void ImageTexture::setBorderColor(Color borderColor)
  418. {
  419.     bind();
  420.     SetBorderColor(borderColor, GL_TEXTURE_2D);
  421. }
  422. TiledTexture::TiledTexture(Image& img,
  423.                            int _uSplit, int _vSplit,
  424.                            MipMapMode mipMapMode) :
  425.     Texture(img.getWidth(), img.getHeight()),
  426.     uSplit(_uSplit),
  427.     vSplit(_vSplit),
  428.     glNames(NULL)
  429. {
  430.     glNames = new uint[uSplit * vSplit];
  431.     {
  432.         for (int i = 0; i < uSplit * vSplit; i++)
  433.             glNames[i] = 0;
  434.     }
  435.     alpha = img.hasAlpha();
  436.     compressed = img.isCompressed();
  437.     bool mipmap = mipMapMode != NoMipMaps;
  438.     bool precomputedMipMaps = false;
  439.     // Require a complete set of mipmaps
  440.     int mipLevelCount = img.getMipLevelCount();
  441.     int completeMipCount = CalcMipLevelCount(img.getWidth(), img.getHeight());
  442.     // Allow a bit of slack here--it turns out that some tools don't want to
  443.     // calculate the 1x1 mip level.  Rather than turn off mipmaps, we'll just
  444.     // point the 1x1 mip to the 2x1.
  445.     if (mipmap && mipLevelCount >= completeMipCount - 1)
  446.         precomputedMipMaps = true;
  447.     // We can't automatically generate mipmaps for compressed textures.
  448.     // If a precomputed mipmap set isn't provided, turn of mipmapping entirely.
  449.     if (!precomputedMipMaps && img.isCompressed())
  450.         mipmap = false;
  451.     GLenum texAddress = GetGLTexAddressMode(EdgeClamp);
  452.     int internalFormat = getInternalFormat(img.getFormat());
  453.     int components = img.getComponents();
  454.     // Create a temporary image which we'll use for the tile texels
  455.     int tileWidth = img.getWidth() / uSplit;
  456.     int tileHeight = img.getHeight() / vSplit;
  457.     int tileMipLevelCount = CalcMipLevelCount(tileWidth, tileHeight);
  458.     Image* tile = new Image(img.getFormat(),
  459.                             tileWidth, tileHeight,
  460.                             tileMipLevelCount);
  461.     if (tile == NULL)
  462.         return;
  463.     for (int v = 0; v < vSplit; v++)
  464.     {
  465.         for (int u = 0; u < uSplit; u++)
  466.         {
  467.             // Create the texture and set up sampling and addressing
  468.             glGenTextures(1, (GLuint*)&glNames[v * uSplit + u]);
  469.             glBindTexture(GL_TEXTURE_2D, glNames[v * uSplit + u]);
  470.             glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, texAddress);
  471.             glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, texAddress);
  472.             glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  473.             glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
  474.                             mipmap ? GL_LINEAR_MIPMAP_LINEAR : GL_LINEAR);
  475.             // Copy texels from the subtexture area to the pixel buffer.  This
  476.             // is straightforward for normal textures, but an immense headache
  477.             // for compressed textures with prebuilt mipmaps.
  478.             if (precomputedMipMaps)
  479.             {
  480.                 if (img.isCompressed())
  481.                 {
  482.                     for (int mip = 0; mip < tileMipLevelCount; mip++)
  483.                     {
  484.                         int blockSize = getCompressedBlockSize(img.getFormat());
  485.                         unsigned char* imgMip =
  486.                             img.getMipLevel(min(mip, mipLevelCount));
  487.                         uint mipWidth  = max((uint) img.getWidth() >> mip, 1u);
  488.                         unsigned char* tileMip = tile->getMipLevel(mip);
  489.                         uint tileMipWidth  = max((uint) tile->getWidth() >> mip, 1u);
  490.                         uint tileMipHeight = max((uint) tile->getHeight() >> mip, 1u);
  491.                         int uBlocks = max(tileMipWidth / 4, 1u);
  492.                         int vBlocks = max(tileMipHeight / 4, 1u);
  493.                         int destBytesPerRow = uBlocks * blockSize;
  494.                         int srcBytesPerRow = max(mipWidth / 4, 1u) * blockSize;
  495.                         int srcU = u * tileMipWidth / 4;
  496.                         int srcV = v * tileMipHeight / 4;
  497.                         int tileOffset = srcV * srcBytesPerRow +
  498.                             srcU * blockSize;
  499.                         for (int y = 0; y < vBlocks; y++)
  500.                         {
  501.                             memcpy(tileMip + y * destBytesPerRow,
  502.                                    imgMip + tileOffset + y * srcBytesPerRow,
  503.                                    destBytesPerRow);
  504.                         }
  505.                     }
  506.                 }
  507.                 else
  508.                 {
  509.                     // TODO: Handle uncompressed textures with prebuilt mipmaps
  510.                 }
  511.                 LoadMipmapSet(*tile, GL_TEXTURE_2D);
  512.             }
  513.             else
  514.             {
  515.                 if (img.isCompressed())
  516.                 {
  517.                     int blockSize = getCompressedBlockSize(img.getFormat());
  518.                     int uBlocks = max(tileWidth / 4, 1);
  519.                     int vBlocks = max(tileHeight / 4, 1);
  520.                     int destBytesPerRow = uBlocks * blockSize;
  521.                     int srcBytesPerRow = max(img.getWidth() / 4, 1) * blockSize;
  522.                     int srcU = u * tileWidth / 4;
  523.                     int srcV = v * tileHeight / 4;
  524.                     int tileOffset = srcV * srcBytesPerRow +
  525.                             srcU * blockSize;
  526.                     for (int y = 0; y < vBlocks; y++)
  527.                     {
  528.                         memcpy(tile->getPixels() + y * destBytesPerRow,
  529.                                img.getPixels() + tileOffset + y * srcBytesPerRow,
  530.                                destBytesPerRow);
  531.                     }
  532.                 }
  533.                 else
  534.                 {
  535.                     unsigned char* tilePixels = img.getPixels() +
  536.                         (v * tileHeight * img.getWidth() + u * tileWidth) * components;
  537.                     for (int y = 0; y < tileHeight; y++)
  538.                     {
  539.                         memcpy(tile->getPixels() + y * tileWidth * components,
  540.                                tilePixels + y * img.getWidth() * components,
  541.                                tileWidth * components);
  542.                     }
  543.                 }
  544.                 if (mipmap)
  545.                 {
  546.                     gluBuild2DMipmaps(GL_TEXTURE_2D,
  547.                                       internalFormat,
  548.                                       tileWidth, tileHeight,
  549.                                       (GLenum) tile->getFormat(),
  550.                                       GL_UNSIGNED_BYTE,
  551.                                       tile->getPixels());
  552.                 }
  553.                 else
  554.                 {
  555.                     LoadMiplessTexture(*tile, GL_TEXTURE_2D);
  556.                 }
  557.             }
  558.         }
  559.     }
  560.     delete tile;
  561. }
  562. TiledTexture::~TiledTexture()
  563. {
  564.     if (glNames != NULL)
  565.     {
  566.         for (int i = 0; i < uSplit * vSplit; i++)
  567.         {
  568.             if (glNames[i] != 0)
  569.                 glDeleteTextures(1, (const GLuint*) &glNames[i]);
  570.         }
  571.         delete[] glNames;
  572.     }
  573. }
  574. void TiledTexture::bind()
  575. {
  576. }
  577. void TiledTexture::setBorderColor(Color borderColor)
  578. {
  579.     for (int i = 0; i < vSplit; i++)
  580.     {
  581.         for (int j = 0; j < uSplit; j++)
  582.         {
  583.             glBindTexture(GL_TEXTURE_2D, glNames[i * uSplit + j]);
  584.             SetBorderColor(borderColor, GL_TEXTURE_2D);
  585.         }
  586.     }
  587. }
  588. int TiledTexture::getUTileCount(int) const
  589. {
  590.     return uSplit;
  591. }
  592. int TiledTexture::getVTileCount(int) const
  593. {
  594.     return vSplit;
  595. }
  596. const TextureTile TiledTexture::getTile(int lod, int u, int v)
  597. {
  598.     if (lod != 0 || u >= uSplit || u < 0 || v >= vSplit || v < 0)
  599.         return TextureTile(0);
  600.     else
  601.     {
  602.         return TextureTile(glNames[v * uSplit + u]);
  603.     }
  604. }
  605. CubeMap::CubeMap(Image* faces[]) :
  606.     Texture(faces[0]->getWidth(), faces[0]->getHeight()),
  607.     glName(0)
  608. {
  609.     // Verify that all the faces are square and have the same size
  610.     int width = faces[0]->getWidth();
  611.     int format = faces[0]->getFormat();
  612.     int i = 0;
  613.     for (i = 0; i < 6; i++)
  614.     {
  615.         if (faces[i]->getWidth() != width ||
  616.             faces[i]->getHeight() != width ||
  617.             faces[i]->getFormat() != format)
  618.             return;
  619.     }
  620.     // For now, always enable mipmaps; in the future, it should be possible to
  621.     // override this.
  622.     bool mipmap = true;
  623.     bool precomputedMipMaps = false;
  624.     // Require a complete set of mipmaps
  625.     int mipLevelCount = faces[0]->getMipLevelCount();
  626.     if (mipmap && mipLevelCount == CalcMipLevelCount(width, width))
  627.         precomputedMipMaps = true;
  628.     // We can't automatically generate mipmaps for compressed textures.
  629.     // If a precomputed mipmap set isn't provided, turn of mipmapping entirely.
  630.     if (!precomputedMipMaps && faces[0]->isCompressed())
  631.         mipmap = false;
  632.     glGenTextures(1, (GLuint*) &glName);
  633.     glBindTexture(GL_TEXTURE_CUBE_MAP_ARB, glName);
  634.     glTexParameteri(GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
  635.     glTexParameteri(GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
  636.     glTexParameteri(GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  637.     glTexParameteri(GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_MIN_FILTER,
  638.                     mipmap ? GL_LINEAR_MIPMAP_LINEAR : GL_LINEAR);
  639.     int internalFormat = getInternalFormat(format);
  640.     for (i = 0; i < 6; i++)
  641.     {
  642.         GLenum targetFace = (GLenum) ((int) GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB + i);
  643.         Image* face = faces[i];
  644.         if (mipmap)
  645.         {
  646.             if (precomputedMipMaps)
  647.             {
  648.                 LoadMipmapSet(*face, targetFace);
  649.             }
  650.             else
  651.             {
  652.                 gluBuild2DMipmaps(targetFace,
  653.                                   internalFormat,
  654.                                   getWidth(), getHeight(),
  655.                                   (GLenum) face->getFormat(),
  656.                                   GL_UNSIGNED_BYTE,
  657.                                   face->getPixels());
  658.             }
  659.         }
  660.         else
  661.         {
  662.             LoadMiplessTexture(*face, targetFace);
  663.         }
  664.     }
  665. }
  666. CubeMap::~CubeMap()
  667. {
  668.     if (glName != 0)
  669.         glDeleteTextures(1, (const GLuint*) &glName);
  670. }
  671. void CubeMap::bind()
  672. {
  673.     glBindTexture(GL_TEXTURE_CUBE_MAP_ARB, glName);
  674. }
  675. const TextureTile CubeMap::getTile(int lod, int u, int v)
  676. {
  677.     if (lod != 0 || u != 0 || v != 0)
  678.         return TextureTile(0);
  679.     else
  680.         return TextureTile(glName);
  681. }
  682. void CubeMap::setBorderColor(Color borderColor)
  683. {
  684.     bind();
  685.     SetBorderColor(borderColor, GL_TEXTURE_CUBE_MAP_ARB);
  686. }
  687. Texture* CreateProceduralTexture(int width, int height,
  688.                                  int format,
  689.                                  ProceduralTexEval func,
  690.                                  Texture::AddressMode addressMode,
  691.                                  Texture::MipMapMode mipMode)
  692. {
  693.     Image* img = new Image(format, width, height);
  694.     if (img == NULL)
  695.         return NULL;
  696.     for (int y = 0; y < height; y++)
  697.     {
  698.         for (int x = 0; x < width; x++)
  699.         {
  700.             float u = ((float) x + 0.5f) / (float) width * 2 - 1;
  701.             float v = ((float) y + 0.5f) / (float) height * 2 - 1;
  702.             func(u, v, 0, img->getPixelRow(y) + x * img->getComponents());
  703.         }
  704.     }
  705.     Texture* tex = new ImageTexture(*img, addressMode, mipMode);
  706.     delete img;
  707.     return tex;
  708. }
  709. Texture* CreateProceduralTexture(int width, int height,
  710.                                  int format,
  711.                                  TexelFunctionObject& func,
  712.                                  Texture::AddressMode addressMode,
  713.                                  Texture::MipMapMode mipMode)
  714. {
  715.     Image* img = new Image(format, width, height);
  716.     if (img == NULL)
  717.         return NULL;
  718.     for (int y = 0; y < height; y++)
  719.     {
  720.         for (int x = 0; x < width; x++)
  721.         {
  722.             float u = ((float) x + 0.5f) / (float) width * 2 - 1;
  723.             float v = ((float) y + 0.5f) / (float) height * 2 - 1;
  724.             func(u, v, 0, img->getPixelRow(y) + x * img->getComponents());
  725.         }
  726.     }
  727.     Texture* tex = new ImageTexture(*img, addressMode, mipMode);
  728.     delete img;
  729.     return tex;
  730. }
  731. // Helper function for CreateProceduralCubeMap; return the normalized
  732. // vector pointing to (s, t) on the specified face.
  733. static Vec3f cubeVector(int face, float s, float t)
  734. {
  735.     Vec3f v;
  736.     switch (face)
  737.     {
  738.     case 0:
  739.         v = Vec3f(1.0f, -t, -s);
  740.         break;
  741.     case 1:
  742.         v = Vec3f(-1.0f, -t, s);
  743.         break;
  744.     case 2:
  745.         v = Vec3f(s, 1.0f, t);
  746.         break;
  747.     case 3:
  748.         v = Vec3f(s, -1.0f, -t);
  749.         break;
  750.     case 4:
  751.         v = Vec3f(s, -t, 1.0f);
  752.         break;
  753.     case 5:
  754.         v = Vec3f(-s, -t, -1.0f);
  755.         break;
  756.     default:
  757.         // assert(false);
  758.         break;
  759.     }
  760.     v.normalize();
  761.     return v;
  762. }
  763. extern Texture* CreateProceduralCubeMap(int size, int format,
  764.                                         ProceduralTexEval func)
  765. {
  766.     Image* faces[6];
  767.     bool failed = false;
  768.     int i = 0;
  769.     for (i = 0; i < 6; i++)
  770.     {
  771.         faces[i] = NULL;
  772.         faces[i] = new Image(format, size, size);
  773.         if (faces == NULL)
  774.             failed = true;
  775.     }
  776.     if (!failed)
  777.     {
  778.         for (int i = 0; i < 6; i++)
  779.         {
  780.             Image* face = faces[i];
  781.             for (int y = 0; y < size; y++)
  782.             {
  783.                 for (int x = 0; x < size; x++)
  784.                 {
  785.                     float s = ((float) x + 0.5f) / (float) size * 2 - 1;
  786.                     float t = ((float) y + 0.5f) / (float) size * 2 - 1;
  787.                     Vec3f v = cubeVector(i, s, t);
  788.                     func(v.x, v.y, v.z,
  789.                          face->getPixelRow(y) + x * face->getComponents());
  790.                 }
  791.             }
  792.         }
  793.     }
  794.     Texture* tex = new CubeMap(faces);
  795.     // Clean up the images
  796.     for (i = 0; i < 6; i++)
  797.     {
  798.         if (faces[i] != NULL)
  799.             delete faces[i];
  800.     }
  801.     return tex;
  802. }
  803. #if 0
  804. static bool isPow2(int x)
  805. {
  806.     return ((x & (x - 1)) == 0);
  807. }
  808. #endif
  809. static Texture* CreateTextureFromImage(Image& img,
  810.                                        Texture::AddressMode addressMode,
  811.                                        Texture::MipMapMode mipMode)
  812. {
  813. #if 0
  814.     // Require texture dimensions to be powers of two.  Even though the
  815.     // OpenGL driver will automatically rescale textures with non-power of
  816.     // two sizes, some quality loss may result.  The power of two requirement
  817.     // forces texture creators to resize their textures in an image editing
  818.     // program, hopefully resulting in  textures that look as good as possible
  819.     // when rendered on current hardware.
  820.     if (!isPow2(img.getWidth()) || !isPow2(img.getHeight()))
  821.     {
  822.         clog << "Texture has non-power of two dimensions.n";
  823.         return NULL;
  824.     }
  825. #endif
  826.     // If non power of two textures are supported switch mipmap generation to
  827.     // automatic. gluBuildMipMaps may rescale the texture to a power of two
  828.     // on some drivers even when the hardware supports non power of two textures,
  829.     // whereas auto mipmap generation will properly deal with the dimensions.
  830.     if (GetTextureCaps().nonPow2Supported)
  831.     {
  832.         if (mipMode == Texture::DefaultMipMaps)
  833.             mipMode = Texture::AutoMipMaps;
  834.     }
  835.     bool splittingAllowed = true;
  836.     Texture* tex = NULL;
  837.     int maxDim = GetTextureCaps().maxTextureSize;
  838.     if ((img.getWidth() > maxDim || img.getHeight() > maxDim) &&
  839.         splittingAllowed)
  840.     {
  841.         // The texture is too large; we need to split it.
  842.         int uSplit = max(1, img.getWidth() / maxDim);
  843.         int vSplit = max(1, img.getHeight() / maxDim);
  844.         clog << _("Creating tiled texture. Width=") << img.getWidth() << _(", max=") << maxDim << "n";
  845.         tex = new TiledTexture(img, uSplit, vSplit, mipMode);
  846.     }
  847.     else
  848.     {
  849.         clog << _("Creating ordinary texture: ") << img.getWidth() << "x" << img.getHeight() << "n";
  850.         // The image is small enough to fit in a single texture; or, splitting
  851.         // was disallowed so we'll scale the large image down to fit in
  852.         // an ordinary texture.
  853.         tex = new ImageTexture(img, addressMode, mipMode);
  854.     }
  855.     return tex;
  856. }
  857. Texture* LoadTextureFromFile(const string& filename,
  858.                              Texture::AddressMode addressMode,
  859.                              Texture::MipMapMode mipMode)
  860. {
  861.     // Check for a Celestia texture--these need to be handled specially.
  862.     ContentType contentType = DetermineFileType(filename);
  863.     if (contentType == Content_CelestiaTexture)
  864.         return LoadVirtualTexture(filename);
  865.     // All other texture types are handled by first loading an image, then
  866.     // creating a texture from that image.
  867.     Image* img = LoadImageFromFile(filename);
  868.     if (img == NULL)
  869.         return NULL;
  870.     Texture* tex = CreateTextureFromImage(*img, addressMode, mipMode);
  871.     if (contentType == Content_DXT5NormalMap)
  872.     {
  873.         // If the texture came from a .dxt5nm file then mark it as a dxt5
  874.         // compressed normal map. There's no separate OpenGL format for dxt5
  875.         // normal maps, so the file extension is the only thing that
  876.         // distinguishes it from a plain old dxt5 texture.
  877.         if (img->getFormat() == GL_COMPRESSED_RGBA_S3TC_DXT5_EXT)
  878.         {
  879.             tex->setFormatOptions(Texture::DXT5NormalMap);
  880.         }
  881.     }
  882.     delete img;
  883.     return tex;
  884. }
  885. // Load a height map texture from a file and convert it to a normal map.
  886. Texture* LoadHeightMapFromFile(const string& filename,
  887.                                float height,
  888.                                Texture::AddressMode addressMode)
  889. {
  890.     Image* img = LoadImageFromFile(filename);
  891.     if (img == NULL)
  892.         return NULL;
  893.     Image* normalMap = img->computeNormalMap(height,
  894.                                              addressMode == Texture::Wrap);
  895.     delete img;
  896.     if (normalMap == NULL)
  897.         return NULL;
  898.     Texture* tex = CreateTextureFromImage(*normalMap, addressMode,
  899.                                           Texture::DefaultMipMaps);
  900.     delete normalMap;
  901.     return tex;
  902. }