void emitStatement(refObject term, set wraps) // PRE EMIT. Write an open brace if needed. { void preEmit(int hook) { if (isInSet(hook, wraps)) { writeChar(target, '{'); }} // POST EMIT. Write a close brace if needed. void postEmit(int hook) { if (isInSet(hook, wraps)) { writeChar(target, '}'); }} // Dispatch to an appropriate case based on TERM's outer hook. if (isPair(term)) { switch (toHook(car(term))) // Write C code for a CASE clause. { case caseHook: { refObject subterm; preEmit(caseHook); term = cdr(term); writeFormat(target, "switch"); writeChar(target, '('); emitExpression(car(term), 13); writeChar(target, ')'); writeChar(target, '{'); term = cdr(term); while (cdr(term) != nil) { emitLabels(car(term)); term = cdr(term); subterm = car(term); if (isEffected(subterm)) { emitStatement(subterm, withSet); } writeFormat(target, "break"); writeChar(target, ';'); term = cdr(term); } subterm = car(term); if (isEffected(subterm)) { writeFormat(target, "default"); writeChar(target, ':'); emitStatement(subterm, withSet); } writeChar(target, '}'); postEmit(caseHook); break; } // Write C code for an IF clause. case ifHook: { refObject subterm; preEmit(ifHook); term = cdr(term); while (true) { writeFormat(target, "if"); writeChar(target, '('); emitExpression(car(term), 13); writeChar(target, ')'); term = cdr(term); subterm = car(term); if (isEffected(subterm)) { emitStatement(subterm, ifLastWithSet); } else { writeChar(target, ';'); } term = cdr(term); if (cdr(term) == nil) { subterm = car(term); if (isEffected(subterm)) { writeFormat(target, "else"); writeBlank(target); if (isCar(subterm, ifHook)) { term = cdr(subterm); } else { emitStatement(subterm, lastWithSet); break; }} else { break; }} else { writeFormat(target, "else"); writeBlank(target); }} postEmit(ifHook); break; } // Write C code for a LAST clause. case lastHook: { refObject subterm; preEmit(lastHook); term = cdr(term); while (term != nil) { subterm = car(term); if (isEffected(subterm)) { emitStatement(subterm, withSet); } term = cdr(term); } postEmit(lastHook); break; } // Write C code for a WHILE clause. case whileHook: { preEmit(whileHook); term = cdr(term); writeFormat(target, "while"); writeChar(target, '('); emitExpression(car(term), 13); writeChar(target, ')'); term = cadr(term); if (isEffected(term)) { emitStatement(term, lastWithSet); } else { writeChar(target, ';'); } postEmit(whileHook); break; } // Write C code for a WITH clause. case withHook: { refObject frame; preEmit(withHook); term = cdr(term); frame = car(term); term = cdr(term); if (frame == nil) { emitVariableDeclarations(term); emitFunctionDefinitions(true, term); emitVariableDefinitions(nil, term); term = car(lastPair(term)); if (isEffected(term)) { emitStatement(term, withSet); }} else { emitFrameDeclaration(frame, term); emitVariableDeclarations(term); emitFunctionDefinitions(true, term); emitFramePush(frame, frameLength(term)); emitFrameInitialization(frame, term); emitVariableDefinitions(frame, term); term = car(lastPair(term)); if (isEffected(term)) { emitStatement(term, withSet); } emitFramePop(frame); } postEmit(withHook); break; } // Other TERMs become C expressions. default: { if (isEffected(term)) { emitExpression(term, 13); writeChar(target, ';'); } break; }}} else { if (isEffected(term)) { emitExpression(term, 13); writeChar(target, ';'); }}}
void writingObject(refBuffer buffer, refObject object) { if (object == nil) { writeFormat(buffer, "[Nil]"); } else { switch (tag(object)) { case cellTag: { writeFormat(buffer, "[Cell %X]", object); return; } case characterTag: { writeCharacter(buffer, toCharacter(object)); return; } case evenBinderTag: { writeFormat(buffer, "[EvenBinder %X]", object); return; } case hookTag: { writeFormat(buffer, "?%s", hookTo(object)); return; } case hunkTag: { writeFormat(buffer, "[Hunk %X]", object); return; } case integerTag: { writeFormat(buffer, "%i", toInteger(object)); return; } case jokerTag: { writeFormat(buffer, "[%s]", jokerTo(object)); return; } case leftBinderTag: { writeFormat(buffer, "[LeftBinder %X]", object); return; } case markedTag: { writeFormat(buffer, "[...]"); return; } case matchTag: { writeFormat(buffer, "[Match %X]", object); return; } case nameTag: { writeVisibleName(buffer, object); return; } case pairTag: { refObject pairs = object; tag(object) = markedTag; writeChar(buffer, '('); writingObject(buffer, car(pairs)); pairs = cdr(pairs); while (pairs != nil) { writeBlank(buffer); writingObject(buffer, car(pairs)); pairs = cdr(pairs); } writeChar(buffer, ')'); tag(object) = pairTag; return; } case realTag: { writeFormat(buffer, "%.17E", toReal(object)); return; } case rightBinderTag: { writeFormat(buffer, "[RightBinder %X]", object); return; } case stringTag: { writeQuotedString(buffer, toRefString(object)); return; } default: { writeFormat(buffer, "[Tag%i %X]", tag(object), object); return; }}}}
bool PtexIncrWriter::writeFace(int faceid, const FaceInfo& f, const void* data, int stride) { if (stride == 0) stride = f.res.u()*_pixelSize; // handle constant case if (PtexUtils::isConstant(data, stride, f.res.u(), f.res.v(), _pixelSize)) return writeConstantFace(faceid, f, data); // init headers uint8_t edittype = et_editfacedata; uint32_t editsize; EditFaceDataHeader efdh; efdh.faceid = faceid; // check and store face info if (!storeFaceInfo(faceid, efdh.faceinfo, f)) return 0; // record position and skip headers FilePos pos = ftello(_fp); writeBlank(_fp, sizeof(edittype) + sizeof(editsize) + sizeof(efdh)); // must compute constant (average) val first uint8_t* constval = (uint8_t*) malloc(_pixelSize); if (_header.hasAlpha()) { // must premult alpha before averaging // first copy to temp buffer int rowlen = f.res.u() * _pixelSize, nrows = f.res.v(); uint8_t* temp = (uint8_t*) malloc(rowlen * nrows); PtexUtils::copy(data, stride, temp, rowlen, nrows, rowlen); // multiply alpha PtexUtils::multalpha(temp, f.res.size(), _header.datatype, _header.nchannels, _header.alphachan); // average PtexUtils::average(temp, rowlen, f.res.u(), f.res.v(), constval, _header.datatype, _header.nchannels); // unmult alpha PtexUtils::divalpha(constval, 1, _header.datatype, _header.nchannels, _header.alphachan); free(temp); } else { // average PtexUtils::average(data, stride, f.res.u(), f.res.v(), constval, _header.datatype, _header.nchannels); } // write const val writeBlock(_fp, constval, _pixelSize); free(constval); // write face data writeFaceData(_fp, data, stride, f.res, efdh.fdh); // update editsize in header editsize = sizeof(efdh) + _pixelSize + efdh.fdh.blocksize(); // rewind and write headers fseeko(_fp, pos, SEEK_SET); writeBlock(_fp, &edittype, sizeof(edittype)); writeBlock(_fp, &editsize, sizeof(editsize)); writeBlock(_fp, &efdh, sizeof(efdh)); fseeko(_fp, 0, SEEK_END); return 1; }
void PtexMainWriter::finish() { // do nothing if there's no new data to write if (!_hasNewData) return; // copy missing faces from _reader if (_reader) { for (int i = 0, nfaces = _header.nfaces; i < nfaces; i++) { if (_faceinfo[i].flags == uint8_t(-1)) { // copy face data const Ptex::FaceInfo& info = _reader->getFaceInfo(i); int size = _pixelSize * info.res.size(); if (info.isConstant()) { PtexPtr<PtexFaceData> data ( _reader->getData(i) ); if (data) { writeConstantFace(i, info, data->getData()); } } else { void* data = malloc(size); _reader->getData(i, data, 0); writeFace(i, info, data, 0); free(data); } } } } else { // just flag missing faces as constant (black) for (int i = 0, nfaces = _header.nfaces; i < nfaces; i++) { if (_faceinfo[i].flags == uint8_t(-1)) _faceinfo[i].flags = FaceInfo::flag_constant; } } // write reductions to tmp file if (_genmipmaps) generateReductions(); // flag faces w/ constant neighborhoods flagConstantNeighorhoods(); // update header _header.nlevels = uint16_t(_levels.size()); _header.nfaces = uint32_t(_faceinfo.size()); // create new file FILE* newfp = fopen(_newpath.c_str(), "wb+"); if (!newfp) { setError(fileError("Can't write to ptex file: ", _newpath.c_str())); return; } // write blank header (to fill in later) writeBlank(newfp, HeaderSize); writeBlank(newfp, ExtHeaderSize); // write compressed face info block _header.faceinfosize = writeZipBlock(newfp, &_faceinfo[0], sizeof(FaceInfo)*_header.nfaces); // write compressed const data block _header.constdatasize = writeZipBlock(newfp, &_constdata[0], int(_constdata.size())); // write blank level info block (to fill in later) FilePos levelInfoPos = ftello(newfp); writeBlank(newfp, LevelInfoSize * _header.nlevels); // write level data blocks (and record level info) std::vector<LevelInfo> levelinfo(_header.nlevels); for (int li = 0; li < _header.nlevels; li++) { LevelInfo& info = levelinfo[li]; LevelRec& level = _levels[li]; int nfaces = int(level.fdh.size()); info.nfaces = nfaces; // output compressed level data header info.levelheadersize = writeZipBlock(newfp, &level.fdh[0], sizeof(FaceDataHeader)*nfaces); info.leveldatasize = info.levelheadersize; // copy level data from tmp file for (int fi = 0; fi < nfaces; fi++) info.leveldatasize += copyBlock(newfp, _tmpfp, level.pos[fi], level.fdh[fi].blocksize()); _header.leveldatasize += info.leveldatasize; } rewind(_tmpfp); // write meta data (if any) if (!_metadata.empty()) writeMetaData(newfp); // update extheader for edit data position _extheader.editdatapos = ftello(newfp); // rewrite level info block fseeko(newfp, levelInfoPos, SEEK_SET); _header.levelinfosize = writeBlock(newfp, &levelinfo[0], LevelInfoSize*_header.nlevels); // rewrite header fseeko(newfp, 0, SEEK_SET); writeBlock(newfp, &_header, HeaderSize); writeBlock(newfp, &_extheader, ExtHeaderSize); fclose(newfp); }
void PtexMainWriter::writeMetaData(FILE* fp) { std::vector<MetaEntry*> lmdEntries; // large meta data items // write small meta data items in a single zip block for (int i = 0, n = _metadata.size(); i < n; i++) { MetaEntry& e = _metadata[i]; #ifndef PTEX_NO_LARGE_METADATA_BLOCKS if (int(e.data.size()) > MetaDataThreshold) { // skip large items, but record for later lmdEntries.push_back(&e); } else #endif { // add small item to zip block _header.metadatamemsize += writeMetaDataBlock(fp, e); } } if (_header.metadatamemsize) { // finish zip block _header.metadatazipsize = writeZipBlock(fp, 0, 0, /*finish*/ true); } // write compatibility barrier writeBlank(fp, sizeof(uint64_t)); // write large items as separate blocks int nLmd = lmdEntries.size(); if (nLmd > 0) { // write data records to tmp file and accumulate zip sizes for lmd header std::vector<FilePos> lmdoffset(nLmd); std::vector<uint32_t> lmdzipsize(nLmd); for (int i = 0; i < nLmd; i++) { MetaEntry* e= lmdEntries[i]; lmdoffset[i] = ftello(_tmpfp); lmdzipsize[i] = writeZipBlock(_tmpfp, &e->data[0], e->data.size()); } // write lmd header records as single zip block for (int i = 0; i < nLmd; i++) { MetaEntry* e = lmdEntries[i]; uint8_t keysize = uint8_t(e->key.size()+1); uint8_t datatype = e->datatype; uint32_t datasize = e->data.size(); uint32_t zipsize = lmdzipsize[i]; writeZipBlock(fp, &keysize, sizeof(keysize), false); writeZipBlock(fp, e->key.c_str(), keysize, false); writeZipBlock(fp, &datatype, sizeof(datatype), false); writeZipBlock(fp, &datasize, sizeof(datasize), false); writeZipBlock(fp, &zipsize, sizeof(zipsize), false); _extheader.lmdheadermemsize += sizeof(keysize) + keysize + sizeof(datatype) + sizeof(datasize) + sizeof(zipsize); } _extheader.lmdheaderzipsize = writeZipBlock(fp, 0, 0, /*finish*/ true); // copy data records for (int i = 0; i < nLmd; i++) { _extheader.lmddatasize += copyBlock(fp, _tmpfp, lmdoffset[i], lmdzipsize[i]); } } }