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);
bool isConstant(const void *data, int stride, int ures, int vres, int pixelSize)
virtual Ptex::BorderMode vBorderMode()=0
Mode for filtering texture access beyond mesh border.
virtual int numChannels()=0
Number of channels stored in file.
Interface for writing data to a ptex file.
void getError(Ptex::String &error)
bool storeFaceInfo(int faceid, FaceInfo &dest, const FaceInfo &src, int flags=0)
virtual ~PtexWriterBase()
virtual bool close(Ptex::String &error)
Close the file.
virtual void release()
Release resources held by this pointer (pointer becomes invalid).
void writeReduction(FILE *fp, const void *data, int stride, Res res)
uint32_t floor_log2(uint32_t x)
virtual bool hasEdits()
True if the file has edit blocks.
const int MetaDataThreshold
virtual const Ptex::FaceInfo & getFaceInfo(int faceid)
Access resolution and adjacency information about a face.
virtual bool hasEdits()=0
True if the file has edit blocks.
std::vector< FaceDataHeader > fdh
PtexUtils::ReduceFn * _reduceFn
void writeFaceData(FILE *fp, const void *data, int stride, Res res, FaceDataHeader &fdh)
int size() const
Total size of specified texture in texels (u * v).
texel access is clamped to border
void writeMetaData(FILE *fp)
void deinterleave(const void *src, int sstride, int uw, int vw, void *dst, int dstride, DataType dt, int nchan)
bool ok(Ptex::String &error)
std::vector< uint32_t > _rfaceids
virtual void setBorderModes(Ptex::BorderMode uBorderMode, Ptex::BorderMode vBorderMode)
Set border modes.
virtual bool writeConstantFace(int faceid, const FaceInfo &f, const void *data)
void storeConstValue(int faceid, const void *data, int stride, Res res)
Single-precision (32-bit) floating point.
virtual PtexMetaData * getMetaData()
Access meta data.
std::vector< FaceInfo > _faceinfo
void generateReductions()
virtual bool close(Ptex::String &error)
Close the file.
virtual int alphaChannel()=0
Index of alpha channel (if any).
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.
void genRfaceids(const FaceInfo *faces, int nfaces, uint32_t *rfaceids, uint32_t *faceids)
static const int MinReductionLog2
int writeMetaDataBlock(FILE *fp, MetaEntry &val)
void reduce(const void *src, int sstride, int uw, int vw, void *dst, int dstride, DataType dt, int nchan)
const char * c_str() const
Double-precision (32-bit) floating point.
void setError(const std::string &error)
virtual Ptex::MeshType meshType()=0
Type of mesh for which texture data is defined.
void reduceTri(const void *src, int sstride, int w, int, void *dst, int dstride, DataType dt, int nchan)
int writeZipBlock(FILE *fp, const void *data, int size, bool finish=true)
static PtexTexture * open(const char *path, Ptex::String &error, bool premultiply=0)
Open a ptex file for reading.
void average(const void *src, int sstride, int uw, int vw, void *dst, DataType dt, int nchan)
virtual bool writeConstantFace(int faceid, const FaceInfo &f, const void *data)
FILE * OpenTempFile(std::string &tmppath)
MeshType
Type of base mesh for which the textures are defined.
Unsigned, 16-bit integer.
int u() const
U resolution in texels.
void encodeDifference(void *data, int size, DataType dt)
#define PtexFileMinorVersion
bool isConstant() const
Determine if face is constant (by checking a flag).
virtual bool hasMipMaps()=0
True if the file has mipmaps.
int copyBlock(FILE *dst, FILE *src, FilePos pos, int size)
PtexMainWriter(const char *path, PtexTexture *tex, Ptex::MeshType mt, Ptex::DataType dt, int nchannels, int alphachan, int nfaces, bool genmipmaps)
std::string fileError(const char *message, const char *path)
int writeBlock(FILE *fp, const void *data, int size)
virtual ~PtexMainWriter()
int readBlock(FILE *fp, void *data, int size)
virtual void addMetaData(const char *key, MetaDataType t, const void *value, int size)
virtual int numFaces()=0
Number of faces stored in file.
virtual void release()
Release resources held by this pointer (pointer becomes invalid).
virtual bool close(Ptex::String &error)
Close the file.
#define PtexFileMajorVersion
virtual void getData(int faceid, void *buffer, int stride)
Access texture data for a face at highest-resolution.
bool checkFormat(Ptex::MeshType mt, Ptex::DataType dt, int nchannels, int alphachan, Ptex::String &error)
PtexWriterBase(const char *path, Ptex::MeshType mt, Ptex::DataType dt, int nchannels, int alphachan, int nfaces, bool compress)
virtual Ptex::DataType dataType()=0
Type of data stored in file.
std::vector< FilePos > _rpos
std::vector< FilePos > pos
Smart-pointer for acquiring and releasing API objects.
virtual bool writeFace(int faceid, const FaceInfo &f, const void *data, int stride)
std::vector< LevelRec > _levels
void flagConstantNeighorhoods()
virtual ~PtexIncrWriter()
virtual Ptex::EdgeFilterMode edgeFilterMode()=0
Mode for filtering textures across edges.
void divalpha(void *data, int npixels, DataType dt, int nchannels, int alphachan)
Res calcTileRes(Res faceres)
Interface for reading data from a ptex file.
static bool applyEdits(const char *path, Ptex::String &error)
Apply edits to a file.
std::vector< uint32_t > _faceids_r
Pixel resolution of a given texture.
Automatically acquire and release lock within enclosing scope.
int writeBlank(FILE *fp, int size)
virtual Ptex::BorderMode uBorderMode()=0
Mode for filtering texture access beyond mesh border.
Single-precision (32-bit) floating point.
int DataSize(DataType dt)
Look up size of given data type (in bytes).
Res res
Resolution of face.
MetaDataType
Type of meta data entry.
void multalpha(void *data, int npixels, DataType dt, int nchannels, int alphachan)
Information about a face, as stored in the Ptex file header.
std::vector< MetaEntry > _metadata
virtual bool close(Ptex::String &error)=0
Close the file.
virtual void writeMeta(const char *key, const char *value)
Write a string as meta data.
PtexIncrWriter(const char *path, FILE *fp, Ptex::MeshType mt, Ptex::DataType dt, int nchannels, int alphachan, int nfaces)
std::map< std::string, int > _metamap
void writeConstFaceBlock(FILE *fp, const void *data, FaceDataHeader &fdh)
DataType datatype() const
virtual bool writeFace(int faceid, const FaceInfo &f, const void *data, int stride)
void writeFaceBlock(FILE *fp, const void *data, int stride, Res res, FaceDataHeader &fdh)
virtual void setEdgeFilterMode(Ptex::EdgeFilterMode edgeFilterMode)
Set edge filter mode.
DataType
Type of data stored in texture file.
std::vector< uint8_t > data
#define PTEX_NAMESPACE_END
void copy(const void *src, int sstride, void *dst, int dstride, int vres, int rowlen)
Public API classes for reading, writing, caching, and filtering Ptex files.
std::vector< uint8_t > _constdata
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.