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