00001 /* 00002 * PROPRIETARY INFORMATION. This software is proprietary to 00003 * Side Effects Software Inc., and is not to be reproduced, 00004 * transmitted, or disclosed in any way without written permission. 00005 * 00006 * Produced by: 00007 * Andrew Clinton 00008 * Side Effects Software Inc 00009 * 477 Richmond Street West 00010 * Toronto, Ontario 00011 * Canada M5V 3E7 00012 * 416-504-9876 00013 * 00014 * NAME: IMG_DeepShadow.h ( IMG Library, C++) 00015 * 00016 * COMMENTS: Deep shadow API 00017 */ 00018 00019 #ifndef __IMG_DeepShadow__ 00020 #define __IMG_DeepShadow__ 00021 00022 #include "IMG_API.h" 00023 #include <UT/UT_PtrArray.h> 00024 00025 class img_DeepShadow; 00026 class img_DeepShadowPixel; 00027 class IMG_DeepShadow; 00028 class IMG_DeepShadowChannel; 00029 class UT_WorkBuffer; 00030 class UT_Options; 00031 00032 typedef enum 00033 { 00034 IMG_DEPTH_NEAREST = 0, 00035 IMG_DEPTH_FARTHEST = 1, 00036 IMG_DEPTH_MIDPOINT = 2 00037 } IMG_DepthMode; 00038 00039 typedef enum 00040 { 00041 IMG_COMPRESS_DISCRETE = 0, 00042 IMG_COMPRESS_LINEAR = 1 00043 } IMG_DepthInterp; 00044 00045 /// @brief Thread-safe convenience class to make reading DSM pixels easy 00046 /// 00047 /// This is a thread-safe convenience class to wrap around reading pixels 00048 /// which ensures that the pixel is closed properly. 00049 /// 00050 /// @warning Beware when declaring an IMG_DeepPixelReader in the same scope 00051 /// as an IMG_DeepShadow. Since the pixel reader keeps a reference to the 00052 /// file, the destruction order is important -- though calling close() 00053 /// should avoid any problems. 00054 /// 00055 /// The class should be used as follows: @code 00056 /// 00057 /// IMG_DeepPixelReader pixel(dsm); 00058 /// for (x, y) in raster { 00059 /// if (pixel.open(x, y)) { 00060 /// for (i = 0; i < pixel.getDepth(); i++) 00061 /// data = pixel.getData(chp, i); 00062 /// } 00063 /// } 00064 /// @endcode 00065 /// 00066 class IMG_API IMG_DeepPixelReader { 00067 public: 00068 IMG_DeepPixelReader(IMG_DeepShadow &dsm); 00069 ~IMG_DeepPixelReader(); 00070 00071 /// Open a pixel for reading 00072 bool open(int x, int y); 00073 /// Close the pixel. This is called automatically on destruction. 00074 /// However, if an IMG_DeepPixelReader and IMG_DeepShadow are created in 00075 /// the same scope, the IMG_DeepPixelReader may hold onto references (and 00076 /// cause crashing errors). Calling close() manually is a safe thing to 00077 /// do. 00078 void close(); 00079 /// Returns the number of z-records 00080 int getDepth() const; 00081 /// Return the data for the channel at the given depth index. 00082 const fpreal *getData(const IMG_DeepShadowChannel &chp, 00083 int depth_index); 00084 00085 /// After opening, you can call either of these methods to ensure that the 00086 /// data is in the correct form for your application. "composited" pixels 00087 /// will have the data accumulated over from front to back. "uncomposited" 00088 /// pixels will have the raw data for each z-record. 00089 /// 00090 /// If the force flag is false, then the state of the file will be used 00091 /// to determine whether the deep records need to be processed or not. 00092 /// 00093 /// These methods should be called after the pixel has been opened. 00094 void composite(const IMG_DeepShadowChannel &pz, 00095 const IMG_DeepShadowChannel &of, 00096 bool force = false); 00097 void uncomposite(const IMG_DeepShadowChannel &pz, 00098 const IMG_DeepShadowChannel &of, 00099 bool force = false); 00100 00101 /// @private Internal constructor - please do not call this 00102 IMG_DeepPixelReader(img_DeepShadow *dsm); 00103 private: 00104 img_DeepShadowPixel *myHandle; 00105 }; 00106 00107 /// @brief Single channel of a Houdini DSM image 00108 /// 00109 /// A Houdini deep shadow/camera file can have any number of image channels 00110 /// (planes). A DSM image contains a single channel for opacity. A deep 00111 /// camera image has the opacity channel along with any number of extra image 00112 /// channels. 00113 class IMG_API IMG_DeepShadowChannel { 00114 public: 00115 /// @param name The unique name of the DSM channel 00116 /// @param float_offset 00117 /// When data is read or written in deep shadow files, the pixel 00118 /// data is interleaved. That is, the data for a single pixel can 00119 /// be represented as an array of floats. Each channel has a 00120 /// unique offset into the array. The user should @b not assume 00121 /// that the offsets are contiguous. For example, the pixel data 00122 /// might look like: @code 00123 /// [ Of.r, // Opacity red 00124 /// Of.g, // Opacity green 00125 /// Of.b, // Opacity blue 00126 /// Cf.r, // Color (red) 00127 /// Cf.g, // Color (green) 00128 /// Cf.b, // Color (blue) 00129 /// s, // s coordinate 00130 /// t, // t coordinate 00131 /// N.x, // Normal x 00132 /// N.y, // Normal y 00133 /// N.z, // Normal z 00134 /// ] 00135 /// @endcode 00136 /// Where the channels would be defined by: @code 00137 /// IMG_DeepShadowChannel("Of", 0, 3); 00138 /// IMG_DeepShadowChannel("Cf", 3, 3); 00139 /// IMG_DeepShadowChannel("s", 6, 1); 00140 /// IMG_DeepShadowChannel("t", 7, 1); 00141 /// IMG_DeepShadowChannel("N", 8, 3); 00142 /// @endcode 00143 /// @param tuple_size Number of floats 00144 /// @param storage 00145 /// Storage type. This may be one of { "real16", "real32", 00146 /// "real64" }. This value represents the storage of the channel 00147 /// in the file. 00148 /// @see IMG_DeepShadow::addExtraChannel() 00149 IMG_DeepShadowChannel(const char *name, 00150 int float_offset, 00151 int tuple_size, 00152 const char *storage="real32"); 00153 /// Copy constructor 00154 IMG_DeepShadowChannel(const IMG_DeepShadowChannel &src); 00155 ~IMG_DeepShadowChannel(); 00156 00157 IMG_DeepShadowChannel &operator=(const IMG_DeepShadowChannel &s); 00158 bool operator==(const IMG_DeepShadowChannel &s) const; 00159 00160 /// @{ 00161 /// Data acceess function 00162 const char *getName() const { return myName; } 00163 const char *getStorage() const { return myStorage; } 00164 int getOffset() const { return myOffset; } 00165 int getTupleSize() const { return myTupleSize; } 00166 /// @} 00167 00168 private: 00169 char *myName; 00170 char *myStorage; 00171 int myOffset; 00172 int myTupleSize; 00173 }; 00174 00175 /// @brief Class to read or write deep shadow/camera images 00176 /// 00177 /// This class provides a creation interface for deep shadow maps. 00178 /// The class can be used as follows: @code 00179 /// setOption(...); 00180 /// setOption(...); 00181 /// ... 00182 /// open(fname, xres, yres); 00183 /// foreach pixel loop 00184 /// pixelStart(pixel); 00185 /// foreach record 00186 /// pixelWrite(record); 00187 /// end loop 00188 /// pixelClose() 00189 /// end loop 00190 /// close(); 00191 /// @endcode 00192 /// 00193 /// To read from an existing deep shadow map, the class can be used as 00194 /// follows: @code 00195 /// IMG_DeepShadow dsm; 00196 /// IMG_DeepPixelReader pixel; 00197 /// dsm.open(fname); 00198 /// foreach (x,y) in raster: 00199 /// pixel.open(x, y) 00200 /// for (i = 0; i < pixel.getDepth(); i++) 00201 /// pixel.getData(chp, i); 00202 /// close(); 00203 /// @endcode 00204 /// 00205 /// @see 00206 /// - TIL_TextureMap - for filtered evaluation of DSM/DCM's) 00207 /// - IMG_DeepPixelReader - For thread-safe reading of DSM pixels 00208 /// - IMG_DeepShadowChannel 00209 class IMG_API IMG_DeepShadow { 00210 public: 00211 IMG_DeepShadow(); 00212 virtual ~IMG_DeepShadow(); 00213 00214 /// Set a file creation option. Options must be set before the 00215 /// file is opened with open() below. 00216 /// 00217 /// Currently (and this list may be out of date), the options are: 00218 /// - "ofstorage" = one of { "int8", "int16", "int32", "int64", 00219 /// "uint8", "uint16", "uint32", "uint64", 00220 /// "real16", "real32", "real64" } 00221 /// - "pzstorage" = one of { "int8" ... "real64" } 00222 /// - "ofsize" = one of { "1", "3" } 00223 /// - "compression = a value between "0" and "9" (lossyness) 00224 /// - "zbias" = minimum delta between z-values (float value) 00225 /// - "depth_mode" = one of { "nearest", "midpoint", "farthest" } 00226 /// - "depth_interp" = one of { "discrete", "continuous" } 00227 /// - "compositing" = "0" will turn off pre-compositing of the z-records 00228 /// This is recommended when dealing with deep camera maps (i.e. if 00229 /// there are extra channels) 00230 void setOption(const char *option, const char *value); 00231 00232 /// Set options based on the "texture:*" options defined in the UT_Options. 00233 /// The UT_Options will be checked for options: 00234 /// - @c texture:ofstorage 00235 /// - @c texture:pzstorage 00236 /// - @c texture:ofsize 00237 /// - @c etc. 00238 void setOptions(const UT_Options &options); 00239 00240 /// Print the current values of the file options into the work buffer 00241 void printArgs(UT_WorkBuffer &wbuf); 00242 00243 /// Get a description of the available options that can be provided in 00244 /// setOption() 00245 const char *getDescription(); 00246 00247 /// Add an extra channel to be stored along with Of and Pz. Any number of 00248 /// channels may be added (though the file size will increase accordingly). 00249 /// - The name must be unique among (and not Of or Pz) 00250 /// - The float_offset is the offset into the "data" in the 00251 /// pixelWrite() method. Note that the opacity must occupy the first 3 00252 /// floats of the data array. So, the float_offset @b must be at least 3. 00253 /// - The tuple_size is the number of elements in the channel 00254 /// Currently, this must be 1, 3 or 4. 00255 /// - The storage specifies the storage type (and uses the same 00256 /// tokens as the "ofstorage" option (i.e. int8, int16, int32, int64, 00257 /// uint8, uint16, uint32, uint64, real16, real32 or real64. 00258 /// The extra channels must be added @b before open() is called. 00259 bool addExtraChannel(const IMG_DeepShadowChannel &def, 00260 const UT_Options *options=0); 00261 00262 /// Open a deep shadow map for writing. This method will return false 00263 /// if there were errors opening the texture. 00264 bool open(const char *name, int xres, int yres); 00265 00266 /// Start writing data to a pixel. This method must be called exactly 00267 /// once for each pixel. Starting pixels in a regular order will 00268 /// be more efficient than writing them in a random order, but is not 00269 /// required. 00270 bool pixelStart(int x, int y); 00271 00272 /// Write data to the currently open pixel. This method inserts an 00273 /// unordered data record with the given z-value and data into the 00274 /// current pixel. vsize is the number of floats that are contained 00275 /// in the data array. 00276 /// 00277 /// The first 3 floats of the data array must be the opacity (RGB). Any 00278 /// extra channel data follows this according to the float_offset 00279 /// associated with the channel. This data may be quantized to a single 00280 /// float depending on the options. 00281 /// 00282 /// If @c vsize doesn't contain a full record, then this method will fail. 00283 /// vsize must be greater or equal to 3 (depending on extra channels) 00284 /// 00285 /// Currently, mantra will always interpret the data as a rgb opacity 00286 /// triple. 00287 bool pixelWrite(float z, const float *data, int vsize); 00288 00289 /// Perform the same operation as pixelWrite() except assume that data 00290 /// is pre-sorted by increasing z-value. This method will perform 00291 /// slightly better than pixelWrite() as data does not need to be sorted. 00292 bool pixelWriteOrdered(float z, const float *data, 00293 int vsize); 00294 00295 /// Close a pixel and flush the pixel's data to file. 00296 bool pixelClose(); 00297 00298 /// Close the deep shadow map and write it to disk. 00299 bool close(); 00300 00301 /// Get UT_Option structure from TBF. These options are stored with the 00302 /// file and may be queried in VEX using teximport(). 00303 UT_Options *getTBFOptions(); 00304 00305 00306 public: 00307 /// Open a deep shadow map for reading. 00308 bool open(const char *name); 00309 00310 /// Get the resolution of the deep shadow map. 00311 void resolution(int &xres, int &yres); 00312 00313 /// Get the number of channels in the DSM 00314 int getChannelCount() const; 00315 00316 /// Get a channel definition 00317 const IMG_DeepShadowChannel *getChannel(int i) const; 00318 00319 /// Get the raw data values for a pixel, in the order that they appear 00320 /// in the file. This method should be called repeatedly for each pixel 00321 /// until a 0 is returned, indicating that all records have been read 00322 /// for that pixel. Reading pixels in a regular order will be more 00323 /// efficient than reading them in a random order. 00324 /// 00325 /// @warning You should copy the data out of the returned pointer before 00326 /// proceeding. Do NOT refer to this pointer after reading more data 00327 /// from the shadow map. Because of this, this method is @b not 00328 /// thread-safe. 00329 /// 00330 /// @deprecated In favour of IMG_DeepPixelReader 00331 float SYS_DEPRECATED *pixelRead(int x, int y, float &z, int &vsize); 00332 00333 private: 00334 friend class IMG_DeepPixelReader; 00335 00336 bool openPixelRead(IMG_DeepPixelReader &h, int x, int y); 00337 void closePixelRead(IMG_DeepPixelReader &h); 00338 00339 // Get the pixel's depth complexity (the number of records in Z) 00340 int getPixelDepth(IMG_DeepPixelReader &h); 00341 00342 // Get the data for the pixel being read: 00343 // You should copy the data out of the returned pointer before proceeding. 00344 // Do NOT refer to this pointer after reading more data from the shadow map. 00345 // The index is must be between 0 and (getPixelDepth()-1) 00346 const fpreal *getPixelData(IMG_DeepPixelReader &h, 00347 const IMG_DeepShadowChannel &chp, 00348 int index); 00349 00350 private: 00351 friend class img_DeepShadow; 00352 virtual void printError(const char *, ...) const; 00353 virtual void printWarning(const char *, ...) const; 00354 00355 private: 00356 img_DeepShadow *myFile; 00357 00358 public: 00359 IMG_DepthInterp depthInterp(); 00360 }; 00361 00362 #endif
1.5.9