\chapter{Texture Access: {\cf TextureSystem}}
\label{chap:texturesystem}
\index{Texture System|(}

\def\TextureSystem{{\kw TextureSystem}\xspace}
\def\TextureOptions{{\kw TextureOptions}\xspace}
\def\TextureOptBatch{{\kw TextureOptBatch}\xspace}
\def\TextureOpt{{\kw TextureOpt}\xspace}


\section{Texture System Introduction and Theory of Operation}
\label{sec:texturesys:intro}

Coming soon.
FIXME

\section{Helper Classes}
\label{sec:texturesys:helperclasses}

\subsection{Imath}

The texture functinality of \product uses the excellent open source
{\cf Ilmbase} package's {\cf Imath} types when it requires 3D vectors
and transformation matrixes.  Specifically, we use {\cf Imath::V3f}
for 3D positions and directions, and {\cf Imath::M44f} for $4 \times 4$
transformation matrices.  To use these yourself, we recommend that you:

\begin{code}
    #include <OpenEXR/ImathVec.h>
    #include <OpenEXR/ImathMatrix.h>
\end{code}

Please refer to the {\cf Ilmbase} and {\cf OpenEXR}
documentation and header files for more complete information about
use of these types in your own application.  However, note that you
are not strictly required to use these classes in your application ---
{\cf Imath::V3f} has a memory layout identical to {\cf float[3]}
and {\cf Imath::M44f} has a memory layout identical to {\cf float[16]},
so as long as your own internal vectors and matrices have the same
memory layout, it's ok to just cast pointers to them when passing
as arguments to \TextureSystem methods.


\subsection{\TextureOpt}
\indexapi{TextureOpt}
\label{sec:textureopt}

\TextureOpt is a structure that holds many options controlling
single-point texture lookups.  Because each texture lookup API call takes
a reference to a \TextureOpt, the call signatures remain uncluttered
rather than having an ever-growing list of parameters, most of which
will never vary from their defaults.  Here is a brief description of
the data members of a \TextureOpt structure:

\apiitem{int firstchannel}
The beginning channel for the lookup.  For example, to retrieve just the blue
channel, you should have {\cf firstchannel} = 2 while passing {\cf nchannels} = 1
to the appropriate texture function.
\apiend

\apiitem{int subimage \\
ustring subimagename}
Specifies the subimage or face within the file to use for the texture lookup.
If {\cf subimagename} is set (it defaults to the empty string), it will
try to use the subimage that had a matching metadata
\qkw{oiio:subimagename}, otherwise the integer {\cf subimage} will be
used (which defaults to 0, i.e., the first/default subimage).  Nonzero
subimage indices only make sense for a texture file that supports
subimages or separate images per face (such as Ptex).  This will be
ignored if the file does not have multiple subimages or separate
per-face textures.
\apiend

\apiitem{Wrap swrap, twrap}
Specify the \emph{wrap mode} for 2D texture lookups (and 3D volume
texture lookups, using the additional {\cf rwrap} field).  These fields
are ignored for shadow and environment lookups.

These specify what happens when texture coordinates are found to be
outside the usual $[0,1]$ range over which the texture is defined.
{\cf Wrap} is an enumerated type that may take on any of the
following values:
\begin{description}
\item[\spc] \spc
\item[\rm \kw{WrapBlack}] The texture is black outside the [0,1] range.
\item[\rm \kw{WrapClamp}] The texture coordinates will be clamped to
  [0,1], i.e., the value outside [0,1] will be the same as the color
  at the nearest point on the border.
\item[\rm \kw{WrapPeriodic}] The texture is periodic, i.e., wraps back
  to 0 after going past 1.
\item[\rm \kw{WrapMirror}] The texture presents a mirror image at the
  edges, i.e., the coordinates go from 0 to 1, then back down to 0, then
  back up to 1, etc.
\item[\rm \kw{WrapDefault}] Use whatever wrap might be specified in the
  texture file itself, or some other suitable default (caveat emptor).
\end{description}

The wrap mode does not need to be identical in the $s$ and $t$
directions.
\apiend

\apiitem{float swidth, twidth}
For each direction, gives a multiplier for the derivatives.  Note that
a width of 0 indicates a point sampled lookup (assuming that blur is
also zero).  The default width is 1, indicating that the derivatives
should guide the amount of blur applied to the texture filtering (not
counting any additional \emph{blur} specified).
\apiend

\apiitem{float sblur, tblur}
For each direction, specifies an additional amount of pre-blur to apply
to the texture (\emph{after} derivatives are taken into account),
expressed as a portion of the width of the texture.  In other words,
blur = 0.1 means that the texture lookup should act as if the texture
was pre-blurred with a filter kernel with a width 1/10 the size of the
full image.  The default blur amount is 0, indicating a sharp texture
lookup.
\apiend

\apiitem{float fill}
Specifies the value that will be used for any color channels that are
requested but not found in the file.  For example, if you perform a
4-channel lookup on a 3-channel texture, the last channel will
get the fill value.  (Note: this behavior is affected by the
\qkw{gray_to_rgb} attribute described in 
Section~\ref{sec:texturesys:attributes}.)
\apiend

\apiitem{const float* missingcolor}
If not NULL, indicates that a missing or broken texture should \emph{not}
be treated as an error, but rather will simply return the supplied color
as the texture lookup color and {\cf texture()} will return {\cf true}.  
If the {\cf missingcolor} field is left at its default (a NULL pointer),
a missing or broken texture will be treated as an error and
{\cf texture()} will return {\cf false}.
Note: When not NULL, the data must point to \emph{nchannels} contiguous floats.
\apiend

\apiitem{float bias}
For shadow map lookups only, this gives the ``shadow bias'' amount.
\apiend

\apiitem{int samples}
For shadow map lookups only, the number of samples to use for the lookup.
\apiend

\apiitem{Wrap rwrap \\
float rblur, rwidth}
Specifies wrap, blur, and width for the third component of 3D volume texture
lookups.  These are not used for 2D texture lookups.
\apiend




\newpage
\section{TextureSystem Setup}
\label{sec:texturesys:api}

\subsection{Creating and destroying texture systems}
\label{sec:texturesys:api:createdestroy}

\TextureSystem is an abstract API described as a pure
virtual class.  The actual internal implementation is not exposed
through the external API of \product.  Because of this, you cannot
construct or destroy the concrete implementation, so two static
methods of \TextureSystem are provided:

\apiitem{static TextureSystem *TextureSystem::{\ce create} (bool share=true,\\
\bigspc\bigspc ImageCache *imagecache=nullptr)}
Creates a new \TextureSystem and returns a pointer to it.
If {\cf shared} is {\cf true}, the \TextureSystem returned will be a global
shared one, with a globally shared cache. If {\cf shared} is {\cf false}, a
new private \TextureSystem will be created, either with a newly created
private \ImageCache (if {\cf imagecache} is {\cf nullptr}), or with the
\ImageCache passed from (and owned by) the caller.
\apiend

\apiitem{static void TextureSystem::{\ce destroy} (TextureSystem *x, \\
\bigspc\bigspc bool teardown_imagecache=false)}
Destroys an allocated \TextureSystem, including freeing all system
resources that it holds (such as its underlying \ImageCache).

This is necessary to ensure that the memory is freed in a way that
matches the way it was allocated within the library.  Note that simply
using {\cf delete} on the pointer will not always work (at least,
not on some platforms in which a DSO/DLL can end up using a different
allocator than the main program).

If {\cf teardown_imagecache} is {\cf true}, and the \TextureSystem's
underlying \ImageCache is the \emph{shared} one, then that \ImageCache will
be thoroughly destroyed, not merely releasing the reference. \apiend

\subsection{Setting options and limits for the texture system}
\label{sec:texturesys:api:options}

The following member functions of \TextureSystem allow you to set
(and in some cases retrieve) options that control the overall
behavior of the texture system:

\apiitem{bool {\ce attribute} (string_view name, TypeDesc type,
  const void *val)}
\indexapi{attribute}

Sets an attribute (i.e., a property or option) of the \TextureSystem.
The {\cf name} designates the name of the attribute, {\cf type}
describes the type of data, and {\cf val} is a pointer to memory 
containing the new value for the attribute.

If the \TextureSystem recognizes a valid attribute name that matches the
type specified, the attribute will be set to the new value and {\cf
  attribute()} will return {\cf true}.  If {\cf name} is not recognized
as a valid attribute name, or if the types do not match (e.g., {\cf
  type} is {\cf TypeDesc::FLOAT} but the named attribute is a string),
the attribute will not be modified, and {\cf attribute()} will return
{\cf false}.

Here are examples:

\begin{code}
      TextureSystem *ts; 
      ...
      int maxfiles = 50;
      ts->attribute ("max_open_files", TypeDesc::INT, &maxfiles);

      const char *path = "/my/path";
      ts->attribute ("searchpath", TypeDesc::STRING, &path);
\end{code}

Note that when passing a string, you need to pass a pointer to the {\cf
  char*}, not a pointer to the first character.  (Rationale: for an {\cf
  int} attribute, you pass the address of the {\cf int}.  So for a
string, which is a {\cf char*}, you need to pass the address of the
string, i.e., a {\cf char**}).

The complete list of attributes can be found at the end of this section.

\apiend

\apiitem{bool {\ce attribute} (string_view name, int val) \\
bool {\ce attribute} (string_view name, float val) \\
bool {\ce attribute} (string_view name, double val) \\
bool {\ce attribute} (string_view name, string_view val)}
Specialized versions of {\cf attribute()} in which the data type is
implied by the type of the argument.

For example, the following are equivalent to the example above for the
general (pointer) form of {\cf attribute()}:

\begin{code}
      ts->attribute ("max_open_files", 50);
      ts->attribute ("searchpath", "/my/path");
\end{code}

\apiend


\apiitem{bool {\ce getattribute} (string_view name, TypeDesc type,
  void *val)}
\indexapi{getattribute}

Gets the current value of an attribute of the \TextureSystem.
The {\cf name} designates the name of the attribute, {\cf type}
describes the type of data, and {\cf val} is a pointer to memory 
where the user would like the value placed.

If the \TextureSystem recognizes a valid attribute name that matches the
type specified, the attribute value will be stored at address {\cf val}
and {\cf attribute()} will return {\cf true}.  If {\cf name} is not recognized
as a valid attribute name, or if the types do not match (e.g., {\cf
  type} is {\cf TypeDesc::FLOAT} but the named attribute is a string),
no data will be written to {\cf val}, and {\cf attribute()} will return
{\cf false}.

Here are examples:

\begin{code}
      TextureSystem *ts; 
      ...
      int maxfiles;
      ts->getattribute ("max_open_files", TypeDesc::INT, &maxfiles);

      const char *path;
      ts->getattribute ("searchpath", TypeDesc::STRING, &path);
\end{code}

Note that when passing a string, you need to pass a pointer to the {\cf
  char*}, not a pointer to the first character.  Also, the {\cf char*}
will end up pointing to characters owned by the \TextureSystem; the
caller does not need to ever free the memory that contains the
characters.

The complete list of attributes can be found at the end of this section.


\apiend

\apiitem{bool {\ce getattribute} (string_view name, int \&val) \\
bool {\ce getattribute} (string_view name, float \&val) \\
bool {\ce getattribute} (string_view name, double \&val) \\
bool {\ce getattribute} (string_view name, char **val) \\
bool {\ce getattribute} (string_view name, std::string \& val)}
Specialized versions of {\cf getattribute()} in which the data type is
implied by the type of the argument.

For example, the following are equivalent to the example above for the
general (pointer) form of {\cf getattribute()}:

\begin{code}
      int maxfiles;
      ts->getattribute ("max_open_files", &maxfiles);
      const char *path;
      ts->getattribute ("searchpath", &path);
\end{code}

\apiend


\subsubsection*{Texture system attributes}
\label{sec:texturesys:attributes}

Recognized attributes include the following:

\apiitem{int max_open_files \\
float max_memory_MB \\
string searchpath \\
string plugin_searchpath \\
int autotile \\
int autoscanline \\
int automip \\
int accept_untiled \\
int accept_unmipped \\
int failure_retries \\
int deduplicate \\
string substitute_image \\
int max_errors_per_file}

These attributes are all passed along to the underlying \ImageCache that
is used internally by the \TextureSystem.  Please consult the
\ImageCache attribute list in Section~\ref{sec:imagecache:api:attribute}
for explanations of these attributes.

\apiend

\apiitem{matrix worldtocommon}
The $4 \times 4$ matrix that provides the spatial transformation
from ``world'' to a ``common'' coordinate system.  This is used for
shadow map lookups, in which the shadow map itself encodes the
world coordinate system, but positions passed to {\cf shadow()} are
expressed in ``common'' coordinates.
\apiend

\apiitem{matrix commontoworld}
The $4 \times 4$ matrix that is the inverse of {\cf worldtocommon} ---
that is, it transforms points from ``common'' to ``world'' coordinates.

You do not need to set {\cf commontoworld} and {\cf worldtocommon}
separately; just setting either one will implicitly set the other, since
each is the inverse of the other.
\apiend

\apiitem{int gray_to_rgb}
If set to nonzero, texture lookups of single-channel (grayscale) 
images will replicate the sole channel's values into the next two
channels, making it behave like an RGB image that happens to have all
three channels with identical pixel values.  (Channels beyond the third
will get the ``fill'' value.)

The default value of zero means that all missing channels will get
the ``fill'' color.
\apiend

\apiitem{int max_tile_channels}
Sets the maximum number of color channels in a texture file for which all
channels will be loaded as cached tiles. Files with more than this number
of color channels will have only the requested subset loaded, in order
to save cache space (but at the possible wasted expense of separate tiles
that overlap their channel ranges). The default is 5.
\apiend

\apiitem{string latlong_up}
Sets the default ``up'' direction for latlong environment maps (only
applies if the map itself doesn't specify a format or is in a format
that explicitly requires a particular orientation).  The default is
\qkw{y}.  (Currently any other value will result in $z$ being ``up.'')
\apiend

\apiitem{int flip_t}
If nonzero, $t$ coordinates will be flipped ($1-t$) for texture lookups.
The default is 0.
\apiend

\apiitem{string options}
This catch-all is simply a comma-separated list of {\cf name=value}
settings of named options, which will be parsed and individually set.
\begin{code}
        ic->attribute ("options", "max_memory_MB=512.0,autotile=1");
\end{code}
Note that if an option takes a string value that must itself contain a
comma, it is permissible to enclose the value in either single ({\cf ' '})
or double ({\cf " "}) quotes.
\apiend



\subsection{Opaque data for performance lookups}
\label{sec:texturesys:api:opaque}

\apiitem{Perthread * {\ce get_perthread_info} (Perthread *thread_info=NULL) \\
Perthread * {\ce create_perthread_info} () \\
void {\ce destroy_perthread_info} (Perthread *thread_info)}
\indexapi{get_perthread_info}
\indexapi{create_perthread_info} \indexapi{destroy_perthread_info}

The \TextureSystem implementation needs to maintain certain per-thread
state, and some \TextureSystem methods take an opaque {\cf Perthread} pointer
to this record. There are three options for how to deal with it:

1. Don't worry about it at all: don't use the methods that want {\cf
Perthread} pointers, or always pass {\cf NULL} for any {\cf Perthread*}
arguments, and \TextureSystem will do thread-specific-pointer retrieval as
necessary (though at some small cost).

2. If your app already stores per-thread information of its own, you may
call {\cf get_perthread_info(NULL)} to retrieve it for that thread, and then
pass it into the functions that allow it (thus sparing them the need and
expense of retrieving the thread-specific pointer). However, it is crucial
that this pointer not be shared between multiple threads. In this case,
the \TextureSystem manages the storage, which will automatically be released
when the thread terminates.

3. If your app also wants to manage the storage of the {\cf Perthread},
it can explicitly create one with {\cf create_perthread_info}, pass it around,
and eventually be responsible for destroying it with {\cf destroy_perthread_info}.
When managing the storage, the app may reuse the {\cf Perthread} for another
thread after the first is terminated, but still may not use the same
{\cf Perthread} for two threads running concurrently.
\apiend


\apiitem{TextureHandle * {\ce get_texture_handle} (ustring filename,\\
\bigspc\bigspc\bigspc  Perthread *thread_info=NULL)}
\indexapi{get_texture_handle}
Retrieve an opaque handle for fast texture lookups.  The optional opaque
pointer {\cf thread_info} is thread-specific information returned by
{\cf get_perthread_info()}.  Return {\cf NULL} if something has gone
horribly wrong.
\apiend

\apiitem{bool {\ce good} (TextureHandle *texture_handle)}
\indexapi{good}
Return true if the texture handle (previously returned by
{\cf get_texture_handle()}) is a valid image that can be subsequently read
or sampled.
\apiend


\newpage
\section{Texture Lookups -- single point}

\subsection{2D Texture Lookups}
\label{sec:texturesys:api:texture}

\apiitem{bool {\ce texture} (ustring filename, TextureOpt \&options,\\
\bigspc\spc                   float s, float t, float dsdx, float dtdx,\\
\bigspc\spc                   float dsdy, float dtdy, int nchannels, float *result),\\
\bigspc\spc                   float *dresultds=NULL, float *dresultdt=NULL)}
\indexapi{texture}

