PtexImporter/ptex/Ptexture.h

#ifndef Ptexture_h
#define Ptexture_h

/* 
PTEX SOFTWARE
Copyright 2009 Disney Enterprises, Inc.  All rights reserved

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:

  * Redistributions of source code must retain the above copyright
    notice, this list of conditions and the following disclaimer.

  * Redistributions in binary form must reproduce the above copyright
    notice, this list of conditions and the following disclaimer in
    the documentation and/or other materials provided with the
    distribution.

  * The names "Disney", "Walt Disney Pictures", "Walt Disney Animation
    Studios" or the names of its contributors may NOT be used to
    endorse or promote products derived from this software without
    specific prior written permission from Walt Disney Pictures.

Disclaimer: THIS SOFTWARE IS PROVIDED BY WALT DISNEY PICTURES AND
CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE, NONINFRINGEMENT AND TITLE ARE DISCLAIMED.
IN NO EVENT SHALL WALT DISNEY PICTURES, THE COPYRIGHT HOLDER OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND BASED ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
*/

#if defined(_WIN32) || defined(_WINDOWS) || defined(_MSC_VER)
#  ifndef PTEX_STATIC
#    ifdef PTEX_EXPORTS
#       define PTEXAPI __declspec(dllexport)
#    else
#       define PTEXAPI __declspec(dllimport)
#    endif
#  else
#    define PTEXAPI
#  endif
#else
#  define PTEXAPI
#  ifndef DOXYGEN
#    define PTEX_USE_STDSTRING
#  endif
#endif

#include "PtexInt.h"
#include <ostream>

#define PtexAPIVersion 2
#define PtexFileMajorVersion 1
#define PtexFileMinorVersion 3

struct Ptex {
    enum MeshType {
    mt_triangle,        
    mt_quad         
    };

    enum DataType {
    dt_uint8,       
    dt_uint16,      
    dt_half,        
    dt_float        
    };

    enum BorderMode {
    m_clamp,        
    m_black,        
    m_periodic      
    };

    enum EdgeId {
    e_bottom,       
    e_right,        
    e_top,          
    e_left          
    };

    enum MetaDataType {
    mdt_string,     
    mdt_int8,       
    mdt_int16,      
    mdt_int32,      
    mdt_float,      
    mdt_double      
    };

    PTEXAPI static const char* MeshTypeName(MeshType mt);

    PTEXAPI static const char* DataTypeName(DataType dt);

    PTEXAPI static const char* BorderModeName(BorderMode m);

    PTEXAPI static const char* EdgeIdName(EdgeId eid);

    PTEXAPI static const char* MetaDataTypeName(MetaDataType mdt);

    static int DataSize(DataType dt) {
    static const int sizes[] = { 1,2,2,4 };
    return sizes[dt]; 
    }

    static double OneValue(DataType dt) {
    static const double one[] = { 255.0, 65535.0, 1.0, 1.0 };
    return one[dt]; 
    }

    static double OneValueInv(DataType dt) {
    static const double one[] = { 1.0/255.0, 1.0/65535.0, 1.0, 1.0 };
    return one[dt]; 
    }

    PTEXAPI static void ConvertToFloat(float* dst, const void* src,
                       Ptex::DataType dt, int numChannels);

    PTEXAPI static void ConvertFromFloat(void* dst, const float* src,
                     Ptex::DataType dt, int numChannels);

    struct Res {
    int8_t ulog2;       
    int8_t vlog2;       

    Res() : ulog2(0), vlog2(0) {}

    Res(int8_t ulog2, int8_t vlog2) : ulog2(ulog2), vlog2(vlog2) {}

    Res(uint16_t value) { val() = value; }
    
    int u() const { return 1<<(unsigned)ulog2; }

    int v() const { return 1<<(unsigned)vlog2; }

    uint16_t& val() { return *(uint16_t*)this; }

    const uint16_t& val() const { return *(uint16_t*)this; }

    int size() const { return u() * v(); }

    bool operator==(const Res& r) const { return val() == r.val(); }

    bool operator!=(const Res& r) const { return val() != r.val(); }

    bool operator>=(const Res& r) const { return ulog2 >= r.ulog2 && vlog2 >= r.vlog2; }

    Res swappeduv() const { return Res(vlog2, ulog2); }

    void swapuv() { *this = swappeduv(); }

    void clamp(const Res& r) { 
        if (ulog2 > r.ulog2) ulog2 = r.ulog2;
        if (vlog2 > r.vlog2) vlog2 = r.vlog2;
    }

    int ntilesu(Res tileres) const { return 1<<(ulog2-tileres.ulog2); }

    int ntilesv(Res tileres) const { return 1<<(vlog2-tileres.vlog2); }

    int ntiles(Res tileres) const { return ntilesu(tileres) * ntilesv(tileres); }
    };

