VOXELFORMAT: csm format support #56

master
Martin Gerhardy 2020-09-15 18:26:32 +02:00
parent 76b22af829
commit 76af2d04c5
11 changed files with 197 additions and 1 deletions

Binary file not shown.

2
debian/changelog vendored
View File

@ -7,9 +7,11 @@ vengi (0.0.7.0-1) UNRELEASED; urgency=low
* Added stacktrace support for windows
* Refactored module structure (split app and core)
* Optimized character animations
* Hot reload character animation C++ source changes in debug builds
* Added quaternion lua support
* Updated external dependencies
* Refactored lua bindings
* Support Chronovox-Studio files (csm)
* VoxEdit:
* Converted some voxel generation functions to lua

View File

@ -12,9 +12,11 @@ General:
- Added stacktrace support for windows
- Refactored module structure (split app and core)
- Optimized character animations
- Hot reload character animation C++ source changes in debug builds
- Added quaternion lua support
- Updated external dependencies
- Refactored lua bindings
- Support Chronovox-Studio files (csm)
VoxEdit:

View File

@ -2,6 +2,7 @@ set(LIB voxelformat)
set(SRCS
AoSVXLFormat.h AoSVXLFormat.cpp
BinVoxFormat.h BinVoxFormat.cpp
CSMFormat.h CSMFormat.cpp
KVXFormat.h KVXFormat.cpp
KV6Format.h KV6Format.cpp
VoxFileFormat.h VoxFileFormat.cpp
@ -28,6 +29,7 @@ set(TEST_SRCS
tests/QBFormatTest.cpp
tests/QEFFormatTest.cpp
tests/CubFormatTest.cpp
tests/CSMFormatTest.cpp
tests/KVXFormatTest.cpp
tests/KV6FormatTest.cpp
tests/VXLFormatTest.cpp
@ -38,6 +40,7 @@ set(TEST_FILES
tests/qubicle.qbt
tests/qubicle.qef
tests/aceofspades.vxl
tests/chronovox-studio.csm
tests/cc.vxl
tests/test.binvox
tests/test.kvx

View File

@ -0,0 +1,138 @@
/**
* @file
*/
#include "CSMFormat.h"
#include "core/Color.h"
#include "core/FourCC.h"
#include "core/Log.h"
#include "glm/common.hpp"
#include "io/FileStream.h"
#include "voxel/MaterialColor.h"
#include "voxel/Voxel.h"
namespace voxel {
#define wrap(read) \
if ((read) != 0) { \
Log::error("Could not load csm file: Not enough data in stream " CORE_STRINGIFY(read) " - still %i bytes left", (int)stream.remaining()); \
return false; \
}
#define wrapBool(read) \
if (!(read)) { \
Log::debug("Error: " CORE_STRINGIFY(read) " at " SDL_FILE ":%i", SDL_LINE); \
return false; \
}
static bool readString(io::FileStream& stream, core::String& str, int version) {
if (version < 4) {
uint8_t length;
wrap(stream.readByte(length))
char name[256];
wrapBool(stream.readString(length, name))
name[length] = '\0';
str = name;
} else {
uint32_t length;
wrap(stream.readInt(length))
if (length > 4096) {
// sanity check
return false;
}
char name[4096];
wrapBool(stream.readString(length, name))
name[length] = '\0';
str = name;
}
return true;
}
bool CSMFormat::loadGroups(const io::FilePtr &file, VoxelVolumes &volumes) {
if (!(bool)file || !file->exists()) {
Log::error("Could not load csm file: File doesn't exist");
return false;
}
const MaterialColorArray& materialColors = getMaterialColors();
io::FileStream stream(file.get());
uint32_t magic, version, blank, matrixCount;
wrap(stream.readInt(magic))
wrap(stream.readInt(version))
wrap(stream.readInt(blank))
wrap(stream.readInt(matrixCount))
for (uint16_t i = 0u; (uint16_t)i < matrixCount; ++i) {
core::String name;
core::String parent;
wrapBool(readString(stream, name, version))
if (version > 1) {
wrapBool(readString(stream, parent, version))
}
uint16_t posx, posy, posz;
wrap(stream.readShort(posx))
wrap(stream.readShort(posy))
wrap(stream.readShort(posz))
uint16_t sizex, sizey, sizez;
wrap(stream.readShort(sizex))
wrap(stream.readShort(sizey))
wrap(stream.readShort(sizez))
if (sizex > MaxRegionSize || sizey > MaxRegionSize || sizez > MaxRegionSize) {
Log::error("Volume exceeds the max allowed size: %i:%i:%i", sizex, sizey, sizez);
return false;
}
const voxel::Region region(0, 0, 0, sizex - 1, sizey - 1, sizez - 1);
if (!region.isValid()) {
Log::error("Invalid region: %i:%i:%i", sizex, sizey, sizez);
return false;
}
uint32_t voxels = sizex * sizey * sizez;
uint32_t matrixIndex = 0u;
RawVolume *volume = new RawVolume(region);
volumes.push_back(VoxelVolume{volume, name, true});
while (matrixIndex < voxels) {
uint8_t count;
wrap(stream.readByte(count))
uint8_t r;
wrap(stream.readByte(r))
uint8_t g;
wrap(stream.readByte(g))
uint8_t b;
wrap(stream.readByte(b))
uint8_t interactiontype;
wrap(stream.readByte(interactiontype))
if (interactiontype == 0u) {
matrixIndex += count;
continue;
}
const glm::vec4& color = core::Color::fromRGBA(r, g, b, 255);
const int index = core::Color::getClosestMatch(color, materialColors);
const voxel::Voxel& voxel = voxel::createVoxel(voxel::VoxelType::Generic, index);
for (uint32_t v = matrixIndex; v < matrixIndex + count; ++v) {
const int x = glm::mod((float)glm::floor((float)v / (float)(sizez * sizey)), (float)sizex);
const int y = glm::mod((float)glm::floor((float)v / (float)(sizez)), (float)sizey);
const int z = glm::mod((float)v, (float)sizez);
volume->setVoxel(x, y, z, voxel);
}
matrixIndex += count;
}
}
return true;
}
#undef wrap
#undef wrapBool
bool CSMFormat::saveGroups(const VoxelVolumes &volumes, const io::FilePtr &file) {
return false;
}
}

View File

@ -0,0 +1,23 @@
/**
* @file
*/
#pragma once
#include "VoxFileFormat.h"
#include "io/FileStream.h"
#include "io/File.h"
#include "core/String.h"
namespace voxel {
/**
* @brief Chronovox Studio Model
*/
class CSMFormat : public VoxFileFormat {
public:
bool loadGroups(const io::FilePtr& file, VoxelVolumes& volumes) override;
bool saveGroups(const VoxelVolumes& volumes, const io::FilePtr& file) override;
};
}

View File

@ -17,11 +17,12 @@
#include "KVXFormat.h"
#include "KV6Format.h"
#include "AoSVXLFormat.h"
#include "voxelformat/CSMFormat.h"
namespace voxelformat {
// this is the list of supported voxel volume formats that are have importers implemented
const char *SUPPORTED_VOXEL_FORMATS_LOAD = "vox,qbt,qb,vxm,binvox,cub,kvx,kv6,vxl,qef";
const char *SUPPORTED_VOXEL_FORMATS_LOAD = "vox,qbt,qb,vxm,binvox,cub,kvx,kv6,vxl,qef,csm";
// this is the list of internal formats that are supported engine-wide (the format we save our own models in)
const char *SUPPORTED_VOXEL_FORMATS_LOAD_LIST[] = { "qb", "vox", nullptr };
// this is the list of supported voxel volume formats that have exporters implemented
@ -89,6 +90,11 @@ bool loadVolumeFormat(const io::FilePtr& filePtr, voxel::VoxelVolumes& newVolume
if (!f.loadGroups(filePtr, newVolumes)) {
voxelformat::clearVolumes(newVolumes);
}
} else if (ext == "csm" || magic == FourCC('.','C','S','M')) {
voxel::CSMFormat f;
if (!f.loadGroups(filePtr, newVolumes)) {
voxelformat::clearVolumes(newVolumes);
}
} else if (ext == "binvox" || magic == FourCC('#','b','i','n')) {
voxel::BinVoxFormat f;
if (!f.loadGroups(filePtr, newVolumes)) {

View File

@ -0,0 +1,19 @@
/**
* @file
*/
#include "AbstractVoxFormatTest.h"
#include "voxelformat/CSMFormat.h"
namespace voxel {
class CSMFormatTest: public AbstractVoxFormatTest {
};
TEST_F(CSMFormatTest, testLoad) {
CSMFormat f;
std::unique_ptr<RawVolume> volume(load("chronovox-studio.csm", f));
ASSERT_NE(nullptr, volume) << "Could not load volume";
}
}

View File

@ -13,6 +13,7 @@ class CubFormatTest: public AbstractVoxFormatTest {
TEST_F(CubFormatTest, testLoad) {
CubFormat f;
std::unique_ptr<RawVolume> volume(load("cw.cub", f));
ASSERT_NE(nullptr, volume) << "Could not load volume";
}
}

View File

@ -13,6 +13,7 @@ class KV6FormatTest: public AbstractVoxFormatTest {
TEST_F(KV6FormatTest, testLoad) {
KV6Format f;
std::unique_ptr<RawVolume> volume(load("test.kv6", f));
ASSERT_NE(nullptr, volume) << "Could not load volume";
}
}

View File

@ -13,6 +13,7 @@ class KVXFormatTest: public AbstractVoxFormatTest {
TEST_F(KVXFormatTest, testLoad) {
KVXFormat f;
std::unique_ptr<RawVolume> volume(load("test.kvx", f));
ASSERT_NE(nullptr, volume) << "Could not load volume";
}
}