Perform a filtered 2D texture lookup on a position centered at 2D
coordinates ({\cf s}, {\cf t}) from the texture identified by
{\cf filename}, and using relevant texture {\cf options}.  The
{\cf nchannels} parameter determines the number of channels to retrieve
(e.g., 1 for a single value, 3 for an RGB triple, etc.).
The filtered results will be stored in {\cf result[0..nchannels-1]}.

We assume that this lookup will be part of an image that has pixel
coordinates {\cf x} and {\cf y}.  By knowing how {\cf s} and {\cf t}
change from pixel to pixel in the final image, we can properly
\emph{filter} or antialias the texture lookups.  This information is
given via derivatives {\cf dsdx} and {\cf dtdx} that define the change
in {\cf s} and {\cf t} per unit of {\cf x}, and {\cf dsdy} and {\cf
  dtdy} that define the change in {\cf s} and {\cf t} per unit of {\cf
  y}.  If it is impossible to know the derivatives, you may pass 0 for
them, but in that case you will not receive an antialiased texture lookup.

If the {\cf dresultds} and {\cf dresultdt} parameters are not {\cf NULL}
(the default), these specify locations in which to store the
\emph{derivatives} of the texture lookup, i.e., the change of the filtered
texture per unit of $s$ and $t$, respectively.  Each must point to at least
{\cf nchannels} contiguous floats.  If they are {\cf NULL}, the derivative
computations will not be performed.

