85 static std::string tmpdir;
86 static int initialized = 0;
91 DWORD result = ::GetTempPath(0, (LPTSTR) L
"");
93 std::vector<TCHAR> tempPath(result + 1);
94 result = ::GetTempPath(
static_cast<DWORD
>(tempPath.size()), &tempPath[0]);
95 if (result > 0 && result <= tempPath.size())
96 tmpdir = std::string(tempPath.begin(),
97 tempPath.begin() +
static_cast<std::size_t
>(result));
103 const char* t = getenv(
"TEMP");
104 if (!t) t = getenv(
"TMP");
115 static int count = 0;
116 s << tmpdir <<
"/" <<
"PtexTmp" << _getpid() <<
"_" << ++count;
118 return fopen((
char*) tmppath.c_str(),
"wb+");
121 tmppath = tmpdir +
"/PtexTmpXXXXXX";
122 int fd = mkstemp(&tmppath[0]);
123 return fdopen(fd,
"w+");
127 std::string
fileError(
const char* message,
const char* path)
129 std::stringstream str;
130 str << message << path <<
"\n" << strerror(errno);
139 error =
"PtexWriter doesn't currently support big-endian cpu's";
144 error =
"PtexWriter error: Invalid mesh type";
149 error =
"PtexWriter error: Invalid data type";
153 if (nchannels <= 0) {
154 error =
"PtexWriter error: Invalid number of channels";
158 if (alphachan != -1 && (alphachan < 0 || alphachan >= nchannels)) {
159 error =
"PtexWriter error: Invalid alpha channel";
170 int nchannels,
int alphachan,
int nfaces,
173 if (!
checkFormat(mt, dt, nchannels, alphachan, error))
177 mt, dt, nchannels, alphachan, nfaces,
189 int nchannels,
int alphachan,
int nfaces,
192 if (!
checkFormat(mt, dt, nchannels, alphachan, error))
196 FILE* fp = fopen(path,
"rb+");
197 if (!fp && errno != ENOENT) {
198 error =
fileError(
"Can't open ptex file for update: ", path).c_str();
203 if (incremental && fp) {
204 w =
new PtexIncrWriter(path, fp, mt, dt, nchannels, alphachan, nfaces);
218 bool headerMatch = (mt == tex->
meshType() &&
224 std::stringstream str;
225 str <<
"PtexWriter::edit error: header doesn't match existing file, "
226 <<
"conversions not currently supported";
227 error = str.str().
c_str();
256 if (!w->close(error))
return 0;
264 int nchannels,
int alphachan,
int nfaces,
291 deflateInit(&
_zstream, compress ? Z_DEFAULT_COMPRESSION : 0);
307 std::cerr << error.
c_str() << std::endl;
333 setError(
"PtexWriter error: faceid out of range");
338 setError(
"PtexWriter error: asymmetric face res not supported for triangle textures");
353 f.flags &= FaceInfo::flag_subface;
357 f.flags |= (uint8_t)flags;
401 for (
int i = 0; i < nkeys; i++) {
404 data->
getKey(i, key, type);
423 const int16_t* val=0;
430 const int32_t* val=0;
455 const void* value,
int size)
457 if (strlen(key) > 255) {
458 std::stringstream str;
459 str <<
"PtexWriter error: meta data key too long (max=255) \"" << key <<
"\"";
464 std::stringstream str;
465 str <<
"PtexWriter error: meta data size <= 0 for \"" << key <<
"\"";
468 std::map<std::string,int>::iterator iter =
_metamap.find(key);
472 index = iter->second;
484 memcpy(&m.
data[0], value, size);
503 if (!fwrite(data, size, 1, fp)) {
504 setError(
"PtexWriter error: file write failed");
515 _zstream.next_in = (Bytef*)
const_cast<void*
>(data);
521 int zresult = deflate(&
_zstream, finishArg ? Z_FINISH : Z_NO_FLUSH);
523 if (sizeval > 0)
writeBlock(fp, buff, sizeval);
524 if (zresult == Z_STREAM_END)
break;
525 if (zresult != Z_OK) {
526 setError(
"PtexWriter error: data compression internal error");
529 if (!finishArg &&
_zstream.avail_out != 0)
534 if (!finishArg)
return 0;
536 int total = (int)
_zstream.total_out;
544 if (!fread(data, size, 1, fp)) {
545 setError(
"PtexWriter error: temp file read failed");
554 if (size <= 0)
return 0;
555 fseeko(src, pos, SEEK_SET);
560 if (!fread(buff, nbytes, 1, src)) {
561 setError(
"PtexWriter error: temp file read failed");
576 if (ntileslog2 == 0)
return faceres;
582 int n = faceres.ulog2 + faceres.vlog2 - ntileslog2;
587 tileres.ulog2 = (int8_t)
PtexUtils::min(
int((n+1)/2), int(faceres.ulog2));
588 tileres.vlog2 = (int8_t)
PtexUtils::min(
int(n - tileres.ulog2), int(faceres.vlog2));
608 int ures = res.u(), vres = res.v();
611 char* buff = useNew ?
new char [blockSize] : (
char*)alloca(blockSize);
626 if (useNew)
delete [] buff;
635 int ntilesu = res.ntilesu(tileres);
636 int ntilesv = res.ntilesv(tileres);
637 int ntiles = ntilesu * ntilesv;
646 std::vector<FaceDataHeader> tileHeader(ntiles);
647 int tileures = tileres.u();
648 int tilevres = tileres.v();
650 int tilevstride = tilevres*stride;
655 const char* rowp = (
const char*) data;
656 const char* rowpend = rowp + ntilesv * tilevstride;
657 for (; rowp != rowpend; rowp += tilevstride) {
658 const char* p = rowp;
659 const char* pend = p + ntilesu * tileustride;
660 for (; p != pend; tdh++, p += tileustride) {
677 totalsize +=
writeBlock(fp, &tileres,
sizeof(Res));
678 totalsize +=
writeBlock(fp, &tileheadersize,
sizeof(tileheadersize));
694 Ptex::Res newres((int8_t)(res.ulog2-1), (int8_t)(res.vlog2-1));
697 char* buff = useNew ?
new char [buffsize] : (
char*)alloca(buffsize);
703 if (useNew)
delete [] buff;
710 uint8_t keysize = uint8_t(val.
key.size()+1);
712 uint32_t datasize = uint32_t(val.
data.size());
718 int memsize = int(
sizeof(keysize) + (
size_t)keysize +
sizeof(
datatype)
719 +
sizeof(datasize) + datasize);
726 int nchannels,
int alphachan,
int nfaces,
bool genmipmaps)
730 _genmipmaps(genmipmaps),
747 for (
int i = 0; i < nfaces; i++)
_faceinfo[i].flags = uint8_t(-1);
749 _levels.front().pos.resize(nfaces);
750 _levels.front().fdh.resize(nfaces);
751 _rpos.resize(nfaces);
797 unlink(
_path.c_str());
799 error =
fileError(
"Can't write to ptex file: ",
_path.c_str()).c_str();
812 if (stride == 0) stride = f.res.u()*
_pixelSize;
834 int rowlen = f.res.u() *
_pixelSize, nrows = f.res.v();
835 temp =
new uint8_t [rowlen * nrows];
858 if (temp)
delete [] temp;
909 char* data =
new char [size];
921 _faceinfo[i].flags = FaceInfo::flag_constant;
937 FILE* newfp = fopen(
_newpath.c_str(),
"wb+");
955 FilePos levelInfoPos = ftello(newfp);
964 int nfaces = int(level.
fdh.size());
971 for (
int fi = 0; fi < nfaces; fi++)
973 level.
fdh[fi].blocksize());
986 fseeko(newfp, levelInfoPos, SEEK_SET);
990 fseeko(newfp, 0, SEEK_SET);
1000 for (
int faceid = 0, n =
int(
_faceinfo.size()); faceid < n; faceid++) {
1002 if (!f.isConstant())
continue;
1006 bool isConst =
true;
1008 int nedges = isTriangle ? 3 : 4;
1009 for (
int eid = 0; isConst && (eid < nedges); eid++) {
1010 bool prevWasSubface = f.isSubface();
1011 int prevFid = faceid;
1014 int afid = f.adjface(eid);
1015 int aeid = f.adjedge(eid);
1017 const int maxcount = 10;
1018 while (afid != faceid && afid >= 0 && ++count < maxcount) {
1021 if (!af.isConstant() ||
1023 { isConst =
false;
break; }
1026 bool isSubface = af.isSubface();
1027 bool isT = !isTriangle && prevWasSubface && !isSubface && af.adjface(aeid) == prevFid;
1029 prevWasSubface = isSubface;
1033 aeid = (aeid + 1) % nedges;
1034 afid = af.adjface(aeid);
1035 aeid = af.adjedge(aeid);
1046 aeid = (aeid - 1 + nedges) % nedges;
1047 afid = f.adjface(aeid);
1048 aeid = f.adjedge(aeid);
1050 while (afid != faceid && afid >= 0 && ++count < maxcount) {
1053 if (!af.isConstant() ||
1055 { isConst =
false;
break; }
1059 aeid = (aeid - 1 + nedges) % nedges;
1060 afid = af.adjface(aeid);
1061 aeid = af.adjedge(aeid);
1064 bool isSubface = af.isSubface();
1065 if (isSubface && !prevWasSubface) {
1066 aeid = (aeid + 3) % 4;
1067 afid = af.adjface(aeid);
1068 aeid = (af.adjedge(aeid) + 3) % 4;
1070 prevWasSubface = isSubface;
1075 if (isConst) f.flags |= FaceInfo::flag_nbconstant;
1092 for (
int rfaceid = nfaces-1, cutoffres =
MinReductionLog2; rfaceid >= 0; rfaceid--) {
1097 while (
min > cutoffres) {
1099 int size = rfaceid+1;
1102 level.
pos.resize(size);
1103 level.
fdh.resize(size);
1111 for (
int i = 0; i < nfaces; i++)
1114 char* buff =
new char [buffsize];
1116 int nlevels = int(
_levels.size());
1117 for (
int i = 1; i < nlevels; i++) {
1119 int nextsize = (i+1 < nlevels)?
int(
_levels[i+1].fdh.size()) : 0;
1120 for (
int rfaceid = 0, size =
int(level.
fdh.size()); rfaceid < size; rfaceid++) {
1124 res.ulog2 = (int8_t)(res.ulog2 - i);
1125 res.vlog2 = (int8_t)(res.vlog2 - i);
1130 fseeko(
_tmpfp, 0, SEEK_END);
1136 if (rfaceid < nextsize) {
1146 fseeko(
_tmpfp, 0, SEEK_END);
1153 std::vector<MetaEntry*> lmdEntries;
1156 for (
int i = 0, n = (
int)
_metadata.size(); i < n; i++) {
1158 #ifndef PTEX_NO_LARGE_METADATA_BLOCKS
1161 lmdEntries.push_back(&e);
1179 int nLmd = (int)lmdEntries.size();
1182 std::vector<FilePos> lmdoffset(nLmd);
1183 std::vector<uint32_t> lmdzipsize(nLmd);
1184 for (
int i = 0; i < nLmd; i++) {
1186 lmdoffset[i] = ftello(
_tmpfp);
1191 for (
int i = 0; i < nLmd; i++) {
1193 uint8_t keysize = uint8_t(e->
key.size()+1);
1195 uint32_t datasize = (uint32_t)e->
data.size();
1196 uint32_t zipsize = lmdzipsize[i];
1204 (uint32_t)(
sizeof(keysize) + (size_t)keysize +
sizeof(
datatype) +
1205 sizeof(datasize) +
sizeof(zipsize));
1210 for (
int i = 0; i < nLmd; i++) {
1220 int nchannels,
int alphachan,
int nfaces)
1233 std::stringstream str;
1234 str <<
"Not a ptex file: " << path;
1245 std::stringstream str;
1246 str <<
"PtexWriter::edit error: header doesn't match existing file, "
1247 <<
"conversions not currently supported";
1255 std::stringstream str;
1256 str <<
"Error reading extended header: " << path;
1262 fseeko(
_fp, 0, SEEK_END);
1273 if (stride == 0) stride = f.res.u()*
_pixelSize;
1291 writeBlank(
_fp,
sizeof(edittype) +
sizeof(editsize) +
sizeof(efdh));
1294 uint8_t* constval =
new uint8_t [
_pixelSize];
1299 int rowlen = f.res.u() *
_pixelSize, nrows = f.res.v();
1300 uint8_t* temp =
new uint8_t [rowlen * nrows];
1330 fseeko(
_fp, pos, SEEK_SET);
1334 fseeko(
_fp, 0, SEEK_END);
1347 editsize = (uint32_t)
sizeof(efdh) +
_pixelSize;
1374 writeBlank(
_fp,
sizeof(edittype) +
sizeof(editsize) +
sizeof(emdh));
1377 for (
size_t i = 0, n =
_metadata.size(); i < n; i++) {
1388 fseeko(
_fp, pos, SEEK_SET);
1392 fseeko(
_fp, 0, SEEK_END);
const int MetaDataThreshold
#define PTEX_NAMESPACE_END
#define PtexFileMinorVersion
#define PtexFileMajorVersion
Public API classes for reading, writing, caching, and filtering Ptex files.
Automatically acquire and release lock within enclosing scope.
virtual bool close(Ptex::String &error)
Close the file.
PtexIncrWriter(const char *path, FILE *fp, Ptex::MeshType mt, Ptex::DataType dt, int nchannels, int alphachan, int nfaces)
virtual bool writeConstantFace(int faceid, const FaceInfo &f, const void *data)
virtual ~PtexIncrWriter()
virtual bool writeFace(int faceid, const FaceInfo &f, const void *data, int stride)
void generateReductions()
std::vector< uint8_t > _constdata
std::vector< uint32_t > _rfaceids
virtual bool close(Ptex::String &error)
Close the file.
virtual bool writeConstantFace(int faceid, const FaceInfo &f, const void *data)
std::vector< uint32_t > _faceids_r
void storeConstValue(int faceid, const void *data, int stride, Res res)
std::vector< FaceInfo > _faceinfo
void writeMetaData(FILE *fp)
virtual ~PtexMainWriter()
static const int MinReductionLog2
virtual bool writeFace(int faceid, const FaceInfo &f, const void *data, int stride)
PtexMainWriter(const char *path, PtexTexture *tex, Ptex::MeshType mt, Ptex::DataType dt, int nchannels, int alphachan, int nfaces, bool genmipmaps)
std::vector< FilePos > _rpos
std::vector< LevelRec > _levels
void flagConstantNeighorhoods()
Smart-pointer for acquiring and releasing API objects.
virtual void release()
Release resources held by this pointer (pointer becomes invalid).
virtual PtexMetaData * getMetaData()
Access meta data.
virtual void getData(int faceid, void *buffer, int stride)
Access texture data for a face at highest-resolution.
virtual const Ptex::FaceInfo & getFaceInfo(int faceid)
Access resolution and adjacency information about a face.
virtual bool hasEdits()
True if the file has edit blocks.
Interface for reading data from a ptex file.
virtual Ptex::MeshType meshType()=0
Type of mesh for which texture data is defined.
virtual Ptex::BorderMode uBorderMode()=0
Mode for filtering texture access beyond mesh border.
virtual bool hasMipMaps()=0
True if the file has mipmaps.
virtual int numFaces()=0
Number of faces stored in file.
virtual Ptex::DataType dataType()=0
Type of data stored in file.
virtual int alphaChannel()=0
Index of alpha channel (if any).
virtual Ptex::EdgeFilterMode edgeFilterMode()=0
Mode for filtering textures across edges.
static PtexTexture * open(const char *path, Ptex::String &error, bool premultiply=0)
Open a ptex file for reading.
virtual bool hasEdits()=0
True if the file has edit blocks.
virtual Ptex::BorderMode vBorderMode()=0
Mode for filtering texture access beyond mesh border.
virtual int numChannels()=0
Number of channels stored in file.
std::map< std::string, int > _metamap
DataType datatype() const
int writeBlank(FILE *fp, int size)
virtual void setEdgeFilterMode(Ptex::EdgeFilterMode edgeFilterMode)
Set edge filter mode.
int copyBlock(FILE *dst, FILE *src, FilePos pos, int size)
void setError(const std::string &error)
int writeZipBlock(FILE *fp, const void *data, int size, bool finish=true)
virtual void writeMeta(const char *key, const char *value)
Write a string as meta data.
virtual void addMetaData(const char *key, MetaDataType t, const void *value, int size)
virtual void release()
Release resources held by this pointer (pointer becomes invalid).
int writeBlock(FILE *fp, const void *data, int size)
virtual bool close(Ptex::String &error)
Close the file.
void writeFaceData(FILE *fp, const void *data, int stride, Res res, FaceDataHeader &fdh)
int readBlock(FILE *fp, void *data, int size)
std::vector< MetaEntry > _metadata
void writeConstFaceBlock(FILE *fp, const void *data, FaceDataHeader &fdh)
int writeMetaDataBlock(FILE *fp, MetaEntry &val)
PtexUtils::ReduceFn * _reduceFn
void writeReduction(FILE *fp, const void *data, int stride, Res res)
bool storeFaceInfo(int faceid, FaceInfo &dest, const FaceInfo &src, int flags=0)
virtual void setBorderModes(Ptex::BorderMode uBorderMode, Ptex::BorderMode vBorderMode)
Set border modes.
virtual ~PtexWriterBase()
void getError(Ptex::String &error)
PtexWriterBase(const char *path, Ptex::MeshType mt, Ptex::DataType dt, int nchannels, int alphachan, int nfaces, bool compress)
bool ok(Ptex::String &error)
void writeFaceBlock(FILE *fp, const void *data, int stride, Res res, FaceDataHeader &fdh)
Res calcTileRes(Res faceres)
Interface for writing data to a ptex file.
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)
Open an existing texture file for writing.
static bool applyEdits(const char *path, Ptex::String &error)
Apply edits to a file.
static PtexWriter * open(const char *path, Ptex::MeshType mt, Ptex::DataType dt, int nchannels, int alphachan, int nfaces, Ptex::String &error, bool genmipmaps=true)
Open a new texture file for writing.
const char * c_str() const
bool checkFormat(Ptex::MeshType mt, Ptex::DataType dt, int nchannels, int alphachan, Ptex::String &error)
std::string fileError(const char *message, const char *path)
FILE * OpenTempFile(std::string &tmppath)
void genRfaceids(const FaceInfo *faces, int nfaces, uint32_t *rfaceids, uint32_t *faceids)
bool isConstant(const void *data, int stride, int ures, int vres, int pixelSize)
void divalpha(void *data, int npixels, DataType dt, int nchannels, int alphachan)
void encodeDifference(void *data, int size, DataType dt)
void reduce(const void *src, int sstride, int uw, int vw, void *dst, int dstride, DataType dt, int nchan)
void deinterleave(const void *src, int sstride, int uw, int vw, void *dst, int dstride, DataType dt, int nchan)
void reduceTri(const void *src, int sstride, int w, int, void *dst, int dstride, DataType dt, int nchan)
void copy(const void *src, int sstride, void *dst, int dstride, int vres, int rowlen)
uint32_t floor_log2(uint32_t x)
void multalpha(void *data, int npixels, DataType dt, int nchannels, int alphachan)
void average(const void *src, int sstride, int uw, int vw, void *dst, DataType dt, int nchan)
int DataSize(DataType dt)
Look up size of given data type (in bytes).
DataType
Type of data stored in texture file.
@ dt_float
Single-precision (32-bit) floating point.
@ dt_uint16
Unsigned, 16-bit integer.
@ dt_uint8
Unsigned, 8-bit integer.
MeshType
Type of base mesh for which the textures are defined.
@ mt_triangle
Mesh is triangle-based.
@ mt_quad
Mesh is quad-based.
@ m_clamp
texel access is clamped to border
MetaDataType
Type of meta data entry.
@ mdt_string
Null-terminated string.
@ mdt_float
Single-precision (32-bit) floating point.
@ mdt_int32
Signed 32-bit integer.
@ mdt_int8
Signed 8-bit integer.
@ mdt_double
Double-precision (32-bit) floating point.
@ mdt_int16
Signed 16-bit integer.
std::vector< FilePos > pos
std::vector< FaceDataHeader > fdh
std::vector< uint8_t > data
Information about a face, as stored in the Ptex file header.
Res res
Resolution of face.
bool isConstant() const
Determine if face is constant (by checking a flag).
Pixel resolution of a given texture.
int size() const
Total size of specified texture in texels (u * v).
int u() const
U resolution in texels.