Ptex

PtexWriter.cpp
Go to the documentation of this file.
1/*
2 PTEX SOFTWARE
3 Copyright 2014 Disney Enterprises, Inc. All rights reserved
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions are
7 met:
8
9 * Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
11
12 * Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions and the following disclaimer in
14 the documentation and/or other materials provided with the
15 distribution.
16
17 * The names "Disney", "Walt Disney Pictures", "Walt Disney Animation
18 Studios" or the names of its contributors may NOT be used to
19 endorse or promote products derived from this software without
20 specific prior written permission from Walt Disney Pictures.
21
22 Disclaimer: THIS SOFTWARE IS PROVIDED BY WALT DISNEY PICTURES AND
23 CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
24 BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
25 FOR A PARTICULAR PURPOSE, NONINFRINGEMENT AND TITLE ARE DISCLAIMED.
26 IN NO EVENT SHALL WALT DISNEY PICTURES, THE COPYRIGHT HOLDER OR
27 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
28 EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
29 PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
30 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND BASED ON ANY
31 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
33 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
34*/
35
36#include "PtexPlatform.h"
37#include <errno.h>
38#include <signal.h>
39#include <stdio.h>
40#include <stdlib.h>
41#include <string.h>
42#include <algorithm>
43#include <iostream>
44#include <sstream>
45#if defined(__FreeBSD__)
46 #include <unistd.h>
47 #include <stddef.h>
48#endif
49#include <libdeflate.h>
50
51#include "Ptexture.h"
52#include "PtexUtils.h"
53#include "PtexWriter.h"
54
55 PTEX_NAMESPACE_BEGIN
56
57 namespace {
58
59 std::string fileError(const char* message, const char* path)
60 {
61 std::stringstream str;
62 str << message << path << "\n" << strerror(errno);
63 return str.str();
64 }
65
66 bool checkFormat(Ptex::MeshType mt, Ptex::DataType dt, int nchannels, int alphachan,
67 Ptex::String& error)
68 {
69 // check to see if given file attributes are valid
70 if (!LittleEndian()) {
71 error = "PtexWriter doesn't currently support big-endian cpu's";
72 return 0;
73 }
74
75 if (mt < Ptex::mt_triangle || mt > Ptex::mt_quad) {
76 error = "PtexWriter error: Invalid mesh type";
77 return 0;
78 }
79
80 if (dt < Ptex::dt_uint8 || dt > Ptex::dt_float) {
81 error = "PtexWriter error: Invalid data type";
82 return 0;
83 }
84
85 if (nchannels <= 0) {
86 error = "PtexWriter error: Invalid number of channels";
87 return 0;
88 }
89
90 if (alphachan != -1 && (alphachan < 0 || alphachan >= nchannels)) {
91 error = "PtexWriter error: Invalid alpha channel";
92 return 0;
93 }
94
95 return 1;
96 }
97}
98
99
100 PtexWriter* PtexWriter::open(const char* path,
101 Ptex::MeshType mt, Ptex::DataType dt,
102 int nchannels, int alphachan, int nfaces,
103 Ptex::String& error, bool genmipmaps)
104{
105 if (!checkFormat(mt, dt, nchannels, alphachan, error))
106 return 0;
107
108 PtexMainWriter* w = new PtexMainWriter(path, 0,
109 mt, dt, nchannels, alphachan, nfaces,
110 genmipmaps);
111 if (!w->ok(error)) {
112 w->release();
113 return 0;
114 }
115 return w;
116}
117
118
119 PtexWriter* PtexWriter::edit(const char* path,
120 Ptex::MeshType mt, Ptex::DataType dt,
121 int nchannels, int alphachan, int nfaces,
122 Ptex::String& error, bool genmipmaps)
123{
124 if (!checkFormat(mt, dt, nchannels, alphachan, error))
125 return 0;
126
127 // try to open existing file (it might not exist)
128 FILE* fp = fopen(path, "rb+");
129 if (!fp && errno != ENOENT) {
130 error = fileError("Can't open ptex file for update: ", path).c_str();
131 }
132
133 PtexTexture* tex = 0;
134 if (fp) {
135 // got an existing file, close and reopen with PtexReader
136 fclose(fp);
137
138 // open reader for existing file
139 tex = PtexTexture::open(path, error);
140 if (!tex) return 0;
141
142 // make sure header matches
143 bool headerMatch = (mt == tex->meshType() &&
144 dt == tex->dataType() &&
145 nchannels == tex->numChannels() &&
146 alphachan == tex->alphaChannel() &&
147 nfaces == tex->numFaces());
148 if (!headerMatch) {
149 std::stringstream str;
150 str << "PtexWriter::edit error: header doesn't match existing file, "
151 << "conversions not supported";
152 error = str.str().c_str();
153 return 0;
154 }
155 }
156 PtexMainWriter* w = new PtexMainWriter(path, tex, mt, dt, nchannels, alphachan,
157 nfaces, genmipmaps);
158
159 if (!w->ok(error)) {
160 w->release();
161 return 0;
162 }
163 return w;
164}
165
166 PtexWriter* PtexWriter::edit(const char* path, bool /*incremental*/,
167 Ptex::MeshType mt, Ptex::DataType dt,
168 int nchannels, int alphachan, int nfaces,
169 Ptex::String& error, bool genmipmaps)
170{
171 // This function is deprecated
172 return edit(path, mt, dt, nchannels, alphachan, nfaces, error, genmipmaps);
173}
174
175 bool PtexWriter::applyEdits(const char*, Ptex::String&)
176{
177 // This function is obsolete
178 return 1;
179}
180
181
182 void PtexMainWriter::release()
183{
184 Ptex::String error;
185 // close writer if app didn't, and report error if any
186 if (!close(error))
187 std::cerr << error.c_str() << std::endl;
188 delete this;
189}
190
191
192 bool PtexMainWriter::storeFaceInfo(int faceid, FaceInfo& f, const FaceInfo& src, int flags)
193{
194 if (faceid < 0 || size_t(faceid) >= _header.nfaces) {
195 setError("PtexWriter error: faceid out of range");
196 return 0;
197 }
198
199 if (_header.meshtype == mt_triangle && (f.res.ulog2 != f.res.vlog2)) {
200 setError("PtexWriter error: asymmetric face res not supported for triangle textures");
201 return 0;
202 }
203
204 // copy all values
205 f = src;
206
207 // and clear extraneous ones
208 if (_header.meshtype == mt_triangle) {
209 f.flags = 0; // no user-settable flags on triangles
210 f.adjfaces[3] = -1;
211 f.adjedges &= 0x3f; // clear all but bottom six bits
212 }
213 else {
214 // clear non-user-settable flags
215 f.flags &= FaceInfo::flag_subface;
216 }
217
218 // set new flags
219 f.flags |= (uint8_t)flags;
220 return 1;
221}
222
223
224 void PtexMainWriter::writeMeta(const char* key, const char* value)
225{
226 addMetaData(key, mdt_string, value, int(strlen(value)+1));
227}
228
229
230 void PtexMainWriter::writeMeta(const char* key, const int8_t* value, int count)
231{
232 addMetaData(key, mdt_int8, value, count);
233}
234
235
236 void PtexMainWriter::writeMeta(const char* key, const int16_t* value, int count)
237{
238 addMetaData(key, mdt_int16, value, count*(int)sizeof(int16_t));
239}
240
241
242 void PtexMainWriter::writeMeta(const char* key, const int32_t* value, int count)
243{
244 addMetaData(key, mdt_int32, value, count*(int)sizeof(int32_t));
245}
246
247
248 void PtexMainWriter::writeMeta(const char* key, const float* value, int count)
249{
250 addMetaData(key, mdt_float, value, count*(int)sizeof(float));
251}
252
253
254 void PtexMainWriter::writeMeta(const char* key, const double* value, int count)
255{
256 addMetaData(key, mdt_double, value, count*(int)sizeof(double));
257}
258
259
260 void PtexMainWriter::writeMeta(PtexMetaData* data)
261{
262 int nkeys = data->numKeys();
263 for (int i = 0; i < nkeys; i++) {
264 const char* key = 0;
265 MetaDataType type;
266 data->getKey(i, key, type);
267 int count;
268 switch (type) {
269 case mdt_string:
270 {
271 const char* val=0;
272 data->getValue(key, val);
273 writeMeta(key, val);
274 }
275 break;
276 case mdt_int8:
277 {
278 const int8_t* val=0;
279 data->getValue(key, val, count);
280 writeMeta(key, val, count);
281 }
282 break;
283 case mdt_int16:
284 {
285 const int16_t* val=0;
286 data->getValue(key, val, count);
287 writeMeta(key, val, count);
288 }
289 break;
290 case mdt_int32:
291 {
292 const int32_t* val=0;
293 data->getValue(key, val, count);
294 writeMeta(key, val, count);
295 }
296 break;
297 case mdt_float:
298 {
299 const float* val=0;
300 data->getValue(key, val, count);
301 writeMeta(key, val, count);
302 }
303 break;
304 case mdt_double:
305 {
306 const double* val=0;
307 data->getValue(key, val, count);
308 writeMeta(key, val, count);
309 }
310 break;
311 }
312 }
313}
314
315
316 void PtexMainWriter::addMetaData(const char* key, MetaDataType t,
317 const void* value, int size)
318{
319 if (strlen(key) > 255) {
320 std::stringstream str;
321 str << "PtexWriter error: meta data key too long (max=255) \"" << key << "\"";
322 setError(str.str());
323 return;
324 }
325 if (size <= 0) {
326 std::stringstream str;
327 str << "PtexWriter error: meta data size <= 0 for \"" << key << "\"";
328 setError(str.str());
329 }
330 std::map<std::string,int>::iterator iter = _metamap.find(key);
331 int index;
332 if (iter != _metamap.end()) {
333 // see if we already have this entry - if so, overwrite it
334 index = iter->second;
335 }
336 else {
337 // allocate a new entry
338 index = (int)_metadata.size();
339 _metadata.resize(index+1);
340 _metamap[key] = index;
341 }
342 MetaEntry& m = _metadata[index];
343 m.key = key;
344 m.datatype = t;
345 m.data.resize(size);
346 memcpy(&m.data[0], value, size);
347}
348
349
350 size_t PtexMainWriter::writeBlock(FILE* fp, const void* data, size_t size)
351{
352 if (!_ok) return 0;
353 if (!fwrite(data, size, 1, fp)) {
354 setError("PtexWriter error: file write failed");
355 return 0;
356 }
357 return size;
358}
359
360
361 void PtexMainWriter::addToDataBlock(std::vector<std::byte>& dataBlock, const void* data, size_t size)
362{
363 size_t previousSize = dataBlock.size();
364 dataBlock.resize(previousSize+size);
365 memcpy(dataBlock.data() + previousSize, data, size);
366}
367
368
369libdeflate_compressor* PtexMainWriter::getCompressor()
370{
371 AutoMutex lock(_compressorMutex);
372 libdeflate_compressor* compressor;
373 if (!_compressors.empty()) {
374 compressor = _compressors.back();
375 _compressors.pop_back();
376 } else {
377 const int compressionLevel = 4;
378 compressor = libdeflate_alloc_compressor(compressionLevel);
379 }
380 return compressor;
381}
382
383
384 void PtexMainWriter::releaseCompressor(libdeflate_compressor* compressor)
385{
386 AutoMutex lock(_compressorMutex);
387 _compressors.push_back(compressor);
388}
389
390
391 void PtexMainWriter::compressDataBlock(libdeflate_compressor* compressor, std::vector<std::byte>& compressedData, const void* data, size_t size)
392{
393 compressedData.resize(libdeflate_zlib_compress_bound(compressor, size));
394 int compressedSize = int(libdeflate_zlib_compress(compressor, data, size, compressedData.data(), compressedData.size()));
395 if (!compressedSize) {
396 setError("PtexWriter error: compression failed");
397 }
398 compressedData.resize(compressedSize);
399}
400
401
402 Ptex::Res PtexMainWriter::calcTileRes(Res faceres)
403{
404 // desired number of tiles = floor(log2(facesize / tilesize))
405 size_t facesize = faceres.size64() * _pixelSize;
406 int ntileslog2 = PtexUtils::floor_log2(facesize/TileSize);
407 if (ntileslog2 == 0) return faceres;
408
409 // number of tiles is defined as:
410 // ntileslog2 = ureslog2 + vreslog2 - (tile_ureslog2 + tile_vreslog2)
411 // rearranging to solve for the tile res:
412 // tile_ureslog2 + tile_vreslog2 = ureslog2 + vreslog2 - ntileslog2
413 int n = faceres.ulog2 + faceres.vlog2 - ntileslog2;
414
415 // choose u and v sizes for roughly square result (u ~= v ~= n/2)
416 // and make sure tile isn't larger than face
417 Res tileres;
418 tileres.ulog2 = (int8_t)std::min(int((n+1)/2), int(faceres.ulog2));
419 tileres.vlog2 = (int8_t)std::min(int(n - tileres.ulog2), int(faceres.vlog2));
420 return tileres;
421}
422
423
424 void PtexMainWriter::compressFaceDataBlock(libdeflate_compressor* compressor, std::vector<std::byte>& compressedData, FaceDataHeader& fdh,
425 Res res, const void* uncompressedData, int stride)
426{
427 // compress a single face data block; could be a whole face or just a tile
428
429 // first, copy to temp buffer, and deinterleave
430 int ures = res.u(), vres = res.v();
431 size_t tempSize = ures*vres*_pixelSize;
432 std::vector<std::byte> temp(tempSize);
433 PtexUtils::deinterleave(uncompressedData, stride, ures, vres, temp.data(),
434 ures*DataSize(datatype()),
435 datatype(), _header.nchannels);
436
437 // difference if needed
438 bool diff = (datatype() == dt_uint8 ||
439 datatype() == dt_uint16);
440 if (diff) PtexUtils::encodeDifference(temp.data(), tempSize, datatype());
441
442 // compress
443 compressDataBlock(compressor, compressedData, temp.data(), tempSize);
444
445 // record compressed size and encoding in data header
446 fdh.set(compressedData.size(), diff ? enc_diffzipped : enc_zipped);
447}
448
449
450 void PtexMainWriter::compressFaceData(libdeflate_compressor* compressor, std::vector<std::byte>& compressedData, FaceDataHeader& fdh,
451 Res res, const void* uncompressedData)
452{
453 // determine whether to break into tiles
454 int stride = res.u() * _pixelSize;
455 Res tileRes = calcTileRes(res);
456 size_t ntilesu = res.ntilesu(tileRes);
457 size_t ntilesv = res.ntilesv(tileRes);
458 size_t ntiles = ntilesu * ntilesv;
459 if (ntiles == 1) {
460 // output single block
461 compressFaceDataBlock(compressor, compressedData, fdh, res, uncompressedData, stride);
462 } else {
463 // alloc tiles
464 std::vector<std::vector<std::byte>> tiles(ntiles);
465 std::vector<FaceDataHeader> tileHeader(ntiles);
466 size_t tileures = tileRes.u();
467 size_t tilevres = tileRes.v();
468 size_t tileustride = tileures*_pixelSize;
469 size_t tilevstride = tilevres*stride;
470
471 // compress tiles
472 std::vector<std::byte>* tile = tiles.data();
473 FaceDataHeader* tdh = tileHeader.data();
474 const std::byte* rowp = reinterpret_cast<const std::byte*>(uncompressedData);
475 const std::byte* rowpend = rowp + ntilesv * tilevstride;
476 for (; rowp != rowpend; rowp += tilevstride) {
477 const std::byte* p = rowp;
478 const std::byte* pend = p + ntilesu * tileustride;
479 for (; p != pend; tile++, tdh++, p += tileustride) {
480 // determine if tile is constant
481 if (PtexUtils::isConstant(p, stride, tileures, tilevres, _pixelSize)) {
482 // output a const tile
483 tile->assign(p, p + _pixelSize);
484 tdh->set(_pixelSize, enc_constant);
485 } else {
486 // output a compressed tile
487 compressFaceDataBlock(compressor, *tile, *tdh, tileRes, p, stride);
488 }
489 }
490 }
491
492 // compress tile header
493 std::vector<std::byte> compressedTileHeader;
494 compressDataBlock(compressor, compressedTileHeader, reinterpret_cast<std::byte*>(tileHeader.data()),
495 ntiles * sizeof(FaceDataHeader));
496 uint32_t compressedTileHeaderSize = compressedTileHeader.size();
497
498 size_t totalSize = sizeof(tileRes) + sizeof(compressedTileHeaderSize) + compressedTileHeaderSize;
499 for (auto& tile : tiles) {
500 totalSize += tile.size();
501 }
502 compressedData.reserve(totalSize);
503 addToDataBlock(compressedData, &tileRes, sizeof(tileRes));
504 addToDataBlock(compressedData, &compressedTileHeaderSize, sizeof(compressedTileHeaderSize));
505 addToDataBlock(compressedData, compressedTileHeader.data(), compressedTileHeaderSize);
506 for (auto& tile : tiles) {
507 addToDataBlock(compressedData, tile.data(), tile.size());
508 }
509
510 fdh.set(totalSize, enc_tiled);
511 }
512}
513
514
515 void PtexMainWriter::addToMetaDataBlock(std::vector<std::byte>& metaDataBlock, const MetaEntry& val)
516{
517 uint8_t keysize = uint8_t(val.key.size()+1);
518 uint8_t datatype = val.datatype;
519 uint32_t datasize = uint32_t(val.data.size());
520 addToDataBlock(metaDataBlock, &keysize, sizeof(keysize));
521 addToDataBlock(metaDataBlock, val.key.c_str(), keysize);
522 addToDataBlock(metaDataBlock, &datatype, sizeof(datatype));
523 addToDataBlock(metaDataBlock, &datasize, sizeof(datasize));
524 addToDataBlock(metaDataBlock, &val.data[0], datasize);
525}
526
527
528 PtexMainWriter::PtexMainWriter(const char* path, PtexTexture* tex,
529 Ptex::MeshType mt, Ptex::DataType dt,
530 int nchannels, int alphachan, int nfaces, bool genmipmaps)
531 : _ok(true),
532 _path(path),
533 _genmipmaps(genmipmaps),
534 _reader(0)
535{
536 memset(&_header, 0, sizeof(_header));
537 _header.magic = Magic;
538 _header.version = PtexFileMajorVersion;
539 _header.minorversion = PtexFileMinorVersion;
540 _header.meshtype = mt;
541 _header.datatype = dt;
542 _header.alphachan = alphachan;
543 _header.nchannels = (uint16_t)nchannels;
544 _header.nfaces = nfaces;
545 _header.extheadersize = sizeof(_extheader);
546 _pixelSize = _header.pixelSize();
547
548 memset(&_extheader, 0, sizeof(_extheader));
549
550 if (mt == mt_triangle)
551 _reduceFn = &PtexUtils::reduceTri;
552 else
553 _reduceFn = &PtexUtils::reduce;
554
555 // data will be written to a ".new" path and then renamed to final location
556 _newpath = path; _newpath += ".new";
557
558 // init faceinfo and set flags to -1 to mark as uninitialized
559 _faceinfo.resize(nfaces);
560 for (int i = 0; i < nfaces; i++) _faceinfo[i].flags = uint8_t(-1);
561 _faces.resize(nfaces);
562 _constdata.resize(nfaces*_pixelSize);
563
564 if (tex) {
565 // access reader implementation
566 // Note: we can assume we have a PtexReader because we opened the tex from the cache
567 _reader = static_cast<PtexReader*>(tex);
568
569 // copy border modes
570 setBorderModes(tex->uBorderMode(), tex->vBorderMode());
571
572 // copy edge filter mode
573 setEdgeFilterMode(tex->edgeFilterMode());
574
575 // copy meta data from existing file
576 PtexPtr<PtexMetaData> meta ( _reader->getMetaData() );
577 writeMeta(meta);
578 }
579}
580
581
582 PtexMainWriter::~PtexMainWriter()
583{
584 for (libdeflate_compressor* compressor : _compressors) {
585 libdeflate_free_compressor(compressor);
586 }
587 if (_reader) _reader->release();
588}
589
590
591 bool PtexMainWriter::close(Ptex::String& error)
592{
593 if (_ok) finish();
594 if (_reader) {
595 if (!_reader->ok()) {
596 _ok = false;
597 }
598 _reader->release();
599 _reader = 0;
600 }
601 if (_ok) {
602 // rename temppath into final location
603 unlink(_path.c_str());
604 if (rename(_newpath.c_str(), _path.c_str()) == -1) {
605 setError(fileError("Can't write to ptex file: ", _path.c_str()).c_str());
606 unlink(_newpath.c_str());
607 }
608 }
609 if (!_ok) getError(error);
610 return _ok;
611}
612
613 bool PtexMainWriter::writeFace(int faceid, const FaceInfo& f, const void* data, int stride)
614{
615 if (!_ok) return false;
616
617 FaceRec& face = _faces[faceid];
618 AutoMutex lock(face.mutex);
619
620 // reset face data in case it was written previously
621 face.faceData.clear();
622 face.fdh.clear();
623
624 // auto-compute stride
625 if (stride == 0) stride = f.res.u()*_pixelSize;
626
627 // handle constant case
628 if (PtexUtils::isConstant(data, stride, f.res.u(), f.res.v(), _pixelSize)) {
629 return writeConstantFace(faceid, f, data);
630 }
631
632 // non-constant case, ...
633
634 // check and store face info
635 if (!storeFaceInfo(faceid, _faceinfo[faceid], f)) return false;
636
637 // determine how many mipmap levels for face
638 int nlevels = 1;
639 if (_genmipmaps) {
640 nlevels += std::max(0, std::min(f.res.ulog2, f.res.vlog2) - MinReductionLog2);
641 }
642 face.faceData.resize(nlevels);
643 face.fdh.resize(nlevels);
644
645 // copy data into face level 0
646 Ptex::Res res = f.res;
647 size_t rowlen = res.u() * _pixelSize, nrows = res.v();
648 face.faceData[0].resize(rowlen * nrows);
649 PtexUtils::copy(data, stride, face.faceData[0].data(), rowlen, nrows, rowlen);
650 data = face.faceData[0].data();
651 stride = rowlen;
652
653 // premultiply into temp copy (if needed)
654 std::vector<std::byte> premultData;
655 if (_header.hasAlpha()) {
656 // copy to temp buffer, and premultiply alpha
657 premultData = face.faceData[0];
658 PtexUtils::multalpha(premultData.data(), res.size64(), datatype(), _header.nchannels,
659 _header.alphachan);
660 data = premultData.data();
661 }
662
663 // generate reductions (as needed)
664 libdeflate_compressor* compressor = getCompressor();
665 for (int level = 1; level < nlevels; level++) {
666 Ptex::Res nextres((int8_t)(res.ulog2-1), (int8_t)(res.vlog2-1));
667 face.faceData[level].resize(nextres.size64() * _pixelSize);
668 int dstride = nextres.u() * _pixelSize;
669 _reduceFn(data, stride, res.u(), res.v(), face.faceData[level].data(), dstride, datatype(), _header.nchannels);
670 data = face.faceData[level].data();
671 stride = dstride;
672 res = nextres;
673 }
674
675 // compute and store constant value from last level (note: level 0 would be more accurate, but slower)
676 storeConstValue(faceid, data, stride, res);
677
678 // free premultData (if allocated) as it is no longer needed
679 premultData.clear();
680 premultData.shrink_to_fit();
681
682 // compress face data for each level
683 for (int level = 0; level < nlevels; level++) {
684 Ptex::Res res((int8_t)(f.res.ulog2-level), (int8_t)(f.res.vlog2-level));
685 std::vector<std::byte> compressedData;
686 compressFaceData(compressor, compressedData, face.fdh[level], res, face.faceData[level].data());
687 face.faceData[level] = std::move(compressedData);
688 }
689 releaseCompressor(compressor);
690
691 return true;
692}
693
694
695 bool PtexMainWriter::writeConstantFace(int faceid, const FaceInfo& f, const void* data)
696{
697 if (!_ok) return 0;
698
699 // check and store face info
700 if (!storeFaceInfo(faceid, _faceinfo[faceid], f, FaceInfo::flag_constant)) return 0;
701
702 // store face value in constant block
703 memcpy(&_constdata[faceid*_pixelSize], data, _pixelSize);
704 return 1;
705}
706
707
708
709 void PtexMainWriter::storeConstValue(int faceid, const void* data, int stride, Res res)
710{
711 // compute average value and store in _constdata block
712 std::byte* constdata = &_constdata[faceid*_pixelSize];
713 PtexUtils::average(data, stride, res.u(), res.v(), constdata,
714 datatype(), _header.nchannels);
715 if (_header.hasAlpha())
716 PtexUtils::divalpha(constdata, 1, datatype(), _header.nchannels, _header.alphachan);
717}
718
719
720
721 void PtexMainWriter::finish()
722{
723 uint32_t nfaces = _header.nfaces;
724 // copy missing faces from _reader
725 if (_reader) {
726 for (uint32_t faceid = 0; faceid < nfaces; faceid++) {
727 if (_faceinfo[faceid].flags == uint8_t(-1)) {
728 // copy constant data
729 memcpy(&_constdata[faceid*_pixelSize], _reader->getConstantData(faceid), _pixelSize);
730
731 // update faceinfo and copy face data
732 const Ptex::FaceInfo& info = _reader->getFaceInfo(faceid);
733 if (info.isConstant()) {
734 storeFaceInfo(faceid, _faceinfo[faceid], info, FaceInfo::flag_constant);
735 } else if (_genmipmaps && !_reader->hasMipMaps()) {
736 // read uncompressed data and generate mipmaps
737 size_t size = _pixelSize * info.res.size64();
738 char* data = new char [size];
739 _reader->getData(faceid, data, 0);
740 writeFace(faceid, info, data, 0);
741 delete [] data;
742 } else {
743 // read compressed data, including mipmaps if any
744 FaceRec& face = _faces[faceid];
745 storeFaceInfo(faceid, _faceinfo[faceid], info);
746 int nlevels = 1;
747 if (_genmipmaps) {
748 nlevels += std::max(0, std::min(info.res.ulog2, info.res.vlog2) - MinReductionLog2);
749 }
750 face.fdh.resize(nlevels);
751 face.faceData.resize(nlevels);
752 for (int level = 0; level < nlevels; level++) {
753 _reader->getCompressedData(faceid, level, face.fdh[level], face.faceData[level]);
754 }
755 }
756 }
757 }
758 }
759 else {
760 // just flag missing faces as constant (black)
761 for (uint32_t faceid = 0; faceid < nfaces; faceid++) {
762 if (_faceinfo[faceid].flags == uint8_t(-1))
763 _faceinfo[faceid].flags = FaceInfo::flag_constant;
764 }
765 }
766
767 // generate "rfaceids", reduction faceids, which are faceids reordered by decreasing smaller dimension
768 if (_genmipmaps) {
769 _rfaceids.resize(nfaces);
770 _faceids_r.resize(nfaces);
771 PtexUtils::genRfaceids(&_faceinfo[0], nfaces, &_rfaceids[0], &_faceids_r[0]);
772 }
773
774 // flag faces w/ constant neighborhoods
775 flagConstantNeighorhoods();
776
777 // compress face info block
778 std::vector<std::byte> compressedFaceInfo;
779 libdeflate_compressor* compressor = getCompressor();
780 compressDataBlock(compressor, compressedFaceInfo, _faceinfo.data(), _faceinfo.size()*sizeof(FaceInfo));
781
782 // compress const data block
783 std::vector<std::byte> compressedConstData;
784 compressDataBlock(compressor, compressedConstData, _constdata.data(), _constdata.size());
785
786 // create level info and compress level headers
787 std::vector<LevelInfo> levelInfo(1);
788 for (auto& face : _faces) {
789 size_t nlevelsThisFace = face.faceData.size();
790 if (nlevelsThisFace > levelInfo.size()) {
791 levelInfo.resize(nlevelsThisFace);
792 }
793 for (size_t level = 0; level < nlevelsThisFace; level++) {
794 levelInfo[level].leveldatasize += face.faceData[level].size();
795 levelInfo[level].nfaces++;
796 }
797 }
798 levelInfo[0].nfaces = _header.nfaces; // constant faces weren't counted in the loop above, but level 0 needs them
799
800 int nlevels = int(levelInfo.size());
801
802 // gather fdh for faces in each level into LevelInfo, and compress level data headers
803 std::vector<std::vector<std::byte>> compressedLevelDataHeaders(nlevels);
804 std::vector<std::vector<size_t>> largeFaceHeaders(nlevels);
805 size_t totalLevelDataSize = 0;
806 for (int level = 0; level < nlevels; level++) {
807 uint32_t nfacesThisLevel = levelInfo[level].nfaces;
808 std::vector<FaceDataHeader> levelDataHeader(nfacesThisLevel);
809 for (uint32_t f = 0; f < nfacesThisLevel; f++) {
810 uint32_t faceId = level==0? f : _faceids_r[f];
811 if (_faces[faceId].fdh.size() > size_t(level)) {
812 levelDataHeader[f] = _faces[faceId].fdh[level];
813 if (levelDataHeader[f].isLargeFace()) {
814 // large faces have a compressed size too big for the fdh; store in largeFaceHeader
815 largeFaceHeaders[level].push_back(_faces[faceId].faceData[level].size());
816 }
817 }
818 }
819 compressDataBlock(compressor, compressedLevelDataHeaders[level], levelDataHeader.data(), nfacesThisLevel * sizeof(FaceDataHeader));
820 levelInfo[level].levelheadersize = uint32_t(compressedLevelDataHeaders[level].size());
821 levelInfo[level].leveldatasize += levelInfo[level].levelheadersize + sizeof(size_t) * largeFaceHeaders[level].size();
822 totalLevelDataSize += levelInfo[level].leveldatasize;
823 }
824
825 // compress meta data
826 std::vector<MetaEntry*> lmdEntries; // large meta data items
827 std::vector<std::byte> metaData, compressedMetaData;
828 for (size_t i = 0, n = _metadata.size(); i < n; i++) {
829 MetaEntry& e = _metadata[i];
830 if (e.data.size() > MetaDataThreshold) {
831 // skip large items, but record for later
832 lmdEntries.push_back(&e);
833 } else {
834 // add small item to meta data block
835 addToMetaDataBlock(metaData, e);
836 }
837 }
838 if (!metaData.empty()) {
839 compressDataBlock(compressor, compressedMetaData, metaData.data(), metaData.size());
840 }
841
842 // compress large meta data
843 size_t nLmd = lmdEntries.size();
844 std::vector<std::byte> lmdHeader, compressedLmdHeader;
845 std::vector<std::vector<std::byte>> compressedLargeMetaData(nLmd);
846 if (nLmd > 0) {
847 // compress lmd data items
848 for (size_t i = 0; i < nLmd; i++) {
849 MetaEntry* e= lmdEntries[i];
850 compressDataBlock(compressor, compressedLargeMetaData[i], &e->data[0], e->data.size());
851
852 uint8_t keysize = uint8_t(e->key.size()+1);
853 uint8_t datatype = e->datatype;
854 uint32_t datasize = (uint32_t)e->data.size();
855 uint32_t zipsize = (uint32_t)compressedLargeMetaData[i].size();
856
857 addToDataBlock(lmdHeader, &keysize, sizeof(keysize));
858 addToDataBlock(lmdHeader, e->key.c_str(), keysize);
859 addToDataBlock(lmdHeader, &datatype, sizeof(datatype));
860 addToDataBlock(lmdHeader, &datasize, sizeof(datasize));
861 addToDataBlock(lmdHeader, &zipsize, sizeof(zipsize));
862 }
863 compressDataBlock(compressor, compressedLmdHeader, lmdHeader.data(), lmdHeader.size());
864 }
865 releaseCompressor(compressor);
866 compressor = nullptr;
867
868 // init header
869 _header.nlevels = nlevels;
870 _header.faceinfosize = compressedFaceInfo.size();
871 _header.constdatasize = compressedConstData.size();
872 _header.levelinfosize = LevelInfoSize * nlevels;
873 _header.leveldatasize = totalLevelDataSize;
874 _header.metadatamemsize = uint32_t(metaData.size());
875 _header.metadatazipsize = uint32_t(compressedMetaData.size());
876 _extheader.lmdheadermemsize = lmdHeader.size();
877 _extheader.lmdheaderzipsize = compressedLmdHeader.size();
878
879 // create new file
880 FILE* newfp = fopen(_newpath.c_str(), "wb+");
881 if (!newfp) {
882 setError(fileError("Can't write to ptex file: ", _newpath.c_str()));
883 return;
884 }
885
886 // write header
887 writeBlock(newfp, &_header, HeaderSize);
888 writeBlock(newfp, &_extheader, ExtHeaderSize);
889
890 // write face info block
891 writeBlock(newfp, compressedFaceInfo.data(), compressedFaceInfo.size());
892
893 // write const data block
894 writeBlock(newfp, compressedConstData.data(), compressedConstData.size());
895
896 // write level info block
897 writeBlock(newfp, &levelInfo[0], LevelInfoSize * nlevels);
898
899 // write level data blocks
900 for (int level = 0; level < nlevels; level++) {
901 // write level data header
902 writeBlock(newfp, compressedLevelDataHeaders[level].data(), compressedLevelDataHeaders[level].size());
903
904 // write large face header, if present
905 if (!largeFaceHeaders[level].empty()) {
906 writeBlock(newfp, largeFaceHeaders[level].data(), sizeof(size_t) * largeFaceHeaders[level].size());
907 }
908
909 // write compressed face data for faces in level
910 uint32_t nfacesThisLevel = levelInfo[level].nfaces;
911 for (uint32_t rfaceId = 0; rfaceId < nfacesThisLevel; rfaceId++) {
912 uint32_t faceId = level==0? rfaceId : _faceids_r[rfaceId];
913 if (_faces[faceId].faceData.size() > size_t(level)) {
914 writeBlock(newfp, _faces[faceId].faceData[level].data(), _faces[faceId].faceData[level].size());
915 }
916 }
917 }
918
919 // write meta data
920 if (!compressedMetaData.empty()) {
921 writeBlock(newfp, compressedMetaData.data(), compressedMetaData.size());
922 }
923
924 // write compatibility barrier
925 uint64_t compatibilityBarrier = 0;
926 writeBlock(newfp, &compatibilityBarrier, sizeof(compatibilityBarrier));
927
928 // write large meta data
929 if (!compressedLmdHeader.empty()) {
930 writeBlock(newfp, compressedLmdHeader.data(), compressedLmdHeader.size());
931 for (auto& lmd : compressedLargeMetaData) {
932 writeBlock(newfp, lmd.data(), lmd.size());
933 }
934 }
935 fclose(newfp);
936}
937
938
939 void PtexMainWriter::flagConstantNeighorhoods()
940{
941 // for each constant face
942 for (int faceid = 0, n = int(_faceinfo.size()); faceid < n; faceid++) {
943 FaceInfo& f = _faceinfo[faceid];
944 if (!f.isConstant()) continue;
945 std::byte* constdata = &_constdata[faceid*_pixelSize];
946
947 // check to see if neighborhood is constant
948 bool isConst = true;
949 bool isTriangle = _header.meshtype == mt_triangle;
950 int nedges = isTriangle ? 3 : 4;
951 for (int eid = 0; isConst && (eid < nedges); eid++) {
952 bool prevWasSubface = f.isSubface();
953 int prevFid = faceid;
954
955 // traverse around vertex in CW direction
956 int afid = f.adjface(eid);
957 int aeid = f.adjedge(eid);
958 int count = 0;
959 const int maxcount = 10; // max valence (as safety valve)
960 while (afid != faceid && afid >= 0 && ++count < maxcount) {
961 // check if neighbor is constant, and has the same value as face
962 FaceInfo& af = _faceinfo[afid];
963 if (!af.isConstant() ||
964 0 != memcmp(constdata, &_constdata[afid*_pixelSize], _pixelSize))
965 { isConst = false; break; }
966
967 // if vertex is a T vertex between subface and main face, we can stop
968 bool isSubface = af.isSubface();
969 bool isT = !isTriangle && prevWasSubface && !isSubface && af.adjface(aeid) == prevFid;
970 if (isT) break;
971 prevWasSubface = isSubface;
972
973 // traverse around vertex in CW direction
974 prevFid = afid;
975 aeid = (aeid + 1) % nedges;
976 afid = af.adjface(aeid);
977 aeid = af.adjedge(aeid);
978 }
979
980 if (afid < 0) {
981 // hit boundary edge, check boundary mode
982 if (_extheader.ubordermode != Ptex::m_clamp || _extheader.vbordermode != Ptex::m_clamp) {
983 isConst = false;
984 }
985
986 // and traverse CCW neighbors too
987 if (isConst) {
988 aeid = (aeid - 1 + nedges) % nedges;
989 afid = f.adjface(aeid);
990 aeid = f.adjedge(aeid);
991 count = 0;
992 while (afid != faceid && afid >= 0 && ++count < maxcount) {
993 // check if neighbor is constant, and has the same value as face
994 FaceInfo& af = _faceinfo[afid];
995 if (!af.isConstant() ||
996 0 != memcmp(constdata, &_constdata[afid*_pixelSize], _pixelSize))
997 { isConst = false; break; }
998
999 // traverse around vertex in CCW direction
1000 prevFid = afid;
1001 aeid = (aeid - 1 + nedges) % nedges;
1002 afid = af.adjface(aeid);
1003 aeid = af.adjedge(aeid);
1004
1005 // if traversing to a subface, switch to secondary subface (afid points to primary/CW subface)
1006 bool isSubface = af.isSubface();
1007 if (isSubface && !prevWasSubface) {
1008 aeid = (aeid + 3) % 4;
1009 afid = af.adjface(aeid);
1010 aeid = (af.adjedge(aeid) + 3) % 4;
1011 }
1012 prevWasSubface = isSubface;
1013 }
1014 }
1015 }
1016 }
1017 if (isConst) f.flags |= FaceInfo::flag_nbconstant;
1018 }
1019}
1020
1021
1022 PTEX_NAMESPACE_END
Magic
const uint32_t Magic
Definition PtexIO.h:99
ExtHeaderSize
const int ExtHeaderSize
Definition PtexIO.h:101
HeaderSize
const int HeaderSize
Definition PtexIO.h:100
LevelInfoSize
const int LevelInfoSize
Definition PtexIO.h:102
LittleEndian
bool LittleEndian()
Definition PtexIO.h:112
TileSize
const int TileSize
Definition PtexIO.h:108
enc_diffzipped
@ enc_diffzipped
Definition PtexIO.h:81
enc_zipped
@ enc_zipped
Definition PtexIO.h:81
enc_constant
@ enc_constant
Definition PtexIO.h:81
enc_tiled
@ enc_tiled
Definition PtexIO.h:81
MetaDataThreshold
const int MetaDataThreshold
Definition PtexIO.h:110
AutoMutex
AutoLock< Mutex > AutoMutex
Definition PtexMutex.h:51
PtexPlatform.h
Platform-specific classes, functions, and includes.
PtexUtils.h
PTEX_NAMESPACE_END
#define PTEX_NAMESPACE_END
Definition PtexVersion.h:62
PtexFileMinorVersion
#define PtexFileMinorVersion
Definition PtexVersion.h:41
PtexFileMajorVersion
#define PtexFileMajorVersion
Definition PtexVersion.h:40
PtexWriter.h
Ptexture.h
Public API classes for reading, writing, caching, and filtering Ptex files.
PtexMainWriter
Definition PtexWriter.h:51
PtexMainWriter::calcTileRes
Res calcTileRes(Res faceres)
Definition PtexWriter.cpp:402
PtexMainWriter::releaseCompressor
void releaseCompressor(libdeflate_compressor *compressor)
Definition PtexWriter.cpp:384
PtexMainWriter::_pixelSize
int _pixelSize
Definition PtexWriter.h:123
PtexMainWriter::getError
void getError(Ptex::String &error)
Definition PtexWriter.h:83
PtexMainWriter::compressFaceDataBlock
void compressFaceDataBlock(libdeflate_compressor *compressor, std::vector< std::byte > &compressedData, FaceDataHeader &fdh, Res res, const void *uncompressedData, int stride)
Definition PtexWriter.cpp:424
PtexMainWriter::_compressors
std::vector< libdeflate_compressor * > _compressors
Definition PtexWriter.h:127
PtexMainWriter::storeFaceInfo
bool storeFaceInfo(int faceid, FaceInfo &dest, const FaceInfo &src, int flags=0)
Definition PtexWriter.cpp:192
PtexMainWriter::addToDataBlock
void addToDataBlock(std::vector< std::byte > &dataBlock, const void *data, size_t size)
Definition PtexWriter.cpp:361
PtexMainWriter::_newpath
std::string _newpath
Definition PtexWriter.h:132
PtexMainWriter::_rfaceids
std::vector< uint32_t > _rfaceids
Definition PtexWriter.h:136
PtexMainWriter::writeBlock
size_t writeBlock(FILE *fp, const void *data, size_t size)
Definition PtexWriter.cpp:350
PtexMainWriter::_metamap
std::map< std::string, int > _metamap
Definition PtexWriter.h:125
PtexMainWriter::close
virtual bool close(Ptex::String &error)
Close the file.
Definition PtexWriter.cpp:591
PtexMainWriter::_genmipmaps
bool _genmipmaps
Definition PtexWriter.h:133
PtexMainWriter::writeConstantFace
virtual bool writeConstantFace(int faceid, const FaceInfo &f, const void *data)
Definition PtexWriter.cpp:695
PtexMainWriter::_reader
PtexReader * _reader
Definition PtexWriter.h:147
PtexMainWriter::finish
void finish()
Definition PtexWriter.cpp:721
PtexMainWriter::ok
bool ok(Ptex::String &error)
Definition PtexWriter.h:79
PtexMainWriter::_faceids_r
std::vector< uint32_t > _faceids_r
Definition PtexWriter.h:137
PtexMainWriter::writeMeta
virtual void writeMeta(const char *key, const char *value)
Write a string as meta data.
Definition PtexWriter.cpp:224
PtexMainWriter::compressDataBlock
void compressDataBlock(libdeflate_compressor *compressor, std::vector< std::byte > &compressedData, const void *data, size_t size)
Definition PtexWriter.cpp:391
PtexMainWriter::setError
void setError(const std::string &error)
Definition PtexWriter.h:112
PtexMainWriter::storeConstValue
void storeConstValue(int faceid, const void *data, int stride, Res res)
Definition PtexWriter.cpp:709
PtexMainWriter::_faceinfo
std::vector< FaceInfo > _faceinfo
Definition PtexWriter.h:134
PtexMainWriter::_extheader
ExtHeader _extheader
Definition PtexWriter.h:122
PtexMainWriter::addMetaData
void addMetaData(const char *key, MetaDataType t, const void *value, int size)
Definition PtexWriter.cpp:316
PtexMainWriter::compressFaceData
void compressFaceData(libdeflate_compressor *compressor, std::vector< std::byte > &compressedData, FaceDataHeader &fdh, Res res, const void *uncompressedData)
Definition PtexWriter.cpp:450
PtexMainWriter::~PtexMainWriter
virtual ~PtexMainWriter()
Definition PtexWriter.cpp:582
PtexMainWriter::setEdgeFilterMode
virtual void setEdgeFilterMode(Ptex::EdgeFilterMode edgeFilterMode)
Set edge filter mode.
Definition PtexWriter.h:67
PtexMainWriter::_metadata
std::vector< MetaEntry > _metadata
Definition PtexWriter.h:124
PtexMainWriter::_reduceFn
PtexUtils::ReduceFn * _reduceFn
Definition PtexWriter.h:130
PtexMainWriter::MinReductionLog2
static const int MinReductionLog2
Definition PtexWriter.h:139
PtexMainWriter::addToMetaDataBlock
void addToMetaDataBlock(std::vector< std::byte > &dataBlock, const MetaEntry &val)
Definition PtexWriter.cpp:515
PtexMainWriter::_path
std::string _path
Definition PtexWriter.h:120
PtexMainWriter::_header
Header _header
Definition PtexWriter.h:121
PtexMainWriter::datatype
DataType datatype() const
Definition PtexWriter.h:90
PtexMainWriter::_faces
std::vector< FaceRec > _faces
Definition PtexWriter.h:145
PtexMainWriter::writeFace
virtual bool writeFace(int faceid, const FaceInfo &f, const void *data, int stride)
Definition PtexWriter.cpp:613
PtexMainWriter::_compressorMutex
Mutex _compressorMutex
Definition PtexWriter.h:128
PtexMainWriter::_constdata
std::vector< std::byte > _constdata
Definition PtexWriter.h:135
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:528
PtexMainWriter::_ok
bool _ok
Definition PtexWriter.h:118
PtexMainWriter::setBorderModes
virtual void setBorderModes(Ptex::BorderMode uBorderMode, Ptex::BorderMode vBorderMode)
Set border modes.
Definition PtexWriter.h:62
PtexMainWriter::flagConstantNeighorhoods
void flagConstantNeighorhoods()
Definition PtexWriter.cpp:939
PtexMainWriter::release
virtual void release()
Release resources held by this pointer (pointer becomes invalid).
Definition PtexWriter.cpp:182
PtexMainWriter::getCompressor
libdeflate_compressor * getCompressor()
Definition PtexWriter.cpp:369
PtexMetaData
Meta data accessor.
Definition Ptexture.h:331
PtexMetaData::numKeys
virtual int numKeys()=0
Query number of meta data entries stored in file.
PtexMetaData::getValue
virtual void getValue(const char *key, const char *&value)=0
Query the value of a given meta data entry.
PtexMetaData::getKey
virtual void getKey(int index, const char *&key, Ptex::MetaDataType &type)=0
Query the name and type of a meta data entry.
PtexPtr
Smart-pointer for acquiring and releasing API objects.
Definition Ptexture.h:1067
PtexReader
Definition PtexReader.h:53
PtexTexture
Interface for reading data from a ptex file.
Definition Ptexture.h:460
PtexTexture::meshType
virtual Ptex::MeshType meshType()=0
Type of mesh for which texture data is defined.
PtexTexture::uBorderMode
virtual Ptex::BorderMode uBorderMode()=0
Mode for filtering texture access beyond mesh border.
PtexTexture::numFaces
virtual int numFaces()=0
Number of faces stored in file.
PtexTexture::dataType
virtual Ptex::DataType dataType()=0
Type of data stored in file.
PtexTexture::alphaChannel
virtual int alphaChannel()=0
Index of alpha channel (if any).
PtexTexture::edgeFilterMode
virtual Ptex::EdgeFilterMode edgeFilterMode()=0
Mode for filtering textures across edges.
PtexTexture::open
static PtexTexture * open(const char *path, Ptex::String &error, bool premultiply=0)
Open a ptex file for reading.
Definition PtexReader.cpp:61
PtexTexture::vBorderMode
virtual Ptex::BorderMode vBorderMode()=0
Mode for filtering texture access beyond mesh border.
PtexTexture::numChannels
virtual int numChannels()=0
Number of channels stored in file.
PtexWriter
Interface for writing data to a ptex file.
Definition Ptexture.h:819
PtexWriter::applyEdits
static bool applyEdits(const char *path, Ptex::String &error)
Obsolete (returns true).
Definition PtexWriter.cpp:175
PtexWriter::edit
static PtexWriter * edit(const char *path, 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:119
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:100
Ptex::String
Memory-managed string.
Definition Ptexture.h:299
Ptex::String::c_str
const char * c_str() const
Definition Ptexture.h:307
PTEX_NAMESPACE_BEGIN
Definition PtexSeparableKernel.cpp:42
PTEX_NAMESPACE_BEGIN::checkFormat
bool checkFormat(Ptex::MeshType mt, Ptex::DataType dt, int nchannels, int alphachan, Ptex::String &error)
Definition PtexWriter.cpp:66
PTEX_NAMESPACE_BEGIN::fileError
std::string fileError(const char *message, const char *path)
Definition PtexWriter.cpp:59
PtexUtils::genRfaceids
void genRfaceids(const FaceInfo *faces, int nfaces, uint32_t *rfaceids, uint32_t *faceids)
Definition PtexUtils.cpp:630
PtexUtils::isConstant
bool isConstant(const void *data, int stride, int ures, int vres, int pixelSize)
Definition PtexUtils.cpp:147
PtexUtils::divalpha
void divalpha(void *data, int npixels, DataType dt, int nchannels, int alphachan)
Definition PtexUtils.cpp:618
PtexUtils::reduce
void reduce(const void *src, int sstride, int uw, int vw, void *dst, int dstride, DataType dt, int nchan)
Definition PtexUtils.cpp:299
PtexUtils::deinterleave
void deinterleave(const void *src, int sstride, int uw, int vw, void *dst, int dstride, DataType dt, int nchan)
Definition PtexUtils.cpp:226
PtexUtils::encodeDifference
void encodeDifference(void *data, size_t size, DataType dt)
Definition PtexUtils.cpp:251
PtexUtils::reduceTri
void reduceTri(const void *src, int sstride, int w, int, void *dst, int dstride, DataType dt, int nchan)
Definition PtexUtils.cpp:406
PtexUtils::copy
void copy(const void *src, int sstride, void *dst, int dstride, int vres, int rowlen)
Definition PtexUtils.cpp:438
PtexUtils::floor_log2
uint32_t floor_log2(uint32_t x)
Definition PtexUtils.h:79
PtexUtils::multalpha
void multalpha(void *data, int npixels, DataType dt, int nchannels, int alphachan)
Definition PtexUtils.cpp:579
PtexUtils::average
void average(const void *src, int sstride, int uw, int vw, void *dst, DataType dt, int nchan)
Definition PtexUtils.cpp:522
Ptex::DataType
DataType
Type of data stored in texture file.
Definition Ptexture.h:72
Ptex::dt_float
@ dt_float
Single-precision (32-bit) floating point.
Definition Ptexture.h:76
Ptex::MeshType
MeshType
Type of base mesh for which the textures are defined.
Definition Ptexture.h:66
Ptex::mt_quad
@ mt_quad
Mesh is quad-based.
Definition Ptexture.h:68
Ptex::m_clamp
@ m_clamp
texel access is clamped to border
Definition Ptexture.h:87
FaceDataHeader
Definition PtexIO.h:82
FaceDataHeader::set
void set(size_t blocksizeArg, Encoding encodingArg)
Definition PtexIO.h:89
PtexMainWriter::FaceRec
Definition PtexWriter.h:140
PtexMainWriter::FaceRec::faceData
std::vector< std::vector< std::byte > > faceData
Definition PtexWriter.h:141
PtexMainWriter::FaceRec::fdh
std::vector< FaceDataHeader > fdh
Definition PtexWriter.h:142
PtexMainWriter::FaceRec::mutex
Mutex mutex
Definition PtexWriter.h:143
PtexMainWriter::MetaEntry
Definition PtexWriter.h:92
PtexMainWriter::MetaEntry::key
std::string key
Definition PtexWriter.h:93
PtexMainWriter::MetaEntry::datatype
MetaDataType datatype
Definition PtexWriter.h:94
PtexMainWriter::MetaEntry::data
std::vector< uint8_t > data
Definition PtexWriter.h:95
Ptex::FaceInfo
Information about a face, as stored in the Ptex file header.
Definition Ptexture.h:232
Ptex::FaceInfo::res
Res res
Resolution of face.
Definition Ptexture.h:233
Ptex::FaceInfo::isConstant
bool isConstant() const
Determine if face is constant (by checking a flag).
Definition Ptexture.h:265
Ptex::Res
Pixel resolution of a given texture.
Definition Ptexture.h:159
Ptex::Res::ulog2
int8_t ulog2
log base 2 of u resolution, in texels
Definition Ptexture.h:160
Ptex::Res::v
int v() const
V resolution in texels.
Definition Ptexture.h:176
Ptex::Res::size64
size_t size64() const
Total size of specified texture in texels (u * v), allowing arbitrarily large textures.
Definition Ptexture.h:185
Ptex::Res::u
int u() const
U resolution in texels.
Definition Ptexture.h:173
Ptex::Res::vlog2
int8_t vlog2
log base 2 of v resolution, in texels
Definition Ptexture.h:161