00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include "lux.h"
00025 #include "texture.h"
00026 #include "mipmap.h"
00027 #include "imagereader.h"
00028 #include "paramset.h"
00029 #include "error.h"
00030 #include <map>
00031 using std::map;
00032
00033 namespace lux
00034 {
00035
00036
00037 template <class T>
00038 class ImageTexture : public Texture<T> {
00039 public:
00040
00041 ImageTexture(
00042 TextureMapping2D *m,
00043 ImageTextureFilterType type,
00044 const string &filename,
00045 float maxAniso,
00046 ImageWrap wrapMode,
00047 float gain,
00048 float gamma);
00049 T Evaluate(const DifferentialGeometry &) const;
00050 ~ImageTexture();
00051
00052 u_int getMemoryUsed() const {
00053 if (mipmap)
00054 return mipmap->getMemoryUsed();
00055 else
00056 return 0;
00057 }
00058
00059 void discardMipmaps(int n) {
00060 if (mipmap)
00061 mipmap->discardMipmaps(n);
00062 }
00063
00064 static Texture<float> * CreateFloatTexture(const Transform &tex2world, const TextureParams &tp);
00065 static Texture<Spectrum> * CreateSpectrumTexture(const Transform &tex2world, const TextureParams &tp);
00066
00067 private:
00068
00069 static MIPMap<T> *GetTexture(
00070 ImageTextureFilterType filterType,
00071 const string &filename,
00072 float maxAniso,
00073 ImageWrap wrap,
00074 float gain,
00075 float gamma);
00076 static void convert(const Spectrum &from, Spectrum *to) {
00077 *to = from;
00078 }
00079 static void convert(const Spectrum &from, float *to) {
00080 *to = from.y();
00081 }
00082
00083
00084
00085 ImageTextureFilterType filterType;
00086 MIPMap<T> *mipmap;
00087 TextureMapping2D *mapping;
00088 };
00089
00090 template <class T> inline Texture<float> *ImageTexture<T>::CreateFloatTexture(const Transform &tex2world,
00091 const TextureParams &tp) {
00092
00093 TextureMapping2D *map = NULL;
00094
00095 string sFilterType = tp.FindString("filtertype");
00096 ImageTextureFilterType filterType = BILINEAR;
00097 if ((sFilterType == "") || (sFilterType == "bilinear")) {
00098 filterType = BILINEAR;
00099 } else if (sFilterType == "mipmap_trilinear") {
00100 filterType = MIPMAP_TRILINEAR;
00101 } else if (sFilterType == "mipmap_ewa") {
00102 filterType = MIPMAP_EWA;
00103 } else if (sFilterType == "nearest") {
00104 filterType = NEAREST;
00105 }
00106
00107 string type = tp.FindString("mapping");
00108 if (type == "" || type == "uv") {
00109 float su = tp.FindFloat("uscale", 1.);
00110 float sv = tp.FindFloat("vscale", 1.);
00111 float du = tp.FindFloat("udelta", 0.);
00112 float dv = tp.FindFloat("vdelta", 0.);
00113 map = new UVMapping2D(su, sv, du, dv);
00114 }
00115 else if (type == "spherical") map = new SphericalMapping2D(tex2world.GetInverse());
00116 else if (type == "cylindrical") map = new CylindricalMapping2D(tex2world.GetInverse());
00117 else if (type == "planar")
00118 map = new PlanarMapping2D(tp.FindVector("v1", Vector(1,0,0)),
00119 tp.FindVector("v2", Vector(0,1,0)),
00120 tp.FindFloat("udelta", 0.f), tp.FindFloat("vdelta", 0.f));
00121 else {
00122
00123 std::stringstream ss;
00124 ss<<"2D texture mapping '"<<type<<"' unknown";
00125 luxError(LUX_BADTOKEN,LUX_ERROR,ss.str().c_str());
00126 map = new UVMapping2D;
00127 }
00128
00129
00130 float maxAniso = tp.FindFloat("maxanisotropy", 8.f);
00131 string wrap = tp.FindString("wrap");
00132 ImageWrap wrapMode = TEXTURE_REPEAT;
00133 if (wrap == "" || wrap == "repeat") wrapMode = TEXTURE_REPEAT;
00134 else if (wrap == "black") wrapMode = TEXTURE_BLACK;
00135 else if (wrap == "clamp") wrapMode = TEXTURE_CLAMP;
00136
00137 float gain = tp.FindFloat("gain", 1.0f);
00138 float gamma = tp.FindFloat("gamma", 1.0f);
00139
00140 string filename = tp.FindString("filename");
00141 int discardmm = tp.FindInt("discardmipmaps", 0);
00142
00143 ImageTexture<float> *tex = new ImageTexture<float>(map, filterType,
00144 filename, maxAniso, wrapMode, gain, gamma);
00145
00146 if ((discardmm > 0) &&
00147 ((filterType == MIPMAP_TRILINEAR) || (filterType == MIPMAP_EWA))) {
00148 tex->discardMipmaps(discardmm);
00149
00150 std::stringstream ss;
00151 ss<<"Discarded " << discardmm << " mipmap levels";
00152 luxError(LUX_NOERROR,LUX_INFO,ss.str().c_str());
00153 }
00154
00155 std::stringstream ss;
00156 ss<<"Memory used for imagemap '" << filename << "': " <<
00157 (tex->getMemoryUsed() / 1024) << "KBytes";
00158 luxError(LUX_NOERROR,LUX_INFO,ss.str().c_str());
00159
00160 return tex;
00161 }
00162
00163 template <class T> inline Texture<Spectrum> *ImageTexture<T>::CreateSpectrumTexture(const Transform &tex2world,
00164 const TextureParams &tp) {
00165
00166 TextureMapping2D *map = NULL;
00167
00168 string sFilterType = tp.FindString("filtertype");
00169 ImageTextureFilterType filterType = BILINEAR;
00170 if ((sFilterType == "") || (sFilterType == "bilinear")) {
00171 filterType = BILINEAR;
00172 } else if (sFilterType == "mipmap_trilinear") {
00173 filterType = MIPMAP_TRILINEAR;
00174 } else if (sFilterType == "mipmap_ewa") {
00175 filterType = MIPMAP_EWA;
00176 } else if (sFilterType == "nearest") {
00177 filterType = NEAREST;
00178 }
00179
00180 string type = tp.FindString("mapping");
00181 if (type == "" || type == "uv") {
00182 float su = tp.FindFloat("uscale", 1.);
00183 float sv = tp.FindFloat("vscale", 1.);
00184 float du = tp.FindFloat("udelta", 0.);
00185 float dv = tp.FindFloat("vdelta", 0.);
00186 map = new UVMapping2D(su, sv, du, dv);
00187 }
00188 else if (type == "spherical") map = new SphericalMapping2D(tex2world.GetInverse());
00189 else if (type == "cylindrical") map = new CylindricalMapping2D(tex2world.GetInverse());
00190 else if (type == "planar")
00191 map = new PlanarMapping2D(tp.FindVector("v1", Vector(1,0,0)),
00192 tp.FindVector("v2", Vector(0,1,0)),
00193 tp.FindFloat("udelta", 0.f), tp.FindFloat("vdelta", 0.f));
00194 else {
00195
00196 std::stringstream ss;
00197 ss<<"2D texture mapping '"<<type<<"' unknown";
00198 luxError(LUX_BADTOKEN,LUX_ERROR,ss.str().c_str());
00199 map = new UVMapping2D;
00200 }
00201
00202
00203 float maxAniso = tp.FindFloat("maxanisotropy", 8.f);
00204 string wrap = tp.FindString("wrap");
00205 ImageWrap wrapMode = TEXTURE_REPEAT;
00206 if (wrap == "" || wrap == "repeat") wrapMode = TEXTURE_REPEAT;
00207 else if (wrap == "black") wrapMode = TEXTURE_BLACK;
00208 else if (wrap == "clamp") wrapMode = TEXTURE_CLAMP;
00209
00210 float gain = tp.FindFloat("gain", 1.0f);
00211 float gamma = tp.FindFloat("gamma", 1.0f);
00212
00213 string filename = tp.FindString("filename");
00214 int discardmm = tp.FindInt("discardmipmaps", 0);
00215
00216 ImageTexture<Spectrum> *tex = new ImageTexture<Spectrum>(map, filterType,
00217 filename, maxAniso, wrapMode, gain, gamma);
00218
00219 if ((discardmm > 0) &&
00220 ((filterType == MIPMAP_TRILINEAR) || (filterType == MIPMAP_EWA))) {
00221 tex->discardMipmaps(discardmm);
00222
00223 std::stringstream ss;
00224 ss<<"Discarded " << discardmm << " mipmap levels";
00225 luxError(LUX_NOERROR,LUX_INFO,ss.str().c_str());
00226 }
00227
00228 std::stringstream ss;
00229 ss<<"Memory used for imagemap '" << filename << "': " <<
00230 (tex->getMemoryUsed() / 1024) << "KBytes";
00231 luxError(LUX_NOERROR,LUX_INFO,ss.str().c_str());
00232
00233 return tex;
00234 }
00235
00236
00237 template <class T> inline
00238 ImageTexture<T>::ImageTexture(
00239 TextureMapping2D *m,
00240 ImageTextureFilterType type,
00241 const string &filename,
00242 float maxAniso,
00243 ImageWrap wrapMode,
00244 float gain,
00245 float gamma) {
00246 filterType = type;
00247 mapping = m;
00248 mipmap = GetTexture(filterType, filename, maxAniso, wrapMode, gain, gamma);
00249 }
00250
00251 template <class T> inline ImageTexture<T>::~ImageTexture() {
00252 delete mapping;
00253 }
00254
00255 struct TexInfo {
00256 TexInfo(ImageTextureFilterType type, const string &f, float ma,
00257 ImageWrap wm, float ga, float gam)
00258 : filterType(type), filename(f), maxAniso(ma),
00259 wrapMode(wm), gain(ga), gamma(gam) { }
00260
00261 ImageTextureFilterType filterType;
00262 string filename;
00263 float maxAniso;
00264 ImageWrap wrapMode;
00265 float gain;
00266 float gamma;
00267
00268 bool operator<(const TexInfo &t2) const {
00269 if (filterType != t2.filterType) return filterType < t2.filterType;
00270 if (filename != t2.filename) return filename < t2.filename;
00271 if (maxAniso != t2.maxAniso) return maxAniso < t2.maxAniso;
00272 if (wrapMode != t2.wrapMode) return wrapMode < t2.wrapMode;
00273 if (gain != t2.gain) return gain < t2.gain;
00274
00275 return gamma < t2.gamma;
00276 }
00277 };
00278
00279 template <class T> inline MIPMap<T> *ImageTexture<T>::
00280 GetTexture(
00281 ImageTextureFilterType filterType,
00282 const string &filename,
00283 float maxAniso,
00284 ImageWrap wrap,
00285 float gain,
00286 float gamma) {
00287
00288 static map<TexInfo, MIPMap<T> *> textures;
00289 TexInfo texInfo(filterType, filename, maxAniso, wrap, gain, gamma);
00290 if (textures.find(texInfo) != textures.end())
00291 return textures[texInfo];
00292
00293
00294
00295 int width, height;
00296 auto_ptr<ImageData> imgdata(ReadImage(filename));
00297 MIPMap<T> *ret = NULL;
00298 if (imgdata.get() != NULL) {
00299 width=imgdata->getWidth();
00300 height=imgdata->getHeight();
00301 ret = imgdata->createMIPMap<T>(filterType, maxAniso, wrap, gain, gamma);
00302 } else {
00303
00304 T *oneVal = new T[1];
00305 oneVal[0] = 1.;
00306
00307 ret = new MIPMapFastImpl<T,T>(filterType, 1, 1, oneVal);
00308
00309 delete[] oneVal;
00310 }
00311 textures[texInfo] = ret;
00312
00313 return ret;
00314 }
00315
00316 template <class T> inline
00317 T ImageTexture<T>::Evaluate(
00318 const DifferentialGeometry &dg) const {
00319 float s, t, dsdx, dtdx, dsdy, dtdy;
00320 mapping->Map(dg, &s, &t, &dsdx, &dtdx, &dsdy, &dtdy);
00321 return mipmap->Lookup(s, t, dsdx, dtdx, dsdy, dtdy);
00322 }
00323
00324 }