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,
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;
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);
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--) {
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;
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);
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)
DataType datatype() const
uint32_t floor_log2(uint32_t x)
virtual bool hasEdits()
True if the file has edit blocks.
const int MetaDataThreshold
bool isConstant() const
Determine if face is constant (by checking a flag).
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)
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)
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)
int u() const
U resolution in texels.
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.
void encodeDifference(void *data, int size, DataType dt)
#define PtexFileMinorVersion
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)
int size() const
Total size of specified texture in texels (u * v).
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)
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
const char * c_str() const
#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.