Fields within {\cf options} that are honored for 2D texture lookups
include the following:

\vspace{-12pt}
\apiitem{int firstchannel}
\vspace{10pt}
The index of the first channel to look up from the texture.
\apiend

\vspace{-24pt}
\apiitem{int subimage}
\vspace{10pt}
The subimage or face within the file.
This will be ignored if the file does not have multiple subimages or
separate per-face textures.
\apiend

\vspace{-24pt}
\apiitem{Wrap swrap, twrap}
\vspace{10pt}
Specify the \emph{wrap mode} for each direction, one of: 
{\cf WrapBlack}, {\cf WrapClamp}, {\cf WrapPeriodic}, {\cf WrapMirror},
or {\cf WrapDefault}.
\apiend

\vspace{-24pt}
\apiitem{float swidth, twidth}
\vspace{10pt}
For each direction, gives a multiplier for the derivatives.
\apiend

\vspace{-24pt}
\apiitem{float sblur, tblur}
\vspace{10pt}
For each direction, specifies an additional amount of pre-blur to apply
to the texture (\emph{after} derivatives are taken into account),
expressed as a portion of the width of the texture.
\apiend

\vspace{-24pt}
\apiitem{float fill}
\vspace{10pt}
Specifies the value that will be used for any color channels that are
requested but not found in the file.  For example, if you perform a
4-channel lookup on a 3-channel texture, the last channel will
get the fill value.  (Note: this behavior is affected by the
\qkw{gray_to_rgb} attribute described in 
Section~\ref{sec:texturesys:attributes}.)
\apiend

\vspace{-24pt}
\apiitem{const float *missingcolor}
\vspace{10pt}
If not NULL, specifies the color that will be returned for missing or
broken textures (rather than being an error).
\apiend

This function returns {\cf true} upon success, or {\cf false} if the
file was not found or could not be opened by any available ImageIO
plugin.
\apiend


\apiitem{bool {\ce texture} (TextureHandle *texture_handle,
                          Perthread *thread_info, \\
\bigspc                   TextureOpt \&options, float s, float t, float dsdx, float dtdx,\\
\bigspc                   float dsdy, float dtdy, int nchannels, float *result,\\
\bigspc                   float *dresultds=NULL, float *dresultdt=NULL)}
A slightly faster {\cf texture} call for applications that are willing
to do the extra housekeeping of knowing the handle of the texture they
are accessing and the per-thread info for the curent thread.  These
may be retrieved by the {\cf get_texture_handle()} and 
{\cf get_perthread_info()} methods, respectively.
\apiend



%\newpage
\subsection{Volume Texture Lookups}
\label{sec:texturesys:api:texture3d}

