Пример #1
0
void PtexWriterBase::writeFaceData(FILE* fp, const void* data, int stride,
				   Res res, FaceDataHeader& fdh)
{
    // determine whether to break into tiles
    Res tileres = calcTileRes(res);
    int ntilesu = res.ntilesu(tileres);
    int ntilesv = res.ntilesv(tileres);
    int ntiles = ntilesu * ntilesv;
    if (ntiles == 1) {
	// write single block
	writeFaceBlock(fp, data, stride, res, fdh);
    } else {
	// write tiles to tilefp temp file
	rewind(_tilefp);

	// alloc tile header
	std::vector<FaceDataHeader> tileHeader(ntiles);
	int tileures = tileres.u();
	int tilevres = tileres.v();
	int tileustride = tileures*_pixelSize;
	int tilevstride = tilevres*stride;

	// output tiles
	FaceDataHeader* tdh = &tileHeader[0];
	int datasize = 0;
	const char* rowp = (const char*) data;
	const char* rowpend = rowp + ntilesv * tilevstride;
	for (; rowp != rowpend; rowp += tilevstride) {
	    const char* p = rowp;
	    const char* pend = p + ntilesu * tileustride;
	    for (; p != pend; tdh++, p += tileustride) {
		// determine if tile is constant
		if (PtexUtils::isConstant(p, stride, tileures, tilevres, _pixelSize))
		    writeConstFaceBlock(_tilefp, p, *tdh);
		else
		    writeFaceBlock(_tilefp, p, stride, tileres, *tdh);
		datasize += tdh->blocksize();
	    }
	}

	// output compressed tile header
	uint32_t tileheadersize = writeZipBlock(_tilefp, &tileHeader[0],
						int(sizeof(FaceDataHeader)*tileHeader.size()));


	// output tile data pre-header
	int totalsize = 0;
	totalsize += writeBlock(fp, &tileres, sizeof(Res));
	totalsize += writeBlock(fp, &tileheadersize, sizeof(tileheadersize));

	// copy compressed tile header from temp file
	totalsize += copyBlock(fp, _tilefp, datasize, tileheadersize);

	// copy tile data from temp file
	totalsize += copyBlock(fp, _tilefp, 0, datasize);

	fdh.set(totalsize, enc_tiled);
    }
}
Пример #2
0
void PtexReader::readFaceData(FilePos pos, FaceDataHeader fdh, Res res, int levelid,
                              FaceData*& face)
{
    // keep new face local until fully initialized
    FaceData* volatile newface = 0;

    seek(pos);
    switch (fdh.encoding()) {
    case enc_constant:
    {
        ConstantFace* pf = new ConstantFace((void**)&face, _cache, _pixelsize);
        readBlock(pf->data(), _pixelsize);
        if (levelid==0 && _premultiply && _header.hasAlpha())
            PtexUtils::multalpha(pf->data(), 1, _header.datatype,
                                 _header.nchannels, _header.alphachan);
        newface = pf;
    }
    break;
    case enc_tiled:
    {
        Res tileres;
        readBlock(&tileres, sizeof(tileres));
        uint32_t tileheadersize;
        readBlock(&tileheadersize, sizeof(tileheadersize));
        TiledFace* tf = new TiledFace((void**)&face, _cache, res, tileres, levelid, this);
        readZipBlock(&tf->_fdh[0], tileheadersize, FaceDataHeaderSize * tf->_ntiles);
        computeOffsets(tell(), tf->_ntiles, &tf->_fdh[0], &tf->_offsets[0]);
        newface = tf;
    }
    break;
    case enc_zipped:
    case enc_diffzipped:
    {
        int uw = res.u(), vw = res.v();
        int npixels = uw * vw;
        int unpackedSize = _pixelsize * npixels;
        PackedFace* pf = new PackedFace((void**)&face, _cache,
                                        res, _pixelsize, unpackedSize);
        bool useMalloc = unpackedSize > AllocaMax;
        void* tmp = useMalloc ? malloc(unpackedSize) : alloca(unpackedSize);
        readZipBlock(tmp, fdh.blocksize(), unpackedSize);
        if (fdh.encoding() == enc_diffzipped)
            PtexUtils::decodeDifference(tmp, unpackedSize, _header.datatype);
        PtexUtils::interleave(tmp, uw * DataSize(_header.datatype), uw, vw,
                              pf->data(), uw * _pixelsize,
                              _header.datatype, _header.nchannels);
        if (levelid==0 && _premultiply && _header.hasAlpha())
            PtexUtils::multalpha(pf->data(), npixels, _header.datatype,
                                 _header.nchannels, _header.alphachan);
        newface = pf;
        if (useMalloc) free(tmp);
    }
    break;
    }

    face = newface;
}
Пример #3
0
void PtexWriterBase::writeFaceBlock(FILE* fp, const void* data, int stride,
				    Res res, FaceDataHeader& fdh)
{
    // write a single face data block
    // copy to temp buffer, and deinterleave
    int ures = res.u(), vres = res.v();
    int blockSize = ures*vres*_pixelSize;
    bool useMalloc = blockSize > AllocaMax;
    char* buff = useMalloc ? (char*) malloc(blockSize) : (char*)alloca(blockSize);
    PtexUtils::deinterleave(data, stride, ures, vres, buff,
			    ures*DataSize(_header.datatype),
			    _header.datatype, _header.nchannels);

    // difference if needed
    bool diff = (_header.datatype == dt_uint8 ||
		 _header.datatype == dt_uint16);
    if (diff) PtexUtils::encodeDifference(buff, blockSize, _header.datatype);

    // compress and stream data to file, and record size in header
    int zippedsize = writeZipBlock(fp, buff, blockSize);

    // record compressed size and encoding in data header
    fdh.set(zippedsize, diff ? enc_diffzipped : enc_zipped);
    if (useMalloc) free(buff);
}
Пример #4
0
void PtexWriterBase::writeConstFaceBlock(FILE* fp, const void* data,
					 FaceDataHeader& fdh)
{
    // write a single const face data block
    // record level data for face and output the one pixel value
    fdh.set(_pixelSize, enc_constant);
    writeBlock(fp, data, _pixelSize);
}
Пример #5
0
void PtexReader::readFace(int levelid, Level* level, int faceid)
{
    // temporarily release cache lock so other threads can proceed
    _cache->cachelock.unlock();

    // get read lock and make sure we still need to read
    FaceData*& face = level->faces[faceid];
    AutoMutex locker(readlock);

    if (face) {
        // another thread must have read it while we were waiting
        _cache->cachelock.lock();
        // make sure it's still there now that we have the lock
        if (face) {
            face->ref();
            return;
        }
        _cache->cachelock.unlock();
    }

    // Go ahead and read the face, and read nearby faces if
    // possible. The goal is to coalesce small faces into single
    // runs of consecutive reads to minimize seeking and take
    // advantage of read-ahead buffering.

    // Try to read as many faces as will fit in BlockSize.  Use the
    // in-memory size rather than the on-disk size to prevent flooding
    // the memory cache.  And don't coalesce w/ tiled faces as these
    // are meant to be read individually.

    // scan both backwards and forwards looking for unread faces
    int first = faceid, last = faceid;
    int totalsize = 0;

    FaceDataHeader fdh = level->fdh[faceid];
    if (fdh.encoding() != enc_tiled) {
        totalsize += unpackedSize(fdh, levelid, faceid);

        int nfaces = int(level->fdh.size());
        while (1) {
            int f = first-1;
            if (f < 0 || level->faces[f]) break;
            fdh = level->fdh[f];
            if (fdh.encoding() == enc_tiled) break;
            int size = totalsize + unpackedSize(fdh, levelid, f);
            if (size > BlockSize) break;
            first = f;
            totalsize = size;
        }
        while (1) {
            int f = last+1;
            if (f >= nfaces || level->faces[f]) break;
            fdh = level->fdh[f];
            if (fdh.encoding() == enc_tiled) break;
            int size = totalsize + unpackedSize(fdh, levelid, f);
            if (size > BlockSize) break;
            last = f;
            totalsize = size;
        }
    }

    // read all faces in range
    // keep track of extra faces we read so we can add them to the cache later
    std::vector<FaceData*> extraFaces;
    extraFaces.reserve(last-first);

    for (int i = first; i <= last; i++) {
        fdh = level->fdh[i];
        // skip faces with zero size (which is true for level-0 constant faces)
        if (fdh.blocksize()) {
            FaceData*& face = level->faces[i];
            readFaceData(level->offsets[i], fdh, getRes(levelid, i), levelid, face);
            if (i != faceid) extraFaces.push_back(face);
        }
    }

    // reacquire cache lock, then unref extra faces to add them to the cache
    _cache->cachelock.lock();
    for (size_t i = 0, size = extraFaces.size(); i < size; i++)
        extraFaces[i]->unref();
}