    struct FaceInfo {
    Res res;        
    uint8_t adjedges;       
    uint8_t flags;      
    int32_t adjfaces[4];    

    FaceInfo() : res(), adjedges(0), flags(0) 
    { 
        adjfaces[0] = adjfaces[1] = adjfaces[2] = adjfaces[3] = -1; 
    }

    FaceInfo(Res res) : res(res), adjedges(0), flags(0) 
    { 
        adjfaces[0] = adjfaces[1] = adjfaces[2] = adjfaces[3] = -1; 
    }

    FaceInfo(Res res, int adjfaces[4], int adjedges[4], bool isSubface=false)
        : res(res), flags(isSubface ? flag_subface : 0)
    {
        setadjfaces(adjfaces[0], adjfaces[1], adjfaces[2], adjfaces[3]);
        setadjedges(adjedges[0], adjedges[1], adjedges[2], adjedges[3]);
    }

    EdgeId adjedge(int eid) const { return EdgeId((adjedges >> (2*eid)) & 3); }

    int adjface(int eid) const { return adjfaces[eid]; }

    bool isConstant() const { return (flags & flag_constant) != 0; }

    bool isNeighborhoodConstant() const { return (flags & flag_nbconstant) != 0; }

    bool hasEdits() const { return (flags & flag_hasedits) != 0; }

    bool isSubface() const { return (flags & flag_subface) != 0; }

    void setadjfaces(int f0, int f1, int f2, int f3)
    { adjfaces[0] = f0, adjfaces[1] = f1, adjfaces[2] = f2; adjfaces[3] = f3; }

    void setadjedges(int e0, int e1, int e2, int e3)
    { adjedges = (e0&3) | ((e1&3)<<2) | ((e2&3)<<4) | ((e3&3)<<6); }

    enum { flag_constant = 1, flag_hasedits = 2, flag_nbconstant = 4, flag_subface = 8 };
    };


#ifdef PTEX_USE_STDSTRING
    typedef std::string String;
#else
    class String
    {
     public:
    String() : _str(0) {}
    String(const String& str) : _str(0) { *this = str; }
    PTEXAPI ~String();
    PTEXAPI String& operator=(const char* str);
    String& operator=(const String& str) { *this = str._str; return *this; }
    const char* c_str() const { return _str ? _str : ""; }
    bool empty() const { return _str == 0; }

     private:
    char* _str;
    };
#endif

}
#ifndef DOXYGEN
;
#endif

#ifndef PTEX_USE_STDSTRING
std::ostream& operator << (std::ostream& stream, const Ptex::String& str);
#endif


class PtexMetaData {
 protected:
    virtual ~PtexMetaData() {}

 public:
    virtual void release() = 0;

    virtual int numKeys() = 0;

    virtual void getKey(int n, const char*& key, Ptex::MetaDataType& type) = 0;

    virtual void getValue(const char* key, const char*& value) = 0;

    virtual void getValue(const char* key, const int8_t*& value, int& count) = 0;

    virtual void getValue(const char* key, const int16_t*& value, int& count) = 0;

    virtual void getValue(const char* key, const int32_t*& value, int& count) = 0;

    virtual void getValue(const char* key, const float*& value, int& count) = 0;

    virtual void getValue(const char* key, const double*& value, int& count) = 0;
};


class PtexFaceData {
 protected:
    virtual ~PtexFaceData() {} 

 public:
    virtual void release() = 0;

    virtual bool isConstant() = 0;

    virtual Ptex::Res res() = 0;

    virtual void getPixel(int u, int v, void* result) = 0;

    virtual void* getData() = 0;

    virtual bool isTiled() = 0;

    virtual Ptex::Res tileRes() = 0;

    virtual PtexFaceData* getTile(int tile) = 0;
};


class PtexTexture {
 protected:
    virtual ~PtexTexture() {} 

 public:
    PTEXAPI static PtexTexture* open(const char* path, Ptex::String& error, bool premultiply=0);


    virtual void release() = 0;

    virtual const char* path() = 0;

    virtual Ptex::MeshType meshType() = 0;

    virtual Ptex::DataType dataType() = 0;

    virtual Ptex::BorderMode uBorderMode() = 0;

    virtual Ptex::BorderMode vBorderMode() = 0;

    virtual int alphaChannel() = 0;

    virtual int numChannels() = 0;

    virtual int numFaces() = 0;

    virtual bool hasEdits() = 0;

    virtual bool hasMipMaps() = 0;

    virtual PtexMetaData* getMetaData() = 0;

    virtual const Ptex::FaceInfo& getFaceInfo(int faceid) = 0;

    virtual void getData(int faceid, void* buffer, int stride) = 0;

    virtual void getData(int faceid, void* buffer, int stride, Ptex::Res res) = 0;

