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