// // VoxelModel.cpp // OpenSpades // // Created by yvt on 7/15/13. // Copyright (c) 2013 yvt.jp. All rights reserved. // #include "VoxelModel.h" #include "Exception.h" #include #include #include "Debug.h" namespace spades { VoxelModel::VoxelModel(int w, int h, int d) { SPADES_MARK_FUNCTION(); width = w; height = h; depth = d; if(d > 64){ SPRaise("Voxel model with depth > 64 is not supported."); } solidBits = new uint64_t[w * h]; colors = new uint32_t[w * h * d]; std::fill(solidBits, solidBits + w * h, 0); } VoxelModel::~VoxelModel() { SPADES_MARK_FUNCTION(); delete[] solidBits; delete[] colors; } struct KV6Block { uint32_t color; uint16_t zPos; uint8_t visFaces; uint8_t lighting; }; struct KV6Header { uint32_t xsiz, ysiz, zsiz; float xpivot, ypivot, zpivot; uint32_t blklen; }; static uint32_t swapColor(uint32_t col ){ union { uint8_t bytes[4]; uint32_t c; } u; u.c = col; std::swap(u.bytes[0], u.bytes[2]); return (u.c & 0xffffff); } VoxelModel *VoxelModel::LoadKV6(spades::IStream *stream) { SPADES_MARK_FUNCTION(); if(stream->Read(4) != "Kvxl"){ SPRaise("Invalid magic"); } KV6Header header; if(stream->Read(&header, sizeof(header)) < sizeof(header)){ SPRaise("File truncated: failed to read header"); } std::vector blkdata; blkdata.resize(header.blklen); if(stream->Read(blkdata.data(), sizeof(KV6Block) * header.blklen) < sizeof(KV6Block) * header.blklen){ SPRaise("File truncated: failed to read blocks"); } std::vector xoffset; xoffset.resize(header.xsiz); if(stream->Read(xoffset.data(), sizeof(uint32_t) * header.xsiz) < sizeof(uint32_t) * header.xsiz){ SPRaise("File truncated: failed to read xoffset"); } std::vector xyoffset; xyoffset.resize(header.xsiz * header.ysiz); if(stream->Read(xyoffset.data(), sizeof(uint16_t) * header.xsiz * header.ysiz) < sizeof(uint16_t) * header.xsiz * header.ysiz){ SPRaise("File truncated: failed to read xyoffset"); } // validate: zpos < depth for(size_t i = 0; i < blkdata.size(); i++) if(blkdata[i].zPos >= header.zsiz) SPRaise("File corrupted: blkData[i].zPos >= header.zsiz"); // validate sum(xyoffset) = blkLen { uint64_t ttl = 0; for(size_t i = 0; i < xyoffset.size(); i++){ ttl += (uint32_t)xyoffset[i]; } if(ttl != (uint64_t)blkdata.size()) SPRaise("File corrupted: sum(xyoffset) != blkdata.size()"); } VoxelModel *model = new VoxelModel(header.xsiz, header.ysiz, header.zsiz); model->SetOrigin(MakeVector3(-header.xpivot, -header.ypivot, -header.zpivot)); try{ int pos = 0; for(int x = 0; x < (int)header.xsiz; x++) for(int y = 0; y < (int)header.ysiz; y++){ int spanBlocks = (int)xyoffset[x *header.ysiz + y]; int lastZ = -1; //printf("pos: %d, (%d, %d): %d\n", // pos, x, y, spanBlocks); while(spanBlocks--){ const KV6Block& b = blkdata[pos]; //printf("%d, %d, %d: %d, %d\n", x, y, b.zPos, // b.visFaces, b.lighting); if(model->IsSolid(x, y, b.zPos)){ SPRaise("Duplicate voxel (%d, %d, %d)", x, y, b.zPos); } if(b.zPos <= lastZ){ SPRaise("Not Z-sorted"); } lastZ = b.zPos; model->SetSolid(x, y, b.zPos, swapColor(b.color)); pos++; } } SPAssert(pos == blkdata.size()); return model; }catch(...){ delete model; throw; } } }