Ptex
PtexWriter.cpp
Go to the documentation of this file.
1 /*
2 PTEX SOFTWARE
3 Copyright 2014 Disney Enterprises, Inc. All rights reserved
4 
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions are
7 met:
8 
9  * Redistributions of source code must retain the above copyright
10  notice, this list of conditions and the following disclaimer.
11 
12  * Redistributions in binary form must reproduce the above copyright
13  notice, this list of conditions and the following disclaimer in
14  the documentation and/or other materials provided with the
15  distribution.
16 
17  * The names "Disney", "Walt Disney Pictures", "Walt Disney Animation
18  Studios" or the names of its contributors may NOT be used to
19  endorse or promote products derived from this software without
20  specific prior written permission from Walt Disney Pictures.
21 
22 Disclaimer: THIS SOFTWARE IS PROVIDED BY WALT DISNEY PICTURES AND
23 CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
24 BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
25 FOR A PARTICULAR PURPOSE, NONINFRINGEMENT AND TITLE ARE DISCLAIMED.
26 IN NO EVENT SHALL WALT DISNEY PICTURES, THE COPYRIGHT HOLDER OR
27 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
28 EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
29 PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
30 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND BASED ON ANY
31 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
33 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
34 */
35 
36 /* Ptex writer classes:
37 
38  PtexIncrWriter implements "incremental" mode and simply appends
39  "edit" blocks to the end of the file.
40 
41  PtexMainWriter implements both writing from scratch and updating
42  an existing file, either to add data or to "roll up" previous
43  incremental edits.
44 
45  Because the various headers (faceinfo, levelinfo, etc.) are
46  variable-length and precede the data, and because the data size
47  is not known until it is compressed and written, all data
48  are written to a temp file and then copied at the end to the
49  final location. This happens during the "finish" phase.
50 
51  Each time a texture is written to the file, a reduction of the
52  texture is also generated and stored. These reductions are stored
53  in a temporary form and recalled later as the resolution levels are
54  generated.
55 
56  The final reduction for each face is averaged and stored in the
57  const data block.
58 */
59 
60 #include "PtexPlatform.h"
61 #include <errno.h>
62 #include <signal.h>
63 #include <stdio.h>
64 #include <stdlib.h>
65 #include <string.h>
66 #include <algorithm>
67 #include <iostream>
68 #include <sstream>
69 #include <unistd.h>
70 
71 #include "Ptexture.h"
72 #include "PtexUtils.h"
73 #include "PtexWriter.h"
74 
76 
77 namespace {
78 
79  FILE* OpenTempFile(std::string& tmppath)
80  {
81  static Mutex lock;
82  AutoMutex locker(lock);
83 
84  // choose temp dir
85  static std::string tmpdir;
86  static int initialized = 0;
87  if (!initialized) {
88  initialized = 1;
89 #ifdef WINDOWS
90  // use GetTempPath API (first call determines length of result)
91  DWORD result = ::GetTempPath(0, (LPTSTR) L"");
92  if (result > 0) {
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));
98  else
99  tmpdir = ".";
100  }
101 #else
102  // try $TEMP or $TMP, use /tmp as last resort
103  const char* t = getenv("TEMP");
104  if (!t) t = getenv("TMP");
105  if (!t) t = "/tmp";
106  tmpdir = t;
107 #endif
108  }
109 
110  // build temp path
111 
112 #ifdef WINDOWS
113  // use process id and counter to make unique filename
114  std::stringstream s;
115  static int count = 0;
116  s << tmpdir << "/" << "PtexTmp" << _getpid() << "_" << ++count;
117  tmppath = s.str();
118  return fopen((char*) tmppath.c_str(), "wb+");
119 #else
120  // use mkstemp to open unique file
121  tmppath = tmpdir + "/PtexTmpXXXXXX";
122  int fd = mkstemp(&tmppath[0]);
123  return fdopen(fd, "w+");
124 #endif
125  }
126 
127  std::string fileError(const char* message, const char* path)
128  {
129  std::stringstream str;
130  str << message << path << "\n" << strerror(errno);
131  return str.str();
132  }
133 
134  bool checkFormat(Ptex::MeshType mt, Ptex::DataType dt, int nchannels, int alphachan,
135  Ptex::String& error)
136  {
137  // check to see if given file attributes are valid
138  if (!LittleEndian()) {
139  error = "PtexWriter doesn't currently support big-endian cpu's";
140  return 0;
141  }
142 
143  if (mt < Ptex::mt_triangle || mt > Ptex::mt_quad) {
144  error = "PtexWriter error: Invalid mesh type";
145  return 0;
146  }
147 
148  if (dt < Ptex::dt_uint8 || dt > Ptex::dt_float) {
149  error = "PtexWriter error: Invalid data type";
150  return 0;
151  }
152 
153  if (nchannels <= 0) {
154  error = "PtexWriter error: Invalid number of channels";
155  return 0;
156  }
157 
158  if (alphachan != -1 && (alphachan < 0 || alphachan >= nchannels)) {
159  error = "PtexWriter error: Invalid alpha channel";
160  return 0;
161  }
162 
163  return 1;
164  }
165 }
166 
167 
168 PtexWriter* PtexWriter::open(const char* path,
170  int nchannels, int alphachan, int nfaces,
171  Ptex::String& error, bool genmipmaps)
172 {
173  if (!checkFormat(mt, dt, nchannels, alphachan, error))
174  return 0;
175 
176  PtexMainWriter* w = new PtexMainWriter(path, 0,
177  mt, dt, nchannels, alphachan, nfaces,
178  genmipmaps);
179  if (!w->ok(error)) {
180  w->release();
181  return 0;
182  }
183  return w;
184 }
185 
186 
187 PtexWriter* PtexWriter::edit(const char* path, bool incremental,
189  int nchannels, int alphachan, int nfaces,
190  Ptex::String& error, bool genmipmaps)
191 {
192  if (!checkFormat(mt, dt, nchannels, alphachan, error))
193  return 0;
194 
195  // try to open existing file (it might not exist)
196  FILE* fp = fopen(path, "rb+");
197  if (!fp && errno != ENOENT) {
198  error = fileError("Can't open ptex file for update: ", path).c_str();
199  }
200 
201  PtexWriterBase* w = 0;
202  // use incremental writer iff incremental mode requested and file exists
203  if (incremental && fp) {
204  w = new PtexIncrWriter(path, fp, mt, dt, nchannels, alphachan, nfaces);
205  }
206  // otherwise use main writer
207  else {
208  PtexTexture* tex = 0;
209  if (fp) {
210  // got an existing file, close and reopen with PtexReader
211  fclose(fp);
212 
213  // open reader for existing file
214  tex = PtexTexture::open(path, error);
215  if (!tex) return 0;
216 
217  // make sure header matches
218  bool headerMatch = (mt == tex->meshType() &&
219  dt == tex->dataType() &&
220  nchannels == tex->numChannels() &&
221  alphachan == tex->alphaChannel() &&
222  nfaces == tex->numFaces());
223  if (!headerMatch) {
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();
228  return 0;
229  }
230  }
231  w = new PtexMainWriter(path, tex, mt, dt, nchannels, alphachan,
232  nfaces, genmipmaps);
233  }
234 
235  if (!w->ok(error)) {
236  w->release();
237  return 0;
238  }
239  return w;
240 }
241 
242 
243 bool PtexWriter::applyEdits(const char* path, Ptex::String& error)
244 {
245  // open reader for existing file
246  PtexTexture* tex = PtexTexture::open(path, error);
247  if (!tex) return 0;
248 
249  // see if we have any edits to apply
250  if (tex->hasEdits()) {
251  // create non-incremental writer
252  PtexPtr<PtexWriter> w(new PtexMainWriter(path, tex, tex->meshType(), tex->dataType(),
253  tex->numChannels(), tex->alphaChannel(), tex->numFaces(),
254  tex->hasMipMaps()));
255  // close to rebuild file
256  if (!w->close(error)) return 0;
257  }
258  return 1;
259 }
260 
261 
264  int nchannels, int alphachan, int nfaces,
265  bool compress)
266  : _ok(true),
267  _path(path),
268  _tilefp(0)
269 {
270  memset(&_header, 0, sizeof(_header));
271  _header.magic = Magic;
274  _header.meshtype = mt;
275  _header.datatype = dt;
276  _header.alphachan = alphachan;
277  _header.nchannels = (uint16_t)nchannels;
278  _header.nfaces = nfaces;
279  _header.nlevels = 0;
280  _header.extheadersize = sizeof(_extheader);
282 
283  memset(&_extheader, 0, sizeof(_extheader));
284 
285  if (mt == mt_triangle)
287  else
289 
290  memset(&_zstream, 0, sizeof(_zstream));
291  deflateInit(&_zstream, compress ? Z_DEFAULT_COMPRESSION : 0);
292 
293  // create temp file for writing tiles
294  // (must compress each tile before assembling a tiled face)
296  if (!_tilefp) {
297  setError(fileError("Error creating temp file: ", _tilepath.c_str()));
298  }
299 }
300 
301 
303 {
304  Ptex::String error;
305  // close writer if app didn't, and report error if any
306  if (_tilefp && !close(error))
307  std::cerr << error.c_str() << std::endl;
308  delete this;
309 }
310 
312 {
313  deflateEnd(&_zstream);
314 }
315 
316 
318 {
319  if (_ok) finish();
320  if (!_ok) getError(error);
321  if (_tilefp) {
322  fclose(_tilefp);
323  unlink(_tilepath.c_str());
324  _tilefp = 0;
325  }
326  return _ok;
327 }
328 
329 
330 bool PtexWriterBase::storeFaceInfo(int faceid, FaceInfo& f, const FaceInfo& src, int flags)
331 {
332  if (faceid < 0 || size_t(faceid) >= _header.nfaces) {
333  setError("PtexWriter error: faceid out of range");
334  return 0;
335  }
336 
337  if (_header.meshtype == mt_triangle && (f.res.ulog2 != f.res.vlog2)) {
338  setError("PtexWriter error: asymmetric face res not supported for triangle textures");
339  return 0;
340  }
341 
342  // copy all values
343  f = src;
344 
345  // and clear extraneous ones
346  if (_header.meshtype == mt_triangle) {
347  f.flags = 0; // no user-settable flags on triangles
348  f.adjfaces[3] = -1;
349  f.adjedges &= 0x3f; // clear all but bottom six bits
350  }
351  else {
352  // clear non-user-settable flags
353  f.flags &= FaceInfo::flag_subface;
354  }
355 
356  // set new flags
357  f.flags |= (uint8_t)flags;
358  return 1;
359 }
360 
361 
362 void PtexWriterBase::writeMeta(const char* key, const char* value)
363 {
364  addMetaData(key, mdt_string, value, int(strlen(value)+1));
365 }
366 
367 
368 void PtexWriterBase::writeMeta(const char* key, const int8_t* value, int count)
369 {
370  addMetaData(key, mdt_int8, value, count);
371 }
372 
373 
374 void PtexWriterBase::writeMeta(const char* key, const int16_t* value, int count)
375 {
376  addMetaData(key, mdt_int16, value, count*(int)sizeof(int16_t));
377 }
378 
379 
380 void PtexWriterBase::writeMeta(const char* key, const int32_t* value, int count)
381 {
382  addMetaData(key, mdt_int32, value, count*(int)sizeof(int32_t));
383 }
384 
385 
386 void PtexWriterBase::writeMeta(const char* key, const float* value, int count)
387 {
388  addMetaData(key, mdt_float, value, count*(int)sizeof(float));
389 }
390 
391 
392 void PtexWriterBase::writeMeta(const char* key, const double* value, int count)
393 {
394  addMetaData(key, mdt_double, value, count*(int)sizeof(double));
395 }
396 
397 
399 {
400  int nkeys = data->numKeys();
401  for (int i = 0; i < nkeys; i++) {
402  const char* key = 0;
403  MetaDataType type;
404  data->getKey(i, key, type);
405  int count;
406  switch (type) {
407  case mdt_string:
408  {
409  const char* val=0;
410  data->getValue(key, val);
411  writeMeta(key, val);
412  }
413  break;
414  case mdt_int8:
415  {
416  const int8_t* val=0;
417  data->getValue(key, val, count);
418  writeMeta(key, val, count);
419  }
420  break;
421  case mdt_int16:
422  {
423  const int16_t* val=0;
424  data->getValue(key, val, count);
425  writeMeta(key, val, count);
426  }
427  break;
428  case mdt_int32:
429  {
430  const int32_t* val=0;
431  data->getValue(key, val, count);
432  writeMeta(key, val, count);
433  }
434  break;
435  case mdt_float:
436  {
437  const float* val=0;
438  data->getValue(key, val, count);
439  writeMeta(key, val, count);
440  }
441  break;
442  case mdt_double:
443  {
444  const double* val=0;
445  data->getValue(key, val, count);
446  writeMeta(key, val, count);
447  }
448  break;
449  }
450  }
451 }
452 
453 
455  const void* value, int size)
456 {
457  if (strlen(key) > 255) {
458  std::stringstream str;
459  str << "PtexWriter error: meta data key too long (max=255) \"" << key << "\"";
460  setError(str.str());
461  return;
462  }
463  if (size <= 0) {
464  std::stringstream str;
465  str << "PtexWriter error: meta data size <= 0 for \"" << key << "\"";
466  setError(str.str());
467  }
468  std::map<std::string,int>::iterator iter = _metamap.find(key);
469  int index;
470  if (iter != _metamap.end()) {
471  // see if we already have this entry - if so, overwrite it
472  index = iter->second;
473  }
474  else {
475  // allocate a new entry
476  index = (int)_metadata.size();
477  _metadata.resize(index+1);
478  _metamap[key] = index;
479  }
480  MetaEntry& m = _metadata[index];
481  m.key = key;
482  m.datatype = t;
483  m.data.resize(size);
484  memcpy(&m.data[0], value, size);
485 }
486 
487 
488 int PtexWriterBase::writeBlank(FILE* fp, int size)
489 {
490  if (!_ok) return 0;
491  static char zeros[BlockSize] = {0};
492  int remain = size;
493  while (remain > 0) {
494  remain -= writeBlock(fp, zeros, remain < BlockSize ? remain : BlockSize);
495  }
496  return size;
497 }
498 
499 
500 int PtexWriterBase::writeBlock(FILE* fp, const void* data, int size)
501 {
502  if (!_ok) return 0;
503  if (!fwrite(data, size, 1, fp)) {
504  setError("PtexWriter error: file write failed");
505  return 0;
506  }
507  return size;
508 }
509 
510 
511 int PtexWriterBase::writeZipBlock(FILE* fp, const void* data, int size, bool finishArg)
512 {
513  if (!_ok) return 0;
514  void* buff = alloca(BlockSize);
515  _zstream.next_in = (Bytef*) const_cast<void*>(data);
516  _zstream.avail_in = size;
517 
518  while (1) {
519  _zstream.next_out = (Bytef*)buff;
520  _zstream.avail_out = BlockSize;
521  int zresult = deflate(&_zstream, finishArg ? Z_FINISH : Z_NO_FLUSH);
522  int sizeval = BlockSize - _zstream.avail_out;
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");
527  break;
528  }
529  if (!finishArg && _zstream.avail_out != 0)
530  // waiting for more input
531  break;
532  }
533 
534  if (!finishArg) return 0;
535 
536  int total = (int)_zstream.total_out;
537  deflateReset(&_zstream);
538  return total;
539 }
540 
541 
542 int PtexWriterBase::readBlock(FILE* fp, void* data, int size)
543 {
544  if (!fread(data, size, 1, fp)) {
545  setError("PtexWriter error: temp file read failed");
546  return 0;
547  }
548  return size;
549 }
550 
551 
552 int PtexWriterBase::copyBlock(FILE* dst, FILE* src, FilePos pos, int size)
553 {
554  if (size <= 0) return 0;
555  fseeko(src, pos, SEEK_SET);
556  int remain = size;
557  void* buff = alloca(BlockSize);
558  while (remain) {
559  int nbytes = remain < BlockSize ? remain : BlockSize;
560  if (!fread(buff, nbytes, 1, src)) {
561  setError("PtexWriter error: temp file read failed");
562  return 0;
563  }
564  if (!writeBlock(dst, buff, nbytes)) break;
565  remain -= nbytes;
566  }
567  return size;
568 }
569 
570 
572 {
573  // desired number of tiles = floor(log2(facesize / tilesize))
574  int facesize = faceres.size() * _pixelSize;
575  int ntileslog2 = PtexUtils::floor_log2(facesize/TileSize);
576  if (ntileslog2 == 0) return faceres;
577 
578  // number of tiles is defined as:
579  // ntileslog2 = ureslog2 + vreslog2 - (tile_ureslog2 + tile_vreslog2)
580  // rearranging to solve for the tile res:
581  // tile_ureslog2 + tile_vreslog2 = ureslog2 + vreslog2 - ntileslog2
582  int n = faceres.ulog2 + faceres.vlog2 - ntileslog2;
583 
584  // choose u and v sizes for roughly square result (u ~= v ~= n/2)
585  // and make sure tile isn't larger than face
586  Res tileres;
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));
589  return tileres;
590 }
591 
592 
593 void PtexWriterBase::writeConstFaceBlock(FILE* fp, const void* data,
594  FaceDataHeader& fdh)
595 {
596  // write a single const face data block
597  // record level data for face and output the one pixel value
599  writeBlock(fp, data, _pixelSize);
600 }
601 
602 
603 void PtexWriterBase::writeFaceBlock(FILE* fp, const void* data, int stride,
604  Res res, FaceDataHeader& fdh)
605 {
606  // write a single face data block
607  // copy to temp buffer, and deinterleave
608  int ures = res.u(), vres = res.v();
609  int blockSize = ures*vres*_pixelSize;
610  bool useNew = blockSize > AllocaMax;
611  char* buff = useNew ? new char [blockSize] : (char*)alloca(blockSize);
612  PtexUtils::deinterleave(data, stride, ures, vres, buff,
613  ures*DataSize(datatype()),
615 
616  // difference if needed
617  bool diff = (datatype() == dt_uint8 ||
618  datatype() == dt_uint16);
619  if (diff) PtexUtils::encodeDifference(buff, blockSize, datatype());
620 
621  // compress and stream data to file, and record size in header
622  int zippedsize = writeZipBlock(fp, buff, blockSize);
623 
624  // record compressed size and encoding in data header
625  fdh.set(zippedsize, diff ? enc_diffzipped : enc_zipped);
626  if (useNew) delete [] buff;
627 }
628 
629 
630 void PtexWriterBase::writeFaceData(FILE* fp, const void* data, int stride,
631  Res res, FaceDataHeader& fdh)
632 {
633  // determine whether to break into tiles
634  Res tileres = calcTileRes(res);
635  int ntilesu = res.ntilesu(tileres);
636  int ntilesv = res.ntilesv(tileres);
637  int ntiles = ntilesu * ntilesv;
638  if (ntiles == 1) {
639  // write single block
640  writeFaceBlock(fp, data, stride, res, fdh);
641  } else {
642  // write tiles to tilefp temp file
643  rewind(_tilefp);
644 
645  // alloc tile header
646  std::vector<FaceDataHeader> tileHeader(ntiles);
647  int tileures = tileres.u();
648  int tilevres = tileres.v();
649  int tileustride = tileures*_pixelSize;
650  int tilevstride = tilevres*stride;
651 
652  // output tiles
653  FaceDataHeader* tdh = &tileHeader[0];
654  int datasize = 0;
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) {
661  // determine if tile is constant
662  if (PtexUtils::isConstant(p, stride, tileures, tilevres, _pixelSize))
663  writeConstFaceBlock(_tilefp, p, *tdh);
664  else
665  writeFaceBlock(_tilefp, p, stride, tileres, *tdh);
666  datasize += tdh->blocksize();
667  }
668  }
669 
670  // output compressed tile header
671  uint32_t tileheadersize = writeZipBlock(_tilefp, &tileHeader[0],
672  int(sizeof(FaceDataHeader)*tileHeader.size()));
673 
674 
675  // output tile data pre-header
676  int totalsize = 0;
677  totalsize += writeBlock(fp, &tileres, sizeof(Res));
678  totalsize += writeBlock(fp, &tileheadersize, sizeof(tileheadersize));
679 
680  // copy compressed tile header from temp file
681  totalsize += copyBlock(fp, _tilefp, datasize, tileheadersize);
682 
683  // copy tile data from temp file
684  totalsize += copyBlock(fp, _tilefp, 0, datasize);
685 
686  fdh.set(totalsize, enc_tiled);
687  }
688 }
689 
690 
691 void PtexWriterBase::writeReduction(FILE* fp, const void* data, int stride, Res res)
692 {
693  // reduce and write to file
694  Ptex::Res newres((int8_t)(res.ulog2-1), (int8_t)(res.vlog2-1));
695  int buffsize = newres.size() * _pixelSize;
696  bool useNew = buffsize > AllocaMax;
697  char* buff = useNew ? new char [buffsize] : (char*)alloca(buffsize);
698 
699  int dstride = newres.u() * _pixelSize;
700  _reduceFn(data, stride, res.u(), res.v(), buff, dstride, datatype(), _header.nchannels);
701  writeBlock(fp, buff, buffsize);
702 
703  if (useNew) delete [] buff;
704 }
705 
706 
707 
709 {
710  uint8_t keysize = uint8_t(val.key.size()+1);
711  uint8_t datatype = val.datatype;
712  uint32_t datasize = uint32_t(val.data.size());
713  writeZipBlock(fp, &keysize, sizeof(keysize), false);
714  writeZipBlock(fp, val.key.c_str(), keysize, false);
715  writeZipBlock(fp, &datatype, sizeof(datatype), false);
716  writeZipBlock(fp, &datasize, sizeof(datasize), false);
717  writeZipBlock(fp, &val.data[0], datasize, false);
718  int memsize = int(sizeof(keysize) + (size_t)keysize + sizeof(datatype)
719  + sizeof(datasize) + datasize);
720  return memsize;
721 }
722 
723 
726  int nchannels, int alphachan, int nfaces, bool genmipmaps)
727  : PtexWriterBase(path, mt, dt, nchannels, alphachan, nfaces,
728  /* compress */ true),
729  _hasNewData(false),
730  _genmipmaps(genmipmaps),
731  _reader(0)
732 {
734  if (!_tmpfp) {
735  setError(fileError("Error creating temp file: ", _tmppath.c_str()));
736  return;
737  }
738 
739  // data will be written to a ".new" path and then renamed to final location
740  _newpath = path; _newpath += ".new";
741 
742  _levels.reserve(20);
743  _levels.resize(1);
744 
745  // init faceinfo and set flags to -1 to mark as uninitialized
746  _faceinfo.resize(nfaces);
747  for (int i = 0; i < nfaces; i++) _faceinfo[i].flags = uint8_t(-1);
748 
749  _levels.front().pos.resize(nfaces);
750  _levels.front().fdh.resize(nfaces);
751  _rpos.resize(nfaces);
752  _constdata.resize(nfaces*_pixelSize);
753 
754  if (tex) {
755  // access reader implementation
756  // Note: we can assume we have a PtexReader because we opened the tex from the cache
757  _reader = static_cast<PtexReader*>(tex);
758 
759  // copy border modes
760  setBorderModes(tex->uBorderMode(), tex->vBorderMode());
761 
762  // copy edge filter mode
764 
765  // copy meta data from existing file
767  writeMeta(meta);
768 
769  // see if we have any edits
771  }
772 }
773 
774 
776 {
777  if (_reader) _reader->release();
778 }
779 
780 
782 {
783  // closing base writer will write all pending data via finish() method
784  // and will close _fp (which in this case is on the temp disk)
785  bool result = PtexWriterBase::close(error);
786  if (_reader) {
787  _reader->release();
788  _reader = 0;
789  }
790  if (_tmpfp) {
791  fclose(_tmpfp);
792  unlink(_tmppath.c_str());
793  _tmpfp = 0;
794  }
795  if (result && _hasNewData) {
796  // rename temppath into final location
797  unlink(_path.c_str());
798  if (rename(_newpath.c_str(), _path.c_str()) == -1) {
799  error = fileError("Can't write to ptex file: ", _path.c_str()).c_str();
800  unlink(_newpath.c_str());
801  result = false;
802  }
803  }
804  return result;
805 }
806 
807 bool PtexMainWriter::writeFace(int faceid, const FaceInfo& f, const void* data, int stride)
808 {
809  if (!_ok) return 0;
810 
811  // auto-compute stride
812  if (stride == 0) stride = f.res.u()*_pixelSize;
813 
814  // handle constant case
815  if (PtexUtils::isConstant(data, stride, f.res.u(), f.res.v(), _pixelSize))
816  return writeConstantFace(faceid, f, data);
817 
818  // non-constant case, ...
819 
820  // check and store face info
821  if (!storeFaceInfo(faceid, _faceinfo[faceid], f)) return 0;
822 
823  // record position of current face
824  _levels.front().pos[faceid] = ftello(_tmpfp);
825 
826  // write face data
827  writeFaceData(_tmpfp, data, stride, f.res, _levels.front().fdh[faceid]);
828  if (!_ok) return 0;
829 
830  // premultiply (if needed) before making reductions; use temp copy of data
831  uint8_t* temp = 0;
832  if (_header.hasAlpha()) {
833  // first copy to temp buffer
834  int rowlen = f.res.u() * _pixelSize, nrows = f.res.v();
835  temp = new uint8_t [rowlen * nrows];
836  PtexUtils::copy(data, stride, temp, rowlen, nrows, rowlen);
837 
838  // multiply alpha
839  PtexUtils::multalpha(temp, f.res.size(), datatype(), _header.nchannels,
841 
842  // override source buffer
843  data = temp;
844  stride = rowlen;
845  }
846 
847  // generate first reduction (if needed)
848  if (_genmipmaps &&
849  (f.res.ulog2 > MinReductionLog2 && f.res.vlog2 > MinReductionLog2))
850  {
851  _rpos[faceid] = ftello(_tmpfp);
852  writeReduction(_tmpfp, data, stride, f.res);
853  }
854  else {
855  storeConstValue(faceid, data, stride, f.res);
856  }
857 
858  if (temp) delete [] temp;
859  _hasNewData = true;
860  return 1;
861 }
862 
863 
864 bool PtexMainWriter::writeConstantFace(int faceid, const FaceInfo& f, const void* data)
865 {
866  if (!_ok) return 0;
867 
868  // check and store face info
869  if (!storeFaceInfo(faceid, _faceinfo[faceid], f, FaceInfo::flag_constant)) return 0;
870 
871  // store face value in constant block
872  memcpy(&_constdata[faceid*_pixelSize], data, _pixelSize);
873  _hasNewData = true;
874  return 1;
875 }
876 
877 
878 
879 void PtexMainWriter::storeConstValue(int faceid, const void* data, int stride, Res res)
880 {
881  // compute average value and store in _constdata block
882  uint8_t* constdata = &_constdata[faceid*_pixelSize];
883  PtexUtils::average(data, stride, res.u(), res.v(), constdata,
885  if (_header.hasAlpha())
887 }
888 
889 
890 
892 {
893  // do nothing if there's no new data to write
894  if (!_hasNewData) return;
895 
896  // copy missing faces from _reader
897  if (_reader) {
898  for (int i = 0, nfaces = _header.nfaces; i < nfaces; i++) {
899  if (_faceinfo[i].flags == uint8_t(-1)) {
900  // copy face data
901  const Ptex::FaceInfo& info = _reader->getFaceInfo(i);
902  int size = _pixelSize * info.res.size();
903  if (info.isConstant()) {
905  if (data) {
906  writeConstantFace(i, info, data->getData());
907  }
908  } else {
909  char* data = new char [size];
910  _reader->getData(i, data, 0);
911  writeFace(i, info, data, 0);
912  delete [] data;
913  }
914  }
915  }
916  }
917  else {
918  // just flag missing faces as constant (black)
919  for (int i = 0, nfaces = _header.nfaces; i < nfaces; i++) {
920  if (_faceinfo[i].flags == uint8_t(-1))
921  _faceinfo[i].flags = FaceInfo::flag_constant;
922  }
923  }
924 
925  // write reductions to tmp file
926  if (_genmipmaps)
928 
929  // flag faces w/ constant neighborhoods
931 
932  // update header
933  _header.nlevels = uint16_t(_levels.size());
934  _header.nfaces = uint32_t(_faceinfo.size());
935 
936  // create new file
937  FILE* newfp = fopen(_newpath.c_str(), "wb+");
938  if (!newfp) {
939  setError(fileError("Can't write to ptex file: ", _newpath.c_str()));
940  return;
941  }
942 
943  // write blank header (to fill in later)
944  writeBlank(newfp, HeaderSize);
945  writeBlank(newfp, ExtHeaderSize);
946 
947  // write compressed face info block
949  (int)sizeof(FaceInfo)*_header.nfaces);
950 
951  // write compressed const data block
952  _header.constdatasize = writeZipBlock(newfp, &_constdata[0], int(_constdata.size()));
953 
954  // write blank level info block (to fill in later)
955  FilePos levelInfoPos = ftello(newfp);
957 
958  // write level data blocks (and record level info)
959  std::vector<LevelInfo> levelinfo(_header.nlevels);
960  for (int li = 0; li < _header.nlevels; li++)
961  {
962  LevelInfo& info = levelinfo[li];
963  LevelRec& level = _levels[li];
964  int nfaces = int(level.fdh.size());
965  info.nfaces = nfaces;
966  // output compressed level data header
967  info.levelheadersize = writeZipBlock(newfp, &level.fdh[0],
968  (int)sizeof(FaceDataHeader)*nfaces);
969  info.leveldatasize = info.levelheadersize;
970  // copy level data from tmp file
971  for (int fi = 0; fi < nfaces; fi++)
972  info.leveldatasize += copyBlock(newfp, _tmpfp, level.pos[fi],
973  level.fdh[fi].blocksize());
975  }
976  rewind(_tmpfp);
977 
978  // write meta data (if any)
979  if (!_metadata.empty())
980  writeMetaData(newfp);
981 
982  // update extheader for edit data position
983  _extheader.editdatapos = ftello(newfp);
984 
985  // rewrite level info block
986  fseeko(newfp, levelInfoPos, SEEK_SET);
987  _header.levelinfosize = writeBlock(newfp, &levelinfo[0], LevelInfoSize*_header.nlevels);
988 
989  // rewrite header
990  fseeko(newfp, 0, SEEK_SET);
991  writeBlock(newfp, &_header, HeaderSize);
993  fclose(newfp);
994 }
995 
996 
998 {
999  // for each constant face
1000  for (int faceid = 0, n = int(_faceinfo.size()); faceid < n; faceid++) {
1001  FaceInfo& f = _faceinfo[faceid];
1002  if (!f.isConstant()) continue;
1003  uint8_t* constdata = &_constdata[faceid*_pixelSize];
1004 
1005  // check to see if neighborhood is constant
1006  bool isConst = true;
1007  bool isTriangle = _header.meshtype == mt_triangle;
1008  int nedges = isTriangle ? 3 : 4;
1009  for (int eid = 0; isConst && (eid < nedges); eid++) {
1010  bool prevWasSubface = f.isSubface();
1011  int prevFid = faceid;
1012 
1013  // traverse around vertex in CW direction
1014  int afid = f.adjface(eid);
1015  int aeid = f.adjedge(eid);
1016  int count = 0;
1017  const int maxcount = 10; // max valence (as safety valve)
1018  while (afid != faceid && afid >= 0 && ++count < maxcount) {
1019  // check if neighbor is constant, and has the same value as face
1020  FaceInfo& af = _faceinfo[afid];
1021  if (!af.isConstant() ||
1022  0 != memcmp(constdata, &_constdata[afid*_pixelSize], _pixelSize))
1023  { isConst = false; break; }
1024 
1025  // if vertex is a T vertex between subface and main face, we can stop
1026  bool isSubface = af.isSubface();
1027  bool isT = !isTriangle && prevWasSubface && !isSubface && af.adjface(aeid) == prevFid;
1028  if (isT) break;
1029  prevWasSubface = isSubface;
1030 
1031  // traverse around vertex in CW direction
1032  prevFid = afid;
1033  aeid = (aeid + 1) % nedges;
1034  afid = af.adjface(aeid);
1035  aeid = af.adjedge(aeid);
1036  }
1037 
1038  if (afid < 0) {
1039  // hit boundary edge, check boundary mode
1041  isConst = false;
1042  }
1043 
1044  // and traverse CCW neighbors too
1045  if (isConst) {
1046  aeid = (aeid - 1 + nedges) % nedges;
1047  afid = f.adjface(aeid);
1048  aeid = f.adjedge(aeid);
1049  count = 0;
1050  while (afid != faceid && afid >= 0 && ++count < maxcount) {
1051  // check if neighbor is constant, and has the same value as face
1052  FaceInfo& af = _faceinfo[afid];
1053  if (!af.isConstant() ||
1054  0 != memcmp(constdata, &_constdata[afid*_pixelSize], _pixelSize))
1055  { isConst = false; break; }
1056 
1057  // traverse around vertex in CCW direction
1058  prevFid = afid;
1059  aeid = (aeid - 1 + nedges) % nedges;
1060  afid = af.adjface(aeid);
1061  aeid = af.adjedge(aeid);
1062 
1063  // if traversing to a subface, switch to secondary subface (afid points to primary/CW subface)
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;
1069  }
1070  prevWasSubface = isSubface;
1071  }
1072  }
1073  }
1074  }
1075  if (isConst) f.flags |= FaceInfo::flag_nbconstant;
1076  }
1077 }
1078 
1079 
1081 {
1082  // first generate "rfaceids", reduction faceids,
1083  // which are faceids reordered by decreasing smaller dimension
1084  int nfaces = _header.nfaces;
1085  _rfaceids.resize(nfaces);
1086  _faceids_r.resize(nfaces);
1087  PtexUtils::genRfaceids(&_faceinfo[0], nfaces, &_rfaceids[0], &_faceids_r[0]);
1088 
1089  // determine how many faces in each level, and resize _levels
1090  // traverse in reverse rfaceid order to find number of faces
1091  // larger than cutoff size of each level
1092  for (int rfaceid = nfaces-1, cutoffres = MinReductionLog2; rfaceid >= 0; rfaceid--) {
1093  int faceid = _faceids_r[rfaceid];
1094  FaceInfo& face = _faceinfo[faceid];
1095  Res res = face.res;
1096  int min = face.isConstant() ? 1 : PtexUtils::min(res.ulog2, res.vlog2);
1097  while (min > cutoffres) {
1098  // i == last face for current level
1099  int size = rfaceid+1;
1100  _levels.push_back(LevelRec());
1101  LevelRec& level = _levels.back();
1102  level.pos.resize(size);
1103  level.fdh.resize(size);
1104  cutoffres++;
1105  }
1106  }
1107 
1108  // generate and cache reductions (including const data)
1109  // first, find largest face and allocate tmp buffer
1110  int buffsize = 0;
1111  for (int i = 0; i < nfaces; i++)
1112  buffsize = PtexUtils::max(buffsize, _faceinfo[i].res.size());
1113  buffsize *= _pixelSize;
1114  char* buff = new char [buffsize];
1115 
1116  int nlevels = int(_levels.size());
1117  for (int i = 1; i < nlevels; i++) {
1118  LevelRec& level = _levels[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++) {
1121  // output current reduction for face (previously generated)
1122  int faceid = _faceids_r[rfaceid];
1123  Res res = _faceinfo[faceid].res;
1124  res.ulog2 = (int8_t)(res.ulog2 - i);
1125  res.vlog2 = (int8_t)(res.vlog2 - i);
1126  int stride = res.u() * _pixelSize;
1127  int blocksize = res.size() * _pixelSize;
1128  fseeko(_tmpfp, _rpos[faceid], SEEK_SET);
1129  readBlock(_tmpfp, buff, blocksize);
1130  fseeko(_tmpfp, 0, SEEK_END);
1131  level.pos[rfaceid] = ftello(_tmpfp);
1132  writeFaceData(_tmpfp, buff, stride, res, level.fdh[rfaceid]);
1133  if (!_ok) return;
1134 
1135  // write a new reduction if needed for next level
1136  if (rfaceid < nextsize) {
1137  fseeko(_tmpfp, _rpos[faceid], SEEK_SET);
1138  writeReduction(_tmpfp, buff, stride, res);
1139  }
1140  else {
1141  // the last reduction for each face is its constant value
1142  storeConstValue(faceid, buff, stride, res);
1143  }
1144  }
1145  }
1146  fseeko(_tmpfp, 0, SEEK_END);
1147  delete [] buff;
1148 }
1149 
1150 
1152 {
1153  std::vector<MetaEntry*> lmdEntries; // large meta data items
1154 
1155  // write small meta data items in a single zip block
1156  for (int i = 0, n = (int)_metadata.size(); i < n; i++) {
1157  MetaEntry& e = _metadata[i];
1158 #ifndef PTEX_NO_LARGE_METADATA_BLOCKS
1159  if (int(e.data.size()) > MetaDataThreshold) {
1160  // skip large items, but record for later
1161  lmdEntries.push_back(&e);
1162  }
1163  else
1164 #endif
1165  {
1166  // add small item to zip block
1168  }
1169  }
1170  if (_header.metadatamemsize) {
1171  // finish zip block
1172  _header.metadatazipsize = writeZipBlock(fp, 0, 0, /*finish*/ true);
1173  }
1174 
1175  // write compatibility barrier
1176  writeBlank(fp, sizeof(uint64_t));
1177 
1178  // write large items as separate blocks
1179  int nLmd = (int)lmdEntries.size();
1180  if (nLmd > 0) {
1181  // write data records to tmp file and accumulate zip sizes for lmd header
1182  std::vector<FilePos> lmdoffset(nLmd);
1183  std::vector<uint32_t> lmdzipsize(nLmd);
1184  for (int i = 0; i < nLmd; i++) {
1185  MetaEntry* e= lmdEntries[i];
1186  lmdoffset[i] = ftello(_tmpfp);
1187  lmdzipsize[i] = writeZipBlock(_tmpfp, &e->data[0], (int)e->data.size());
1188  }
1189 
1190  // write lmd header records as single zip block
1191  for (int i = 0; i < nLmd; i++) {
1192  MetaEntry* e = lmdEntries[i];
1193  uint8_t keysize = uint8_t(e->key.size()+1);
1194  uint8_t datatype = e->datatype;
1195  uint32_t datasize = (uint32_t)e->data.size();
1196  uint32_t zipsize = lmdzipsize[i];
1197 
1198  writeZipBlock(fp, &keysize, sizeof(keysize), false);
1199  writeZipBlock(fp, e->key.c_str(), keysize, false);
1200  writeZipBlock(fp, &datatype, sizeof(datatype), false);
1201  writeZipBlock(fp, &datasize, sizeof(datasize), false);
1202  writeZipBlock(fp, &zipsize, sizeof(zipsize), false);
1204  (uint32_t)(sizeof(keysize) + (size_t)keysize + sizeof(datatype) +
1205  sizeof(datasize) + sizeof(zipsize));
1206  }
1207  _extheader.lmdheaderzipsize = writeZipBlock(fp, 0, 0, /*finish*/ true);
1208 
1209  // copy data records
1210  for (int i = 0; i < nLmd; i++) {
1212  copyBlock(fp, _tmpfp, lmdoffset[i], lmdzipsize[i]);
1213  }
1214  }
1215 }
1216 
1217 
1218 PtexIncrWriter::PtexIncrWriter(const char* path, FILE* fp,
1220  int nchannels, int alphachan, int nfaces)
1221  : PtexWriterBase(path, mt, dt, nchannels, alphachan, nfaces,
1222  /* compress */ false),
1223  _fp(fp)
1224 {
1225  // note: incremental saves are not compressed (see compress flag above)
1226  // to improve save time in the case where in incremental save is followed by
1227  // a full save (which ultimately it always should be). With a compressed
1228  // incremental save, the data would be compressed twice and decompressed once
1229  // on every save vs. just compressing once.
1230 
1231  // make sure existing header matches
1232  if (!fread(&_header, HeaderSize, 1, fp) || _header.magic != Magic) {
1233  std::stringstream str;
1234  str << "Not a ptex file: " << path;
1235  setError(str.str());
1236  return;
1237  }
1238 
1239  bool headerMatch = (mt == _header.meshtype &&
1240  dt == datatype() &&
1241  nchannels == _header.nchannels &&
1242  alphachan == int(_header.alphachan) &&
1243  nfaces == int(_header.nfaces));
1244  if (!headerMatch) {
1245  std::stringstream str;
1246  str << "PtexWriter::edit error: header doesn't match existing file, "
1247  << "conversions not currently supported";
1248  setError(str.str());
1249  return;
1250  }
1251 
1252  // read extended header
1253  memset(&_extheader, 0, sizeof(_extheader));
1254  if (!fread(&_extheader, PtexUtils::min(uint32_t(ExtHeaderSize), _header.extheadersize), 1, fp)) {
1255  std::stringstream str;
1256  str << "Error reading extended header: " << path;
1257  setError(str.str());
1258  return;
1259  }
1260 
1261  // seek to end of file to append
1262  fseeko(_fp, 0, SEEK_END);
1263 }
1264 
1265 
1267 {
1268 }
1269 
1270 
1271 bool PtexIncrWriter::writeFace(int faceid, const FaceInfo& f, const void* data, int stride)
1272 {
1273  if (stride == 0) stride = f.res.u()*_pixelSize;
1274 
1275  // handle constant case
1276  if (PtexUtils::isConstant(data, stride, f.res.u(), f.res.v(), _pixelSize))
1277  return writeConstantFace(faceid, f, data);
1278 
1279  // init headers
1280  uint8_t edittype = et_editfacedata;
1281  uint32_t editsize;
1282  EditFaceDataHeader efdh;
1283  efdh.faceid = faceid;
1284 
1285  // check and store face info
1286  if (!storeFaceInfo(faceid, efdh.faceinfo, f))
1287  return 0;
1288 
1289  // record position and skip headers
1290  FilePos pos = ftello(_fp);
1291  writeBlank(_fp, sizeof(edittype) + sizeof(editsize) + sizeof(efdh));
1292 
1293  // must compute constant (average) val first
1294  uint8_t* constval = new uint8_t [_pixelSize];
1295 
1296  if (_header.hasAlpha()) {
1297  // must premult alpha before averaging
1298  // first copy to temp buffer
1299  int rowlen = f.res.u() * _pixelSize, nrows = f.res.v();
1300  uint8_t* temp = new uint8_t [rowlen * nrows];
1301  PtexUtils::copy(data, stride, temp, rowlen, nrows, rowlen);
1302 
1303  // multiply alpha
1304  PtexUtils::multalpha(temp, f.res.size(), datatype(), _header.nchannels,
1305  _header.alphachan);
1306  // average
1307  PtexUtils::average(temp, rowlen, f.res.u(), f.res.v(), constval,
1309  // unmult alpha
1311  _header.alphachan);
1312  delete [] temp;
1313  }
1314  else {
1315  // average
1316  PtexUtils::average(data, stride, f.res.u(), f.res.v(), constval,
1318  }
1319  // write const val
1320  writeBlock(_fp, constval, _pixelSize);
1321  delete [] constval;
1322 
1323  // write face data
1324  writeFaceData(_fp, data, stride, f.res, efdh.fdh);
1325 
1326  // update editsize in header
1327  editsize = (uint32_t)(sizeof(efdh) + (size_t)_pixelSize + efdh.fdh.blocksize());
1328 
1329  // rewind and write headers
1330  fseeko(_fp, pos, SEEK_SET);
1331  writeBlock(_fp, &edittype, sizeof(edittype));
1332  writeBlock(_fp, &editsize, sizeof(editsize));
1333  writeBlock(_fp, &efdh, sizeof(efdh));
1334  fseeko(_fp, 0, SEEK_END);
1335  return 1;
1336 }
1337 
1338 
1339 bool PtexIncrWriter::writeConstantFace(int faceid, const FaceInfo& f, const void* data)
1340 {
1341  // init headers
1342  uint8_t edittype = et_editfacedata;
1343  uint32_t editsize;
1344  EditFaceDataHeader efdh;
1345  efdh.faceid = faceid;
1346  efdh.fdh.set(0, enc_constant);
1347  editsize = (uint32_t)sizeof(efdh) + _pixelSize;
1348 
1349  // check and store face info
1350  if (!storeFaceInfo(faceid, efdh.faceinfo, f, FaceInfo::flag_constant))
1351  return 0;
1352 
1353  // write headers
1354  writeBlock(_fp, &edittype, sizeof(edittype));
1355  writeBlock(_fp, &editsize, sizeof(editsize));
1356  writeBlock(_fp, &efdh, sizeof(efdh));
1357  // write data
1358  writeBlock(_fp, data, _pixelSize);
1359  return 1;
1360 }
1361 
1362 
1364 {
1365  // init headers
1366  uint8_t edittype = et_editmetadata;
1367  uint32_t editsize;
1368  EditMetaDataHeader emdh;
1369  emdh.metadatazipsize = 0;
1370  emdh.metadatamemsize = 0;
1371 
1372  // record position and skip headers
1373  FilePos pos = ftello(_fp);
1374  writeBlank(_fp, sizeof(edittype) + sizeof(editsize) + sizeof(emdh));
1375 
1376  // write meta data
1377  for (size_t i = 0, n = _metadata.size(); i < n; i++) {
1378  MetaEntry& e = _metadata[i];
1380  }
1381  // finish zip block
1382  emdh.metadatazipsize = writeZipBlock(_fp, 0, 0, /*finish*/ true);
1383 
1384  // update headers
1385  editsize = (uint32_t)(sizeof(emdh) + emdh.metadatazipsize);
1386 
1387  // rewind and write headers
1388  fseeko(_fp, pos, SEEK_SET);
1389  writeBlock(_fp, &edittype, sizeof(edittype));
1390  writeBlock(_fp, &editsize, sizeof(editsize));
1391  writeBlock(_fp, &emdh, sizeof(emdh));
1392  fseeko(_fp, 0, SEEK_END);
1393 }
1394 
1395 
1397 {
1398  // closing base writer will write all pending data via finish() method
1399  bool result = PtexWriterBase::close(error);
1400  if (_fp) {
1401  fclose(_fp);
1402  _fp = 0;
1403  }
1404  return result;
1405 }
1406 
1407 
1409 {
1410  // write meta data edit block (if any)
1411  if (!_metadata.empty()) writeMetaDataEdit();
1412 
1413  // rewrite extheader for updated editdatasize
1414  if (_extheader.editdatapos) {
1415  _extheader.editdatasize = uint64_t(ftello(_fp)) - _extheader.editdatapos;
1416  fseeko(_fp, HeaderSize, SEEK_SET);
1417  fwrite(&_extheader, PtexUtils::min(uint32_t(ExtHeaderSize), _header.extheadersize), 1, _fp);
1418  }
1419 }
1420 
const uint32_t Magic
Definition: PtexIO.h:104
const int ExtHeaderSize
Definition: PtexIO.h:106
const int AllocaMax
Definition: PtexIO.h:116
const int HeaderSize
Definition: PtexIO.h:105
const int LevelInfoSize
Definition: PtexIO.h:107
const int BlockSize
Definition: PtexIO.h:114
bool LittleEndian()
Definition: PtexIO.h:119
@ et_editfacedata
Definition: PtexIO.h:92
@ et_editmetadata
Definition: PtexIO.h:92
const int TileSize
Definition: PtexIO.h:115
@ enc_diffzipped
Definition: PtexIO.h:81
@ enc_zipped
Definition: PtexIO.h:81
@ enc_constant
Definition: PtexIO.h:81
@ enc_tiled
Definition: PtexIO.h:81
const int MetaDataThreshold
Definition: PtexIO.h:117
Platform-specific classes, functions, and includes.
off_t FilePos
Definition: PtexPlatform.h:89
#define PTEX_NAMESPACE_END
Definition: PtexVersion.h:62
#define PtexFileMinorVersion
Definition: PtexVersion.h:41
#define PtexFileMajorVersion
Definition: PtexVersion.h:40
Public API classes for reading, writing, caching, and filtering Ptex files.
Automatically acquire and release lock within enclosing scope.
Definition: PtexMutex.h:43
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 void finish()
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 writeMetaDataEdit()
void generateReductions()
std::string _tmppath
Definition: PtexWriter.h:155
std::vector< uint8_t > _constdata
Definition: PtexWriter.h:160
std::string _newpath
Definition: PtexWriter.h:154
std::vector< uint32_t > _rfaceids
Definition: PtexWriter.h:161
virtual bool close(Ptex::String &error)
Close the file.
Definition: PtexWriter.cpp:781
virtual bool writeConstantFace(int faceid, const FaceInfo &f, const void *data)
Definition: PtexWriter.cpp:864
PtexReader * _reader
Definition: PtexWriter.h:177
virtual void finish()
Definition: PtexWriter.cpp:891
std::vector< uint32_t > _faceids_r
Definition: PtexWriter.h:162
void storeConstValue(int faceid, const void *data, int stride, Res res)
Definition: PtexWriter.cpp:879
std::vector< FaceInfo > _faceinfo
Definition: PtexWriter.h:159
void writeMetaData(FILE *fp)
virtual ~PtexMainWriter()
Definition: PtexWriter.cpp:775
static const int MinReductionLog2
Definition: PtexWriter.h:164
virtual bool writeFace(int faceid, const FaceInfo &f, const void *data, int stride)
Definition: PtexWriter.cpp:807
PtexMainWriter(const char *path, PtexTexture *tex, Ptex::MeshType mt, Ptex::DataType dt, int nchannels, int alphachan, int nfaces, bool genmipmaps)
Definition: PtexWriter.cpp:724
std::vector< FilePos > _rpos
Definition: PtexWriter.h:175
std::vector< LevelRec > _levels
Definition: PtexWriter.h:174
void flagConstantNeighorhoods()
Definition: PtexWriter.cpp:997
Meta data accessor.
Definition: Ptexture.h:341
virtual int numKeys()=0
Query number of meta data entries stored in file.
virtual void getValue(const char *key, const char *&value)=0
Query the value of a given meta data entry.
virtual void getKey(int index, const char *&key, Ptex::MetaDataType &type)=0
Query the name and type of a meta data entry.
Smart-pointer for acquiring and releasing API objects.
Definition: Ptexture.h:1045
virtual void release()
Release resources held by this pointer (pointer becomes invalid).
Definition: PtexReader.h:56
virtual PtexMetaData * getMetaData()
Access meta data.
Definition: PtexReader.cpp:335
virtual void getData(int faceid, void *buffer, int stride)
Access texture data for a face at highest-resolution.
Definition: PtexReader.cpp:711
virtual const Ptex::FaceInfo & getFaceInfo(int faceid)
Access resolution and adjacency information about a face.
Definition: PtexReader.cpp:267
virtual bool hasEdits()
True if the file has edit blocks.
Definition: PtexReader.h:98
Interface for reading data from a ptex file.
Definition: Ptexture.h:470
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.
Definition: PtexReader.cpp:59
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
Definition: PtexWriter.h:122
DataType datatype() const
Definition: PtexWriter.h:80
int writeBlank(FILE *fp, int size)
Definition: PtexWriter.cpp:488
virtual void setEdgeFilterMode(Ptex::EdgeFilterMode edgeFilterMode)
Set edge filter mode.
Definition: PtexWriter.h:57
std::string _path
Definition: PtexWriter.h:115
int copyBlock(FILE *dst, FILE *src, FilePos pos, int size)
Definition: PtexWriter.cpp:552
void setError(const std::string &error)
Definition: PtexWriter.h:110
int writeZipBlock(FILE *fp, const void *data, int size, bool finish=true)
Definition: PtexWriter.cpp:511
virtual void writeMeta(const char *key, const char *value)
Write a string as meta data.
Definition: PtexWriter.cpp:362
z_stream_s _zstream
Definition: PtexWriter.h:123
virtual void finish()=0
virtual void addMetaData(const char *key, MetaDataType t, const void *value, int size)
Definition: PtexWriter.cpp:454
virtual void release()
Release resources held by this pointer (pointer becomes invalid).
Definition: PtexWriter.cpp:302
int writeBlock(FILE *fp, const void *data, int size)
Definition: PtexWriter.cpp:500
FILE * _tilefp
Definition: PtexWriter.h:117
std::string _tilepath
Definition: PtexWriter.h:116
virtual bool close(Ptex::String &error)
Close the file.
Definition: PtexWriter.cpp:317
void writeFaceData(FILE *fp, const void *data, int stride, Res res, FaceDataHeader &fdh)
Definition: PtexWriter.cpp:630
int readBlock(FILE *fp, void *data, int size)
Definition: PtexWriter.cpp:542
std::vector< MetaEntry > _metadata
Definition: PtexWriter.h:121
void writeConstFaceBlock(FILE *fp, const void *data, FaceDataHeader &fdh)
Definition: PtexWriter.cpp:593
int writeMetaDataBlock(FILE *fp, MetaEntry &val)
Definition: PtexWriter.cpp:708
ExtHeader _extheader
Definition: PtexWriter.h:119
PtexUtils::ReduceFn * _reduceFn
Definition: PtexWriter.h:125
void writeReduction(FILE *fp, const void *data, int stride, Res res)
Definition: PtexWriter.cpp:691
bool storeFaceInfo(int faceid, FaceInfo &dest, const FaceInfo &src, int flags=0)
Definition: PtexWriter.cpp:330
virtual void setBorderModes(Ptex::BorderMode uBorderMode, Ptex::BorderMode vBorderMode)
Set border modes.
Definition: PtexWriter.h:52
virtual ~PtexWriterBase()
Definition: PtexWriter.cpp:311
void getError(Ptex::String &error)
Definition: PtexWriter.h:75
PtexWriterBase(const char *path, Ptex::MeshType mt, Ptex::DataType dt, int nchannels, int alphachan, int nfaces, bool compress)
Definition: PtexWriter.cpp:262
Header _header
Definition: PtexWriter.h:118
bool ok(Ptex::String &error)
Definition: PtexWriter.h:71
void writeFaceBlock(FILE *fp, const void *data, int stride, Res res, FaceDataHeader &fdh)
Definition: PtexWriter.cpp:603
Res calcTileRes(Res faceres)
Definition: PtexWriter.cpp:571
Interface for writing data to a ptex file.
Definition: Ptexture.h:823
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.
Definition: PtexWriter.cpp:187
static bool applyEdits(const char *path, Ptex::String &error)
Apply edits to a file.
Definition: PtexWriter.cpp:243
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.
Definition: PtexWriter.cpp:168
Memory-managed string.
Definition: Ptexture.h:309
const char * c_str() const
Definition: Ptexture.h:317
bool checkFormat(Ptex::MeshType mt, Ptex::DataType dt, int nchannels, int alphachan, Ptex::String &error)
Definition: PtexWriter.cpp:134
std::string fileError(const char *message, const char *path)
Definition: PtexWriter.cpp:127
FILE * OpenTempFile(std::string &tmppath)
Definition: PtexWriter.cpp:79
void genRfaceids(const FaceInfo *faces, int nfaces, uint32_t *rfaceids, uint32_t *faceids)
Definition: PtexUtils.cpp:624
bool isConstant(const void *data, int stride, int ures, int vres, int pixelSize)
Definition: PtexUtils.cpp:141
T min(T a, T b)
Definition: PtexUtils.h:147
void divalpha(void *data, int npixels, DataType dt, int nchannels, int alphachan)
Definition: PtexUtils.cpp:612
void encodeDifference(void *data, int size, DataType dt)
Definition: PtexUtils.cpp:245
void reduce(const void *src, int sstride, int uw, int vw, void *dst, int dstride, DataType dt, int nchan)
Definition: PtexUtils.cpp:293
void deinterleave(const void *src, int sstride, int uw, int vw, void *dst, int dstride, DataType dt, int nchan)
Definition: PtexUtils.cpp:220
T max(T a, T b)
Definition: PtexUtils.h:150
void reduceTri(const void *src, int sstride, int w, int, void *dst, int dstride, DataType dt, int nchan)
Definition: PtexUtils.cpp:400
void copy(const void *src, int sstride, void *dst, int dstride, int vres, int rowlen)
Definition: PtexUtils.cpp:432
uint32_t floor_log2(uint32_t x)
Definition: PtexUtils.h:68
void multalpha(void *data, int npixels, DataType dt, int nchannels, int alphachan)
Definition: PtexUtils.cpp:573
void average(const void *src, int sstride, int uw, int vw, void *dst, DataType dt, int nchan)
Definition: PtexUtils.cpp:516
int DataSize(DataType dt)
Look up size of given data type (in bytes).
Definition: Ptexture.h:143
DataType
Type of data stored in texture file.
Definition: Ptexture.h:85
@ dt_float
Single-precision (32-bit) floating point.
Definition: Ptexture.h:89
@ dt_uint16
Unsigned, 16-bit integer.
Definition: Ptexture.h:87
@ dt_uint8
Unsigned, 8-bit integer.
Definition: Ptexture.h:86
MeshType
Type of base mesh for which the textures are defined.
Definition: Ptexture.h:79
@ mt_triangle
Mesh is triangle-based.
Definition: Ptexture.h:80
@ mt_quad
Mesh is quad-based.
Definition: Ptexture.h:81
@ m_clamp
texel access is clamped to border
Definition: Ptexture.h:100
MetaDataType
Type of meta data entry.
Definition: Ptexture.h:115
@ mdt_string
Null-terminated string.
Definition: Ptexture.h:116
@ mdt_float
Single-precision (32-bit) floating point.
Definition: Ptexture.h:120
@ mdt_int32
Signed 32-bit integer.
Definition: Ptexture.h:119
@ mdt_int8
Signed 8-bit integer.
Definition: Ptexture.h:117
@ mdt_double
Double-precision (32-bit) floating point.
Definition: Ptexture.h:121
@ mdt_int16
Signed 16-bit integer.
Definition: Ptexture.h:118
uint32_t faceid
Definition: PtexIO.h:94
FaceDataHeader fdh
Definition: PtexIO.h:96
FaceInfo faceinfo
Definition: PtexIO.h:95
uint32_t metadatazipsize
Definition: PtexIO.h:99
uint32_t metadatamemsize
Definition: PtexIO.h:100
uint16_t vbordermode
Definition: PtexIO.h:67
uint16_t ubordermode
Definition: PtexIO.h:65
uint64_t lmddatasize
Definition: PtexIO.h:71
uint64_t editdatapos
Definition: PtexIO.h:73
uint32_t lmdheadermemsize
Definition: PtexIO.h:70
uint32_t lmdheaderzipsize
Definition: PtexIO.h:69
uint64_t editdatasize
Definition: PtexIO.h:72
void set(uint32_t blocksizeArg, Encoding encodingArg)
Definition: PtexIO.h:88
uint32_t blocksize() const
Definition: PtexIO.h:84
uint32_t metadatamemsize
Definition: PtexIO.h:60
uint32_t faceinfosize
Definition: PtexIO.h:54
uint16_t nlevels
Definition: PtexIO.h:51
uint16_t nchannels
Definition: PtexIO.h:50
uint32_t meshtype
Definition: PtexIO.h:47
uint32_t constdatasize
Definition: PtexIO.h:55
uint32_t levelinfosize
Definition: PtexIO.h:56
uint32_t extheadersize
Definition: PtexIO.h:53
uint32_t minorversion
Definition: PtexIO.h:57
uint32_t metadatazipsize
Definition: PtexIO.h:59
uint32_t datatype
Definition: PtexIO.h:48
int pixelSize() const
Definition: PtexIO.h:61
int32_t alphachan
Definition: PtexIO.h:49
uint32_t magic
Definition: PtexIO.h:45
uint32_t nfaces
Definition: PtexIO.h:52
uint64_t leveldatasize
Definition: PtexIO.h:58
uint32_t version
Definition: PtexIO.h:46
bool hasAlpha() const
Definition: PtexIO.h:62
uint32_t levelheadersize
Definition: PtexIO.h:77
uint64_t leveldatasize
Definition: PtexIO.h:76
uint32_t nfaces
Definition: PtexIO.h:78
std::vector< FilePos > pos
Definition: PtexWriter.h:171
std::vector< FaceDataHeader > fdh
Definition: PtexWriter.h:172
std::vector< uint8_t > data
Definition: PtexWriter.h:85
Information about a face, as stored in the Ptex file header.
Definition: Ptexture.h:242
Res res
Resolution of face.
Definition: Ptexture.h:243
bool isConstant() const
Determine if face is constant (by checking a flag).
Definition: Ptexture.h:275
Pixel resolution of a given texture.
Definition: Ptexture.h:172
int size() const
Total size of specified texture in texels (u * v).
Definition: Ptexture.h:195
int u() const
U resolution in texels.
Definition: Ptexture.h:186