Ptex: PtexWriter.cpp Source File

Ptex

- Main Page
- Related Pages
- Namespaces
- Classes
- Files

- File List
- File Members

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,
167 Ptex::MeshType mt, Ptex::DataType dt,
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,
187 Ptex::MeshType mt, Ptex::DataType dt,
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
262 PtexWriterBase::PtexWriterBase(const char* path,
263 Ptex::MeshType mt, Ptex::DataType dt,
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;
272 _header.version = PtexFileMajorVersion;
273 _header.minorversion = PtexFileMinorVersion;
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);
281 _pixelSize = _header.pixelSize();
282
283 memset(&_extheader, 0, sizeof(_extheader));
284
285 if (mt == mt_triangle)
286 _reduceFn = &PtexUtils::reduceTri;
287 else
288 _reduceFn = &PtexUtils::reduce;
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
303 void PtexWriterBase::release()
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
312 PtexWriterBase::~PtexWriterBase()
313 {
314 deflateEnd(&_zstream);
315 }
316
317
318 bool PtexWriterBase::close(Ptex::String& error)
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
354 f.flags &= FaceInfo::flag_subface;
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
399 void PtexWriterBase::writeMeta(PtexMetaData* data)
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
455 void PtexWriterBase::addMetaData(const char* key, MetaDataType t,
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
572 Ptex::Res PtexWriterBase::calcTileRes(Res faceres)
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
599 fdh.set(_pixelSize, enc_constant);
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),
615 _header.datatype, _header.nchannels);
616
617 // difference if needed
618 bool diff = (_header.datatype == dt_uint8 ||
619 _header.datatype == dt_uint16);
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
709 int PtexWriterBase::writeMetaDataBlock(FILE* fp, MetaEntry& val)
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
725 PtexMainWriter::PtexMainWriter(const char* path, PtexTexture* tex,
726 Ptex::MeshType mt, Ptex::DataType dt,
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
764 PtexPtr<PtexMetaData> meta ( _reader->getMetaData() );
765 writeMeta(meta);
766
767 // see if we have any edits
768 _hasNewData = _reader->hasEdits();
769 }
770 }
771
772
773 PtexMainWriter::~PtexMainWriter()
774 {
775 if (_reader) _reader->release();
776 }
777
778
779 bool PtexMainWriter::close(Ptex::String& error)
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
837 PtexUtils::multalpha(temp, f.res.size(), _header.datatype, _header.nchannels,
838 _header.alphachan);
839
840 // override source buffer
841 data = temp;
842 stride = rowlen;
843 }
844
845 // generate first reduction (if needed)
846 if (_genmipmaps &&
847 (f.res.ulog2 > MinReductionLog2 && f.res.vlog2 > MinReductionLog2))
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,
882 _header.datatype, _header.nchannels);
883 if (_header.hasAlpha())
884 PtexUtils::divalpha(constdata, 1, _header.datatype, _header.nchannels, _header.alphachan);
885 }
886
887
888
889 void PtexMainWriter::finish()
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()) {
902 PtexPtr<PtexFaceData> data ( _reader->getData(i) );
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))
919 _faceinfo[i].flags = FaceInfo::flag_constant;
920 }
921 }
922
923 // write reductions to tmp file
924 if (_genmipmaps)
925 generateReductions();
926
927 // flag faces w/ constant neighborhoods
928 flagConstantNeighorhoods();
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
946 _header.faceinfosize = writeZipBlock(newfp, &_faceinfo[0],
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);
954 writeBlank(newfp, LevelInfoSize * _header.nlevels);
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());
972 _header.leveldatasize += info.leveldatasize;
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);
990 writeBlock(newfp, &_extheader, ExtHeaderSize);
991 fclose(newfp);
992 }
993
994
995 void PtexMainWriter::flagConstantNeighorhoods()
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
1059 void PtexMainWriter::generateReductions()
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
1130 void PtexMainWriter::writeMetaData(FILE* fp)
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
1146 _header.metadatamemsize += writeMetaDataBlock(fp, e);
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);
1182 _extheader.lmdheadermemsize +=
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++) {
1190 _extheader.lmddatasize +=
1191 copyBlock(fp, _tmpfp, lmdoffset[i], lmdzipsize[i]);
1192 }
1193 }
1194 }
1195
1196
1197 PtexIncrWriter::PtexIncrWriter(const char* path, FILE* fp,
1198 Ptex::MeshType mt, Ptex::DataType dt,
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
1245 PtexIncrWriter::~PtexIncrWriter()
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
1283 PtexUtils::multalpha(temp, f.res.size(), _header.datatype, _header.nchannels,
1284 _header.alphachan);
1285 // average
1286 PtexUtils::average(temp, rowlen, f.res.u(), f.res.v(), constval,
1287 _header.datatype, _header.nchannels);
1288 // unmult alpha
1289 PtexUtils::divalpha(constval, 1, _header.datatype, _header.nchannels,
1290 _header.alphachan);
1291 free(temp);
1292 }
1293 else {
1294 // average
1295 PtexUtils::average(data, stride, f.res.u(), f.res.v(), constval,
1296 _header.datatype, _header.nchannels);
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
1342 void PtexIncrWriter::writeMetaDataEdit()
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];
1358 emdh.metadatamemsize += writeMetaDataBlock(_fp, e);
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
1375 bool PtexIncrWriter::close(Ptex::String& error)
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
1387 void PtexIncrWriter::finish()
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 }
Ptex::mdt_float
Single-precision (32-bit) floating point.
Definition: Ptexture.h:112
PtexIO::LevelInfo::leveldatasize
uint64_t leveldatasize
Definition: PtexIO.h:72
PtexIO::FaceDataHeader::set
void set(uint32_t blocksize, Encoding encoding)
Definition: PtexIO.h:84
Ptex::mt_quad
Mesh is quad-based.
Definition: Ptexture.h:79
PtexTexture::vBorderMode
virtual Ptex::BorderMode vBorderMode()=0
Mode for filtering texture access beyond mesh border.
PtexMetaData::getKey
virtual void getKey(int n, const char *&key, Ptex::MetaDataType &type)=0
Query the name and type of a meta data entry.
PtexIO::Header::meshtype
MeshType meshtype
Definition: PtexIO.h:45
PtexIO::ExtHeader::editdatapos
uint64_t editdatapos
Definition: PtexIO.h:69
PtexWriterBase::_tilepath
std::string _tilepath
Definition: PtexWriter.h:109
Ptex::mdt_int8
Signed 8-bit integer.
Definition: Ptexture.h:109
PtexIO::EditFaceDataHeader::faceinfo
FaceInfo faceinfo
Definition: PtexIO.h:91
PtexIO::Header::nfaces
uint32_t nfaces
Definition: PtexIO.h:50
Ptex::Res::ntilesv
int ntilesv(Res tileres) const
Determine the number of tiles in the v direction for the given tile res.
Definition: Ptexture.h:217
Ptex::FaceInfo::adjface
int adjface(int eid) const
Access an adjacent face id. The eid value must be 0..3.
Definition: Ptexture.h:267
PtexTexture::numChannels
virtual int numChannels()=0
Number of channels stored in file.
PtexIO::Header::levelinfosize
uint32_t levelinfosize
Definition: PtexIO.h:54
PtexWriter
Interface for writing data to a ptex file.
Definition: Ptexture.h:737
PtexWriterBase::getError
void getError(Ptex::String &error)
Definition: PtexWriter.h:70
Ptex::dt_uint8
Unsigned, 8-bit integer.
Definition: Ptexture.h:84
PtexWriterBase::storeFaceInfo
bool storeFaceInfo(int faceid, FaceInfo &dest, const FaceInfo &src, int flags=0)
Definition: PtexWriter.cpp:331
PtexWriterBase::~PtexWriterBase
virtual ~PtexWriterBase()
Definition: PtexWriter.cpp:312
PtexIncrWriter::close
virtual bool close(Ptex::String &error)
Close the file.
Definition: PtexWriter.cpp:1375
PtexWriterBase::MetaEntry
Definition: PtexWriter.h:75
PtexWriterBase::release
virtual void release()
Release resources held by this pointer (pointer becomes invalid).
Definition: PtexWriter.cpp:303
PtexWriterBase::writeReduction
void writeReduction(FILE *fp, const void *data, int stride, Res res)
Definition: PtexWriter.cpp:692
PtexUtils::multalpha
static void multalpha(void *data, int npixels, DataType dt, int nchannels, int alphachan)
Definition: PtexUtils.cpp:562
PtexIO::FaceDataHeader
Definition: PtexIO.h:78
PtexReader::hasEdits
virtual bool hasEdits()
True if the file has edit blocks.
Definition: PtexReader.h:88
PtexWriterBase::_extheader
ExtHeader _extheader
Definition: PtexWriter.h:112
PtexReader::release
virtual void release()
Release resources held by this pointer (pointer becomes invalid).
Definition: PtexReader.cpp:170
Ptex::FaceInfo::isConstant
bool isConstant() const
Determine if face is constant (by checking a flag).
Definition: Ptexture.h:270
PtexIO::Header::nlevels
uint16_t nlevels
Definition: PtexIO.h:49
Ptex::dt_uint16
Unsigned, 16-bit integer.
Definition: Ptexture.h:85
Ptex::DataSize
static int DataSize(DataType dt)
Look up size of given data type (in bytes).
Definition: Ptexture.h:132
Ptex::String
Memory-managed string.
Definition: Ptexture.h:303
PtexWriterBase
Definition: PtexWriter.h:49
PtexReader::getFaceInfo
virtual const Ptex::FaceInfo & getFaceInfo(int faceid)
Access resolution and adjacency information about a face.
Definition: PtexReader.cpp:185
PtexTexture::hasEdits
virtual bool hasEdits()=0
True if the file has edit blocks.
PtexMainWriter::LevelRec::fdh
std::vector< FaceDataHeader > fdh
Definition: PtexWriter.h:165
PtexWriterBase::_reduceFn
PtexUtils::ReduceFn * _reduceFn
Definition: PtexWriter.h:118
PtexWriterBase::writeFaceData
void writeFaceData(FILE *fp, const void *data, int stride, Res res, FaceDataHeader &fdh)
Definition: PtexWriter.cpp:631
PtexIO::ExtHeader::lmdheaderzipsize
uint32_t lmdheaderzipsize
Definition: PtexIO.h:65
PtexUtils::reduceTri
static void reduceTri(const void *src, int sstride, int ures, int vres, void *dst, int dstride, DataType dt, int nchannels)
Definition: PtexUtils.cpp:389
PtexIO::AllocaMax
static const int AllocaMax
Definition: PtexIO.h:111
PtexIO::Header::nchannels
uint16_t nchannels
Definition: PtexIO.h:48
Ptex::DataType
DataType
Type of data stored in texture file.
Definition: Ptexture.h:83
PtexIO::EditMetaDataHeader::metadatamemsize
uint32_t metadatamemsize
Definition: PtexIO.h:96
PtexMetaData
Meta data accessor.
Definition: Ptexture.h:337
PtexIO::HeaderSize
static const int HeaderSize
Definition: PtexIO.h:100
PtexIncrWriter::finish
virtual void finish()
Definition: PtexWriter.cpp:1387
Ptex::FaceInfo::flags
uint8_t flags
Flags.
Definition: Ptexture.h:240
PtexWriterBase::_ok
bool _ok
Definition: PtexWriter.h:106
PtexMainWriter::LevelRec
Definition: PtexWriter.h:158
PtexMainWriter::writeMetaData
void writeMetaData(FILE *fp)
Definition: PtexWriter.cpp:1130
PtexUtils::average
static void average(const void *src, int sstride, int ures, int vres, void *dst, DataType dt, int nchannels)
Definition: PtexUtils.cpp:505
PtexWriterBase::ok
bool ok(Ptex::String &error)
Definition: PtexWriter.h:66
PtexUtils::min
static T min(T a, T b)
Definition: PtexUtils.h:116
Ptex::mt_triangle
Mesh is triangle-based.
Definition: Ptexture.h:78
PtexIO::Header::constdatasize
uint32_t constdatasize
Definition: PtexIO.h:53
PtexIO::Header::pixelSize
int pixelSize() const
Definition: PtexIO.h:59
PtexMainWriter::_rfaceids
std::vector< uint32_t > _rfaceids
Definition: PtexWriter.h:154
PtexWriterBase::setBorderModes
virtual void setBorderModes(Ptex::BorderMode uBorderMode, Ptex::BorderMode vBorderMode)
Set border modes.
Definition: PtexWriter.h:51
PtexMainWriter::writeConstantFace
virtual bool writeConstantFace(int faceid, const FaceInfo &f, const void *data)
Write constant texture data for a face.
Definition: PtexWriter.cpp:862
PtexWriterBase::_pixelSize
int _pixelSize
Definition: PtexWriter.h:113
PtexIO::Header::faceinfosize
uint32_t faceinfosize
Definition: PtexIO.h:52
PtexMainWriter::storeConstValue
void storeConstValue(int faceid, const void *data, int stride, Res res)
Definition: PtexWriter.cpp:877
PtexUtils::copy
static void copy(const void *src, int sstride, void *dst, int dstride, int nrows, int rowlen)
Definition: PtexUtils.cpp:421
PtexIO::LevelInfoSize
static const int LevelInfoSize
Definition: PtexIO.h:102
PtexWriterBase::_path
std::string _path
Definition: PtexWriter.h:108
PtexReader::getMetaData
virtual PtexMetaData * getMetaData()
Access meta data.
Definition: PtexReader.cpp:255
PtexMainWriter::_faceinfo
std::vector< FaceInfo > _faceinfo
Definition: PtexWriter.h:152
PtexIO::et_editfacedata
Definition: PtexIO.h:88
Ptex::mdt_string
Null-terminated string.
Definition: Ptexture.h:108
PtexPlatform.h
Platform-specific classes, functions, and includes.
PtexMainWriter::_newpath
std::string _newpath
Definition: PtexWriter.h:147
PtexMainWriter::generateReductions
void generateReductions()
Definition: PtexWriter.cpp:1059
PtexMainWriter::close
virtual bool close(Ptex::String &error)
Close the file.
Definition: PtexWriter.cpp:779
Ptex::MetaDataType
MetaDataType
Type of meta data entry.
Definition: Ptexture.h:107
Ptex::Res::v
int v() const
V resolution in texels.
Definition: Ptexture.h:181
PtexIO::Header::metadatazipsize
uint32_t metadatazipsize
Definition: PtexIO.h:57
PtexTexture::alphaChannel
virtual int alphaChannel()=0
Index of alpha channel (if any).
PtexIO::EditFaceDataHeader
Definition: PtexIO.h:89
PtexWriter::open
static PtexWriter * open(const char *path, Ptex::MeshType mt, Ptex::DataType dt, int nchannels, int alphachan, int nfaces, Ptex::String &error, bool genmipmaps=true)
Open a new texture file for writing.
Definition: PtexWriter.cpp:166
PtexMainWriter::MinReductionLog2
static const int MinReductionLog2
Definition: PtexWriter.h:157
PtexWriterBase::writeMetaDataBlock
int writeMetaDataBlock(FILE *fp, MetaEntry &val)
Definition: PtexWriter.cpp:709
PtexFileMinorVersion
#define PtexFileMinorVersion
Definition: Ptexture.h:70
PtexIncrWriter::_fp
FILE * _fp
Definition: PtexWriter.h:190
PtexMainWriter::finish
virtual void finish()
Definition: PtexWriter.cpp:889
PtexInternal::_Mutex
Definition: PtexPlatform.h:120
PtexIO::enc_constant
Definition: PtexIO.h:77
FilePos
off_t FilePos
Definition: PtexPlatform.h:85
PtexWriterBase::_zstream
z_stream_s _zstream
Definition: PtexWriter.h:116
PtexMainWriter::_reader
PtexReader * _reader
Definition: PtexWriter.h:170
Ptex::FaceInfo::adjfaces
int32_t adjfaces[4]
Adjacent faces (-1 == no adjacent face).
Definition: Ptexture.h:241
PtexIO::LevelInfo::levelheadersize
uint32_t levelheadersize
Definition: PtexIO.h:73
PtexWriterBase::setError
void setError(const std::string &error)
Definition: PtexWriter.h:103
PtexIO::EditMetaDataHeader::metadatazipsize
uint32_t metadatazipsize
Definition: PtexIO.h:95
PtexTexture::meshType
virtual Ptex::MeshType meshType()=0
Type of mesh for which texture data is defined.
PtexIO::ExtHeader::lmdheadermemsize
uint32_t lmdheadermemsize
Definition: PtexIO.h:66
PtexWriterBase::writeZipBlock
int writeZipBlock(FILE *fp, const void *data, int size, bool finish=true)
Definition: PtexWriter.cpp:512
PtexIO::FaceDataHeader::blocksize
uint32_t blocksize() const
Definition: PtexIO.h:80
PtexIO::ExtHeaderSize
static const int ExtHeaderSize
Definition: PtexIO.h:101
Ptex::Res::u
int u() const
U resolution in texels.
Definition: Ptexture.h:178
Ptex::Res::vlog2
int8_t vlog2
log base 2 of v resolution, in texels
Definition: Ptexture.h:163
PtexUtils::genRfaceids
static void genRfaceids(const FaceInfo *faces, int nfaces, uint32_t *rfaceids, uint32_t *faceids)
Definition: PtexUtils.cpp:613
Ptex::Res::ntilesu
int ntilesu(Res tileres) const
Determine the number of tiles in the u direction for the given tile res.
Definition: Ptexture.h:214
PtexIncrWriter::writeConstantFace
virtual bool writeConstantFace(int faceid, const FaceInfo &f, const void *data)
Write constant texture data for a face.
Definition: PtexWriter.cpp:1318
PtexIO::MetaDataThreshold
static const int MetaDataThreshold
Definition: PtexIO.h:112
PtexIO::Header::version
uint32_t version
Definition: PtexIO.h:44
PtexWriterBase::_tilefp
FILE * _tilefp
Definition: PtexWriter.h:110
Ptex::dt_float
Single-precision (32-bit) floating point.
Definition: Ptexture.h:87
PtexIO::LevelInfo::nfaces
uint32_t nfaces
Definition: PtexIO.h:74
PtexIO::Header::hasAlpha
bool hasAlpha() const
Definition: PtexIO.h:60
Ptex::FaceInfo::isSubface
bool isSubface() const
Determine if face is a subface (by checking a flag).
Definition: Ptexture.h:279
PtexIncrWriter
Definition: PtexWriter.h:174
PtexIO::Header::datatype
DataType datatype
Definition: PtexIO.h:46
PtexTexture::hasMipMaps
virtual bool hasMipMaps()=0
True if the file has mipmaps.
PtexWriterBase::copyBlock
int copyBlock(FILE *dst, FILE *src, FilePos pos, int size)
Definition: PtexWriter.cpp:553
PtexReader
Definition: PtexReader.h:72
PtexMainWriter::PtexMainWriter
PtexMainWriter(const char *path, PtexTexture *tex, Ptex::MeshType mt, Ptex::DataType dt, int nchannels, int alphachan, int nfaces, bool genmipmaps)
Definition: PtexWriter.cpp:725
PtexIO::enc_zipped
Definition: PtexIO.h:77
PtexWriterBase::writeBlock
int writeBlock(FILE *fp, const void *data, int size)
Definition: PtexWriter.cpp:501
PtexMainWriter::~PtexMainWriter
virtual ~PtexMainWriter()
Definition: PtexWriter.cpp:773
PtexWriterBase::readBlock
int readBlock(FILE *fp, void *data, int size)
Definition: PtexWriter.cpp:543
PtexWriterBase::addMetaData
virtual void addMetaData(const char *key, MetaDataType t, const void *value, int size)
Definition: PtexWriter.cpp:455
PtexMainWriter::_hasNewData
bool _hasNewData
Definition: PtexWriter.h:150
PtexFileMajorVersion
#define PtexFileMajorVersion
Definition: Ptexture.h:69
PtexWriter.h
PtexTexture::numFaces
virtual int numFaces()=0
Number of faces stored in file.
Ptex::mdt_int32
Signed 32-bit integer.
Definition: Ptexture.h:111
PtexWriterBase::close
virtual bool close(Ptex::String &error)
Close the file.
Definition: PtexWriter.cpp:318
PtexIO::Magic
static const uint32_t Magic
Definition: PtexIO.h:99
PtexIO::Header::magic
uint32_t magic
Definition: PtexIO.h:43
Ptex::MeshType
MeshType
Type of base mesh for which the textures are defined.
Definition: Ptexture.h:77
PtexIO::Header::alphachan
int32_t alphachan
Definition: PtexIO.h:47
PtexReader::getData
virtual void getData(int faceid, void *buffer, int stride)
Access texture data for a face at highest-resolution.
Definition: PtexReader.cpp:759
Ptex::FaceInfo::adjedge
EdgeId adjedge(int eid) const
Access an adjacent edge id. The eid value must be 0..3.
Definition: Ptexture.h:264
PtexIO::TileSize
static const int TileSize
Definition: PtexIO.h:110
PtexIO::Header::minorversion
uint32_t minorversion
Definition: PtexIO.h:55
PtexIO::EditFaceDataHeader::faceid
uint32_t faceid
Definition: PtexIO.h:90
PtexUtils::floor_log2
static uint32_t floor_log2(uint32_t x)
Definition: PtexUtils.h:59
Ptex::Res::size
int size() const
Total size of specified texture in texels (u * v).
Definition: Ptexture.h:190
PtexIncrWriter::writeMetaDataEdit
void writeMetaDataEdit()
Definition: PtexWriter.cpp:1342
PtexWriterBase::PtexWriterBase
PtexWriterBase(const char *path, Ptex::MeshType mt, Ptex::DataType dt, int nchannels, int alphachan, int nfaces, bool compress)
Definition: PtexWriter.cpp:262
PtexUtils::encodeDifference
static void encodeDifference(void *data, int size, DataType dt)
Definition: PtexUtils.cpp:233
PtexTexture::dataType
virtual Ptex::DataType dataType()=0
Type of data stored in file.
PtexTexture::open
static PtexTexture * open(const char *path, Ptex::String &error, bool premultiply=0)
Open a ptex file for reading.
Definition: PtexReader.cpp:46
PtexMainWriter::_rpos
std::vector< FilePos > _rpos
Definition: PtexWriter.h:168
PtexMainWriter::LevelRec::pos
std::vector< FilePos > pos
Definition: PtexWriter.h:164
PtexPtr
Smart-pointer for acquiring and releasing API objects.
Definition: Ptexture.h:955
PtexIO::ExtHeader::lmddatasize
uint64_t lmddatasize
Definition: PtexIO.h:67
PtexMainWriter::writeFace
virtual bool writeFace(int faceid, const FaceInfo &f, const void *data, int stride)
Write texture data for a face.
Definition: PtexWriter.cpp:805
PtexMainWriter::_levels
std::vector< LevelRec > _levels
Definition: PtexWriter.h:167
PtexMainWriter::flagConstantNeighorhoods
void flagConstantNeighorhoods()
Definition: PtexWriter.cpp:995
Ptex::mdt_int16
Signed 16-bit integer.
Definition: Ptexture.h:110
PtexIncrWriter::~PtexIncrWriter
virtual ~PtexIncrWriter()
Definition: PtexWriter.cpp:1245
PtexIO::Header::metadatamemsize
uint32_t metadatamemsize
Definition: PtexIO.h:58
PtexIO::ExtHeader::editdatasize
uint64_t editdatasize
Definition: PtexIO.h:68
Ptex::Res::ulog2
int8_t ulog2
log base 2 of u resolution, in texels
Definition: Ptexture.h:162
PtexIO::Header::extheadersize
uint32_t extheadersize
Definition: PtexIO.h:51
PtexWriterBase::calcTileRes
Res calcTileRes(Res faceres)
Definition: PtexWriter.cpp:572
PtexTexture
Interface for reading data from a ptex file.
Definition: Ptexture.h:439
PtexWriterBase::_header
Header _header
Definition: PtexWriter.h:111
PtexMetaData::numKeys
virtual int numKeys()=0
Query number of meta data entries stored in file.
PtexMainWriter::_genmipmaps
bool _genmipmaps
Definition: PtexWriter.h:151
PtexIO::BlockSize
static const int BlockSize
Definition: PtexIO.h:109
PtexWriter::applyEdits
static bool applyEdits(const char *path, Ptex::String &error)
Apply edits to a file.
Definition: PtexWriter.cpp:242
PtexMainWriter::_faceids_r
std::vector< uint32_t > _faceids_r
Definition: PtexWriter.h:155
Ptex::Res
Pixel resolution of a given texture.
Definition: Ptexture.h:161
PtexUtils::divalpha
static void divalpha(void *data, int npixels, DataType dt, int nchannels, int alphachan)
Definition: PtexUtils.cpp:601
PtexUtils::deinterleave
static void deinterleave(const void *src, int sstride, int ures, int vres, void *dst, int dstride, DataType dt, int nchannels)
Definition: PtexUtils.cpp:208
PtexWriterBase::writeBlank
int writeBlank(FILE *fp, int size)
Definition: PtexWriter.cpp:489
PtexIO::enc_tiled
Definition: PtexIO.h:77
Ptex::FaceInfo::flag_subface
Definition: Ptexture.h:290
PtexWriterBase::finish
virtual void finish()=0
PtexTexture::uBorderMode
virtual Ptex::BorderMode uBorderMode()=0
Mode for filtering texture access beyond mesh border.
PtexMainWriter
Definition: PtexWriter.h:122
Ptex::FaceInfo::res
Res res
Resolution of face.
Definition: Ptexture.h:238
Ptex::FaceInfo::adjedges
uint8_t adjedges
Adjacent edges, 2 bits per edge.
Definition: Ptexture.h:239
PtexInternal::AutoLock
Automatically acquire and release lock within enclosing scope.
Definition: PtexMutex.h:58
PtexIO::EditMetaDataHeader
Definition: PtexIO.h:94
Ptex::FaceInfo
Information about a face, as stored in the Ptex file header.
Definition: Ptexture.h:237
PtexIO::Header::leveldatasize
uint64_t leveldatasize
Definition: PtexIO.h:56
PtexIO::enc_diffzipped
Definition: PtexIO.h:77
PtexWriterBase::_metadata
std::vector< MetaEntry > _metadata
Definition: PtexWriter.h:114
PtexWriter::close
virtual bool close(Ptex::String &error)=0
Close the file.
PtexWriterBase::writeMeta
virtual void writeMeta(const char *key, const char *value)
Write a string as meta data.
Definition: PtexWriter.cpp:363
PtexIncrWriter::PtexIncrWriter
PtexIncrWriter(const char *path, FILE *fp, Ptex::MeshType mt, Ptex::DataType dt, int nchannels, int alphachan, int nfaces)
Definition: PtexWriter.cpp:1197
PtexWriterBase::_metamap
std::map< std::string, int > _metamap
Definition: PtexWriter.h:115
PtexWriterBase::writeConstFaceBlock
void writeConstFaceBlock(FILE *fp, const void *data, FaceDataHeader &fdh)
Definition: PtexWriter.cpp:594
Ptex::FaceInfo::flag_nbconstant
Definition: Ptexture.h:290
PtexIncrWriter::writeFace
virtual bool writeFace(int faceid, const FaceInfo &f, const void *data, int stride)
Write texture data for a face.
Definition: PtexWriter.cpp:1250
PtexMainWriter::_tmppath
std::string _tmppath
Definition: PtexWriter.h:148
PtexMainWriter::_tmpfp
FILE * _tmpfp
Definition: PtexWriter.h:149
PtexWriter::release
virtual void release()=0
Release resources held by this pointer (pointer becomes invalid).
PtexIO::LevelInfo
Definition: PtexIO.h:71
PtexWriterBase::MetaEntry::key
std::string key
Definition: PtexWriter.h:76
PtexWriterBase::writeFaceBlock
void writeFaceBlock(FILE *fp, const void *data, int stride, Res res, FaceDataHeader &fdh)
Definition: PtexWriter.cpp:604
PtexUtils::reduce
static void reduce(const void *src, int sstride, int ures, int vres, void *dst, int dstride, DataType dt, int nchannels)
Definition: PtexUtils.cpp:282
Ptex::mdt_double
Double-precision (32-bit) floating point.
Definition: Ptexture.h:113
PtexUtils.h
PtexWriterBase::MetaEntry::data
std::vector< uint8_t > data
Definition: PtexWriter.h:78
PtexIO::LittleEndian
static bool LittleEndian()
Definition: PtexIO.h:114
Ptex::FaceInfo::flag_constant
Definition: Ptexture.h:290
Ptex::String::c_str
const char * c_str() const
Definition: Ptexture.h:312
PtexIO::et_editmetadata
Definition: PtexIO.h:88
PtexIO::EditFaceDataHeader::fdh
FaceDataHeader fdh
Definition: PtexIO.h:92
PtexMetaData::getValue
virtual void getValue(const char *key, const char *&value)=0
Query the value of a given meta data entry.
PtexUtils::isConstant
static bool isConstant(const void *data, int stride, int ures, int vres, int pixelSize)
Definition: PtexUtils.cpp:129
Ptexture.h
Public API classes for reading, writing, caching, and filtering Ptex files.
PtexWriterBase::MetaEntry::datatype
MetaDataType datatype
Definition: PtexWriter.h:77
PtexMainWriter::_constdata
std::vector< uint8_t > _constdata
Definition: PtexWriter.h:153
PtexWriter::edit
static PtexWriter * edit(const char *path, bool incremental, Ptex::MeshType mt, Ptex::DataType dt, int nchannels, int alphachan, int nfaces, Ptex::String &error, bool genmipmaps=true)
Open an existing texture file for writing.
Definition: PtexWriter.cpp:186
PtexUtils::max
static T max(T a, T b)
Definition: PtexUtils.h:119