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