69#if defined(__FreeBSD__)
88 static std::string tmpdir;
89 static int initialized = 0;
92#ifdef PTEX_PLATFORM_WINDOWS
94 DWORD result = ::GetTempPath(0, (LPTSTR) L
"");
96 std::vector<TCHAR> tempPath(result + 1);
97 result = ::GetTempPath(
static_cast<DWORD
>(tempPath.size()), &tempPath[0]);
98 if (result > 0 && result <= tempPath.size())
99 tmpdir = std::string(tempPath.begin(),
100 tempPath.begin() +
static_cast<std::size_t
>(result));
106 const char* t = getenv(
"TEMP");
107 if (!t) t = getenv(
"TMP");
115#ifdef PTEX_PLATFORM_WINDOWS
118 static int count = 0;
119 s << tmpdir <<
"/" <<
"PtexTmp" << _getpid() <<
"_" << ++count;
121 return fopen((
char*) tmppath.c_str(),
"wb+");
124 tmppath = tmpdir +
"/PtexTmpXXXXXX";
125 int fd = mkstemp(&tmppath[0]);
126 return fdopen(fd,
"w+");
130 std::string
fileError(
const char* message,
const char* path)
132 std::stringstream str;
133 str << message << path <<
"\n" << strerror(errno);
142 error =
"PtexWriter doesn't currently support big-endian cpu's";
147 error =
"PtexWriter error: Invalid mesh type";
152 error =
"PtexWriter error: Invalid data type";
156 if (nchannels <= 0) {
157 error =
"PtexWriter error: Invalid number of channels";
161 if (alphachan != -1 && (alphachan < 0 || alphachan >= nchannels)) {
162 error =
"PtexWriter error: Invalid alpha channel";
173 int nchannels,
int alphachan,
int nfaces,
176 if (!checkFormat(mt, dt, nchannels, alphachan, error))
180 mt, dt, nchannels, alphachan, nfaces,
192 int nchannels,
int alphachan,
int nfaces,
195 if (!checkFormat(mt, dt, nchannels, alphachan, error))
199 FILE* fp = fopen(path,
"rb+");
200 if (!fp && errno != ENOENT) {
201 error = fileError(
"Can't open ptex file for update: ", path).c_str();
206 if (incremental && fp) {
207 w =
new PtexIncrWriter(path, fp, mt, dt, nchannels, alphachan, nfaces);
221 bool headerMatch = (mt == tex->
meshType() &&
227 std::stringstream str;
228 str <<
"PtexWriter::edit error: header doesn't match existing file, "
229 <<
"conversions not currently supported";
230 error = str.str().c_str();
259 if (!w->close(error))
return 0;
267 int nchannels,
int alphachan,
int nfaces,
288 if (mt == mt_triangle)
294 deflateInit(&
_zstream, compress ? Z_DEFAULT_COMPRESSION : 0);
310 std::cerr << error.
c_str() << std::endl;
336 setError(
"PtexWriter error: faceid out of range");
341 setError(
"PtexWriter error: asymmetric face res not supported for triangle textures");
356 f.flags &= FaceInfo::flag_subface;
360 f.flags |= (uint8_t)flags;
367 addMetaData(key, mdt_string, value,
int(strlen(value)+1));
379 addMetaData(key, mdt_int16, value, count*(
int)
sizeof(int16_t));
385 addMetaData(key, mdt_int32, value, count*(
int)
sizeof(int32_t));
391 addMetaData(key, mdt_float, value, count*(
int)
sizeof(
float));
397 addMetaData(key, mdt_double, value, count*(
int)
sizeof(
double));
404 for (
int i = 0; i < nkeys; i++) {
407 data->
getKey(i, key, type);
426 const int16_t* val=0;
433 const int32_t* val=0;
458 const void* value,
int size)
460 if (strlen(key) > 255) {
461 std::stringstream str;
462 str <<
"PtexWriter error: meta data key too long (max=255) \"" << key <<
"\"";
467 std::stringstream str;
468 str <<
"PtexWriter error: meta data size <= 0 for \"" << key <<
"\"";
471 std::map<std::string,int>::iterator iter =
_metamap.find(key);
475 index = iter->second;
487 memcpy(&m.
data[0], value, size);
506 if (!fwrite(data, size, 1, fp)) {
507 setError(
"PtexWriter error: file write failed");
518 _zstream.next_in = (Bytef*)
const_cast<void*
>(data);
524 int zresult = deflate(&
_zstream, finishArg ? Z_FINISH : Z_NO_FLUSH);
526 if (sizeval > 0)
writeBlock(fp, buff, sizeval);
527 if (zresult == Z_STREAM_END)
break;
528 if (zresult != Z_OK) {
529 setError(
"PtexWriter error: data compression internal error");
532 if (!finishArg &&
_zstream.avail_out != 0)
537 if (!finishArg)
return 0;
539 int total = (int)
_zstream.total_out;
547 if (!fread(data, size, 1, fp)) {
548 setError(
"PtexWriter error: temp file read failed");
557 if (size <= 0)
return 0;
558 fseeko(src, pos, SEEK_SET);
563 if (!fread(buff, nbytes, 1, src)) {
564 setError(
"PtexWriter error: temp file read failed");
579 if (ntileslog2 == 0)
return faceres;
585 int n = faceres.ulog2 + faceres.vlog2 - ntileslog2;
590 tileres.ulog2 = (int8_t)
PtexUtils::min(
int((n+1)/2),
int(faceres.ulog2));
591 tileres.vlog2 = (int8_t)
PtexUtils::min(
int(n - tileres.ulog2),
int(faceres.vlog2));
611 int ures = res.u(), vres = res.v();
614 char* buff = useNew ?
new char [blockSize] : (
char*)alloca(blockSize);
620 bool diff = (
datatype() == dt_uint8 ||
629 if (useNew)
delete [] buff;
638 int ntilesu = res.ntilesu(tileres);
639 int ntilesv = res.ntilesv(tileres);
640 int ntiles = ntilesu * ntilesv;
649 std::vector<FaceDataHeader> tileHeader(ntiles);
650 int tileures = tileres.u();
651 int tilevres = tileres.v();
653 int tilevstride = tilevres*stride;
658 const char* rowp = (
const char*) data;
659 const char* rowpend = rowp + ntilesv * tilevstride;
660 for (; rowp != rowpend; rowp += tilevstride) {
661 const char* p = rowp;
662 const char* pend = p + ntilesu * tileustride;
663 for (; p != pend; tdh++, p += tileustride) {
680 totalsize +=
writeBlock(fp, &tileres,
sizeof(Res));
681 totalsize +=
writeBlock(fp, &tileheadersize,
sizeof(tileheadersize));
697 Ptex::Res newres((int8_t)(res.ulog2-1), (int8_t)(res.vlog2-1));
700 char* buff = useNew ?
new char [buffsize] : (
char*)alloca(buffsize);
706 if (useNew)
delete [] buff;
713 uint8_t keysize = uint8_t(val.
key.size()+1);
715 uint32_t datasize = uint32_t(val.
data.size());
721 int memsize = int(
sizeof(keysize) + (
size_t)keysize +
sizeof(
datatype)
722 +
sizeof(datasize) + datasize);
729 int nchannels,
int alphachan,
int nfaces,
bool genmipmaps)
733 _genmipmaps(genmipmaps),
750 for (
int i = 0; i < nfaces; i++)
_faceinfo[i].flags = uint8_t(-1);
752 _levels.front().pos.resize(nfaces);
753 _levels.front().fdh.resize(nfaces);
754 _rpos.resize(nfaces);
800 unlink(
_path.c_str());
802 error = fileError(
"Can't write to ptex file: ",
_path.c_str()).c_str();
815 if (stride == 0) stride = f.res.u()*
_pixelSize;
837 int rowlen = f.res.u() *
_pixelSize, nrows = f.res.v();
838 temp =
new uint8_t [rowlen * nrows];
861 if (temp)
delete [] temp;
912 char* data =
new char [size];
924 _faceinfo[i].flags = FaceInfo::flag_constant;
940 FILE* newfp = fopen(
_newpath.c_str(),
"wb+");
958 FilePos levelInfoPos = ftello(newfp);
967 int nfaces = int(level.
fdh.size());
974 for (
int fi = 0; fi < nfaces; fi++)
976 level.
fdh[fi].blocksize());
989 fseeko(newfp, levelInfoPos, SEEK_SET);
993 fseeko(newfp, 0, SEEK_SET);
1003 for (
int faceid = 0, n =
int(
_faceinfo.size()); faceid < n; faceid++) {
1005 if (!f.isConstant())
continue;
1009 bool isConst =
true;
1011 int nedges = isTriangle ? 3 : 4;
1012 for (
int eid = 0; isConst && (eid < nedges); eid++) {
1013 bool prevWasSubface = f.isSubface();
1014 int prevFid = faceid;
1017 int afid = f.adjface(eid);
1018 int aeid = f.adjedge(eid);
1020 const int maxcount = 10;
1021 while (afid != faceid && afid >= 0 && ++count < maxcount) {
1024 if (!af.isConstant() ||
1026 { isConst =
false;
break; }
1029 bool isSubface = af.isSubface();
1030 bool isT = !isTriangle && prevWasSubface && !isSubface && af.adjface(aeid) == prevFid;
1032 prevWasSubface = isSubface;
1036 aeid = (aeid + 1) % nedges;
1037 afid = af.adjface(aeid);
1038 aeid = af.adjedge(aeid);
1049 aeid = (aeid - 1 + nedges) % nedges;
1050 afid = f.adjface(aeid);
1051 aeid = f.adjedge(aeid);
1053 while (afid != faceid && afid >= 0 && ++count < maxcount) {
1056 if (!af.isConstant() ||
1058 { isConst =
false;
break; }
1062 aeid = (aeid - 1 + nedges) % nedges;
1063 afid = af.adjface(aeid);
1064 aeid = af.adjedge(aeid);
1067 bool isSubface = af.isSubface();
1068 if (isSubface && !prevWasSubface) {
1069 aeid = (aeid + 3) % 4;
1070 afid = af.adjface(aeid);
1071 aeid = (af.adjedge(aeid) + 3) % 4;
1073 prevWasSubface = isSubface;
1078 if (isConst) f.flags |= FaceInfo::flag_nbconstant;
1095 for (
int rfaceid = nfaces-1, cutoffres =
MinReductionLog2; rfaceid >= 0; rfaceid--) {
1099 int min = face.isConstant() ? 1 :
PtexUtils::min(res.ulog2, res.vlog2);
1100 while (min > cutoffres) {
1102 int size = rfaceid+1;
1105 level.
pos.resize(size);
1106 level.
fdh.resize(size);
1114 for (
int i = 0; i < nfaces; i++)
1117 char* buff =
new char [buffsize];
1119 int nlevels = int(
_levels.size());
1120 for (
int i = 1; i < nlevels; i++) {
1122 int nextsize = (i+1 < nlevels)?
int(
_levels[i+1].fdh.size()) : 0;
1123 for (
int rfaceid = 0, size =
int(level.
fdh.size()); rfaceid < size; rfaceid++) {
1127 res.ulog2 = (int8_t)(res.ulog2 - i);
1128 res.vlog2 = (int8_t)(res.vlog2 - i);
1133 fseeko(
_tmpfp, 0, SEEK_END);
1139 if (rfaceid < nextsize) {
1149 fseeko(
_tmpfp, 0, SEEK_END);
1156 std::vector<MetaEntry*> lmdEntries;
1159 for (
int i = 0, n = (
int)
_metadata.size(); i < n; i++) {
1161#ifndef PTEX_NO_LARGE_METADATA_BLOCKS
1164 lmdEntries.push_back(&e);
1182 int nLmd = (int)lmdEntries.size();
1185 std::vector<FilePos> lmdoffset(nLmd);
1186 std::vector<uint32_t> lmdzipsize(nLmd);
1187 for (
int i = 0; i < nLmd; i++) {
1189 lmdoffset[i] = ftello(
_tmpfp);
1194 for (
int i = 0; i < nLmd; i++) {
1196 uint8_t keysize = uint8_t(e->
key.size()+1);
1198 uint32_t datasize = (uint32_t)e->
data.size();
1199 uint32_t zipsize = lmdzipsize[i];
1207 (uint32_t)(
sizeof(keysize) + (
size_t)keysize +
sizeof(
datatype) +
1208 sizeof(datasize) +
sizeof(zipsize));
1213 for (
int i = 0; i < nLmd; i++) {
1223 int nchannels,
int alphachan,
int nfaces)
1236 std::stringstream str;
1237 str <<
"Not a ptex file: " << path;
1238 setError(str.str());
1248 std::stringstream str;
1249 str <<
"PtexWriter::edit error: header doesn't match existing file, "
1250 <<
"conversions not currently supported";
1258 std::stringstream str;
1259 str <<
"Error reading extended header: " << path;
1265 fseeko(
_fp, 0, SEEK_END);
1276 if (stride == 0) stride = f.res.u()*
_pixelSize;
1294 writeBlank(
_fp,
sizeof(edittype) +
sizeof(editsize) +
sizeof(efdh));
1297 uint8_t* constval =
new uint8_t [
_pixelSize];
1302 int rowlen = f.res.u() *
_pixelSize, nrows = f.res.v();
1303 uint8_t* temp =
new uint8_t [rowlen * nrows];
1333 fseeko(
_fp, pos, SEEK_SET);
1337 fseeko(
_fp, 0, SEEK_END);
1350 editsize = (uint32_t)
sizeof(efdh) +
_pixelSize;
1377 writeBlank(
_fp,
sizeof(edittype) +
sizeof(editsize) +
sizeof(emdh));
1380 for (
size_t i = 0, n =
_metadata.size(); i < n; i++) {
1391 fseeko(
_fp, pos, SEEK_SET);
1395 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)
FILE * OpenTempFile(std::string &tmppath)
std::string fileError(const char *message, const char *path)
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)
DataType
Type of data stored in texture file.
@ dt_float
Single-precision (32-bit) floating point.
MeshType
Type of base mesh for which the textures are defined.
@ mt_quad
Mesh is quad-based.
@ m_clamp
texel access is clamped to border
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.