1 // Copyright 2008-present Contributors to the OpenImageIO project.
2 // SPDX-License-Identifier: BSD-3-Clause
3 // https://github.com/OpenImageIO/oiio/blob/master/LICENSE.md
4
5
6 /// \file
7 /// Non-public classes used internally by TextureSystemImpl.
8
9
10 #ifndef OPENIMAGEIO_TEXTURE_PVT_H
11 #define OPENIMAGEIO_TEXTURE_PVT_H
12
13 #include <OpenImageIO/simd.h>
14 #include <OpenImageIO/texture.h>
15
16 OIIO_NAMESPACE_BEGIN
17
18 class ImageCache;
19 class Filter1D;
20
21 namespace pvt {
22
23 class TextureSystemImpl;
24
25 #ifndef OPENIMAGEIO_IMAGECACHE_PVT_H
26 class ImageCacheImpl;
27 class ImageCacheFile;
28 class ImageCacheTile;
29 class ImageCacheTileRef;
30 #endif
31
32
33
34 /// Working implementation of the abstract TextureSystem class.
35 ///
36 class TextureSystemImpl : public TextureSystem {
37 public:
38 typedef ImageCacheFile TextureFile;
39
40 TextureSystemImpl(ImageCache* imagecache);
41 virtual ~TextureSystemImpl();
42
43 virtual bool attribute(string_view name, TypeDesc type, const void* val);
attribute(string_view name,int val)44 virtual bool attribute(string_view name, int val)
45 {
46 return attribute(name, TypeDesc::INT, &val);
47 }
attribute(string_view name,float val)48 virtual bool attribute(string_view name, float val)
49 {
50 return attribute(name, TypeDesc::FLOAT, &val);
51 }
attribute(string_view name,double val)52 virtual bool attribute(string_view name, double val)
53 {
54 float f = (float)val;
55 return attribute(name, TypeDesc::FLOAT, &f);
56 }
attribute(string_view name,string_view val)57 virtual bool attribute(string_view name, string_view val)
58 {
59 const char* s = val.c_str();
60 return attribute(name, TypeDesc::STRING, &s);
61 }
62
63 virtual bool getattribute(string_view name, TypeDesc type, void* val) const;
getattribute(string_view name,int & val)64 virtual bool getattribute(string_view name, int& val) const
65 {
66 return getattribute(name, TypeDesc::INT, &val);
67 }
getattribute(string_view name,float & val)68 virtual bool getattribute(string_view name, float& val) const
69 {
70 return getattribute(name, TypeDesc::FLOAT, &val);
71 }
getattribute(string_view name,double & val)72 virtual bool getattribute(string_view name, double& val) const
73 {
74 float f;
75 bool ok = getattribute(name, TypeDesc::FLOAT, &f);
76 if (ok)
77 val = f;
78 return ok;
79 }
getattribute(string_view name,char ** val)80 virtual bool getattribute(string_view name, char** val) const
81 {
82 return getattribute(name, TypeDesc::STRING, val);
83 }
getattribute(string_view name,std::string & val)84 virtual bool getattribute(string_view name, std::string& val) const
85 {
86 const char* s;
87 bool ok = getattribute(name, TypeDesc::STRING, &s);
88 if (ok)
89 val = s;
90 return ok;
91 }
92
93
94 // Retrieve options
get_commontoworld(Imath::M44f & result)95 void get_commontoworld(Imath::M44f& result) const { result = m_Mc2w; }
96
97 virtual Perthread* get_perthread_info(Perthread* thread_info = NULL)
98 {
99 return (Perthread*)m_imagecache->get_perthread_info(
100 (ImageCachePerThreadInfo*)thread_info);
101 }
create_thread_info()102 virtual Perthread* create_thread_info()
103 {
104 OIIO_ASSERT(m_imagecache);
105 return (Perthread*)m_imagecache->create_thread_info();
106 }
destroy_thread_info(Perthread * threadinfo)107 virtual void destroy_thread_info(Perthread* threadinfo)
108 {
109 OIIO_ASSERT(m_imagecache);
110 m_imagecache->destroy_thread_info((ImageCachePerThreadInfo*)threadinfo);
111 }
112
get_texture_handle(ustring filename,Perthread * thread)113 virtual TextureHandle* get_texture_handle(ustring filename,
114 Perthread* thread)
115 {
116 PerThreadInfo* thread_info = thread
117 ? ((PerThreadInfo*)thread)
118 : m_imagecache->get_perthread_info();
119 return (TextureHandle*)find_texturefile(filename, thread_info);
120 }
121
good(TextureHandle * texture_handle)122 virtual bool good(TextureHandle* texture_handle)
123 {
124 return texture_handle && !((TextureFile*)texture_handle)->broken();
125 }
126
127 virtual bool texture(ustring filename, TextureOpt& options, float s,
128 float t, float dsdx, float dtdx, float dsdy,
129 float dtdy, int nchannels, float* result,
130 float* dresultds = NULL, float* dresultdt = NULL);
131 virtual bool texture(TextureHandle* texture_handle, Perthread* thread_info,
132 TextureOpt& options, float s, float t, float dsdx,
133 float dtdx, float dsdy, float dtdy, int nchannels,
134 float* result, float* dresultds = NULL,
135 float* dresultdt = NULL);
136 virtual bool texture(ustring filename, TextureOptBatch& options,
137 Tex::RunMask mask, const float* s, const float* t,
138 const float* dsdx, const float* dtdx,
139 const float* dsdy, const float* dtdy, int nchannels,
140 float* result, float* dresultds = nullptr,
141 float* dresultdt = nullptr);
142 virtual bool texture(TextureHandle* texture_handle, Perthread* thread_info,
143 TextureOptBatch& options, Tex::RunMask mask,
144 const float* s, const float* t, const float* dsdx,
145 const float* dtdx, const float* dsdy,
146 const float* dtdy, int nchannels, float* result,
147 float* dresultds = nullptr,
148 float* dresultdt = nullptr);
149 virtual bool texture(ustring filename, TextureOptions& options,
150 Runflag* runflags, int beginactive, int endactive,
151 VaryingRef<float> s, VaryingRef<float> t,
152 VaryingRef<float> dsdx, VaryingRef<float> dtdx,
153 VaryingRef<float> dsdy, VaryingRef<float> dtdy,
154 int nchannels, float* result, float* dresultds = NULL,
155 float* dresultdt = NULL);
156 virtual bool texture(TextureHandle* texture_handle, Perthread* thread_info,
157 TextureOptions& options, Runflag* runflags,
158 int beginactive, int endactive, VaryingRef<float> s,
159 VaryingRef<float> t, VaryingRef<float> dsdx,
160 VaryingRef<float> dtdx, VaryingRef<float> dsdy,
161 VaryingRef<float> dtdy, int nchannels, float* result,
162 float* dresultds = NULL, float* dresultdt = NULL);
163
164 virtual bool texture3d(ustring filename, TextureOpt& options,
165 const Imath::V3f& P, const Imath::V3f& dPdx,
166 const Imath::V3f& dPdy, const Imath::V3f& dPdz,
167 int nchannels, float* result,
168 float* dresultds = NULL, float* dresultdt = NULL,
169 float* dresultdr = NULL);
170 virtual bool texture3d(TextureHandle* texture_handle,
171 Perthread* thread_info, TextureOpt& options,
172 const Imath::V3f& P, const Imath::V3f& dPdx,
173 const Imath::V3f& dPdy, const Imath::V3f& dPdz,
174 int nchannels, float* result,
175 float* dresultds = NULL, float* dresultdt = NULL,
176 float* dresultdr = NULL);
177 virtual bool texture3d(ustring filename, TextureOptBatch& options,
178 Tex::RunMask mask, const float* P, const float* dPdx,
179 const float* dPdy, const float* dPdz, int nchannels,
180 float* result, float* dresultds = nullptr,
181 float* dresultdt = nullptr,
182 float* dresultdr = nullptr);
183 virtual bool texture3d(TextureHandle* texture_handle,
184 Perthread* thread_info, TextureOptBatch& options,
185 Tex::RunMask mask, const float* P, const float* dPdx,
186 const float* dPdy, const float* dPdz, int nchannels,
187 float* result, float* dresultds = nullptr,
188 float* dresultdt = nullptr,
189 float* dresultdr = nullptr);
190 virtual bool texture3d(ustring filename, TextureOptions& options,
191 Runflag* runflags, int beginactive, int endactive,
192 VaryingRef<Imath::V3f> P,
193 VaryingRef<Imath::V3f> dPdx,
194 VaryingRef<Imath::V3f> dPdy,
195 VaryingRef<Imath::V3f> dPdz, int nchannels,
196 float* result, float* dresultds = NULL,
197 float* dresultdt = NULL, float* dresultdr = NULL);
198 virtual bool texture3d(TextureHandle* texture_handle,
199 Perthread* thread_info, TextureOptions& options,
200 Runflag* runflags, int beginactive, int endactive,
201 VaryingRef<Imath::V3f> P,
202 VaryingRef<Imath::V3f> dPdx,
203 VaryingRef<Imath::V3f> dPdy,
204 VaryingRef<Imath::V3f> dPdz, int nchannels,
205 float* result, float* dresultds = NULL,
206 float* dresultdt = NULL, float* dresultdr = NULL);
207
shadow(ustring,TextureOpt &,const Imath::V3f &,const Imath::V3f &,const Imath::V3f &,float *,float *,float *)208 virtual bool shadow(ustring /*filename*/, TextureOpt& /*options*/,
209 const Imath::V3f& /*P*/, const Imath::V3f& /*dPdx*/,
210 const Imath::V3f& /*dPdy*/, float* /*result*/,
211 float* /*dresultds*/, float* /*dresultdt*/)
212 {
213 return false;
214 }
shadow(TextureHandle *,Perthread *,TextureOpt &,const Imath::V3f &,const Imath::V3f &,const Imath::V3f &,float *,float *,float *)215 virtual bool shadow(TextureHandle* /*texture_handle*/,
216 Perthread* /*thread_info*/, TextureOpt& /*options*/,
217 const Imath::V3f& /*P*/, const Imath::V3f& /*dPdx*/,
218 const Imath::V3f& /*dPdy*/, float* /*result*/,
219 float* /*dresultds*/, float* /*dresultdt*/)
220 {
221 return false;
222 }
shadow(ustring,TextureOptBatch &,Tex::RunMask,const float *,const float *,const float *,float *,float *,float *)223 virtual bool shadow(ustring /*filename*/, TextureOptBatch& /*options*/,
224 Tex::RunMask /*mask*/, const float* /*P*/,
225 const float* /*dPdx*/, const float* /*dPdy*/,
226 float* /*result*/, float* /*dresultds*/,
227 float* /*dresultdt*/)
228 {
229 return false;
230 }
shadow(TextureHandle *,Perthread *,TextureOptBatch &,Tex::RunMask,const float *,const float *,const float *,float *,float *,float *)231 virtual bool shadow(TextureHandle* /*texture_handle*/,
232 Perthread* /*thread_info*/,
233 TextureOptBatch& /*options*/, Tex::RunMask /*mask*/,
234 const float* /*P*/, const float* /*dPdx*/,
235 const float* /*dPdy*/, float* /*result*/,
236 float* /*dresultds*/, float* /*dresultdt*/)
237 {
238 return false;
239 }
shadow(ustring,TextureOptions &,Runflag *,int,int,VaryingRef<Imath::V3f>,VaryingRef<Imath::V3f>,VaryingRef<Imath::V3f>,float *,float *,float *)240 virtual bool shadow(ustring /*filename*/, TextureOptions& /*options*/,
241 Runflag* /*runflags*/, int /*beginactive*/,
242 int /*endactive*/, VaryingRef<Imath::V3f> /*P*/,
243 VaryingRef<Imath::V3f> /*dPdx*/,
244 VaryingRef<Imath::V3f> /*dPdy*/, float* /*result*/,
245 float* /*dresultds*/, float* /*dresultdt*/)
246 {
247 return false;
248 }
shadow(TextureHandle *,Perthread *,TextureOptions &,Runflag *,int,int,VaryingRef<Imath::V3f>,VaryingRef<Imath::V3f>,VaryingRef<Imath::V3f>,float *,float *,float *)249 virtual bool shadow(TextureHandle* /*texture_handle*/,
250 Perthread* /*thread_info*/, TextureOptions& /*options*/,
251 Runflag* /*runflags*/, int /*beginactive*/,
252 int /*endactive*/, VaryingRef<Imath::V3f> /*P*/,
253 VaryingRef<Imath::V3f> /*dPdx*/,
254 VaryingRef<Imath::V3f> /*dPdy*/, float* /*result*/,
255 float* /*dresultds*/, float* /*dresultdt*/)
256 {
257 return false;
258 }
259
260
261 virtual bool environment(ustring filename, TextureOpt& options,
262 const Imath::V3f& R, const Imath::V3f& dRdx,
263 const Imath::V3f& dRdy, int nchannels,
264 float* result, float* dresultds = NULL,
265 float* dresultdt = NULL);
266 virtual bool environment(TextureHandle* texture_handle,
267 Perthread* thread_info, TextureOpt& options,
268 const Imath::V3f& R, const Imath::V3f& dRdx,
269 const Imath::V3f& dRdy, int nchannels,
270 float* result, float* dresultds = NULL,
271 float* dresultdt = NULL);
272 virtual bool environment(ustring filename, TextureOptBatch& options,
273 Tex::RunMask mask, const float* R,
274 const float* dRdx, const float* dRdy,
275 int nchannels, float* result,
276 float* dresultds = nullptr,
277 float* dresultdt = nullptr);
278 virtual bool environment(TextureHandle* texture_handle,
279 Perthread* thread_info, TextureOptBatch& options,
280 Tex::RunMask mask, const float* R,
281 const float* dRdx, const float* dRdy,
282 int nchannels, float* result,
283 float* dresultds = nullptr,
284 float* dresultdt = nullptr);
285 virtual bool environment(ustring filename, TextureOptions& options,
286 Runflag* runflags, int beginactive, int endactive,
287 VaryingRef<Imath::V3f> R,
288 VaryingRef<Imath::V3f> dRdx,
289 VaryingRef<Imath::V3f> dRdy, int nchannels,
290 float* result, float* dresultds = NULL,
291 float* dresultdt = NULL);
292 virtual bool environment(TextureHandle* texture_handle,
293 Perthread* thread_info, TextureOptions& options,
294 Runflag* runflags, int beginactive, int endactive,
295 VaryingRef<Imath::V3f> R,
296 VaryingRef<Imath::V3f> dRdx,
297 VaryingRef<Imath::V3f> dRdy, int nchannels,
298 float* result, float* dresultds = NULL,
299 float* dresultdt = NULL);
300
301 virtual std::string resolve_filename(const std::string& filename) const;
302
303 virtual bool get_texture_info(ustring filename, int subimage,
304 ustring dataname, TypeDesc datatype,
305 void* data);
306 virtual bool get_texture_info(TextureHandle* texture_handle,
307 Perthread* thread_info, int subimage,
308 ustring dataname, TypeDesc datatype,
309 void* data);
310
311 virtual bool get_imagespec(ustring filename, int subimage, ImageSpec& spec);
312 virtual bool get_imagespec(TextureHandle* texture_handle,
313 Perthread* thread_info, int subimage,
314 ImageSpec& spec);
315
316 virtual const ImageSpec* imagespec(ustring filename, int subimage = 0);
317 virtual const ImageSpec* imagespec(TextureHandle* texture_handle,
318 Perthread* thread_info = NULL,
319 int subimage = 0);
320
321 virtual bool get_texels(ustring filename, TextureOpt& options, int miplevel,
322 int xbegin, int xend, int ybegin, int yend,
323 int zbegin, int zend, int chbegin, int chend,
324 TypeDesc format, void* result);
325 virtual bool get_texels(TextureHandle* texture_handle,
326 Perthread* thread_info, TextureOpt& options,
327 int miplevel, int xbegin, int xend, int ybegin,
328 int yend, int zbegin, int zend, int chbegin,
329 int chend, TypeDesc format, void* result);
330
331 virtual std::string geterror() const;
332 virtual std::string getstats(int level = 1, bool icstats = true) const;
333 virtual void reset_stats();
334
335 virtual void invalidate(ustring filename, bool force);
336 virtual void invalidate_all(bool force = false);
337 virtual void close(ustring filename);
338 virtual void close_all();
339
delete(void * todel)340 void operator delete(void* todel) { ::delete ((char*)todel); }
341
342 typedef bool (*wrap_impl)(int& coord, int origin, int width);
343
344 /// Return an opaque, non-owning pointer to the underlying ImageCache
345 /// (if there is one).
imagecache()346 virtual ImageCache* imagecache() const { return m_imagecache; }
347
348 private:
349 typedef ImageCacheTileRef TileRef;
350 typedef ImageCachePerThreadInfo PerThreadInfo;
351
352 void init();
353
354 /// Find the TextureFile record for the named texture, or NULL if no
355 /// such file can be found.
find_texturefile(ustring filename,PerThreadInfo * thread_info)356 TextureFile* find_texturefile(ustring filename, PerThreadInfo* thread_info)
357 {
358 return m_imagecache->find_file(filename, thread_info);
359 }
verify_texturefile(TextureFile * texturefile,PerThreadInfo * thread_info)360 TextureFile* verify_texturefile(TextureFile* texturefile,
361 PerThreadInfo* thread_info)
362 {
363 texturefile = m_imagecache->verify_file(texturefile, thread_info);
364 if (!texturefile || texturefile->broken()) {
365 std::string err = m_imagecache->geterror();
366 if (err.size())
367 errorf("%s", err);
368 #if 0
369 // If the file is "broken", at least one verbose error message
370 // has already been issued about it, so don't belabor the point.
371 // But for debugging purposes, these might help:
372 else if (texturefile && texturefile->broken())
373 error ("(unknown error - broken texture \"%s\")", texturefile->filename());
374 else
375 error ("(unknown error - NULL texturefile)");
376 #endif
377 }
378 return texturefile;
379 }
380
381 /// Find the tile specified by id. Just a pass-through to the
382 /// underlying ImageCache.
find_tile(const TileID & id,PerThreadInfo * thread_info,bool mark_same_tile_used)383 bool find_tile(const TileID& id, PerThreadInfo* thread_info,
384 bool mark_same_tile_used)
385 {
386 return m_imagecache->find_tile(id, thread_info, mark_same_tile_used);
387 }
388
389 // Define a prototype of a member function pointer for texture
390 // lookups.
391 // If simd is nonzero, it's guaranteed that all float* inputs and
392 // outputs are padded to length 'simd' and aligned to a simd*4-byte
393 // boundary (for example, 4 for SSE). This means that the functions can
394 // behave AS IF the number of channels being retrieved is simd, and any
395 // extra values returned will be discarded by the caller.
396 typedef bool (TextureSystemImpl::*texture_lookup_prototype)(
397 TextureFile& texfile, PerThreadInfo* thread_info, TextureOpt& options,
398 int nchannels_result, int actualchannels, float _s, float _t,
399 float _dsdx, float _dtdx, float _dsdy, float _dtdy, float* result,
400 float* dresultds, float* resultdt);
401
402 /// Look up texture from just ONE point
403 ///
404 bool texture_lookup(TextureFile& texfile, PerThreadInfo* thread_info,
405 TextureOpt& options, int nchannels_result,
406 int actualchannels, float _s, float _t, float _dsdx,
407 float _dtdx, float _dsdy, float _dtdy, float* result,
408 float* dresultds, float* resultdt);
409
410 bool texture_lookup_nomip(TextureFile& texfile, PerThreadInfo* thread_info,
411 TextureOpt& options, int nchannels_result,
412 int actualchannels, float _s, float _t,
413 float _dsdx, float _dtdx, float _dsdy,
414 float _dtdy, float* result, float* dresultds,
415 float* resultdt);
416
417 bool texture_lookup_trilinear_mipmap(
418 TextureFile& texfile, PerThreadInfo* thread_info, TextureOpt& options,
419 int nchannels_result, int actualchannels, float _s, float _t,
420 float _dsdx, float _dtdx, float _dsdy, float _dtdy, float* result,
421 float* dresultds, float* resultdt);
422
423 // For the samplers, it's guaranteed that all float* inputs and outputs
424 // are padded to length 'simd' and aligned to a simd*4-byte boundary
425 // (for example, 4 for SSE). This means that the functions can behave AS
426 // IF the number of channels being retrieved is simd, and any extra
427 // values returned will be discarded by the caller.
428 typedef bool (TextureSystemImpl::*sampler_prototype)(
429 int nsamples, const float* s, const float* t, int level,
430 TextureFile& texturefile, PerThreadInfo* thread_info,
431 TextureOpt& options, int nchannels_result, int actualchannels,
432 const float* weight, simd::vfloat4* accum, simd::vfloat4* daccumds,
433 simd::vfloat4* daccumdt);
434 bool sample_closest(int nsamples, const float* s, const float* t, int level,
435 TextureFile& texturefile, PerThreadInfo* thread_info,
436 TextureOpt& options, int nchannels_result,
437 int actualchannels, const float* weight,
438 simd::vfloat4* accum, simd::vfloat4* daccumds,
439 simd::vfloat4* daccumdt);
440 bool sample_bilinear(int nsamples, const float* s, const float* t,
441 int level, TextureFile& texturefile,
442 PerThreadInfo* thread_info, TextureOpt& options,
443 int nchannels_result, int actualchannels,
444 const float* weight, simd::vfloat4* accum,
445 simd::vfloat4* daccumds, simd::vfloat4* daccumdt);
446 bool sample_bicubic(int nsamples, const float* s, const float* t, int level,
447 TextureFile& texturefile, PerThreadInfo* thread_info,
448 TextureOpt& options, int nchannels_result,
449 int actualchannels, const float* weight,
450 simd::vfloat4* accum, simd::vfloat4* daccumds,
451 simd::vfloat4* daccumdt);
452
453 // Define a prototype of a member function pointer for texture3d
454 // lookups.
455 typedef bool (TextureSystemImpl::*texture3d_lookup_prototype)(
456 TextureFile& texfile, PerThreadInfo* thread_info, TextureOpt& options,
457 int nchannels_result, int actualchannels, const Imath::V3f& P,
458 const Imath::V3f& dPdx, const Imath::V3f& dPdy, const Imath::V3f& dPdz,
459 float* result, float* dresultds, float* dresultdt, float* dresultdr);
460 bool texture3d_lookup_nomip(TextureFile& texfile,
461 PerThreadInfo* thread_info, TextureOpt& options,
462 int nchannels_result, int actualchannels,
463 const Imath::V3f& P, const Imath::V3f& dPdx,
464 const Imath::V3f& dPdy, const Imath::V3f& dPdz,
465 float* result, float* dresultds,
466 float* dresultdt, float* dresultdr);
467 typedef bool (TextureSystemImpl::*accum3d_prototype)(
468 const Imath::V3f& P, int level, TextureFile& texturefile,
469 PerThreadInfo* thread_info, TextureOpt& options, int nchannels_result,
470 int actualchannels, float weight, float* accum, float* daccumds,
471 float* daccumdt, float* daccumdr);
472 bool accum3d_sample_closest(const Imath::V3f& P, int level,
473 TextureFile& texturefile,
474 PerThreadInfo* thread_info, TextureOpt& options,
475 int nchannels_result, int actualchannels,
476 float weight, float* accum, float* daccumds,
477 float* daccumdt, float* daccumdr);
478 bool accum3d_sample_bilinear(const Imath::V3f& P, int level,
479 TextureFile& texturefile,
480 PerThreadInfo* thread_info,
481 TextureOpt& options, int nchannels_result,
482 int actualchannels, float weight, float* accum,
483 float* daccumds, float* daccumdt,
484 float* daccumdr);
485
486 /// Helper function to calculate the anisotropic aspect ratio from
487 /// the major and minor ellipse axis lengths. The "clamped" aspect
488 /// ratio is returned (possibly adjusting major and minorlength to
489 /// conform to the aniso limits) but the true aspect is stored in
490 /// 'trueaspect'.
491 static float anisotropic_aspect(float& majorlength, float& minorlength,
492 TextureOpt& options, float& trueaspect);
493
494 /// Convert texture coordinates (s,t), which range on 0-1 for the
495 /// "full" image boundary, to texel coordinates (i+ifrac,j+jfrac)
496 /// where (i,j) is the texel to the immediate upper left of the
497 /// sample position, and ifrac and jfrac are the fractional (0-1)
498 /// portion of the way to the next texel to the right or down,
499 /// respectively.
500 void st_to_texel(float s, float t, TextureFile& texturefile,
501 const ImageSpec& spec, int& i, int& j, float& ifrac,
502 float& jfrac);
503
504 /// Called when the requested texture is missing, fills in the
505 /// results.
506 bool missing_texture(TextureOpt& options, int nchannels, float* result,
507 float* dresultds, float* dresultdt,
508 float* dresultdr = NULL);
509
510 /// Handle gray-to-RGB promotion.
511 void fill_gray_channels(const ImageSpec& spec, int nchannels, float* result,
512 float* dresultds, float* dresultdt,
513 float* dresultdr = NULL);
514
515 static bool wrap_periodic_sharedborder(int& coord, int origin, int width);
516 static const wrap_impl wrap_functions[];
517
518 /// Helper function for lat-long environment maps: compute a "pole"
519 /// pixel that's the average of all of row y. This will only be
520 /// called for levels where the whole mipmap level fits on one tile.
521 const float* pole_color(TextureFile& texturefile,
522 PerThreadInfo* thread_info,
523 const ImageCacheFile::LevelInfo& levelinfo,
524 TileRef& tile, int subimage, int miplevel,
525 int pole);
526 /// Helper function for lat-long environment maps: called near pole
527 /// regions, this figures out the average pole color and fades to it
528 /// right at the pole, and also adjusts weight so that the regular
529 /// interpolated texture color will be added in correctly.
530 /// This should only be called on the edge texels.
531 void fade_to_pole(float t, float* accum, float& weight,
532 TextureFile& texturefile, PerThreadInfo* thread_info,
533 const ImageCacheFile::LevelInfo& levelinfo,
534 TextureOpt& options, int miplevel, int nchannels);
535
536 /// Perform short unit tests.
537 void unit_test_texture();
538
539 /// Internal error reporting routine, with printf-like arguments.
540 template<typename... Args>
errorf(const char * fmt,const Args &...args)541 void errorf(const char* fmt, const Args&... args) const
542 {
543 append_error(Strutil::sprintf(fmt, args...));
544 }
545 /// Internal error reporting routine, with std::format-like arguments.
546 template<typename... Args>
error(const char * fmt,const Args &...args)547 void error(const char* fmt, const Args&... args) const
548 {
549 append_error(Strutil::fmt::format(fmt, args...));
550 }
551
552 /// Append a string to the current error message
553 void append_error(const std::string& message) const;
554
555 void printstats() const;
556
557 // Debugging aid
558 void visualize_ellipse(const std::string& name, float dsdx, float dtdx,
559 float dsdy, float dtdy, float sblur, float tblur);
560
561 ImageCacheImpl* m_imagecache = nullptr;
562 bool m_imagecache_owner = false; ///< True if we own the ImageCache
563 Imath::M44f m_Mw2c; ///< world-to-"common" matrix
564 Imath::M44f m_Mc2w; ///< common-to-world matrix
565 bool m_gray_to_rgb; ///< automatically copy gray to rgb channels?
566 bool m_flip_t; ///< Flip direction of t coord?
567 int m_max_tile_channels; ///< narrow tile ID channel range when
568 ///< the file has more channels
569 /// Saved error string, per-thread
570 ///
571 mutable thread_specific_ptr<std::string> m_errormessage;
572 Filter1D* hq_filter; ///< Better filter for magnification
573 int m_statslevel;
574 friend class TextureSystem;
575 };
576
577
578
579 inline float
anisotropic_aspect(float & majorlength,float & minorlength,TextureOpt & options,float & trueaspect)580 TextureSystemImpl::anisotropic_aspect(float& majorlength, float& minorlength,
581 TextureOpt& options, float& trueaspect)
582 {
583 float aspect = Imath::clamp(majorlength / minorlength, 1.0f, 1.0e6f);
584 trueaspect = aspect;
585 if (aspect > options.anisotropic) {
586 aspect = options.anisotropic;
587 // We have to clamp the ellipse to the maximum amount of anisotropy
588 // that we allow. How do we do it?
589 // a. Widen the short axis so we never alias along the major
590 // axis, but we over-blur along the minor axis. I've never
591 // been happy with this, it visibly overblurs.
592 // b. Clamp the long axis so we don't blur, but might alias.
593 // c. Split the difference, take the geometric mean, this makes
594 // it slightly too blurry along the minor axis, slightly
595 // aliasing along the major axis. You can't please everybody.
596 if (options.conservative_filter) {
597 #if 0
598 // Solution (a) -- never alias by blurring more along minor axis
599 minorlength = majorlength / options.anisotropic;
600 #else
601 // Solution (c) -- this is our default, usually a nice balance.
602 // We used to take the geometric mean...
603 // majorlength = sqrtf ((majorlength) *
604 // (minorlength * options.anisotropic));
605 // ...but frankly I find the average to be a little more
606 // visually pleasing.
607 majorlength
608 = 0.5f * ((majorlength) + (minorlength * options.anisotropic));
609 minorlength = majorlength / options.anisotropic;
610 #endif
611 } else {
612 // Solution (b) -- alias slightly, never overblur
613 majorlength = minorlength * options.anisotropic;
614 }
615 }
616 return aspect;
617 }
618
619
620
621 inline void
st_to_texel(float s,float t,TextureFile & texturefile,const ImageSpec & spec,int & i,int & j,float & ifrac,float & jfrac)622 TextureSystemImpl::st_to_texel(float s, float t, TextureFile& texturefile,
623 const ImageSpec& spec, int& i, int& j,
624 float& ifrac, float& jfrac)
625 {
626 // As passed in, (s,t) map the texture to (0,1). Remap to texel coords.
627 // Note that we have two modes, depending on the m_sample_border.
628 if (texturefile.m_sample_border == 0) {
629 // texel samples are at 0.5/res, 1.5/res, ..., (res-0.5)/res,
630 s = s * spec.width + spec.x - 0.5f;
631 t = t * spec.height + spec.y - 0.5f;
632 } else {
633 // first and last rows/columns are *exactly* on the boundary,
634 // so samples are at 0, 1/(res-1), ..., 1.
635 s = s * (spec.width - 1) + spec.x;
636 t = t * (spec.height - 1) + spec.y;
637 }
638 ifrac = floorfrac(s, &i);
639 jfrac = floorfrac(t, &j);
640 // Now (i,j) are the integer coordinates of the texel to the
641 // immediate "upper left" of the lookup point, and (ifrac,jfrac) are
642 // the amount that the lookup point is actually offset from the
643 // texel center (with (1,1) being all the way to the next texel down
644 // and to the right).
645 }
646
647
648
649 } // end namespace pvt
650
651 OIIO_NAMESPACE_END
652
653 #endif // OPENIMAGEIO_TEXTURE_PVT_H
654