\apiitem{bool {\ce texture3d} (ustring filename, TextureOpt \&options,\\
\bigspc\spc                    const Imath::V3f \&P, const Imath::V3f \&dPdx,\\
\bigspc\spc                    const Imath::V3f \&dPdy, const Imath::V3f \&dPdz,\\
\bigspc\spc                    int nchannels, float *result,\\
\bigspc\spc                   float *dresultds=NULL, float *dresultdt=NULL,\\
\bigspc\spc                   float *dresultdr=NULL)}
\indexapi{texture3d}

Perform a filtered 3D volumetric texture lookup on a position centered at
3D position {\cf P} from the texture identified by
{\cf filename}, and using relevant texture {\cf options}.  The filtered
results will be stored in {\cf result[0..nchannels-1]}.

We assume that this lookup will be part of an image that has pixel
coordinates {\cf x} and {\cf y} and depth {\cf z}.  
By knowing how {\cf P} changes from
pixel to pixel in the final image, and as we step in $z$ depth, we can properly \emph{filter} or
antialias the texture lookups.  This information is given via
derivatives {\cf dPdx}, {\cf dPdy}, and {\cf dPdz} that define the changes in {\cf P}
per unit of {\cf x}, {\cf y}, and {\cf z}, respectively.  If it is impossible to
know the derivatives, you may pass 0 for them, but in that case you will
not receive an antialiased texture lookup.

The {\cf P} coordinate and {\cf dPdx}, {\cf dPdy}, and {\cf dPdz}
derivatives are assumed to be in some kind of common global coordinate
system (usually \qkw{world} space) and will be automatically transformed
into volume local coordinates, if such a transormation is specified in
the volume file itself.

If the {\cf dresultds}, {\cf dresultdt}, and  {\cf dresultdr} parameters are
not {\cf NULL} (the default), these specify locations in which to store the
\emph{derivatives} of the texture lookup, i.e., the change of the filtered
texture per unit of $s$, $t$ and $r$, respectively.  Each must point to at least
{\cf nchannels} contiguous floats.  If they are {\cf NULL}, the derivative
computations will not be performed.

Fields within {\cf options} that are honored for 3D texture lookups
include the following:

\vspace{-12pt}
\apiitem{int firstchannel}
\vspace{10pt}
The index of the first channel to look up from the texture.
\apiend

\vspace{-24pt}
\apiitem{Wrap swrap, twrap, rwrap}
\vspace{10pt}
Specify the wrap modes for each direction, one of: 
{\cf WrapBlack}, {\cf WrapClamp}, {\cf WrapPeriodic}, {\cf WrapMirror},
or {\cf WrapDefault}.
\apiend

\vspace{-24pt}
\apiitem{float swidth, twidth, rwidth}
\vspace{10pt}
For each direction, gives a multiplier for the derivatives.
\apiend

\vspace{-24pt}
\apiitem{float sblur, tblur, rblur}
\vspace{10pt}
For each direction, specifies an additional amount of pre-blur to apply
to the texture (\emph{after} derivatives are taken into account),
expressed as a portion of the width of the texture.
\apiend

\vspace{-24pt}
\apiitem{float fill}
\vspace{10pt}
Specifies the value that will be used for any color channels that are
requested but not found in the file.  For example, if you perform a
4-channel lookup on a 3-channel texture, the last channel will
get the fill value.  (Note: this behavior is affected by the
\qkw{gray_to_rgb} attribute described in 
Section~\ref{sec:texturesys:attributes}.)
\apiend

\vspace{-24pt}
\apiitem{const float *missingcolor}
\vspace{10pt}
If not NULL, specifies the color that will be returned for missing or
broken textures (rather than being an error).
\apiend

\vspace{-24pt}
\apiitem{float time}
\vspace{10pt}
A time value to use if the volume texture specifies a time-varying
local transformation (default: 0).
\apiend

This function returns {\cf true} upon success, or {\cf false} if the
file was not found or could not be opened by any available ImageIO
plugin.

\apiend

\apiitem{bool {\ce texture3d} (TextureHandle *texture_handle,
                          Perthread *thread_info, \\
\bigspc\spc                   TextureOpt \&opt, const Imath::V3f \&P, const Imath::V3f \&dPdx,\\
\bigspc\spc                          const Imath::V3f \&dPdy, const Imath::V3f \&dPdz,\\
\bigspc\spc                          int nchannels, float *result, float *dresultds=NULL,\\
\bigspc\spc                          float *dresultdt=NULL, float *dresultdr=NULL)}
A slightly faster {\cf texture3d} call for applications that are willing
to do the extra housekeeping of knowing the handle of the texture they
are accessing and the per-thread info for the curent thread.  These
may be retrieved by the {\cf get_texture_handle()} and 
{\cf get_perthread_info()} methods, respectively.
\apiend


%\newpage
\subsection{Shadow Lookups}
\label{sec:texturesys:api:shadow}

\apiitem{bool {\ce shadow} (ustring filename, TextureOpt \&opt,\\
\bigspc                         const Imath::V3f \&P, const Imath::V3f \&dPdx,\\
\bigspc                         const Imath::V3f \&dPdy, int nchannels, float *result,\\
\bigspc                         float *dresultds=NULL, float *dresultdt=NULL)}
\indexapi{shadow}

Perform a shadow map lookup on a position centered at 3D
coordinate {\cf P} (in a designated ``common'' space) from the shadow map identified by
{\cf filename}, and using relevant texture {\cf options}.  The filtered
results will be stored in {\cf result[]}.

We assume that this lookup will be part of an image that has pixel
coordinates {\cf x} and {\cf y}.  By knowing how {\cf P} changes from
pixel to pixel in the final image, we can properly \emph{filter} or
antialias the texture lookups.  This information is given via
derivatives {\cf dPdx} and {\cf dPdy} that define the changes in {\cf P}
per unit of {\cf x} and {\cf y}, respectively.  If it is impossible to
know the derivatives, you may pass 0 for them, but in that case you will
not receive an antialiased texture lookup.

Fields within {\cf options} that are honored for 2D texture lookups
include the following:

\vspace{-12pt}
\apiitem{float swidth, twidth}
\vspace{10pt}
For each direction, gives a multiplier for the derivatives.
\apiend

\vspace{-24pt}
\apiitem{float sblur, tblur}
\vspace{10pt}
For each direction, specifies an additional amount of pre-blur to apply
to the texture (\emph{after} derivatives are taken into account),
expressed as a portion of the width of the texture.
\apiend

\vspace{-24pt}
\apiitem{float bias}
\vspace{10pt}
Specifies the amount of \emph{shadow bias} to use --- this effectively
ignores shadow occlusion that is closer than the bias amount to the
surface, helping to eliminate self-shadowing artifacts.
\apiend

\vspace{-24pt}
\apiitem{int samples}
\vspace{10pt}
Specifies the number of samples to use when evaluating the shadow map.
More samples will give a smoother, less noisy, appearance to the
shadows, but may also take longer to compute.
\apiend

This function returns {\cf true} upon success, or {\cf false} if the
file was not found or could not be opened by any available ImageIO
plugin.
\apiend

\apiitem{bool {\ce shadow} (TextureHandle *texture_handle,
                          Perthread *thread_info, \\
\bigspc                   TextureOpt \&opt, const Imath::V3f \&P,\\
\bigspc                         const Imath::V3f \&dPdx, const Imath::V3f \&dPdy,\\
\bigspc                         int nchannels, float *result,\\
\bigspc                         float *dresultds=NULL, float *dresultdt=NULL)}
A slightly faster {\cf shadow} call for applications that are willing
to do the extra housekeeping of knowing the handle of the texture they
are accessing and the per-thread info for the curent thread.  These
may be retrieved by the {\cf get_texture_handle()} and 
{\cf get_perthread_info()} methods, respectively.
\apiend


