00001
00002
00003
00004
00005
00006
00007
00008
00009
00010 #include <string>
00011 #include <iostream>
00012 #include <fstream>
00013 #include <cmath>
00014 #include <cassert>
00015 #include <cstdio>
00016 #include "celutil/debug.h"
00017 #include "celutil/directory.h"
00018 #include "virtualtex.h"
00019 #include "gl.h"
00020 #include "parser.h"
00021
00022 using namespace std;
00023
00024 static const int MaxResolutionLevels = 11;
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038 static bool isPow2(int x)
00039 {
00040 return ((x & (x - 1)) == 0);
00041 }
00042
00043
00044 #if 0
00045
00046
00047 static inline uint lodOffset(uint lod)
00048 {
00049 return ((1 << (lod << 1)) - 1) & 0xaaaaaaaa;
00050 }
00051 #endif
00052
00053
00054 VirtualTexture::VirtualTexture(const string& _tilePath,
00055 unsigned int _baseSplit,
00056 unsigned int _tileSize,
00057 const string& _tilePrefix,
00058 const string& _tileType) :
00059 Texture(_tileSize << (_baseSplit + 1), _tileSize << _baseSplit),
00060 tilePath(_tilePath),
00061 baseSplit(_baseSplit),
00062 tilePrefix(_tilePrefix),
00063 tileSize(_tileSize),
00064 ticks(0),
00065 nResolutionLevels(0)
00066 {
00067 assert(tileSize != 0 && isPow2(tileSize));
00068 tileTree[0] = new TileQuadtreeNode();
00069 tileTree[1] = new TileQuadtreeNode();
00070 tileExt = string(".") + _tileType;
00071 populateTileTree();
00072 }
00073
00074
00075 VirtualTexture::~VirtualTexture()
00076 {
00077 }
00078
00079
00080 const TextureTile VirtualTexture::getTile(int lod, int u, int v)
00081 {
00082 tilesRequested++;
00083 #if 0
00084 cout << "getTile(" << lod << ", " << u << ", " << v << ")\n";
00085 #endif
00086
00087 lod += baseSplit;
00088
00089 if (lod < 0 || (uint) lod >= nResolutionLevels ||
00090 u < 0 || u >= (2 << lod) ||
00091 v < 0 || v >= (1 << lod))
00092 {
00093 return TextureTile(0);
00094 }
00095 else
00096 {
00097 TileQuadtreeNode* node = tileTree[u >> lod];
00098 Tile* tile = node->tile;
00099 uint tileLOD = 0;
00100
00101 for (int n = 0; n < lod; n++)
00102 {
00103 uint mask = 1 << (lod - n - 1);
00104 uint child = (((v & mask) << 1) | (u & mask)) >> (lod - n - 1);
00105
00106 if (node->children[child] == NULL)
00107 {
00108 break;
00109 }
00110 else
00111 {
00112 node = node->children[child];
00113 if (node->tile != NULL)
00114 {
00115 tile = node->tile;
00116 tileLOD = n + 1;
00117 }
00118 }
00119 }
00120
00121
00122 if (tile == NULL)
00123 {
00124 return TextureTile(0);
00125 }
00126
00127
00128 uint tileU = u >> (lod - tileLOD);
00129 uint tileV = v >> (lod - tileLOD);
00130 makeResident(tile, tileLOD, tileU, tileV);
00131
00132
00133
00134
00135
00136 if (tile->tex == NULL)
00137 {
00138 return TextureTile(0);
00139 }
00140 else
00141 {
00142
00143 float texU = 0.0f;
00144 float texV = 0.0f;
00145 float texDU = 1.0f;
00146 float texDV = 1.0f;
00147
00148
00149
00150 uint lodDiff = lod - tileLOD;
00151 texDU = texDV = 1.0f / (float) (1 << lodDiff);
00152 texU = (u & ((1 << lodDiff) - 1)) * texDU;
00153 texV = (v & ((1 << lodDiff) - 1)) * texDV;
00154
00155 #if 0
00156 cout << "Tile: " << tile->tex->getName() << ", " <<
00157 texU << ", " << texV << ", " << texDU << ", " << texDV << '\n';
00158 #endif
00159 return TextureTile(tile->tex->getName(),
00160 texU, texV, texDU, texDV);
00161 }
00162 }
00163 }
00164
00165
00166 void VirtualTexture::bind()
00167 {
00168
00169
00170 }
00171
00172
00173 int VirtualTexture::getLODCount() const
00174 {
00175 return nResolutionLevels - baseSplit;
00176 }
00177
00178
00179 int VirtualTexture::getUTileCount(int lod) const
00180 {
00181 return 2 << (lod + baseSplit);
00182 }
00183
00184
00185 int VirtualTexture::getVTileCount(int lod) const
00186 {
00187 return 1 << (lod + baseSplit);
00188 }
00189
00190
00191 void VirtualTexture::beginUsage()
00192 {
00193 ticks++;
00194 tilesRequested = 0;
00195 }
00196
00197
00198 void VirtualTexture::endUsage()
00199 {
00200 }
00201
00202
00203 #if 0
00204 uint VirtualTexture::tileIndex(unsigned int lod,
00205 unsigned int u, unsigned int v)
00206 {
00207 unsigned int lodBase = lodOffset(lod + baseSplit) - lodOffset(baseSplit);
00208 return lodBase + (v << (lod << 1)) + u;
00209 }
00210 #endif
00211
00212
00213 ImageTexture* VirtualTexture::loadTileTexture(uint lod, uint u, uint v)
00214 {
00215 lod >>= baseSplit;
00216
00217 assert(lod < (unsigned)MaxResolutionLevels);
00218
00219 char filename[64];
00220 sprintf(filename, "level%d/%s%d_%d", lod, tilePrefix.c_str(), u, v);
00221
00222 string pathname = tilePath + filename + tileExt;
00223 Image* img = LoadImageFromFile(pathname);
00224 if (img == NULL)
00225 return NULL;
00226
00227 ImageTexture* tex = NULL;
00228
00229
00230
00231 MipMapMode mipMapMode = lod == 0 ? DefaultMipMaps : NoMipMaps;
00232
00233 if (isPow2(img->getWidth()) && isPow2(img->getHeight()))
00234 tex = new ImageTexture(*img, EdgeClamp, mipMapMode);
00235 delete img;
00236
00237 return tex;
00238 }
00239
00240
00241 void VirtualTexture::makeResident(Tile* tile, uint lod, uint u, uint v)
00242 {
00243 if (tile->tex == NULL && !tile->loadFailed)
00244 {
00245
00246 tile->tex = loadTileTexture(lod, u, v);
00247 if (tile->tex == NULL)
00248 {
00249
00250 tile->loadFailed = true;
00251 }
00252 }
00253 }
00254
00255
00256 void VirtualTexture::populateTileTree()
00257 {
00258
00259 uint maxLevel = 0;
00260
00261
00262 string pattern;
00263 if (tilePrefix.find('%') == string::npos)
00264 pattern = tilePrefix + "%d_%d.";
00265
00266 for (int i = 0; i < MaxResolutionLevels; i++)
00267 {
00268 char filename[32];
00269 sprintf(filename, "level%d", i);
00270 if (IsDirectory(tilePath + filename))
00271 {
00272 Directory* dir = OpenDirectory(tilePath + filename);
00273 if (dir != NULL)
00274 {
00275 maxLevel = i + baseSplit;
00276 int uLimit = 2 << maxLevel;
00277 int vLimit = 1 << maxLevel;
00278
00279 string filename;
00280 while (dir->nextFile(filename))
00281 {
00282 int u = -1, v = -1;
00283 if (sscanf(filename.c_str(), pattern.c_str(), &u, &v) == 2)
00284 {
00285 if (u >= 0 && v >= 0 && u < uLimit && v < vLimit)
00286 {
00287
00288 Tile* tile = new Tile();
00289 addTileToTree(tile, maxLevel, (uint) u, (uint) v);
00290 }
00291 }
00292 }
00293 }
00294 }
00295 }
00296
00297 nResolutionLevels = maxLevel + 1;
00298 }
00299
00300
00301 void VirtualTexture::addTileToTree(Tile* tile, uint lod, uint u, uint v)
00302 {
00303 TileQuadtreeNode* node = tileTree[u >> lod];
00304
00305 for (uint i = 0; i < lod; i++)
00306 {
00307 uint mask = 1 << (lod - i - 1);
00308 uint child = (((v & mask) << 1) | (u & mask)) >> (lod - i - 1);
00309 if (node->children[child] == NULL)
00310 node->children[child] = new TileQuadtreeNode();
00311 node = node->children[child];
00312 }
00313 #if 0
00314 clog << "addTileToTree: " << node << ", " << lod << ", " << u << ", " << v << '\n';
00315 #endif
00316
00317
00318 if (node->tile == NULL)
00319 node->tile = tile;
00320 }
00321
00322
00323 static VirtualTexture* CreateVirtualTexture(Hash* texParams,
00324 const string& path)
00325 {
00326 string imageDirectory;
00327 if (!texParams->getString("ImageDirectory", imageDirectory))
00328 {
00329 DPRINTF(0, "ImageDirectory missing in virtual texture.\n");
00330 return NULL;
00331 }
00332
00333 double baseSplit = 0.0;
00334 if (!texParams->getNumber("BaseSplit", baseSplit) ||
00335 baseSplit < 0.0 || baseSplit != floor(baseSplit))
00336 {
00337 DPRINTF(0, "BaseSplit in virtual texture missing or has bad value\n");
00338 return NULL;
00339 }
00340
00341 double tileSize = 0.0;
00342 if (!texParams->getNumber("TileSize", tileSize))
00343 {
00344 DPRINTF(0, "TileSize is missing from virtual texture\n");
00345 return NULL;
00346 }
00347
00348 if (tileSize != floor(tileSize) ||
00349 tileSize < 64.0 ||
00350 !isPow2((int) tileSize))
00351 {
00352 DPRINTF(0, "Virtual texture tile size must be a power of two >= 64\n");
00353 return NULL;
00354 }
00355
00356 string tileType = "dds";
00357 texParams->getString("TileType", tileType);
00358
00359 string tilePrefix = "tx_";
00360 texParams->getString("TilePrefix", tilePrefix);
00361
00362 return new VirtualTexture(path + "/" + imageDirectory + "/",
00363 (unsigned int) baseSplit,
00364 (unsigned int) tileSize,
00365 tilePrefix,
00366 tileType);
00367
00368 return NULL;
00369 }
00370
00371
00372 static VirtualTexture* LoadVirtualTexture(istream& in, const string& path)
00373 {
00374 Tokenizer tokenizer(&in);
00375 Parser parser(&tokenizer);
00376
00377 if (tokenizer.nextToken() != Tokenizer::TokenName)
00378 return NULL;
00379
00380 string virtTexString = tokenizer.getNameValue();
00381 if (virtTexString != "VirtualTexture")
00382 return NULL;
00383
00384 Value* texParamsValue = parser.readValue();
00385 if (texParamsValue == NULL || texParamsValue->getType() != Value::HashType)
00386 {
00387 DPRINTF(0, "Error parsing virtual texture\n");
00388 return NULL;
00389 }
00390
00391 Hash* texParams = texParamsValue->getHash();
00392
00393 return CreateVirtualTexture(texParams, path);
00394 }
00395
00396
00397 VirtualTexture* LoadVirtualTexture(const string& filename)
00398 {
00399 ifstream in(filename.c_str(), ios::in);
00400
00401 if (!in.good())
00402 {
00403
00404 return NULL;
00405 }
00406
00407
00408
00409 string path = ".";
00410 string::size_type pos = filename.rfind('/');
00411 if (pos != string::npos)
00412 path = string(filename, 0, pos);
00413
00414 return LoadVirtualTexture(in, path);
00415 }