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

OpenGL

开发平台:

Visual C++

  1. // virtualtex.cpp
  2. //
  3. // Copyright (C) 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. #include <string>
  10. #include <iostream>
  11. #include <fstream>
  12. #include <cmath>
  13. #include <cassert>
  14. #include <cstdio>
  15. #include "celutil/debug.h"
  16. #include "celutil/directory.h"
  17. #include "celutil/filetype.h"
  18. #include "virtualtex.h"
  19. #include "gl.h"
  20. #include "parser.h"
  21. using namespace std;
  22. static const int MaxResolutionLevels = 13;
  23. // Virtual textures are composed of tiles that are loaded from the hard drive
  24. // as they become visible.  Hidden tiles may be evicted from graphics memory
  25. // to make room for other tiles when they become visible.
  26. //
  27. // The virtual texture consists of one or more levels of detail.  Each level
  28. // of detail is twice as wide and twice as high as the previous one, therefore
  29. // having four times as many tiles.  The height and width of each LOD must be
  30. // a power of two, with width = 2 * height.  The baseSplit determines the
  31. // number of tiles at the lowest LOD.  It is the log base 2 of the width in
  32. // tiles of LOD zero.  Though it's not required
  33. static bool isPow2(int x)
  34. {
  35.     return ((x & (x - 1)) == 0);
  36. }
  37. #if 0
  38. // Useful if we want to use a packed quadtree to store tiles instead of
  39. // the currently implemented tree structure.
  40. static inline uint lodOffset(uint lod)
  41. {
  42.     return ((1 << (lod << 1)) - 1) & 0xaaaaaaaa;
  43. }
  44. #endif
  45. VirtualTexture::VirtualTexture(const string& _tilePath,
  46.                                unsigned int _baseSplit,
  47.                                unsigned int _tileSize,
  48.                                const string& _tilePrefix,
  49.                                const string& _tileType) :
  50.     Texture(_tileSize << (_baseSplit + 1), _tileSize << _baseSplit),
  51.     tilePath(_tilePath),
  52.     tilePrefix(_tilePrefix),
  53.     baseSplit(_baseSplit),
  54.     tileSize(_tileSize),
  55.     ticks(0),
  56.     nResolutionLevels(0)
  57. {
  58.     assert(tileSize != 0 && isPow2(tileSize));
  59.     tileTree[0] = new TileQuadtreeNode();
  60.     tileTree[1] = new TileQuadtreeNode();
  61.     tileExt = string(".") + _tileType;
  62.     populateTileTree();
  63.     if (DetermineFileType(tileExt) == Content_DXT5NormalMap)
  64.         setFormatOptions(Texture::DXT5NormalMap);
  65. }
  66. VirtualTexture::~VirtualTexture()
  67. {
  68. }
  69. const TextureTile VirtualTexture::getTile(int lod, int u, int v)
  70. {
  71.     tilesRequested++;
  72. #if 0
  73.     cout << "getTile(" << lod << ", " << u << ", " << v << ")n";
  74. #endif
  75.     lod += baseSplit;
  76.     if (lod < 0 || (uint) lod >= nResolutionLevels ||
  77.         u < 0 || u >= (2 << lod) ||
  78.         v < 0 || v >= (1 << lod))
  79.     {
  80.         return TextureTile(0);
  81.     }
  82.     else
  83.     {
  84.         TileQuadtreeNode* node = tileTree[u >> lod];
  85.         Tile* tile = node->tile;
  86.         uint tileLOD = 0;
  87.         for (int n = 0; n < lod; n++)
  88.         {
  89.             uint mask = 1 << (lod - n - 1);
  90.             uint child = (((v & mask) << 1) | (u & mask)) >> (lod - n - 1);
  91.             //int child = (((v << 1) | u) >> (lod - n - 1)) & 3;
  92.             if (node->children[child] == NULL)
  93.             {
  94.                 break;
  95.             }
  96.             else
  97.             {
  98.                 node = node->children[child];
  99.                 if (node->tile != NULL)
  100.                 {
  101.                     tile = node->tile;
  102.                     tileLOD = n + 1;
  103.                 }
  104.             }
  105.         }
  106.         // No tile was found at all--not even the base texture was found
  107.         if (tile == NULL)
  108.         {
  109.             return TextureTile(0);
  110.         }
  111.         // Make the tile resident.
  112.         uint tileU = u >> (lod - tileLOD);
  113.         uint tileV = v >> (lod - tileLOD);
  114.         makeResident(tile, tileLOD, tileU, tileV);
  115.         // It's possible that we failed to make the tile resident, either
  116.         // because the texture file was bad, or there was an unresolvable
  117.         // out of memory situation.  In that case there is nothing else to
  118.         // do but return a texture tile with a null texture name.
  119.         if (tile->tex == NULL)
  120.         {
  121.             return TextureTile(0);
  122.         }
  123.         else
  124.         {
  125.             // Set up the texture subrect to be the entire texture
  126.             float texU = 0.0f;
  127.             float texV = 0.0f;
  128.             float texDU = 1.0f;
  129.             float texDV = 1.0f;
  130.             // If the tile came from a lower LOD than the requested one,
  131.             // we'll only use a subsection of it.
  132.             uint lodDiff = lod - tileLOD;
  133.             texDU = texDV = 1.0f / (float) (1 << lodDiff);
  134.             texU = (u & ((1 << lodDiff) - 1)) * texDU;
  135.             texV = (v & ((1 << lodDiff) - 1)) * texDV;
  136. #if 0
  137.             cout << "Tile: " << tile->tex->getName() << ", " <<
  138.                 texU << ", " << texV << ", " << texDU << ", " << texDV << 'n';
  139. #endif
  140.             return TextureTile(tile->tex->getName(),
  141.                                texU, texV, texDU, texDV);
  142.         }
  143.     }
  144. }
  145. void VirtualTexture::bind()
  146. {
  147.     // Treating a virtual texture like an ordinary one will not work; this is a
  148.     // weakness in the class hierarchy.
  149. }
  150. int VirtualTexture::getLODCount() const
  151. {
  152.     return nResolutionLevels - baseSplit;
  153. }
  154. int VirtualTexture::getUTileCount(int lod) const
  155. {
  156.     return 2 << (lod + baseSplit);
  157. }
  158. int VirtualTexture::getVTileCount(int lod) const
  159. {
  160.     return 1 << (lod + baseSplit);
  161. }
  162. void VirtualTexture::beginUsage()
  163. {
  164.     ticks++;
  165.     tilesRequested = 0;
  166. }
  167. void VirtualTexture::endUsage()
  168. {
  169. }
  170. #if 0
  171. uint VirtualTexture::tileIndex(unsigned int lod,
  172.                                unsigned int u, unsigned int v)
  173. {
  174.     unsigned int lodBase = lodOffset(lod + baseSplit) - lodOffset(baseSplit);
  175.     return lodBase + (v << (lod << 1)) + u;
  176. }
  177. #endif
  178. ImageTexture* VirtualTexture::loadTileTexture(uint lod, uint u, uint v)
  179. {
  180.     lod >>= baseSplit;
  181.     assert(lod < (unsigned)MaxResolutionLevels);
  182.     char filename[64];
  183.     sprintf(filename, "level%d/%s%d_%d", lod, tilePrefix.c_str(), u, v);
  184.     string pathname = tilePath + filename + tileExt;
  185.     Image* img = LoadImageFromFile(pathname);
  186.     if (img == NULL)
  187.         return NULL;
  188.     ImageTexture* tex = NULL;
  189.     // Only use mip maps for the LOD 0; for higher LODs, the function of mip
  190.     // mapping is built into the texture.
  191.     MipMapMode mipMapMode = lod == 0 ? DefaultMipMaps : NoMipMaps;
  192.     if (isPow2(img->getWidth()) && isPow2(img->getHeight()))
  193.         tex = new ImageTexture(*img, EdgeClamp, mipMapMode);
  194.     // TODO: Virtual textures can have tiles in different formats, some
  195.     // compressed and some not. The compression flag doesn't make much
  196.     // sense for them.
  197.     compressed = img->isCompressed();
  198.     delete img;
  199.     return tex;
  200. }
  201. void VirtualTexture::makeResident(Tile* tile, uint lod, uint u, uint v)
  202. {
  203.     if (tile->tex == NULL && !tile->loadFailed)
  204.     {
  205.         // Potentially evict other tiles in order to make this one fit
  206.         tile->tex = loadTileTexture(lod, u, v);
  207.         if (tile->tex == NULL)
  208.         {
  209.             // cout << "Texture load failed!n";
  210.             tile->loadFailed = true;
  211.         }
  212.     }
  213. }
  214. void VirtualTexture::populateTileTree()
  215. {
  216.     // Count the number of resolution levels present
  217.     uint maxLevel = 0;
  218.     // Crash potential if the tile prefix contains a %, so disallow it
  219.     string pattern;
  220.     if (tilePrefix.find('%') == string::npos)
  221.         pattern = tilePrefix + "%d_%d.";
  222.     for (int i = 0; i < MaxResolutionLevels; i++)
  223.     {
  224.         char filename[32];
  225.         sprintf(filename, "level%d", i);
  226.         if (IsDirectory(tilePath + filename))
  227.         {
  228.             Directory* dir = OpenDirectory(tilePath + filename);
  229.             if (dir != NULL)
  230.             {
  231.                 maxLevel = i + baseSplit;
  232.                 int uLimit = 2 << maxLevel;
  233.                 int vLimit = 1 << maxLevel;
  234.                 string filename;
  235.                 while (dir->nextFile(filename))
  236.                 {
  237.                     int u = -1, v = -1;
  238.                     if (sscanf(filename.c_str(), pattern.c_str(), &u, &v) == 2)
  239.                     {
  240.                         if (u >= 0 && v >= 0 && u < uLimit && v < vLimit)
  241.                         {
  242.                             // Found a tile, so add it to the quadtree
  243.                             Tile* tile = new Tile();
  244.                             addTileToTree(tile, maxLevel, (uint) u, (uint) v);
  245.                         }
  246.                     }
  247.                 }
  248.                 delete dir;
  249.             }
  250.         }
  251.     }
  252.     nResolutionLevels = maxLevel + 1;
  253. }
  254. void VirtualTexture::addTileToTree(Tile* tile, uint lod, uint u, uint v)
  255. {
  256.     TileQuadtreeNode* node = tileTree[u >> lod];
  257.     for (uint i = 0; i < lod; i++)
  258.     {
  259.         uint mask = 1 << (lod - i - 1);
  260.         uint child = (((v & mask) << 1) | (u & mask)) >> (lod - i - 1);
  261.         if (node->children[child] == NULL)
  262.             node->children[child] = new TileQuadtreeNode();
  263.         node = node->children[child];
  264.     }
  265. #if 0
  266.     clog << "addTileToTree: " << node << ", " << lod << ", " << u << ", " << v << 'n';
  267. #endif
  268.     // Verify that the tile doesn't already exist
  269.     if (node->tile == NULL)
  270.         node->tile = tile;
  271. }
  272. static VirtualTexture* CreateVirtualTexture(Hash* texParams,
  273.                                             const string& path)
  274. {
  275.     string imageDirectory;
  276.     if (!texParams->getString("ImageDirectory", imageDirectory))
  277.     {
  278.         DPRINTF(0, "ImageDirectory missing in virtual texture.n");
  279.         return NULL;
  280.     }
  281.     double baseSplit = 0.0;
  282.     if (!texParams->getNumber("BaseSplit", baseSplit) ||
  283.         baseSplit < 0.0 || baseSplit != floor(baseSplit))
  284.     {
  285.         DPRINTF(0, "BaseSplit in virtual texture missing or has bad valuen");
  286.         return NULL;
  287.     }
  288.     double tileSize = 0.0;
  289.     if (!texParams->getNumber("TileSize", tileSize))
  290.     {
  291.         DPRINTF(0, "TileSize is missing from virtual texturen");
  292.         return NULL;
  293.     }
  294.     if (tileSize != floor(tileSize) ||
  295.         tileSize < 64.0 ||
  296.         !isPow2((int) tileSize))
  297.     {
  298.         DPRINTF(0, "Virtual texture tile size must be a power of two >= 64n");
  299.         return NULL;
  300.     }
  301.     string tileType = "dds";
  302.     texParams->getString("TileType", tileType);
  303.     string tilePrefix = "tx_";
  304.     texParams->getString("TilePrefix", tilePrefix);
  305.     // if absolute directory notation for ImageDirectory used, 
  306. // don't prepend the current add-on path.
  307. string directory = imageDirectory + "/";
  308. if (directory.substr(0,1) != "/" && directory.substr(1,1) !=":") 
  309.     {
  310. directory = path + "/" + directory;
  311. }
  312.     return new VirtualTexture(directory,
  313.                               (unsigned int) baseSplit,
  314.                               (unsigned int) tileSize,
  315.                               tilePrefix,
  316.                               tileType);
  317. }
  318. static VirtualTexture* LoadVirtualTexture(istream& in, const string& path)
  319. {
  320.     Tokenizer tokenizer(&in);
  321.     Parser parser(&tokenizer);
  322.     if (tokenizer.nextToken() != Tokenizer::TokenName)
  323.         return NULL;
  324.     string virtTexString = tokenizer.getNameValue();
  325.     if (virtTexString != "VirtualTexture")
  326.         return NULL;
  327.     Value* texParamsValue = parser.readValue();
  328.     if (texParamsValue == NULL || texParamsValue->getType() != Value::HashType)
  329.     {
  330.         DPRINTF(0, "Error parsing virtual texturen");
  331.         delete texParamsValue;
  332.         return NULL;
  333.     }
  334.     Hash* texParams = texParamsValue->getHash();
  335.     VirtualTexture* virtualTex  = CreateVirtualTexture(texParams, path);
  336.     delete texParamsValue;
  337.     return virtualTex;
  338. }
  339. VirtualTexture* LoadVirtualTexture(const string& filename)
  340. {
  341.     ifstream in(filename.c_str(), ios::in);
  342.     if (!in.good())
  343.     {
  344.         //DPRINTF(0, "Error opening virtual texture file: %sn", filename.c_str());
  345.         return NULL;
  346.     }
  347.     // Strip off every character including and after the final slash to get
  348.     // the pathname.
  349.     string path = ".";
  350.     string::size_type pos = filename.rfind('/');
  351.     if (pos != string::npos)
  352.         path = string(filename, 0, pos);
  353.     return LoadVirtualTexture(in, path);
  354. }