%\newpage
\subsection{Environment Lookups}
\label{sec:texturesys:api:environment}

\apiitem{bool {\ce environment} (ustring filename, TextureOpt \&options,\\
\bigspc\spc                      const Imath::V3f \&R, const Imath::V3f \&dRdx,\\
\bigspc\spc                      const Imath::V3f \&dRdy, int nchannels, float *result,\\
\bigspc\spc                     float *dresultds=NULL, float *dresultdt=NULL)}
\indexapi{environment}

Perform a filtered directional environment map lookup in the direction
of vector {\cf R}, from the texture identified by {\cf filename}, and
using relevant texture {\cf options}.  The filtered results will be
stored in {\cf result[]}.

We assume that this lookup will be part of an image that has pixel
coordinates {\cf x} and {\cf y}.  By knowing how {\cf R} changes from
pixel to pixel in the final image, we can properly \emph{filter} or
antialias the texture lookups.  This information is given via
derivatives {\cf dRdx} and {\cf dRdy} that define the changes in {\cf R}
per unit of {\cf x} and {\cf y}, respectively.  If it is impossible to
know the derivatives, you may pass 0 for them, but in that case you will
not receive an antialiased texture lookup.

Fields within {\cf options} that are honored for 3D texture lookups
include the following:

\vspace{-12pt}
\apiitem{int firstchannel}
\vspace{10pt}
The index of the first channel to look up from the texture.
\apiend

\vspace{-24pt}
\apiitem{float swidth, twidth}
\vspace{10pt}
For each direction, gives a multiplier for the derivatives.
\apiend

\vspace{-24pt}
\apiitem{float sblur, tblur}
\vspace{10pt}
For each direction, specifies an additional amount of pre-blur to apply
to the texture (\emph{after} derivatives are taken into account),
expressed as a portion of the width of the texture.
\apiend

\vspace{-24pt}
\apiitem{float fill}
\vspace{10pt}
Specifies the value that will be used for any color channels that are
requested but not found in the file.  For example, if you perform a
4-channel lookup on a 3-channel texture, the last channel will
get the fill value.  (Note: this behavior is affected by the
\qkw{gray_to_rgb} attribute described in 
Section~\ref{sec:texturesys:attributes}.)
\apiend

This function returns {\cf true} upon success, or {\cf false} if the
file was not found or could not be opened by any available ImageIO
plugin.
\apiend

\apiitem{bool {\ce environment} (TextureHandle *texture_handle,
                          Perthread *thread_info, \\
\bigspc\spc               TextureOpt \&opt, const Imath::V3f \&R,\\
\bigspc\spc               const Imath::V3f \&dRdx, onst Imath::V3f \&dRdy,\\
\bigspc\spc               int nchannels, float *result,\\
\bigspc\spc               float *dresultds=NULL, float *dresultdt=NULL)}
A slightly faster {\cf environment} call for applications that are willing
to do the extra housekeeping of knowing the handle of the texture they
are accessing and the per-thread info for the curent thread.  These
may be retrieved by the {\cf get_texture_handle()} and 
{\cf get_perthread_info()} methods, respectively.
\apiend



\section{Batched Texture Lookups}
\label{sec:texturesys:api:batched}
\index{SIMD} \index{batched texture lookups}

On CPU architectures with SIMD processing, texturing entire batches of
samples at once may provide a large speedup compared to texturing each
sample point individually. The batch size is fixed (for any build of
\product) and may be accessed with the following constant:

\apiitem{static const int {\ce Tex::BatchWidth}}
This constant specifies the batch size. This is fixed within any release
of \product, but may change from release to release and also may be
overridden at build time. A typical batch size is 16.
\apiend

All of the batched calls take a \emph{run mask}, which describes which
subset of ``lanes'' should be computed by the batched lookup:

\apiitem{typedef ... {\ce Tex::RunMask}}

The {\cf RunMask} is defined to be an integer large enough to hold at least
{\cf BatchWidth} bits. The least significant bit corresponds to the first
(i.e., {\cf [0]}) position of all batch arrays. For each position
{\cf i} in the batch, the bit identified by {\cf (1 << i)} controls whether
that position will be computed.

The defined constant {\cf RunMaskOn} contants the value with all bits
{\cf 0..BatchWidth-1} set to 1.
\apiend

\subsection{Batched Options}

\apiitem{class {\ce TextureOptBatch}}
\label{sec:textureoptbatch}

\TextureOptBatch is a structure that holds the options for doing an entire
batch of lookups from the same texture at once.
The members of \TextureOptBatch correspond to the similarly named members of
the single-point \TextureOpt, so we refer you to
Section~\ref{sec:textureopt} for detailed explanations, and this section
will only explain the differences between batched and single-point options.

\apiitem{int firstchannel \\
int subimage \\
ustring subimagename \\
Tex::Wrap swrap, twrap, rwrap \\
Tex::MipMode mipmode \\
Tex::InterpMode interpmode \\
int anisotropic \\
bool conservative_filter \\
float fill \\
const float *missingcolor } ~\\
These fields are all scalars --- a single value for each \TextureOptBatch
--- which means that the value of these options must be the same for every
texture sample point within a batch. If you have a number of texture lookups
to perform for the same texture, but they have (for example) differing wrap
modes or subimages from point to point, then you must split them into
separate batch calls.
\apiend

\apiitem{float sblur[Tex::BatchWidth] \\
float tblur[Tex::BatchWidth] \\
float rblur[Tex::BatchWidth] } ~\\
These arrays hold the $s$, and $t$ blur amounts, for each sample in the
batch, respectively. (And the $r$ blur amount, used only for volumetric
{\cf texture3d()} lookups.)
\apiend

\apiitem{float swidth[Tex::BatchWidth] \\
float twidth[Tex::BatchWidth] \\
float rwidth[Tex::BatchWidth] } ~\\
These arrays hold the $s$, and $t$ filtering width multiplier for
derivatives, for each sample in the batch, respectively. (And the $r$
multiplier, used only for volumetric {\cf texture3d()} lookups.)
\apiend
\apiend

\subsection{Batched Texture Lookup Calls}

\apiitem{bool {\ce texture} (ustring filename, TextureOptBatch \&options,\\
\bigspc                   Tex::RunMask mask, const float *s, const float *t,\\
\bigspc                   const float *dsdx, const float *dtdx,\\
\bigspc                   const float *dsdy, const float *dtdy,\\
\bigspc                   int nchannels, float *result,\\
\bigspc                   float *dresultds=nullptr, float *dresultdt=nullptr) \\[2ex]
bool {\ce texture} (TextureHandle *texture_handle,
                          Perthread *thread_info, \\
\bigspc                   TextureOptBatch \&options,\\
\bigspc                   Tex::RunMask mask, const float *s, const float *t,\\
\bigspc                   const float *dsdx, const float *dtdx,\\
\bigspc                   const float *dsdy, const float *dtdy,\\
\bigspc                   int nchannels, float *result,\\
\bigspc                   float *dresultds=nullptr, float *dresultdt=nullptr) \\
}