    virtual PtexFaceData* getData(int faceid) = 0;

    virtual PtexFaceData* getData(int faceid, Ptex::Res res) = 0;

    virtual void getPixel(int faceid, int u, int v,
              float* result, int firstchan, int nchannels) = 0;

    virtual void getPixel(int faceid, int u, int v,
              float* result, int firstchan, int nchannels,
              Ptex::Res res) = 0;
};


class PtexInputHandler {
 protected:
    virtual ~PtexInputHandler() {}

 public:
    typedef void* Handle;

    virtual Handle open(const char* path) = 0;

    virtual void seek(Handle handle, int64_t pos) = 0;

    virtual size_t read(void* buffer, size_t size, Handle handle) = 0;

    virtual bool close(Handle handle) = 0;

    virtual const char* lastError() = 0;
};


class PtexCache {
 protected:
    virtual ~PtexCache() {} 

 public:
    PTEXAPI static PtexCache* create(int maxFiles=0,
                     int maxMem=0,
                     bool premultiply=false,
                     PtexInputHandler* handler=0);

    virtual void release() = 0;

    virtual void setSearchPath(const char* path) = 0;

    virtual const char* getSearchPath() = 0;

    virtual PtexTexture* get(const char* path, Ptex::String& error) = 0;

    virtual void purge(PtexTexture* texture) = 0;

    virtual void purge(const char* path) = 0;

    virtual void purgeAll() = 0;
};


class PtexWriter {
 protected:
    virtual ~PtexWriter() {} 

 public:
    PTEXAPI
    static PtexWriter* open(const char* path,
                Ptex::MeshType mt, Ptex::DataType dt,
                int nchannels, int alphachan, int nfaces,
                Ptex::String& error, bool genmipmaps=true);

    PTEXAPI
    static PtexWriter* edit(const char* path, bool incremental,
                Ptex::MeshType mt, Ptex::DataType dt,
                int nchannels, int alphachan, int nfaces,
                Ptex::String& error, bool genmipmaps=true);

    PTEXAPI
    static bool applyEdits(const char* path, Ptex::String& error);

    virtual void release() = 0;
    
    virtual void setBorderModes(Ptex::BorderMode uBorderMode, Ptex::BorderMode vBorderMode) = 0;

    virtual void writeMeta(const char* key, const char* string) = 0;

    virtual void writeMeta(const char* key, const int8_t* value, int count) = 0;

    virtual void writeMeta(const char* key, const int16_t* value, int count) = 0;

    virtual void writeMeta(const char* key, const int32_t* value, int count) = 0;

    virtual void writeMeta(const char* key, const float* value, int count) = 0;

    virtual void writeMeta(const char* key, const double* value, int count) = 0;

    virtual void writeMeta(PtexMetaData* data) = 0;

    virtual bool writeFace(int faceid, const Ptex::FaceInfo& info, const void* data, int stride=0) = 0;

    virtual bool writeConstantFace(int faceid, const Ptex::FaceInfo& info, const void* data) = 0;

    virtual bool close(Ptex::String& error) = 0;

#if NEW_API
    virtual bool writeFaceReduction(int faceid, const Ptex::Res& res, const void* data, int stride=0) = 0;
    virtual bool writeConstantFaceReduction(int faceid, const Ptex::Res& res, const void* data) = 0;
#endif
};


class PtexFilter {
 protected:
    virtual ~PtexFilter() {}; 

 public:
    enum FilterType {
    f_point,        
    f_bilinear,     
    f_box,          
    f_gaussian,     
    f_bicubic,      
    f_bspline,      
    f_catmullrom,       
    f_mitchell      
    };

    struct Options {
    int __structSize;   
    FilterType filter;  
    bool lerp;      
    float sharpness;    

    Options(FilterType filter=f_box, bool lerp=0, float sharpness=0) :
        __structSize(sizeof(Options)),
        filter(filter), lerp(lerp), sharpness(sharpness) {}
    };

    /* Construct a filter for the given texture.
    */
    PTEXAPI static PtexFilter* getFilter(PtexTexture* tx, const Options& opts);

    virtual void release() = 0;

    virtual void eval(float* result, int firstchan, int nchannels,
              int faceid, float u, float v, float uw1, float vw1, float uw2, float vw2,
              float width=1, float blur=0) = 0;
};


template <class T> class PtexPtr {
    T* _ptr;
 public:
    PtexPtr(T* ptr=0) : _ptr(ptr) {}

    ~PtexPtr() { if (_ptr) _ptr->release(); }

    operator T* () { return _ptr; }

    T* operator-> () { return _ptr; }

    T* get() { return _ptr; }

 private:
    PtexPtr(const PtexPtr& p);

    void operator= (PtexPtr& p);
};

#endif