diff --git a/library/include/PolyVoxUtil/Serialization.h b/library/include/PolyVoxUtil/Serialization.h index e7899cef..a0186fc1 100644 --- a/library/include/PolyVoxUtil/Serialization.h +++ b/library/include/PolyVoxUtil/Serialization.h @@ -33,6 +33,9 @@ namespace PolyVox { POLYVOX_API BlockVolume* loadVolumeRaw(std::istream& stream); POLYVOX_API void saveVolumeRaw(std::ostream& stream, BlockVolume& volume); + + POLYVOX_API BlockVolume* loadVolumeRle(std::istream& stream); + POLYVOX_API void saveVolumeRle(std::ostream& stream, BlockVolume& volume); } #endif diff --git a/library/source/PolyVoxUtil/Serialization.cpp b/library/source/PolyVoxUtil/Serialization.cpp index 34b2a9e6..68a2e51b 100644 --- a/library/source/PolyVoxUtil/Serialization.cpp +++ b/library/source/PolyVoxUtil/Serialization.cpp @@ -77,4 +77,112 @@ namespace PolyVox } } } + + //Note: we don't do much error handling in here - exceptions will simply be propergated up to the caller. + //FIXME - think about pointer ownership issues. Or could return volume by value if the copy constructor is shallow + BlockVolume* loadVolumeRle(istream& stream) + { + //Read volume dimensions + uint8 volumeWidthPower = 0; + uint8 volumeHeightPower = 0; + uint8 volumeDepthPower = 0; + stream.read(reinterpret_cast(&volumeWidthPower), sizeof(volumeWidthPower)); + stream.read(reinterpret_cast(&volumeHeightPower), sizeof(volumeHeightPower)); + stream.read(reinterpret_cast(&volumeDepthPower), sizeof(volumeDepthPower)); + + //FIXME - need to support non cubic volumes + BlockVolume* volume = new BlockVolume(volumeWidthPower); + + uint16 volumeWidth = 0x0001 << volumeWidthPower; + uint16 volumeHeight = 0x0001 << volumeHeightPower; + uint16 volumeDepth = 0x0001 << volumeDepthPower; + + //Read data + BlockVolumeIterator volIter(*volume); + bool firstTime = true; + uint32 runLength = 0; + uint8 value = 0; + stream.read(reinterpret_cast(&value), sizeof(value)); + stream.read(reinterpret_cast(&runLength), sizeof(runLength)); + for(uint16 z = 0; z < volumeDepth; ++z) + { + for(uint16 y = 0; y < volumeHeight; ++y) + { + for(uint16 x = 0; x < volumeWidth; ++x) + { + volIter.setPosition(x,y,z); + if(runLength != 0) + { + volIter.setVoxel(value); + runLength--; + } + else + { + stream.read(reinterpret_cast(&value), sizeof(value)); + stream.read(reinterpret_cast(&runLength), sizeof(runLength)); + + volIter.setVoxel(value); + runLength--; + } + } + } + } + + return volume; + } + + void saveVolumeRle(std::ostream& stream, BlockVolume& volume) + { + //Write volume dimensions + uint16 volumeWidth = volume.getSideLength(); + uint16 volumeHeight = volume.getSideLength(); + uint16 volumeDepth = volume.getSideLength(); + + uint8 volumeWidthPower = logBase2(volumeWidth); + uint8 volumeHeightPower = logBase2(volumeHeight); + uint8 volumeDepthPower = logBase2(volumeDepth); + + stream.write(reinterpret_cast(&volumeWidthPower), sizeof(volumeWidthPower)); + stream.write(reinterpret_cast(&volumeHeightPower), sizeof(volumeHeightPower)); + stream.write(reinterpret_cast(&volumeDepthPower), sizeof(volumeDepthPower)); + + //Write data + BlockVolumeIterator volIter(volume); + uint8 current = 0; + uint32 runLength = 0; + bool firstTime = true; + for(uint16 z = 0; z < volumeDepth; ++z) + { + for(uint16 y = 0; y < volumeHeight; ++y) + { + for(uint16 x = 0; x < volumeWidth; ++x) + { + volIter.setPosition(x,y,z); + uint8 value = volIter.getVoxel(); + if(firstTime) + { + current = value; + runLength = 1; + firstTime = false; + } + else + { + if(value == current) + { + runLength++; + } + else + { + stream.write(reinterpret_cast(¤t), sizeof(current)); + stream.write(reinterpret_cast(&runLength), sizeof(runLength)); + current = value; + runLength = 1; + } + } + } + } + } + stream.write(reinterpret_cast(¤t), sizeof(current)); + stream.write(reinterpret_cast(&runLength), sizeof(runLength)); + } } \ No newline at end of file