Perform filtered 2D texture lookups on a batch of positions from the
same texture, all at once.  The parameters {\cf s},
{\cf t}, {\cf dsdx}, {\cf dtdx}, and {\cf dsdy}, {\cf dtdy} are each
a pointer to {\cf [BatchSize]} values.  The {\cf mask} determines which
of those array elements to actually compute.

The various results are arranged as arrays that behave as if they were
declared

~~~~ {\cf  float result[channels][BatchSize]}

\noindent In other words, all the batch values for channel 0 are
adjacent, followed by all the batch values for channel 1, etc. (This is
``SOA'' order.)

This function returns {\cf true} upon success, or {\cf false} if the
file was not found or could not be opened by any available ImageIO
plugin.
\apiend

\apiitem{bool {\ce texture3d} (ustring filename, TextureOptBatch \&options,\\
\bigspc                        Tex::RunMask mask, const float *P, const float *dPdx,\\
\bigspc                        const float *dPdy, const float *dPdz,\\
\bigspc                        int nchannels, float *result, float *dresultds=nullptr,\\
\bigspc                        float *dresultdt=nullptr,float *dresultdr=nullptr)\\[2ex]
bool {\ce texture3d} (TextureHandle *texture_handle,
                      Perthread *thread_info, \\
\bigspc               TextureOptBatch \&options,\\
\bigspc               Tex::RunMask mask, const float *P, const float *dPdx,\\
\bigspc               const float *dPdy, const float *dPdz,\\
\bigspc               int nchannels, float *result, float *dresultds=nullptr,\\
\bigspc               float *dresultdt=nullptr, float *dresultdr=nullptr)}

Perform filtered 3D volumetric texture lookups on a batch of positions from
the same texture, all at once. The ``point-like'' parameters {\cf P}, {\cf
dPdx}, {\cf dPdy}, and {\cf dPdz} are each a pointers to arrays of
{\cf float value[3][BatchSize]}. That is, each one points to all the $x$ values
for the batch, immediately followed by all the $y$ values, followed by the
$z$ values.

The various results arrays are also arranged as arrays that behave as if
they were declared {\cf  float result[channels][BatchSize]}, where all the
batch values for channel 0 are adjacent, followed by all the batch values
for channel 1, etc.

This function returns {\cf true} upon success, or {\cf false} if the
file was not found or could not be opened by any available ImageIO
plugin.
\apiend

\begin{comment}
\apiitem{bool {\ce shadow} (ustring filename, TextureOptBatch \&options,\\
\bigspc                         Tex::RunMask mask, \\
\bigspc                         const float *P, const float *dPdx,\\
\bigspc                         const float *dPdy, int nchannels, float *result,\\
\bigspc                         float *dresultds=nullptr, float *dresultdt=nullptr)\\[2ex]
bool {\ce shadow} (TextureHandle *texture_handle,  Perthread *thread_info, \\
\bigspc                         TextureOptBatch \&options,\\
\bigspc                         Tex::RunMask mask, \\
\bigspc                         const float *P, const float *dPdx,\\
\bigspc                         const float *dPdy, int nchannels, float *result,\\
\bigspc                         float *dresultds=nullptr, float *dresultdt=nullptr)}

Perform filtered shadow map lookups on a batch of positions from
the same texture, all at once. The ``point-like'' parameters {\cf P},
{\cf dPdx}, and {\cf dPdy} are each a pointers to arrays of
{\cf float value[3][BatchSize]}. That is, each one points to all the $x$ values
for the batch, immediately followed by all the $y$ values, followed by the
$z$ values.

The various results arrays are also arranged as arrays that behave as if
they were declared {\cf  float result[channels][BatchSize]}, where all the
batch values for channel 0 are adjacent, followed by all the batch values
for channel 1, etc.

This function returns {\cf true} upon success, or {\cf false} if the
file was not found or could not be opened by any available ImageIO
plugin.
\apiend
\end{comment}

\apiitem{bool {\ce environment} (ustring filename, TextureOptBatch \&options,\\
\bigspc\spc                      Tex::RunMask mask, \\
\bigspc\spc                      const float *R, const float *dRdx,\\
\bigspc\spc                      const float *dRdy, int nchannels, float *result,\\
\bigspc\spc                      float *dresultds=nullptr, float *dresultdt=nullptr)\\[2ex]
bool {\ce environment} (TextureHandle *texture_handle,
                        Perthread *thread_info, \\
\bigspc\spc             TextureOptBatch \&options, Tex::RunMask mask, \\
\bigspc\spc             const float *R, const float *dRdx,\\
\bigspc\spc             const float *dRdy, int nchannels, float *result,\\
\bigspc\spc             float *dresultds=nullptr, float *dresultdt=nullptr)}

Perform filtered directional environment map lookups on a batch of positions
from the same texture, all at once. The ``point-like'' parameters {\cf R},
{\cf dRdx}, and {\cf dRdy} are each a pointers to arrays of
{\cf float value[3][BatchSize]}. That is, each one points to all the $x$ values
for the batch, immediately followed by all the $y$ values, followed by the
$z$ values.

Perform filtered directional environment map lookups on a collection of
directions all at once, which may be much more efficient than repeatedly
calling the single-point version of {\cf environment()}.  The parameters
{\cf R}, {\cf dRdx}, and {\cf dRdy} are now {\cf VaryingRef}'s that may
refer to either a single or an array of values, as are many the fields in
the {\cf options}.

The various results arrays are also arranged as arrays that behave as if
they were declared {\cf  float result[channels][BatchSize]}, where all the
batch values for channel 0 are adjacent, followed by all the batch values
for channel 1, etc.

This function returns {\cf true} upon success, or {\cf false} if the
file was not found or could not be opened by any available ImageIO
plugin.
\apiend


%\newpage
\section{Texture Metadata and Raw Texels}
\label{sec:texturesys:api:gettextureinfo}
\label{sec:texturesys:api:getimagespec}

\apiitem{bool {\ce get_texture_info} (ustring filename, int subimage, \\
\bigspc\spc\spc ustring dataname, TypeDesc datatype, void *data) \\
bool {\ce get_texture_info} (TextureHandle *texture_handle, \\
\bigspc\spc\spc Perthread *thread_info, int subimage, \\
\bigspc\spc\spc ustring dataname, TypeDesc datatype, void *data)}

Retrieves information about the texture, either named by {\cf filename} or
specified by an opaque handle returned by {\cf get_texture_handle()}.
The {\cf dataname} is a keyword indcating what information should
be retrieved, {\cf datatype} is the type of data expected, and
{\cf data} points to caller-owned memory where the results should be
placed.  It is up to the caller to ensure that {\cf data} contains
enough space to hold an item of the requested {\cf datatype}.

The return value is {\cf true} if {\cf get_texture_info()} is able to answer
the query -- that is, find the requested {\cf dataname} for the texture and
it matched the requested {\cf datatype}.  If the requested data was not
found, or was not of the right data type, {\cf get_texture_info()} will
return {\cf false}. Except for the \qkw{exists} and \qkw{udim} queries, file that does not
exist or could not be read properly as an image also constitutes a query
failure that will return {\cf false}.

Supported {\cf dataname} values include:

