VOXELFORMAT: added incomplete qbcl format support

See issue #88
master
Martin Gerhardy 2021-10-26 18:04:20 +02:00
parent b3c20f5956
commit c337565b28
6 changed files with 234 additions and 6 deletions

BIN
data/tests/qubicle.qbcl Normal file

Binary file not shown.

View File

@ -9,6 +9,7 @@ set(SRCS
VoxFormat.h VoxFormat.cpp
QBTFormat.h QBTFormat.cpp
QBFormat.h QBFormat.cpp
QBCLFormat.h QBCLFormat.cpp
QEFFormat.h QEFFormat.cpp
MCRFormat.h MCRFormat.cpp
VXMFormat.h VXMFormat.cpp
@ -31,6 +32,7 @@ set(TEST_SRCS
tests/VoxFormatTest.cpp
tests/QBTFormatTest.cpp
tests/QBFormatTest.cpp
tests/QBCLFormatTest.cpp
tests/QEFFormatTest.cpp
tests/CubFormatTest.cpp
tests/CSMFormatTest.cpp
@ -44,6 +46,7 @@ set(TEST_FILES
tests/qubicle.qb
tests/qubicle.qbt
tests/qubicle.qef
tests/qubicle.qbcl
tests/testload.qef
tests/aceofspades.vxl
tests/chronovox-studio.csm

View File

@ -0,0 +1,168 @@
/**
* @file
*/
#include "QBCLFormat.h"
#include "core/ArrayLength.h"
#include "core/Enum.h"
#include "core/FourCC.h"
#include "core/Zip.h"
#include "core/Color.h"
#include "core/Assert.h"
#include "core/Log.h"
namespace voxel {
#define wrap(read) \
if ((read) != 0) { \
Log::error("Could not load qbcl file: Not enough data in stream " CORE_STRINGIFY(read) " - still %i bytes left", (int)stream.remaining()); \
return false; \
}
#define wrapBool(read) \
if ((read) == false) { \
Log::error("Could not load qbcl file: Not enough data in stream " CORE_STRINGIFY(read) " - still %i bytes left", (int)stream.remaining()); \
return false; \
}
bool QBCLFormat::saveGroups(const VoxelVolumes& volumes, const io::FilePtr& file) {
return false;
}
#if 0
static bool readString(io::FileStream &stream, core::String &dest) {
uint32_t size;
wrap(stream.readInt(size))
if (size > 1024) {
Log::warn("Found big string - ignore it");
stream.skip(size);
return false;
}
dest.reserve(size);
for (uint32_t i = 0; i < size; ++i) {
uint8_t chr;
wrap(stream.readByte(chr))
dest.append(chr);
}
return true;
}
#endif
bool QBCLFormat::readMatrix(io::FileStream &stream) {
uint32_t mx; // 32
uint32_t my;
uint32_t mz;
wrap(stream.readInt(mx))
wrap(stream.readInt(my))
wrap(stream.readInt(mz))
Log::debug("QBCL: matrix size %u:%u:%u", mx, my, mz);
// TODO
return false;
}
bool QBCLFormat::readModel(io::FileStream &stream) {
uint32_t x;
uint32_t y;
uint32_t z;
wrap(stream.readInt(x))
wrap(stream.readInt(y))
wrap(stream.readInt(z))
Log::debug("QBCL: model size %u:%u:%u", x, y, z);
uint32_t r[6];
for (int i = 0; i < lengthof(r); ++i) {
wrap(stream.readInt(r[i]))
Log::debug("QBCL: r[%i] = %u", i, r[i]);
}
uint32_t n;
uint32_t u;
uint32_t v;
wrap(stream.readInt(n))
wrap(stream.readInt(u))
wrap(stream.readInt(v))
Log::debug("QBCL: n: %u, u: %u, v: %u", n, u, v);
// TODO
return false;
}
bool QBCLFormat::readCompound(io::FileStream &stream) {
return false;
}
bool QBCLFormat::loadGroups(const io::FilePtr& file, VoxelVolumes& volumes) {
if (!(bool)file || !file->exists()) {
Log::error("Could not load qb file: File doesn't exist");
return false;
}
io::FileStream stream(file.get());
uint32_t magic;
wrap(stream.readInt(magic))
if (magic != FourCC('Q', 'B', 'C', 'L')) {
Log::error("Invalid magic found - no qbcl file");
return false;
}
wrap(stream.readInt(_version))
uint32_t flags;
wrap(stream.readInt(flags))
uint32_t thumbWidth;
wrap(stream.readInt(thumbWidth))
uint32_t thumbHeight;
wrap(stream.readInt(thumbHeight))
wrapBool(stream.skip(thumbWidth * thumbHeight * 4))
#if 0
core::String title;
wrapBool(readString(stream, title))
core::String desc;
wrapBool(readString(stream, desc))
core::String metadata;
wrapBool(readString(stream, metadata))
core::String author;
wrapBool(readString(stream, author))
core::String company;
wrapBool(readString(stream, company))
core::String website;
wrapBool(readString(stream, website))
core::String copyright;
wrapBool(readString(stream, copyright))
uint8_t guid[16];
wrap(stream.readBuf(guid, lengthof(guid)))
uint32_t unknown;
stream.readInt(unknown);
Log::debug("QBCL: unknown value %u at offset %u", unknown, (uint32_t)stream.pos());
stream.readInt(unknown);
Log::debug("QBCL: unknown value %u at offset %u", unknown, (uint32_t)stream.pos());
while (stream.remaining() > 0) {
core::String type;
wrapBool(readString(stream, type))
uint8_t unknownByte;
wrap(stream.readByte(unknownByte))
Log::debug("QBCL: unknown value %u at offset %u", unknownByte, (uint32_t)stream.pos());
wrap(stream.readByte(unknownByte))
Log::debug("QBCL: unknown value %u at offset %u", unknownByte, (uint32_t)stream.pos());
wrap(stream.readByte(unknownByte))
Log::debug("QBCL: unknown value %u at offset %u", unknownByte, (uint32_t)stream.pos());
if (type == "Model") {
wrapBool(readModel(stream))
} else if (type == "Matrix") {
wrapBool(readMatrix(stream))
} else if (type == "Compound") {
wrapBool(readCompound(stream))
} else {
Log::warn("Unknown type found: '%s'", type.c_str());
return false;
}
}
#endif
return false;
}
}
#undef wrap
#undef wrapBool

View File

@ -0,0 +1,29 @@
/**
* @file
*/
#pragma once
#include "VoxFileFormat.h"
#include "io/FileStream.h"
namespace voxel {
/**
* @brief Qubicle project file (qbcl) format.
*
* Not yet implemented
*/
class QBCLFormat : public VoxFileFormat {
private:
uint32_t _version;
bool readMatrix(io::FileStream &stream);
bool readModel(io::FileStream &stream);
bool readCompound(io::FileStream &stream);
public:
bool loadGroups(const io::FilePtr& file, VoxelVolumes& volumes) override;
bool saveGroups(const VoxelVolumes& volumes, const io::FilePtr& file) override;
};
}

View File

@ -11,6 +11,7 @@
#include "voxelformat/VoxFormat.h"
#include "voxelformat/QBTFormat.h"
#include "voxelformat/QBFormat.h"
#include "voxelformat/QBCLFormat.h"
#include "voxelformat/QEFFormat.h"
#include "voxelformat/VXMFormat.h"
#include "voxelformat/VXRFormat.h"
@ -28,8 +29,9 @@ namespace voxelformat {
// this is the list of supported voxel volume formats that are have importers implemented
const io::FormatDescription SUPPORTED_VOXEL_FORMATS_LOAD[] = {
{"MagicaVoxel", "vox"},
{"Qubicle", "qbt"},
{"Qubicle", "qb"},
{"Qubicle Binary Tree", "qbt"},
{"Qubicle Binary", "qb"},
//{"Qubicle", "qbcl"},
{"Sandbox VoxEdit", "vxm"},
{"Sandbox VoxEdit", "vxr"},
{"BinVox", "binvox"},
@ -37,7 +39,7 @@ const io::FormatDescription SUPPORTED_VOXEL_FORMATS_LOAD[] = {
{"Build engine", "kvx"},
{"Ace of Spades", "kv6"},
{"Tiberian Sun", "vxl"},
{"Qubicle", "qef"},
{"Qubicle Exchange", "qef"},
{"Chronovox", "csm"},
{"Nicks Voxel Model", "nvm"},
{nullptr, nullptr}
@ -47,14 +49,15 @@ const char *SUPPORTED_VOXEL_FORMATS_LOAD_LIST[] = { "qb", "vox", nullptr };
// this is the list of supported voxel or mesh formats that have exporters implemented
const io::FormatDescription SUPPORTED_VOXEL_FORMATS_SAVE[] = {
{"MagicaVoxel", "vox"},
{"Qubicle", "qbt"},
{"Qubicle", "qb"},
{"Qubicle Binary Tree", "qbt"},
{"Qubicle Binary", "qb"},
//{"Qubicle", "qbcl"},
{"Sandbox VoxEdit", "vxm"},
{"BinVox", "binvox"},
{"CubeWorld", "cub"},
{"Build engine", "kvx"},
{"Tiberian Sun", "vxl"},
{"Qubicle", "qef"},
{"Qubicle Exchange", "qef"},
{"WaveFront OBJ", "obj"},
{"Polygon File Format", "ply"},
{nullptr, nullptr}
@ -150,6 +153,11 @@ bool loadVolumeFormat(const io::FilePtr& filePtr, voxel::VoxelVolumes& newVolume
if (!f.loadGroups(filePtr, newVolumes)) {
voxelformat::clearVolumes(newVolumes);
}
} else if (ext == "qbcl" || magic == FourCC('Q','B','C','L')) {
voxel::QBCLFormat f;
if (!f.loadGroups(filePtr, newVolumes)) {
voxelformat::clearVolumes(newVolumes);
}
} else {
Log::error("Failed to load model file %s - unsupported file format for extension '%s'",
filePtr->name().c_str(), ext.c_str());

View File

@ -0,0 +1,20 @@
/**
* @file
*/
#include "AbstractVoxFormatTest.h"
#include "voxelformat/QBCLFormat.h"
#include "voxelformat/VolumeFormat.h"
namespace voxel {
class QBCLFormatTest: public AbstractVoxFormatTest {
};
TEST_F(QBCLFormatTest, DISABLED_testLoad) {
QBCLFormat f;
std::unique_ptr<RawVolume> volume(load("qubicle.qbcl", f));
ASSERT_NE(nullptr, volume) << "Could not load qbcl file";
}
}