1 /****************************************************************************
2 * imagetex.cc: a texture class for images
3 * This is part of the yafray package
4 * Based on the original by: Mathias Wein; Copyright (C) 2006 Mathias Wein
5 * Copyright (C) 2010 Rodrigo Placencia Vazquez (DarkTide)
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 */
21
22 #include <textures/imagetex.h>
23 #include <core_api/session.h>
24 #include <utilities/stringUtils.h>
25 #include <core_api/params.h>
26
27 __BEGIN_YAFRAY
28
29 float * textureImage_t::ewaWeightLut = nullptr;
30
textureImage_t(imageHandler_t * ih,int intp,float gamma,colorSpaces_t color_space)31 textureImage_t::textureImage_t(imageHandler_t *ih, int intp, float gamma, colorSpaces_t color_space):
32 image(ih), colorSpace(color_space), gamma(gamma), mirrorX(false), mirrorY(false)
33 {
34 intp_type = intp;
35 }
36
~textureImage_t()37 textureImage_t::~textureImage_t()
38 {
39 // Here we simply clear the pointer, yafaray's core will handle the memory cleanup
40 image = nullptr;
41 }
42
resolution(int & x,int & y,int & z) const43 void textureImage_t::resolution(int &x, int &y, int &z) const
44 {
45 x=image->getWidth();
46 y=image->getHeight();
47 z=0;
48 }
49
interpolateImage(const point3d_t & p,mipMapParams_t * mmParams) const50 colorA_t textureImage_t::interpolateImage(const point3d_t &p, mipMapParams_t * mmParams) const
51 {
52 if(mmParams && mmParams->forceImageLevel > 0.f) return mipMapsTrilinearInterpolation(p, mmParams);
53
54 colorA_t interpolatedColor(0.f);
55
56 switch(intp_type)
57 {
58 case INTP_NONE: interpolatedColor = noInterpolation(p); break;
59 case INTP_BICUBIC: interpolatedColor = bicubicInterpolation(p); break;
60 case INTP_MIPMAP_TRILINEAR:
61 if(mmParams) interpolatedColor = mipMapsTrilinearInterpolation(p, mmParams);
62 else interpolatedColor = bilinearInterpolation(p);
63 break;
64 case INTP_MIPMAP_EWA:
65 if(mmParams) interpolatedColor = mipMapsEWAInterpolation(p, ewa_max_anisotropy, mmParams);
66 else interpolatedColor = bilinearInterpolation(p);
67 break;
68 case INTP_BILINEAR:
69 default: interpolatedColor = bilinearInterpolation(p); break; //By default use Bilinear
70 }
71
72 return interpolatedColor;
73 }
74
getColor(const point3d_t & p,mipMapParams_t * mmParams) const75 colorA_t textureImage_t::getColor(const point3d_t &p, mipMapParams_t * mmParams) const
76 {
77 point3d_t p1 = point3d_t(p.x, -p.y, p.z);
78 colorA_t ret(0.f);
79
80 bool outside = doMapping(p1);
81
82 if(outside) return ret;
83
84 ret = interpolateImage(p1, mmParams);
85
86 return applyAdjustments(ret);
87 }
88
getRawColor(const point3d_t & p,mipMapParams_t * mmParams) const89 colorA_t textureImage_t::getRawColor(const point3d_t &p, mipMapParams_t * mmParams) const
90 {
91 // As from v3.2.0 all color buffers are already Linear RGB, if any part of the code requires the original "raw" color, a "de-linearization" (encoding again into the original color space) takes place in this function.
92
93 // For example for Non-RGB / Stencil / Bump / Normal maps, etc, textures are typically already linear and the user should select "linearRGB" in the texture properties, but if the user (by mistake) keeps the default sRGB for them, for example, the default linearization would apply a sRGB to linearRGB conversion that messes up the texture values. This function will try to reconstruct the original texture values. In this case (if the user selected incorrectly sRGB for a normal map, for example), this function will prevent wrong results, but it will be slower and it could be slightly inaccurate as the interpolation will take place in the (incorrectly) linearized texels.
94
95 //If the user correctly selected "linearRGB" for these kind of textures, the function below will not make any changes to the color and will keep the texture "as is" without any linearization nor de-linearization, which is the ideal case (fast and correct).
96
97 //The user is responsible to select the correct textures color spaces, if the user does not do it, results may not be the expected. This function is only a coarse "fail safe"
98
99 colorA_t ret = getColor(p, mmParams);
100 ret.ColorSpace_from_linearRGB(colorSpace, gamma);
101
102 return ret;
103 }
104
getColor(int x,int y,int z,mipMapParams_t * mmParams) const105 colorA_t textureImage_t::getColor(int x, int y, int z, mipMapParams_t * mmParams) const
106 {
107 int resx=image->getWidth();
108 int resy=image->getHeight();
109
110 y = resy - y; //on occasion change image storage from bottom to top...
111
112 x = std::max(0, std::min(resx-1, x));
113 y = std::max(0, std::min(resy-1, y));
114
115 colorA_t ret(0.f);
116
117 if(mmParams && mmParams->forceImageLevel > 0.f) ret = image->getPixel(x, y, (int) floorf(mmParams->forceImageLevel * image->getHighestImgIndex()));
118 else ret = image->getPixel(x, y);
119
120 return applyAdjustments(ret);
121 }
122
getRawColor(int x,int y,int z,mipMapParams_t * mmParams) const123 colorA_t textureImage_t::getRawColor(int x, int y, int z, mipMapParams_t * mmParams) const
124 {
125 // As from v3.2.0 all color buffers are already Linear RGB, if any part of the code requires the original "raw" color, a "de-linearization" (encoding again into the original color space) takes place in this function.
126
127 // For example for Non-RGB / Stencil / Bump / Normal maps, etc, textures are typically already linear and the user should select "linearRGB" in the texture properties, but if the user (by mistake) keeps the default sRGB for them, for example, the default linearization would apply a sRGB to linearRGB conversion that messes up the texture values. This function will try to reconstruct the original texture values. In this case (if the user selected incorrectly sRGB for a normal map, for example), this function will prevent wrong results, but it will be slower and it could be slightly inaccurate as the interpolation will take place in the (incorrectly) linearized texels.
128
129 //If the user correctly selected "linearRGB" for these kind of textures, the function below will not make any changes to the color and will keep the texture "as is" without any linearization nor de-linearization, which is the ideal case (fast and correct).
130
131 //The user is responsible to select the correct textures color spaces, if the user does not do it, results may not be the expected. This function is only a coarse "fail safe"
132
133 colorA_t ret = getColor(x, y, z, mmParams);
134 ret.ColorSpace_from_linearRGB(colorSpace, gamma);
135
136 return ret;
137 }
138
doMapping(point3d_t & texpt) const139 bool textureImage_t::doMapping(point3d_t &texpt) const
140 {
141 bool outside = false;
142
143 texpt = 0.5f*texpt + 0.5f;
144 // repeat, only valid for REPEAT clipmode
145 if (tex_clipmode==TCL_REPEAT) {
146
147 if(xrepeat > 1) texpt.x *= (float)xrepeat;
148 if(yrepeat > 1) texpt.y *= (float)yrepeat;
149
150 if (mirrorX && int(ceilf(texpt.x)) % 2 == 0) texpt.x = -texpt.x;
151 if (mirrorY && int(ceilf(texpt.y)) % 2 == 0) texpt.y = -texpt.y;
152
153 if (texpt.x>1.f) texpt.x -= int(texpt.x);
154 else if (texpt.x<0.f) texpt.x += 1 - int(texpt.x);
155
156 if (texpt.y>1.f) texpt.y -= int(texpt.y);
157 else if (texpt.y<0.f) texpt.y += 1 - int(texpt.y);
158 }
159
160 // crop
161 if (cropx) texpt.x = cropminx + texpt.x*(cropmaxx - cropminx);
162 if (cropy) texpt.y = cropminy + texpt.y*(cropmaxy - cropminy);
163
164 // rot90
165 if(rot90) std::swap(texpt.x, texpt.y);
166
167 // clipping
168 switch (tex_clipmode)
169 {
170 case TCL_CLIPCUBE: {
171 if ((texpt.x<0) || (texpt.x>1) || (texpt.y<0) || (texpt.y>1) || (texpt.z<-1) || (texpt.z>1))
172 outside = true;
173 break;
174 }
175 case TCL_CHECKER: {
176 int xs=(int)floor(texpt.x), ys=(int)floor(texpt.y);
177 texpt.x -= xs;
178 texpt.y -= ys;
179 if ( !checker_odd && !((xs+ys) & 1) )
180 {
181 outside = true;
182 break;
183 }
184 if ( !checker_even && ((xs+ys) & 1) )
185 {
186 outside = true;
187 break;
188 }
189 // scale around center, (0.5, 0.5)
190 if (checker_dist<1.0) {
191 texpt.x = (texpt.x-0.5) / (1.0-checker_dist) + 0.5;
192 texpt.y = (texpt.y-0.5) / (1.0-checker_dist) + 0.5;
193 }
194 // continue to TCL_CLIP
195 }
196 case TCL_CLIP: {
197 if ((texpt.x<0) || (texpt.x>1) || (texpt.y<0) || (texpt.y>1))
198 outside = true;
199 break;
200 }
201 case TCL_EXTEND: {
202 if (texpt.x>0.99999f) texpt.x=0.99999f; else if (texpt.x<0) texpt.x=0;
203 if (texpt.y>0.99999f) texpt.y=0.99999f; else if (texpt.y<0) texpt.y=0;
204 // no break, fall thru to TEX_REPEAT
205 }
206 default:
207 case TCL_REPEAT: outside = false;
208 }
209 return outside;
210 }
211
setCrop(float minx,float miny,float maxx,float maxy)212 void textureImage_t::setCrop(float minx, float miny, float maxx, float maxy)
213 {
214 cropminx=minx, cropmaxx=maxx, cropminy=miny, cropmaxy=maxy;
215 cropx = ((cropminx!=0.0) || (cropmaxx!=1.0));
216 cropy = ((cropminy!=0.0) || (cropmaxy!=1.0));
217 }
218
findTextureInterpolationCoordinates(int & coord0,int & coord1,int & coord2,int & coord3,float & coord_decimal_part,float coord_float,int resolution,bool repeat,bool mirror) const219 void textureImage_t::findTextureInterpolationCoordinates(int &coord0, int &coord1, int &coord2, int &coord3, float &coord_decimal_part, float coord_float, int resolution, bool repeat, bool mirror) const
220 {
221 if(repeat)
222 {
223 coord1 = ((int)coord_float) % resolution;
224
225 if(mirror)
226 {
227
228 if(coord_float < 0.f)
229 {
230 coord0 = 1 % resolution;
231 coord2 = coord1;
232 coord3 = coord0;
233 coord_decimal_part = -coord_float;
234 }
235 else if(coord_float >= resolution - 1.f)
236 {
237 coord0 = (resolution+resolution-1) % resolution;
238 coord2 = coord1;
239 coord3 = coord0;
240 coord_decimal_part = coord_float - ((int)coord_float);
241 }
242 else
243 {
244 coord0 = (resolution+coord1-1) % resolution;
245 coord2 = coord1+1;
246 if(coord2 >= resolution) coord2 = (resolution + resolution - coord2) % resolution;
247 coord3 = coord1+2;
248 if(coord3 >= resolution) coord3 = (resolution + resolution - coord3) % resolution;
249 coord_decimal_part = coord_float - ((int)coord_float);
250 }
251 }
252 else
253 {
254 if(coord_float > 0.f)
255 {
256 coord0 = (resolution+coord1-1) % resolution;
257 coord2 = (coord1+1) % resolution;
258 coord3 = (coord1+2) % resolution;
259 coord_decimal_part = coord_float - ((int)coord_float);
260 }
261 else
262 {
263 coord0 = 1 % resolution;
264 coord2 = (resolution-1) % resolution;
265 coord3 = (resolution-2) % resolution;
266 coord_decimal_part = -coord_float;
267 }
268 }
269 }
270 else
271 {
272 coord1 = std::max(0, std::min(resolution-1, ((int)coord_float)));
273
274 if(coord_float > 0.f) coord2 = std::min(resolution-1, coord1+1);
275 else coord2 = 0;
276
277 coord0 = std::max(0, coord1-1);
278 coord3 = std::min(resolution-1, coord2+1);
279
280 coord_decimal_part = coord_float - floor(coord_float);
281 }
282 }
283
noInterpolation(const point3d_t & p,int mipmaplevel) const284 colorA_t textureImage_t::noInterpolation(const point3d_t &p, int mipmaplevel) const
285 {
286 int resx = image->getWidth(mipmaplevel);
287 int resy = image->getHeight(mipmaplevel);
288
289 float xf = ((float)resx * (p.x - floor(p.x)));
290 float yf = ((float)resy * (p.y - floor(p.y)));
291
292 int x0, x1, x2, x3, y0, y1, y2, y3;
293 float dx, dy;
294 findTextureInterpolationCoordinates(x0, x1, x2, x3, dx, xf, resx, tex_clipmode==TCL_REPEAT, mirrorX);
295 findTextureInterpolationCoordinates(y0, y1, y2, y3, dy, yf, resy, tex_clipmode==TCL_REPEAT, mirrorY);
296
297 return image->getPixel(x1, y1, mipmaplevel);
298 }
299
bilinearInterpolation(const point3d_t & p,int mipmaplevel) const300 colorA_t textureImage_t::bilinearInterpolation(const point3d_t &p, int mipmaplevel) const
301 {
302 int resx = image->getWidth(mipmaplevel);
303 int resy = image->getHeight(mipmaplevel);
304
305 float xf = ((float)resx * (p.x - floor(p.x))) - 0.5f;
306 float yf = ((float)resy * (p.y - floor(p.y))) - 0.5f;
307
308 int x0, x1, x2, x3, y0, y1, y2, y3;
309 float dx, dy;
310 findTextureInterpolationCoordinates(x0, x1, x2, x3, dx, xf, resx, tex_clipmode==TCL_REPEAT, mirrorX);
311 findTextureInterpolationCoordinates(y0, y1, y2, y3, dy, yf, resy, tex_clipmode==TCL_REPEAT, mirrorY);
312
313 colorA_t c11 = image->getPixel(x1, y1, mipmaplevel);
314 colorA_t c21 = image->getPixel(x2, y1, mipmaplevel);
315 colorA_t c12 = image->getPixel(x1, y2, mipmaplevel);
316 colorA_t c22 = image->getPixel(x2, y2, mipmaplevel);
317
318 float w11 = (1-dx) * (1-dy);
319 float w12 = (1-dx) * dy;
320 float w21 = dx * (1-dy);
321 float w22 = dx * dy;
322
323 return (w11 * c11) + (w12 * c12) + (w21 * c21) + (w22 * c22);
324 }
325
bicubicInterpolation(const point3d_t & p,int mipmaplevel) const326 colorA_t textureImage_t::bicubicInterpolation(const point3d_t &p, int mipmaplevel) const
327 {
328 int resx = image->getWidth(mipmaplevel);
329 int resy = image->getHeight(mipmaplevel);
330
331 float xf = ((float)resx * (p.x - floor(p.x))) - 0.5f;
332 float yf = ((float)resy * (p.y - floor(p.y))) - 0.5f;
333
334 int x0, x1, x2, x3, y0, y1, y2, y3;
335 float dx, dy;
336 findTextureInterpolationCoordinates(x0, x1, x2, x3, dx, xf, resx, tex_clipmode==TCL_REPEAT, mirrorX);
337 findTextureInterpolationCoordinates(y0, y1, y2, y3, dy, yf, resy, tex_clipmode==TCL_REPEAT, mirrorY);
338
339 colorA_t c00 = image->getPixel(x0, y0, mipmaplevel);
340 colorA_t c01 = image->getPixel(x0, y1, mipmaplevel);
341 colorA_t c02 = image->getPixel(x0, y2, mipmaplevel);
342 colorA_t c03 = image->getPixel(x0, y3, mipmaplevel);
343
344 colorA_t c10 = image->getPixel(x1, y0, mipmaplevel);
345 colorA_t c11 = image->getPixel(x1, y1, mipmaplevel);
346 colorA_t c12 = image->getPixel(x1, y2, mipmaplevel);
347 colorA_t c13 = image->getPixel(x1, y3, mipmaplevel);
348
349 colorA_t c20 = image->getPixel(x2, y0, mipmaplevel);
350 colorA_t c21 = image->getPixel(x2, y1, mipmaplevel);
351 colorA_t c22 = image->getPixel(x2, y2, mipmaplevel);
352 colorA_t c23 = image->getPixel(x2, y3, mipmaplevel);
353
354 colorA_t c30 = image->getPixel(x3, y0, mipmaplevel);
355 colorA_t c31 = image->getPixel(x3, y1, mipmaplevel);
356 colorA_t c32 = image->getPixel(x3, y2, mipmaplevel);
357 colorA_t c33 = image->getPixel(x3, y3, mipmaplevel);
358
359 colorA_t cy0 = CubicInterpolate(c00, c10, c20, c30, dx);
360 colorA_t cy1 = CubicInterpolate(c01, c11, c21, c31, dx);
361 colorA_t cy2 = CubicInterpolate(c02, c12, c22, c32, dx);
362 colorA_t cy3 = CubicInterpolate(c03, c13, c23, c33, dx);
363
364 return CubicInterpolate(cy0, cy1, cy2, cy3, dy);
365 }
366
mipMapsTrilinearInterpolation(const point3d_t & p,mipMapParams_t * mmParams) const367 colorA_t textureImage_t::mipMapsTrilinearInterpolation(const point3d_t &p, mipMapParams_t * mmParams) const
368 {
369 float dS = std::max(fabsf(mmParams->dSdx), fabsf(mmParams->dSdy)) * image->getWidth();
370 float dT = std::max(fabsf(mmParams->dTdx), fabsf(mmParams->dTdy)) * image->getHeight();
371 float mipmaplevel = 0.5f * log2(dS*dS + dT*dT);
372
373 if(mmParams->forceImageLevel > 0.f) mipmaplevel = mmParams->forceImageLevel * image->getHighestImgIndex();
374
375 mipmaplevel += trilinear_level_bias;
376
377 mipmaplevel = std::min(std::max(0.f, mipmaplevel), (float) image->getHighestImgIndex());
378
379 int mipmaplevelA = (int) floor(mipmaplevel);
380 int mipmaplevelB = (int) ceil(mipmaplevel);
381 float mipmaplevelDelta = mipmaplevel - (float) mipmaplevelA;
382
383 colorA_t col = bilinearInterpolation(p, mipmaplevelA);
384 colorA_t colB = bilinearInterpolation(p, mipmaplevelB);
385
386 col.blend(colB, mipmaplevelDelta);
387
388 return col;
389 }
390
391 //All EWA interpolation/calculation code has been adapted from PBRT v2 (https://github.com/mmp/pbrt-v2). see LICENSES file
392
mipMapsEWAInterpolation(const point3d_t & p,float maxAnisotropy,mipMapParams_t * mmParams) const393 colorA_t textureImage_t::mipMapsEWAInterpolation(const point3d_t &p, float maxAnisotropy, mipMapParams_t * mmParams) const
394 {
395 float dS0 = fabsf(mmParams->dSdx);
396 float dS1 = fabsf(mmParams->dSdy);
397 float dT0 = fabsf(mmParams->dTdx);
398 float dT1 = fabsf(mmParams->dTdy);
399
400 if((dS0*dS0 + dT0*dT0) < (dS1*dS1 + dT1*dT1))
401 {
402 std::swap(dS0, dS1);
403 std::swap(dT0, dT1);
404 }
405
406 float majorLength = sqrtf(dS0*dS0 + dT0*dT0);
407 float minorLength = sqrtf(dS1*dS1 + dT1*dT1);
408
409 if((minorLength * maxAnisotropy < majorLength) && (minorLength > 0.f))
410 {
411 float scale = majorLength / (minorLength * maxAnisotropy);
412 dS1 *= scale;
413 dT1 *= scale;
414 minorLength *= scale;
415 }
416
417 if(minorLength <= 0.f) return bilinearInterpolation(p);
418
419 float mipmaplevel = image->getHighestImgIndex() - 1.f + log2(minorLength);
420
421 mipmaplevel = std::min(std::max(0.f, mipmaplevel), (float) image->getHighestImgIndex());
422
423
424 int mipmaplevelA = (int) floor(mipmaplevel);
425 int mipmaplevelB = (int) ceil(mipmaplevel);
426 float mipmaplevelDelta = mipmaplevel - (float) mipmaplevelA;
427
428 colorA_t col = EWAEllipticCalculation(p, dS0, dT0, dS1, dT1, mipmaplevelA);
429 colorA_t colB = EWAEllipticCalculation(p, dS0, dT0, dS1, dT1, mipmaplevelB);
430
431 col.blend(colB, mipmaplevelDelta);
432
433 return col;
434 }
435
Mod(int a,int b)436 inline int Mod(int a, int b) {
437 int n = int(a/b);
438 a -= n*b;
439 if (a < 0) a += b;
440 return a;
441 }
442
EWAEllipticCalculation(const point3d_t & p,float dS0,float dT0,float dS1,float dT1,int mipmaplevel) const443 colorA_t textureImage_t::EWAEllipticCalculation(const point3d_t &p, float dS0, float dT0, float dS1, float dT1, int mipmaplevel) const
444 {
445 if(mipmaplevel >= image->getHighestImgIndex())
446 {
447 int resx = image->getWidth(mipmaplevel);
448 int resy = image->getHeight(mipmaplevel);
449
450 return image->getPixel(Mod(p.x, resx), Mod(p.y, resy), image->getHighestImgIndex());
451 }
452
453 int resx = image->getWidth(mipmaplevel);
454 int resy = image->getHeight(mipmaplevel);
455
456 float xf = ((float)resx * (p.x - floor(p.x))) - 0.5f;
457 float yf = ((float)resy * (p.y - floor(p.y))) - 0.5f;
458
459 dS0 *= resx;
460 dS1 *= resx;
461 dT0 *= resy;
462 dT1 *= resy;
463
464 float A = dT0*dT0 + dT1*dT1 + 1;
465 float B = -2.f * (dS0*dT0 + dS1*dT1);
466 float C = dS0*dS0 + dS1*dS1 + 1;
467 float invF = 1.f / (A*C - B*B*0.25f);
468 A *= invF;
469 B *= invF;
470 C *= invF;
471
472 float det = -B*B + 4.f*A*C;
473 float invDet = 1.f / det;
474 float uSqrt = sqrtf(det * C);
475 float vSqrt = sqrtf(A * det);
476
477 int s0 = (int) ceilf(xf - 2.f * invDet * uSqrt);
478 int s1 = (int) floorf(xf + 2.f * invDet * uSqrt);
479 int t0 = (int) ceilf(yf - 2.f * invDet * vSqrt);
480 int t1 = (int) floorf(yf + 2.f * invDet * vSqrt);
481
482 colorA_t sumCol(0.f);
483
484 float sumWts = 0.f;
485 for(int it = t0; it <= t1; ++it)
486 {
487 float tt = it - yf;
488 for(int is = s0; is <= s1; ++is)
489 {
490 float ss = is - xf;
491
492 float r2 = A*ss*ss + B*ss*tt + C*tt*tt;
493 if(r2 < 1.f)
494 {
495 float weight = ewaWeightLut[std::min((int)floorf(r2*EWA_WEIGHT_LUT_SIZE), EWA_WEIGHT_LUT_SIZE-1)];
496 int ismod = Mod(is, resx);
497 int itmod = Mod(it, resy);
498
499 sumCol += image->getPixel(ismod, itmod, mipmaplevel) * weight;
500 sumWts += weight;
501 }
502 }
503 }
504
505 if(sumWts > 0.f) sumCol = sumCol / sumWts;
506 else sumCol = colorA_t(0.f);
507
508 return sumCol;
509 }
510
generateEWALookupTable()511 void textureImage_t::generateEWALookupTable()
512 {
513 if(!ewaWeightLut)
514 {
515 Y_DEBUG << "** GENERATING EWA LOOKUP **" << yendl;
516 ewaWeightLut = (float *) malloc(sizeof(float) * EWA_WEIGHT_LUT_SIZE);
517 for(int i = 0; i < EWA_WEIGHT_LUT_SIZE; ++i)
518 {
519 float alpha = 2.f;
520 float r2 = float(i) / float(EWA_WEIGHT_LUT_SIZE - 1);
521 ewaWeightLut[i] = expf(-alpha * r2) - expf(-alpha);
522 }
523 }
524 }
525
string2cliptype(const std::string * clipname)526 int string2cliptype(const std::string *clipname)
527 {
528 // default "repeat"
529 int tex_clipmode = TCL_REPEAT;
530 if(!clipname) return tex_clipmode;
531 if (*clipname=="extend") tex_clipmode = TCL_EXTEND;
532 else if (*clipname=="clip") tex_clipmode = TCL_CLIP;
533 else if (*clipname=="clipcube") tex_clipmode = TCL_CLIPCUBE;
534 else if (*clipname=="checker") tex_clipmode = TCL_CHECKER;
535 return tex_clipmode;
536 }
537
factory(paraMap_t & params,renderEnvironment_t & render)538 texture_t *textureImage_t::factory(paraMap_t ¶ms, renderEnvironment_t &render)
539 {
540 const std::string *name = nullptr;
541 const std::string *intpstr = nullptr;
542 double gamma = 1.0;
543 double expadj = 0.0;
544 bool normalmap = false;
545 std::string color_space_string = "Raw_Manual_Gamma";
546 colorSpaces_t color_space = RAW_MANUAL_GAMMA;
547 std::string texture_optimization_string = "optimized";
548 textureOptimization_t texture_optimization = TEX_OPTIMIZATION_OPTIMIZED;
549 bool img_grayscale = false;
550 textureImage_t *tex = nullptr;
551 imageHandler_t *ih = nullptr;
552 params.getParam("interpolate", intpstr);
553 params.getParam("color_space", color_space_string);
554 params.getParam("gamma", gamma);
555 params.getParam("exposure_adjust", expadj);
556 params.getParam("normalmap", normalmap);
557 params.getParam("filename", name);
558 params.getParam("texture_optimization", texture_optimization_string);
559 params.getParam("img_grayscale", img_grayscale);
560
561 if(!name)
562 {
563 Y_ERROR << "ImageTexture: Required argument filename not found for image texture" << yendl;
564 return nullptr;
565 }
566
567 // interpolation type, bilinear default
568 int intp = INTP_BILINEAR;
569
570 if(intpstr)
571 {
572 if (*intpstr == "none") intp = INTP_NONE;
573 else if (*intpstr == "bicubic") intp = INTP_BICUBIC;
574 else if (*intpstr == "mipmap_trilinear") intp = INTP_MIPMAP_TRILINEAR;
575 else if (*intpstr == "mipmap_ewa") intp = INTP_MIPMAP_EWA;
576 }
577
578 size_t lDot = name->rfind(".") + 1;
579 size_t lSlash = name->rfind("/") + 1;
580
581 std::string ext = toLower(name->substr(lDot));
582
583 std::string fmt = render.getImageFormatFromExtension(ext);
584
585 if(fmt == "")
586 {
587 Y_ERROR << "ImageTexture: Image extension not recognized, dropping texture." << yendl;
588 return nullptr;
589 }
590
591 paraMap_t ihpm;
592 ihpm["type"] = fmt;
593 ihpm["for_output"] = false;
594 std::string ihname = "ih";
595 ihname.append(toLower(name->substr(lSlash, lDot - lSlash - 1)));
596
597 ih = render.createImageHandler(ihname, ihpm);
598
599 if(!ih)
600 {
601 Y_ERROR << "ImageTexture: Couldn't create image handler, dropping texture." << yendl;
602 return nullptr;
603 }
604
605
606 if(ih->isHDR())
607 {
608 if(color_space_string != "LinearRGB") Y_VERBOSE << "ImageTexture: The image is a HDR/EXR file: forcing linear RGB and ignoring selected color space '" << color_space_string <<"' and the gamma setting." << yendl;
609 color_space = LINEAR_RGB;
610 if(texture_optimization_string != "none") Y_VERBOSE << "ImageTexture: The image is a HDR/EXR file: forcing texture optimization to 'none' and ignoring selected texture optimization '" << texture_optimization_string <<"'" << yendl;
611 texture_optimization = TEX_OPTIMIZATION_NONE; //FIXME DAVID: Maybe we should leave this to imageHandler factory code...
612 }
613 else
614 {
615 if(color_space_string == "sRGB") color_space = SRGB;
616 else if(color_space_string == "XYZ") color_space = XYZ_D65;
617 else if(color_space_string == "LinearRGB") color_space = LINEAR_RGB;
618 else if(color_space_string == "Raw_Manual_Gamma") color_space = RAW_MANUAL_GAMMA;
619 else color_space = SRGB;
620
621 if(texture_optimization_string == "none") texture_optimization = TEX_OPTIMIZATION_NONE;
622 else if(texture_optimization_string == "optimized") texture_optimization = TEX_OPTIMIZATION_OPTIMIZED;
623 else if(texture_optimization_string == "compressed") texture_optimization = TEX_OPTIMIZATION_COMPRESSED;
624 else texture_optimization = TEX_OPTIMIZATION_NONE;
625 }
626
627 ih->setColorSpace(color_space, gamma);
628 ih->setTextureOptimization(texture_optimization); //FIXME DAVID: Maybe we should leave this to imageHandler factory code...
629 ih->setGrayScaleSetting(img_grayscale);
630
631 if(!ih->loadFromFile(*name))
632 {
633 Y_ERROR << "ImageTexture: Couldn't load image file, dropping texture." << yendl;
634 return nullptr;
635 }
636
637 tex = new textureImage_t(ih, intp, gamma, color_space);
638
639 if(!tex)
640 {
641 Y_ERROR << "ImageTexture: Couldn't create image texture." << yendl;
642 return nullptr;
643 }
644
645 if(intp == INTP_MIPMAP_TRILINEAR || intp == INTP_MIPMAP_EWA)
646 {
647 ih->generateMipMaps();
648 if(!session.getDifferentialRaysEnabled())
649 {
650 Y_VERBOSE << "At least one texture using mipmaps interpolation, enabling ray differentials." << yendl;
651 session.setDifferentialRaysEnabled(true); //If there is at least one texture using mipmaps, then enable differential rays in the rendering process.
652 }
653
654 /*//FIXME DAVID: TEST SAVING MIPMAPS. CAREFUL: IT COULD CAUSE CRASHES!
655 for(int i=0; i<=ih->getHighestImgIndex(); ++i)
656 {
657 std::stringstream ss;
658 ss << "//tmp//saved_mipmap_" << ihname << "__" << i;
659 ih->saveToFile(ss.str(), i);
660 }*/
661 }
662
663 // setup image
664 bool rot90 = false;
665 bool even_tiles=false, odd_tiles=true;
666 bool use_alpha=true, calc_alpha=false;
667 int xrep=1, yrep=1;
668 double minx=0.0, miny=0.0, maxx=1.0, maxy=1.0;
669 double cdist=0.0;
670 const std::string *clipmode = nullptr;
671 bool mirror_x = false;
672 bool mirror_y = false;
673 float intensity = 1.f, contrast = 1.f, saturation = 1.f, hue = 0.f, factor_red = 1.f, factor_green = 1.f, factor_blue = 1.f;
674 bool clamp = false;
675 float trilinear_level_bias = 0.f;
676 float ewa_max_anisotropy = 8.f;
677
678 params.getParam("xrepeat", xrep);
679 params.getParam("yrepeat", yrep);
680 params.getParam("cropmin_x", minx);
681 params.getParam("cropmin_y", miny);
682 params.getParam("cropmax_x", maxx);
683 params.getParam("cropmax_y", maxy);
684 params.getParam("rot90", rot90);
685 params.getParam("clipping", clipmode);
686 params.getParam("even_tiles", even_tiles);
687 params.getParam("odd_tiles", odd_tiles);
688 params.getParam("checker_dist", cdist);
689 params.getParam("use_alpha", use_alpha);
690 params.getParam("calc_alpha", calc_alpha);
691 params.getParam("mirror_x", mirror_x);
692 params.getParam("mirror_y", mirror_y);
693 params.getParam("trilinear_level_bias", trilinear_level_bias);
694 params.getParam("ewa_max_anisotropy", ewa_max_anisotropy);
695
696 params.getParam("adj_mult_factor_red", factor_red);
697 params.getParam("adj_mult_factor_green", factor_green);
698 params.getParam("adj_mult_factor_blue", factor_blue);
699 params.getParam("adj_intensity", intensity);
700 params.getParam("adj_contrast", contrast);
701 params.getParam("adj_saturation", saturation);
702 params.getParam("adj_hue", hue);
703 params.getParam("adj_clamp", clamp);
704
705 tex->xrepeat = xrep;
706 tex->yrepeat = yrep;
707 tex->rot90 = rot90;
708 tex->setCrop(minx, miny, maxx, maxy);
709 tex->use_alpha = use_alpha;
710 tex->calc_alpha = calc_alpha;
711 tex->normalmap = normalmap;
712 tex->tex_clipmode = string2cliptype(clipmode);
713 tex->checker_even = even_tiles;
714 tex->checker_odd = odd_tiles;
715 tex->checker_dist = cdist;
716 tex->mirrorX = mirror_x;
717 tex->mirrorY = mirror_y;
718
719 tex->setAdjustments(intensity, contrast, saturation, hue, clamp, factor_red, factor_green, factor_blue);
720
721 tex->trilinear_level_bias = trilinear_level_bias;
722 tex->ewa_max_anisotropy = ewa_max_anisotropy;
723
724 if(intp == INTP_MIPMAP_EWA) tex->generateEWALookupTable();
725
726 return tex;
727 }
728
729 __END_YAFRAY
730