\begin{description}
\item[\spc] \spc \vspace{-12pt} 

\item[\rm \kw{exists}] Stores the value 1 (as an {\cf int} if the file
exists and is an image format that \product can read, or 0 if the file
does not exist, or could not be properly read as a texture. Note that
unlike all other queries, this query will ``succeed'' (return {\cf true})
even if the file does not exist.

\item[\rm \kw{udim}] Stores the value 1 (as an {\cf int}) if the file
is a ``virtual UDIM'' or texture atlas file (as described in
Section~\ref{sec:texturesys:udim}) or 0 otherwise.

\item[\rm \kw{subimages}] The number of subimages/faces in the file, as an integer.

\item[\rm \kw{resolution}] The resolution of the texture file, which
is an array of 2 integers (described as {\cf TypeDesc(INT,2)}).

\item[\rm \kw{resolution} (int[3])] The 3D resolution of the texture file, which
is an array of 3 integers (described as {\cf TypeDesc(INT,3)})  The
third value will e 1 unless it's a volumetric (3D) image.

\item[\rm \kw{miplevels}] The number of MIPmap levels for the specified
subimage (an integer).

\item[\rm \kw{texturetype}] A string describing the type of texture
of the given file, which describes how the texture may be used (also
which texture API call is probably the right one for it).
This currently may return one of: \qkw{unknown}, \qkw{Plain Texture},
\qkw{Volume Texture}, \qkw{Shadow}, 
or \qkw{Environment}.

\item[\rm \kw{textureformat}] A string describing the format of the
given file, which describes the kind of texture stored in the file.
This currently may return one of: \qkw{unknown}, \qkw{Plain Texture},
\qkw{Volume Texture}, \qkw{Shadow}, \qkw{CubeFace Shadow}, \qkw{Volume
  Shadow}, \qkw{LatLong Environment}, or \qkw{CubeFace Environment}.
Note that there are several kinds of shadows and environment maps,
all accessible through the same API calls.

\item[\rm \kw{channels}] The number of color channels in the file 
(an integer).

\item[\rm \kw{format}] The native data format of the pixels in the
  file (an integer, giving the {\cf TypeDesc::BASETYPE} of the data).
  Note that this is not necessarily the same as the data format stored
  in the image cache.

\item[\rm \kw{cachedformat}] The native data format of the pixels as
  stored in the image cache (an integer, giving the {\cf
    TypeDesc::BASETYPE} of the data).  Note that this is not necessarily
  the same as the native data format of the file.

\item[\rm \kw{datawindow}] 
Returns the pixel data window of the image, which is either an array of 4
integers (returning xmin, ymin, xmax, ymax) or an array of 6 integers
(returning xmin, ymin, zmin, xmax, ymax, zmax). The $z$ values may be useful
for 3D/volumetric images; for 2D images they will be 0).

\item[\rm \kw{displaywindow}] 
Returns the display (a.k.a.\ full) window of the image, which is either an
array of 4 integers (returning xmin, ymin, xmax, ymax) or an array of 6
integers (returning xmin, ymin, zmin, xmax, ymax, zmax). The $z$ values may
be useful for 3D/volumetric images; for 2D images they will be 0).

\item[\rm \kw{worldtocamera}] The viewing matrix, which is a $4 \times 4$
matrix (an {\cf Imath::M44f}, described as {\cf TypeDesc(FLOAT,MATRIX)}),
giving the world-to-camera 3D transformation matrix that was used when  the
image was created. Generally, only rendered images will have this.

\item[\rm \kw{worldtoscreen}] The projection matrix, which is a $4 \times 4$
matrix (an {\cf Imath::M44f}, described as {\cf TypeDesc(FLOAT,MATRIX)}),
giving the matrix that projected points from world space into a 2D screen
coordinate system where $x$ and $y$ range from $-1$ to $+1$.  Generally,
only rendered images will have this.

\item[\rm \kw{averagecolor}] If available in the metadata (generally only
for files that have been processed by {\cf maketx}), this will return the
average color of the texture (into an array of floats).

\item[\rm \kw{averagealpha}] If available in the metadata (generally only
for files that have been processed by {\cf maketx}), this will return the
average alpha value of the texture (into a float).

\item[\rm \kw{constantcolor}] If the metadata (generally only for files that
have been processed by {\cf maketx}) indicates that the texture has the same
values for all pixels in the texture, this will retrieve the constant color
of the texture (into an array of floats). A non-constant image (or one that
does not have the special metadata tag identifying it as a constant texture)
will fail this query (return false).

\item[\rm \kw{constantalpha}] If the metadata indicates that the texture has
the same values for all pixels in the texture, this will retrieve the
constant alpha value of the texture (into a float). A non-constant image (or
one that does not have the special metadata tag identifying it as a constant
texture) will fail this query (return false).

\item[\rm \kw{stat:tilesread}] Number of tiles read from this file ({\cf int64}).

\item[\rm \kw{stat:bytesread}] Number of bytes of uncompressed pixel data read
from this file ({\cf int64}).

\item[\rm \kw{stat:redundant_tiles}] Number of times a tile was read, where
the same tile had been rad before. ({\cf int64}).

\item[\rm \kw{stat:redundant_bytesread}] Number of bytes (of uncompressed pixel
data) in tiles that were read redundantly. ({\cf int64}).

\item[\rm \kw{stat:redundant_bytesread}] Number of tiles read from this file ({\cf int}).

\item[\rm \kw{stat:timesopened}] Number of times this file was opened ({\cf int}).

\item[\rm \kw{stat:iotime}] Time (in seconds) spent on all I/O for this file ({\cf float}).

\item[\rm \kw{stat:mipsused}] Stores 1 if any MIP levels beyond the highest
resolution were accesed, otherwise 0. ({\cf int})

\item[\rm \kw{stat:is_duplicate}] Stores 1 if this file was a duplicate of
another image, otherwise 0. ({\cf int})

\item[Anything else] -- For all other data names, the
the metadata of the image file will be searched for an item that
matches both the name and data type.

\end{description}
\apiend

\apiitem{bool {\ce get_imagespec} (ustring filename, int subimage, ImageSpec \&spec) \\
bool {\ce get_imagespec} (TextureHandle *texture_handle, Perthread *thread_info,\\
  \bigspc\bigspc int subimage, ImageSpec \&spec)}

If the image (specified by either name or handle)
is found and able to be opened by an available
image format plugin, this function copies its image specification into
{\cf spec} and returns {\cf true}.  Otherwise, if the file is not
found, could not be opened, or is not of a format readable by any
plugin that could be found, the return value is {\cf false}.
\apiend


\apiitem{const ImageSpec * {\ce imagespec} (ustring filename, int subimage) \\
const ImageSpec * {\ce imagespec} (TextureHandle *texture_handle, \\
\bigspc\bigspc Perthread *thread_info, int subimage)}

If the named image is found and able to be opened by an available
image format plugin, and the designated subimage exists, this function
returns a pointer to an \ImageSpec that describes it.  Otherwise, if the
file is not found, could not be opened, is not of a format readable by
any plugin that could be find, or the designated subimage did
not exist in the file, the return value is NULL.

