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