00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #ifndef LUX_MIPMAP_H
00024 #define LUX_MIPMAP_H
00025
00026 #include "lux.h"
00027 #include "spectrum.h"
00028 #include "texture.h"
00029 #include "texturecolor.h"
00030 #include "memory.h"
00031 #include "error.h"
00032
00033 namespace lux
00034 {
00035
00036
00037 enum ImageTextureFilterType {
00038 NEAREST,
00039 BILINEAR,
00040 MIPMAP_TRILINEAR,
00041 MIPMAP_EWA
00042 };
00043
00044
00045 typedef enum {
00046 TEXTURE_REPEAT,
00047 TEXTURE_BLACK,
00048 TEXTURE_CLAMP
00049 } ImageWrap;
00050
00051 template <class T> class MIPMap {
00052 public:
00053
00054 virtual ~MIPMap() {};
00055 virtual T Lookup(float s, float t, float width = 0.f) const = 0;
00056 virtual T Lookup(float s, float t, float ds0, float dt0,
00057 float ds1, float dt1) const = 0;
00058
00059 virtual u_int getMemoryUsed() const = 0;
00060 virtual void discardMipmaps(int n) { }
00061 };
00062
00063 template <class T, class U> class MIPMapImpl : public MIPMap<T> {
00064 public:
00065
00066 MIPMapImpl(
00067 ImageTextureFilterType type,
00068 int xres, int yres, const U *data,
00069 float maxAniso = 8.f, ImageWrap wrapMode = TEXTURE_REPEAT,
00070 float gain = 1.f, float gamma = 1.0f);
00071 ~MIPMapImpl();
00072
00073 T Lookup(float s, float t, float width = 0.f) const;
00074 T Lookup(float s, float t, float ds0, float dt0,
00075 float ds1, float dt1) const;
00076
00077 u_int getMemoryUsed() const {
00078 if ((filterType == MIPMAP_EWA) || (filterType == MIPMAP_TRILINEAR)) {
00079 u_int size = 0;
00080
00081 for (int i = 0; i < nLevels; i++)
00082 size += pyramid[i]->uSize() * pyramid[i]->vSize() * sizeof(U);
00083
00084 return size;
00085 } else if ((filterType == NEAREST) || (filterType == BILINEAR)) {
00086 return singleMap->uSize() * singleMap->vSize() * sizeof(U);
00087 } else {
00088 luxError(LUX_SYSTEM, LUX_ERROR, "Internal error in MIPMapImpl::~MIPMapImpl(), unknown filter type");
00089 return 0;
00090 }
00091 }
00092
00093 void discardMipmaps(int n) {
00094 for (int i = 0; i < n; i++) {
00095 if (nLevels <= 1)
00096 return;
00097
00098 delete pyramid[0];
00099
00100 nLevels--;
00101 BlockedArray<U> **newPyramid = new BlockedArray<U> *[nLevels];
00102 for (int j = 0; j < nLevels; j++)
00103 newPyramid[j] = pyramid[j + 1];
00104
00105 delete[] pyramid;
00106 pyramid = newPyramid;
00107 }
00108 }
00109
00110 protected:
00111
00112 const U& texelInternal(int level, int s, int t) const;
00113 const T texel(int level, int s, int t) const {
00114 T texelValue;
00115 convert(texelValue, texelInternal(level, s, t));
00116
00117 return texelValue;
00118 }
00119
00120
00121 const U& texelInternal(int s, int t) const;
00122 const T texel(int s, int t) const {
00123 T texelValue;
00124 convert(texelValue, texelInternal(s, t));
00125
00126 return texelValue;
00127 }
00128
00129
00130
00131 inline virtual void convert(Spectrum& outputValue, const TextureColor<unsigned char, 1> &internalValue) const
00132 {
00133 float c = static_cast<float>(internalValue.c[0]) * invMaxUnsignedChar;
00134 outputValue = (Spectrum(c) * gain).Pow(gamma);
00135 }
00136 inline virtual void convert(Spectrum& outputValue, const TextureColor<unsigned char, 3> &internalValue) const
00137 {
00138 float c[3];
00139 for (int i = 0; i < 3; ++i) {
00140 c[i] = static_cast<float>(internalValue.c[i]) * invMaxUnsignedChar;
00141 }
00142 outputValue = (Spectrum(c) * gain).Pow(gamma);
00143 }
00144 inline virtual void convert(Spectrum& outputValue, const TextureColor<unsigned char, 4> &internalValue) const
00145 {
00146 float c[3];
00147 for (int i = 0; i < 3; ++i) {
00148 c[i] = static_cast<float>(internalValue.c[i]) * invMaxUnsignedChar;
00149 }
00150 outputValue = (Spectrum(c) * gain).Pow(gamma);
00151 }
00152
00153
00154 inline virtual void convert(Spectrum& outputValue, const TextureColor<unsigned short, 1> &internalValue) const
00155 {
00156 float c = static_cast<float>(internalValue.c[0]) * invMaxUnsignedShort;
00157 outputValue = (Spectrum(c) * gain).Pow(gamma);
00158 }
00159 inline virtual void convert(Spectrum& outputValue, const TextureColor<unsigned short, 3> &internalValue) const
00160 {
00161 float c[3];
00162 for (int i = 0; i < 3; ++i) {
00163 c[i] = static_cast<float>(internalValue.c[i]) * invMaxUnsignedShort;
00164 }
00165 outputValue = (Spectrum(c) * gain).Pow(gamma);
00166 }
00167 inline virtual void convert(Spectrum& outputValue, const TextureColor<unsigned short, 4> &internalValue) const
00168 {
00169 float c[3];
00170 for (int i = 0; i < 3; ++i) {
00171 c[i] = static_cast<float>(internalValue.c[i]) * invMaxUnsignedShort;
00172 }
00173 outputValue= (Spectrum(c) * gain).Pow(gamma);
00174 }
00175
00176
00177 inline virtual void convert(Spectrum& outputValue, const TextureColor<float, 1> &internalValue) const
00178 {
00179 outputValue = (Spectrum(internalValue.c[0]) * gain).Pow(gamma);
00180 }
00181 inline virtual void convert(Spectrum& outputValue, const TextureColor<float, 3> &internalValue) const
00182 {
00183 outputValue = (Spectrum(internalValue.c) * gain).Pow(gamma);
00184 }
00185 inline virtual void convert(Spectrum& outputValue, const TextureColor<float, 4> &internalValue) const
00186 {
00187 outputValue = (Spectrum(internalValue.c) * gain).Pow(gamma);
00188 }
00189 inline virtual void convert(Spectrum& outputValue, const Spectrum &internalValue) const
00190 {
00191 outputValue = (internalValue * gain).Pow(gamma);
00192 }
00193
00194 template<class V, int n>
00195 inline void convert(float& outputValue, const TextureColor<V, n> &internalValue) const
00196 {
00197 Spectrum specValue;
00198 convert(specValue, internalValue);
00199 outputValue = specValue.y();
00200 }
00201 inline virtual void convert(float& outputValue, const float internalValue) const
00202 {
00203 outputValue = powf(internalValue * gain, gamma);
00204 }
00205
00206
00207 static float invMaxUnsignedChar;
00208 static float invMaxUnsignedShort;
00209
00210 private:
00211
00212 struct ResampleWeight {
00213 int firstTexel;
00214 float weight[4];
00215 };
00216
00217 ResampleWeight *resampleWeights(int oldres, int newres) {
00218 BOOST_ASSERT(newres >= oldres);
00219 ResampleWeight *wt = new ResampleWeight[newres];
00220 float filterwidth = 2.f;
00221 for (int i = 0; i < newres; ++i) {
00222
00223 float center = (i + .5f) * oldres / newres;
00224 wt[i].firstTexel = Floor2Int(center - filterwidth + 0.5f);
00225 for (int j = 0; j < 4; ++j) {
00226 float pos = wt[i].firstTexel + j + .5f;
00227 wt[i].weight[j] = Lanczos((pos - center) / filterwidth);
00228 }
00229
00230 float invSumWts = 1.f / (wt[i].weight[0] + wt[i].weight[1] +
00231 wt[i].weight[2] + wt[i].weight[3]);
00232 for (int j = 0; j < 4; ++j)
00233 wt[i].weight[j] *= invSumWts;
00234 }
00235 return wt;
00236 }
00237
00238 inline int uSize(int level) const { return pyramid[level]->uSize(); }
00239 inline int vSize(int level) const { return pyramid[level]->vSize(); }
00240
00241 T triangle(int level, float s, float t) const;
00242 T triangle(float s, float t) const;
00243 T nearest(float s, float t) const;
00244 T EWA(float s, float t, float ds0, float dt0, float ds1, float dt1, int level) const;
00245
00246
00247 ImageTextureFilterType filterType;
00248 float maxAnisotropy;
00249 float gain;
00250 float gamma;
00251 ImageWrap wrapMode;
00252 int nLevels;
00253 union {
00254 BlockedArray<U> **pyramid;
00255 BlockedArray<U> *singleMap;
00256 };
00257
00258 #define WEIGHT_LUT_SIZE 128
00259 static float *weightLut;
00260
00261
00262 inline float clamp(float v) { return max(v, 0.f); }
00263 inline Spectrum clamp(const Spectrum &v) { return v.Clamp(0.f, INFINITY); }
00264 inline TextureColor<unsigned char, 1> clamp(const TextureColor<unsigned char, 1> &v) { return v.Clamp(0.f, INFINITY); }
00265 inline TextureColor<unsigned char, 3> clamp(const TextureColor<unsigned char, 3> &v) { return v.Clamp(0.f, INFINITY); }
00266 inline TextureColor<unsigned char, 4> clamp(const TextureColor<unsigned char, 4> &v) { return v.Clamp(0.f, INFINITY); }
00267 inline TextureColor<unsigned short, 1> clamp(const TextureColor<unsigned short, 1> &v) { return v.Clamp(0.f, INFINITY); }
00268 inline TextureColor<unsigned short, 3> clamp(const TextureColor<unsigned short, 3> &v) { return v.Clamp(0.f, INFINITY); }
00269 inline TextureColor<unsigned short, 4> clamp(const TextureColor<unsigned short, 4> &v) { return v.Clamp(0.f, INFINITY); }
00270 inline TextureColor<float, 1> clamp(const TextureColor<float, 1> &v) { return v.Clamp(0.f, INFINITY); }
00271 inline TextureColor<float, 3> clamp(const TextureColor<float, 3> &v) { return v.Clamp(0.f, INFINITY); }
00272 inline TextureColor<float, 4> clamp(const TextureColor<float, 4> &v) { return v.Clamp(0.f, INFINITY); }
00273 };
00274
00275 template <class T, class U> float *MIPMapImpl<T, U>::weightLut = NULL;
00276 template <class T, class U> float MIPMapImpl<T, U>::invMaxUnsignedChar = 1.0f / (std::numeric_limits<unsigned char>::max() - 1);
00277 template <class T, class U> float MIPMapImpl<T, U>::invMaxUnsignedShort = 1.0f / (std::numeric_limits<unsigned short>::max() - 1);
00278
00279
00280
00281 template <class T, class U>
00282 T MIPMapImpl<T, U>::Lookup(float s, float t, float width) const
00283 {
00284 switch (filterType) {
00285 case MIPMAP_TRILINEAR:
00286 case MIPMAP_EWA: {
00287
00288 float level = nLevels - 1 + Log2(max(width, 1e-8f));
00289
00290 if (level < 0)
00291 return triangle(0, s, t);
00292 else if (level >= nLevels - 1)
00293 return texel(nLevels - 1, 0, 0);
00294 else {
00295 int iLevel = Floor2Int(level);
00296 float delta = level - iLevel;
00297 return Lerp<T>(delta, triangle(iLevel, s, t), triangle(iLevel + 1, s, t));
00298 }
00299 }
00300 case BILINEAR:
00301 return triangle(s, t);
00302 case NEAREST:
00303 return nearest(s, t);
00304 default:
00305 luxError(LUX_SYSTEM, LUX_ERROR, "Internal error in MIPMapImpl::Lookup()");
00306 return T();
00307 }
00308 }
00309
00310 template <class T, class U>
00311 T MIPMapImpl<T, U>::triangle(int level, float s, float t) const {
00312 level = Clamp(level, 0, nLevels - 1);
00313 s = s * uSize(level) - 0.5f;
00314 t = t * vSize(level) - 0.5f;
00315 int s0 = Floor2Int(s), t0 = Floor2Int(t);
00316 float ds = s - s0, dt = t - t0;
00317 return (1.f - ds) * (1.f - dt) * texel(level, s0, t0) +
00318 (1.f - ds) * dt * texel(level, s0, t0 + 1) +
00319 ds * (1.f - dt) * texel(level, s0 + 1, t0) +
00320 ds * dt * texel(level, s0 + 1, t0 + 1);
00321 }
00322
00323 template <class T, class U>
00324 T MIPMapImpl<T, U>::triangle(float s, float t) const {
00325 s = s * singleMap->uSize() - 0.5f;
00326 t = t * singleMap->vSize() - 0.5f;
00327 int s0 = Floor2Int(s), t0 = Floor2Int(t);
00328 float ds = s - s0, dt = t - t0;
00329 return (1.f - ds) * (1.f - dt) * texel(s0, t0) +
00330 (1.f - ds) * dt * texel(s0, t0 + 1) +
00331 ds * (1.f - dt) * texel(s0 + 1, t0) +
00332 ds * dt * texel(s0 + 1, t0 + 1);
00333 }
00334
00335 template <class T, class U>
00336 T MIPMapImpl<T, U>::nearest(float s, float t) const {
00337 s = s * singleMap->uSize() - 0.5f;
00338 t = t * singleMap->vSize() - 0.5f;
00339 int s0 = Floor2Int(s), t0 = Floor2Int(t);
00340
00341 return texel(s0,t0);
00342 }
00343
00344 template <class T, class U>
00345 T MIPMapImpl<T, U>::Lookup(float s, float t, float ds0, float dt0,
00346 float ds1, float dt1) const
00347 {
00348 switch (filterType) {
00349 case MIPMAP_TRILINEAR:
00350 return Lookup(s, t, 2.f * max(max(fabsf(ds0), fabsf(dt0)),
00351 max(fabsf(ds1), fabsf(dt1))));
00352 case MIPMAP_EWA: {
00353
00354 if (ds0 * ds0 + dt0 * dt0 < ds1 * ds1 + dt1 * dt1) {
00355 swap(ds0, ds1);
00356 swap(dt0, dt1);
00357 }
00358 float majorLength = sqrtf(ds0 * ds0 + dt0 * dt0);
00359 float minorLength = sqrtf(ds1 * ds1 + dt1 * dt1);
00360
00361
00362 if (minorLength * maxAnisotropy < majorLength) {
00363 float scale = majorLength / (minorLength * maxAnisotropy);
00364 ds1 *= scale;
00365 dt1 *= scale;
00366 minorLength *= scale;
00367 }
00368
00369
00370 float lod = max(0.f, nLevels - 1 + Log2(minorLength));
00371 int ilod = Floor2Int(lod);
00372 float d = lod - ilod;
00373 return Lerp<T>(d, EWA(s, t, ds0, dt0, ds1, dt1, ilod), EWA(s, t, ds0, dt0, ds1, dt1, ilod + 1));
00374 }
00375 case BILINEAR:
00376 return triangle(s, t);
00377 case NEAREST:
00378 return nearest(s, t);
00379 default:
00380 luxError(LUX_SYSTEM, LUX_ERROR, "Internal error in MIPMapImpl::Lookup()");
00381 return T();
00382 }
00383 }
00384
00385 template <class T, class U>
00386 T MIPMapImpl<T, U>::EWA(float s, float t, float ds0, float dt0,
00387 float ds1, float dt1, int level) const
00388 {
00389 if (level >= nLevels)
00390 return texel(nLevels - 1, 0, 0);
00391
00392 s = s * uSize(level) - 0.5f;
00393 t = t * vSize(level) - 0.5f;
00394 ds0 *= uSize(level);
00395 dt0 *= vSize(level);
00396 ds1 *= uSize(level);
00397 dt1 *= vSize(level);
00398
00399 float A = dt0 * dt0 + dt1 * dt1 + 1.;
00400 float B = -2.f * (ds0 * dt0 + ds1 * dt1);
00401 float C = ds0 * ds0 + ds1 * ds1 + 1.;
00402 float F = A * C - B * B * 0.25f;
00403
00404 float du = sqrt(C), dv = sqrt(A);
00405 int s0 = Ceil2Int(s - du);
00406 int s1 = Floor2Int(s + du);
00407 int t0 = Ceil2Int(t - dv);
00408 int t1 = Floor2Int(t + dv);
00409
00410 float invF = 1.0f / F;
00411 A *= invF;
00412 B *= invF;
00413 C *= invF;
00414
00415
00416
00417 T num(0.f);
00418 float den = 0.f;
00419 for (int it = t0; it <= t1; ++it) {
00420 float tt = it - t;
00421 for (int is = s0; is <= s1; ++is) {
00422 float ss = is - s;
00423
00424 float r2 = A * ss * ss + B * ss * tt + C * tt * tt;
00425 if (r2 < 1.) {
00426 float weight =
00427 weightLut[min(Float2Int(r2 * WEIGHT_LUT_SIZE),
00428 WEIGHT_LUT_SIZE - 1)];
00429 num += texel(level, is, it) * weight;
00430 den += weight;
00431 }
00432 }
00433 }
00434
00435 return num / den;
00436 }
00437
00438 template <class T,class U>
00439 MIPMapImpl<T,U>::~MIPMapImpl() {
00440 if ((filterType == MIPMAP_EWA) || (filterType == MIPMAP_TRILINEAR)) {
00441 for (int i = 0; i < nLevels; ++i)
00442 delete pyramid[i];
00443 delete[] pyramid;
00444 } else if ((filterType == NEAREST) || (filterType == BILINEAR)) {
00445 delete singleMap;
00446 } else {
00447 luxError(LUX_SYSTEM, LUX_ERROR, "Internal error in MIPMapImpl::~MIPMapImpl(), unknown filter type");
00448 }
00449 }
00450
00451 template <class T,class U>
00452 MIPMapImpl<T,U>::MIPMapImpl(
00453 ImageTextureFilterType type, int sres, int tres,
00454 const U *img, float maxAniso, ImageWrap wm,
00455 float gn,float gma) {
00456 filterType = type;
00457 maxAnisotropy = maxAniso;
00458 wrapMode = wm;
00459 gain=gn;
00460 gamma=gma;
00461
00462 if ((filterType == MIPMAP_EWA) || (filterType == MIPMAP_TRILINEAR)) {
00463 U *resampledImage = NULL;
00464 if (!IsPowerOf2(sres) || !IsPowerOf2(tres)) {
00465
00466 int sPow2 = RoundUpPow2(sres), tPow2 = RoundUpPow2(tres);
00467 std::stringstream ss;
00468 ss << "Resampling image from " << sres << "x" << tres <<
00469 " to " << sPow2 << "x" << tPow2;
00470 luxError(LUX_NOERROR, LUX_INFO, ss.str().c_str());
00471
00472
00473 struct ResampleWeight *sWeights = resampleWeights(sres, sPow2);
00474 resampledImage = new U[sPow2 * tPow2];
00475
00476
00477 for (int t = 0; t < tres; ++t) {
00478 for (int s = 0; s < sPow2; ++s) {
00479
00480 resampledImage[t*sPow2+s] = U();
00481
00482 for (int jo = 2; jo < 6; ++jo) {
00483 int j = jo % 4;
00484
00485 int origS = sWeights[s].firstTexel + j;
00486 if (wrapMode == TEXTURE_REPEAT)
00487 origS = Mod(origS, sres);
00488 else if (wrapMode == TEXTURE_CLAMP)
00489 origS = Clamp(origS, 0, sres - 1);
00490
00491 if (origS >= 0 && origS < sres) {
00492 if(sWeights[s].weight[j] > 0.)
00493 resampledImage[t * sPow2 + s] += sWeights[s].weight[j] * img[t * sres + origS];
00494 else
00495 resampledImage[t * sPow2 + s] -= (-sWeights[s].weight[j]) * img[t * sres + origS];
00496 }
00497 }
00498 }
00499 }
00500 delete[] sWeights;
00501
00502
00503 struct ResampleWeight *tWeights = resampleWeights(tres, tPow2);
00504 U *workData = new U[tPow2];
00505 for (int s = 0; s < sPow2; ++s) {
00506 for (int t = 0; t < tPow2; ++t) {
00507 workData[t] = U();
00508
00509 for (int jo = 2; jo < 6; ++jo) {
00510 int j = jo % 4;
00511
00512 int offset = tWeights[t].firstTexel + j;
00513 if (wrapMode == TEXTURE_REPEAT)
00514 offset = Mod(offset, tres);
00515 else if (wrapMode == TEXTURE_CLAMP)
00516 offset = Clamp(offset, 0, tres - 1);
00517
00518 if (offset >= 0 && offset < tres) {
00519 if(tWeights[t].weight[j] > 0.)
00520 workData[t] += tWeights[t].weight[j] * resampledImage[offset * sPow2 + s];
00521 else
00522 workData[t] -= (-tWeights[t].weight[j]) * resampledImage[offset * sPow2 + s];
00523 }
00524 }
00525 }
00526 for (int t = 0; t < tPow2; ++t)
00527 resampledImage[t * sPow2 + s] = clamp(workData[t]);
00528 }
00529 delete[] workData;
00530 delete[] tWeights;
00531 img = resampledImage;
00532
00533 sres = sPow2;
00534 tres = tPow2;
00535 }
00536
00537
00538 nLevels = 1 + Log2Int(max(sres, tres));
00539
00540 std::stringstream ss;
00541 ss << "Generating " << nLevels << " mipmap levels";
00542 luxError(LUX_NOERROR, LUX_INFO, ss.str().c_str());
00543
00544 pyramid = new BlockedArray<U> *[this->nLevels];
00545
00546 pyramid[0] = new BlockedArray<U>(sres, tres, img);
00547 for (int i = 1; i < nLevels; ++i) {
00548
00549 int sRes = max(1, pyramid[i - 1]->uSize() / 2);
00550 int tRes = max(1, pyramid[i - 1]->vSize() / 2);
00551 pyramid[i] = new BlockedArray<U>(sRes, tRes);
00552
00553 for (int t = 0; t < tRes; ++t) {
00554 for (int s = 0; s < sRes; ++s) {
00555
00556 (*pyramid[i])(s, t) =
00557 0.25f * texelInternal(i - 1, 2 * s, 2 * t) +
00558 0.25f * texelInternal(i - 1, 2 * s + 1, 2 * t) +
00559 0.25f * texelInternal(i - 1, 2 * s, 2 * t + 1) +
00560 0.25f * texelInternal(i - 1, 2 * s + 1, 2 * t + 1);
00561 }
00562 }
00563 }
00564 if (resampledImage)
00565 delete[] resampledImage;
00566
00567
00568 if (!weightLut) {
00569 weightLut = (float *)AllocAligned(WEIGHT_LUT_SIZE * sizeof(float));
00570 for (int i = 0; i < WEIGHT_LUT_SIZE; ++i) {
00571 float alpha = 2.;
00572 float r2 = static_cast<float>(i) / static_cast<float>(WEIGHT_LUT_SIZE - 1);
00573 weightLut[i] = expf(-alpha * r2) - expf(-alpha);
00574 }
00575 }
00576 } else if ((filterType == NEAREST) || (filterType == BILINEAR)) {
00577 singleMap = new BlockedArray<U>(sres, tres, img);
00578 } else {
00579 luxError(LUX_SYSTEM, LUX_ERROR, "Internal error in MIPMapImpl::MIPMapImpl(), unknown filter type");
00580 }
00581 }
00582
00583 template <class T, class U>
00584 const U& MIPMapImpl<T, U>::texelInternal(int level, int s, int t) const
00585 {
00586 static const U black = U();
00587 const BlockedArray<U> &l = *pyramid[level];
00588
00589 switch (wrapMode) {
00590 case TEXTURE_REPEAT:
00591 s = Mod(s, l.uSize());
00592 t = Mod(t, l.vSize());
00593 break;
00594 case TEXTURE_CLAMP:
00595 s = Clamp(s, 0, l.uSize() - 1);
00596 t = Clamp(t, 0, l.vSize() - 1);
00597 break;
00598 case TEXTURE_BLACK:
00599 if (s < 0 || s >= l.uSize() ||
00600 t < 0 || t >= l.vSize())
00601 return black;
00602 }
00603
00604 return l(s, t);
00605 }
00606
00607 template <class T, class U>
00608 const U& MIPMapImpl<T, U>::texelInternal(int s, int t) const
00609 {
00610 static const U black = U();
00611 const BlockedArray<U> &l = *singleMap;
00612
00613 switch (wrapMode) {
00614 case TEXTURE_REPEAT:
00615 s = Mod(s, l.uSize());
00616 t = Mod(t, l.vSize());
00617 break;
00618 case TEXTURE_CLAMP:
00619 s = Clamp(s, 0, l.uSize() - 1);
00620 t = Clamp(t, 0, l.vSize() - 1);
00621 break;
00622 case TEXTURE_BLACK:
00623 if (s < 0 || s >= l.uSize() ||
00624 t < 0 || t >= l.vSize())
00625 return black;
00626 }
00627
00628 return l(s, t);
00629 }
00630
00631
00632 template <class T, class U> class MIPMapFastImpl : public MIPMapImpl<T, U> {
00633 public:
00634
00635 MIPMapFastImpl(ImageTextureFilterType type, int xres, int yres,
00636 const U *data, float maxAniso = 8.f, ImageWrap wrapMode = TEXTURE_REPEAT) :
00637 MIPMapImpl<T, U>(type, xres, yres, data, maxAniso, wrapMode, 1.0f, 1.0f) { };
00638
00639 private:
00640
00641
00642 inline void convert(Spectrum& outputValue, const TextureColor<unsigned char, 1> &internalValue) const
00643 {
00644 float c = static_cast<float>(internalValue.c[0]) * MIPMapImpl<T, U>::invMaxUnsignedChar;
00645 outputValue = Spectrum(c);
00646 }
00647 inline void convert(Spectrum& outputValue, const TextureColor<unsigned char, 3> &internalValue) const
00648 {
00649 float c[3];
00650 for (int i = 0; i < 3; ++i) {
00651 c[i] = static_cast<float>(internalValue.c[i]) * MIPMapImpl<T, U>::invMaxUnsignedChar;
00652 }
00653 outputValue = Spectrum(c);
00654 }
00655 inline void convert(Spectrum& outputValue, const TextureColor<unsigned char, 4> &internalValue) const
00656 {
00657 float c[3];
00658 for (int i = 0; i < 3; ++i) {
00659 c[i] = static_cast<float>(internalValue.c[i]) * MIPMapImpl<T, U>::invMaxUnsignedChar;
00660 }
00661 outputValue = Spectrum(c);
00662 }
00663
00664
00665 inline void convert(Spectrum& outputValue, const TextureColor<unsigned short, 1> &internalValue) const
00666 {
00667 float c = static_cast<float>(internalValue.c[0]) * MIPMapImpl<T, U>::invMaxUnsignedShort;
00668 outputValue = Spectrum(c);
00669 }
00670 inline void convert(Spectrum& outputValue, const TextureColor<unsigned short, 3> &internalValue) const
00671 {
00672 float c[3];
00673 for (int i = 0; i < 3; ++i) {
00674 c[i] = static_cast<float>(internalValue.c[i]) * MIPMapImpl<T, U>::invMaxUnsignedShort;
00675 }
00676 outputValue = Spectrum(c);
00677 }
00678 inline void convert(Spectrum& outputValue, const TextureColor<unsigned short, 4> &internalValue) const
00679 {
00680 float c[3];
00681 for (int i = 0; i < 3; ++i) {
00682 c[i] = static_cast<float>(internalValue.c[i]) * MIPMapImpl<T, U>::invMaxUnsignedShort;
00683 }
00684 outputValue = Spectrum(c);
00685 }
00686
00687
00688 inline void convert(Spectrum& outputValue, const TextureColor<float, 1> &internalValue) const
00689 {
00690 outputValue = Spectrum(internalValue.c[0]);
00691 }
00692 inline void convert(Spectrum& outputValue, const TextureColor<float, 3> &internalValue) const
00693 {
00694 outputValue = Spectrum(internalValue.c);
00695 }
00696 inline void convert(Spectrum& outputValue, const TextureColor<float, 4> &internalValue) const
00697 {
00698 outputValue = Spectrum(internalValue.c);
00699 }
00700 inline void convert(Spectrum& outputValue, const Spectrum &internalValue) const
00701 {
00702 outputValue = Spectrum(internalValue.c);
00703 }
00704
00705 inline void convert(float& outputValue, const float internalValue) const
00706 {
00707 outputValue = internalValue;
00708 }
00709 };
00710
00711 }
00712
00713 #endif // LUX_MIPMAP_H