This method is much more efficient than {\cf get_imagespec()}, since it
just returns a pointer to the spec held internally by the underlying \ImageCache
(rather than copying the spec to the user's memory).  However, the
caller must beware that the pointer is only valid as long as nobody
(even other threads) calls {\cf invalidate()} on the file, or {\cf
  invalidate_all()}, or destroys the \TextureSystem.
\apiend

\apiitem{bool {\ce get_texels} (ustring filename, TextureOpt \&options, int miplevel, \\
\bigspc                       int xbegin, int xend, int ybegin, int yend,\\
\bigspc                       int zbegin, int zend, int chbegin, int chend,\\
\bigspc                       TypeDesc format, void *result) \\
bool {\ce get_texels} (TextureHandle *texture_handle, PerThread *thread_info, \\
\bigspc                       Perthread *thread_info, TextureOpt \&options, int miplevel, \\
\bigspc                       int xbegin, int xend, int ybegin, int yend,\\
\bigspc                       int zbegin, int zend, int chbegin, int chend,\\
\bigspc                       TypeDesc format, void *result)}

For a texture identified by either name or handle,
retrieve a rectangle of raw unfiltered texels at the named MIP-map level, storing
the texel values beginning at the address specified by result.
Note that the face/subimage is communicated through {\kw options.subimage}.
The texel values will be converted to the type specified by
format.  It is up to the caller to ensure that result points to
an area of memory big enough to accommodate the requested
rectangle (taking into consideration its dimensions, number of
channels, and data format).  The rectangular region to be
retrieved includes {\cf begin} but does not include {\cf end} (much
like STL begin/end usage).
Requested pixels that are not part of the valid pixel data region of the
image file will be filled with zero values.

Fields within {\cf options} that are honored for raw texel retieval
include the following:

\vspace{-12pt}
\apiitem{int subimage}
\vspace{10pt}
The subimage to retrieve.
\apiend

% FIXME -- we should support this
%\vspace{-24pt}
%\apiitem{Wrap swrap, twrap}
%\vspace{10pt}
%Specify the \emph{wrap mode} for each direction, one of: 
%{\cf WrapBlack}, {\cf WrapClamp}, {\cf WrapPeriodic}, {\cf WrapMirror},
%or {\cf WrapDefault}.
%\apiend

\vspace{-24pt}
\apiitem{float fill}
\vspace{10pt}
Specifies the value that will be used for any color channels that are
requested but not found in the file.  For example, if you perform a
4-channel lookup on a 3-channel texture, the last channel will
get the fill value.  (Note: this behavior is affected by the
\qkw{gray_to_rgb} attribute described in 
Section~\ref{sec:texturesys:attributes}.)
\apiend

Return true if the file is found and could be opened by an
available ImageIO plugin, otherwise return false.

\apiend

\apiitem{std::string {\ce resolve_filename} (const std::string \&filename)}
Returns the true path to the given file name, with searchpath logic
applied.
\apiend

\section{Miscellaneous -- Statistics, errors, flushing the cache}
\label{sec:texturesys:api:geterror}
\label{sec:texturesys:api:getstats}
\label{sec:texturesys:api:resetstats}
\label{sec:texturesys:api:invalidate}

\apiitem{std::string {\ce geterror} ()}
\index{error checking}
If any other API routines return {\cf false}, indicating that an
error has occurred, this routine will retrieve the error and clear
the error status.  If no error has occurred since the last time
{\cf geterror()} was called, it will return an empty string.
\apiend

\apiitem{std::string {\ce getstats} (int level=1, bool icstats=true)}
Returns a big string containing useful statistics about the \ImageCache
operations, suitable for saving to a file or outputting to the terminal.
The {\cf level} indicates the amount of detail in the statistics,
with higher numbers (up to a maximum of 5) yielding more and more
esoteric information.  If {\cf icstats} is true, the returned string
will also contain all the statistics of the underlying \ImageCache,
but if false will only contain texture-specific statistics.
\apiend

\apiitem{void {\ce reset_stats} ()}
Reset most statistics to be as they were with a fresh
\ImageCache.  Caveat emptor: this does not flush the cache
itelf, so the resulting statistics from the next set of texture
requests will not match the number of tile reads, etc., that
would have resulted from a new \ImageCache.
\apiend

\apiitem{void {\ce invalidate} (ustring filename)}
Invalidate any loaded tiles or open file handles associated with
the filename, so that any subsequent queries will be forced to
re-open the file or re-load any tiles (even those that were
previously loaded and would ordinarily be reused).  A client
might do this if, for example, they are aware that an image
being held in the cache has been updated on disk.  This is safe
to do even if other procedures are currently holding 
reference-counted tile pointers from the named image, but those 
procedures will not get updated pixels until they release the 
tiles they are holding.
\apiend

\apiitem{void {\ce invalidate_all} (bool force=false)}
Invalidate all loaded tiles and open file handles, so that any
subsequent queries will be forced to re-open the file or re-load any
tiles (even those that were previously loaded and would ordinarily be
reused).  A client might do this if, for example, they are aware that an
image being held in the cache has been updated on disk.  This is safe to
do even if other procedures are currently holding reference-counted tile
pointers from the named image, but those procedures will not get updated
pixels until they release the tiles they are holding.  If force is true,
everything will be invalidated, no matter how wasteful it is, but if
force is false, in actuality files will only be invalidated if their
modification times have been changed since they were first opened.
\apiend

\apiitem{void {\ce close} (ustring filename) \\
void {\ce close_all} ()}
\NEW % 1.9
Close any open file handles associated with a named file, or for all
files, but do not invalidate any image spec information or pixels
associated with the files.  A client might do this in order to
release OS file handle resources, or to make it safe for other
processes to modify cached files.
\apiend

\subsection{UDIM and texture atlases}
\label{sec:texturesys:udim}
The {\cf texture()} call supports virtual filenames that expand per lookup
for UDIM and other tiled texture atlas techniques. The substitutions will
occur if the texture filename initially passed to {\cf texture()} does not
exist as a concrete file and contains one or more of the following
substrings:

\medskip

%\noindent
\begin{tabular}{p{0.75in} p{4.75in}}
{\cf <UDIM>} & 1001 + \emph{utile} + \emph{vtile}*10 \\
{\cf <u>} & \emph{utile} \\
{\cf <v>} & \emph{vtile} \\
{\cf <U>} & \emph{utile} + 1 \\
{\cf <V>} & \emph{vtile} + 1 \\
\end{tabular}

\medskip

\noindent where the tile numbers are derived from the input $u,v$ texture
coordinates as follows:

\begin{code}
    // Each unit square of texture is a different tile
    utile = max (0, int(u));
    vtile = max (0, int(v));
    // Re-adjust the texture coordinates to the offsets within the tile
    u = u - utile;
    v = v - vtile;
\end{code}
\smallskip

\noindent Example:

\begin{code}
    ustring filename ("paint.<UDIM>.tif");
    float s = 1.4, t = 3.8;
    texsys->texture (filename, s, t, ...);
\end{code}

\noindent will retrieve from file \qkw{paint.1032.tif} at coordinates $(0.4,0.8)$.

\smallskip

Please note that most other calls, including most queries for {\cf
get_texture_info()}, will fail with one of these special filenames, since
it's not a real file and the system doesn't know which concrete file you it
corresponds to in the absence of specific texture coordinates.


\index{Texture System|)}

\chapwidthend
