VOXELFORMAT: improved vxr node handling

master
Martin Gerhardy 2022-01-19 23:19:42 +01:00
parent ac2ebcded9
commit 54549a590c
7 changed files with 109 additions and 144 deletions

View File

@ -220,6 +220,16 @@ inline core::String toString(const float& v) {
return core::String::format("%f", v);
}
template<>
inline core::String toString(const bool& v) {
return v ? "true" : "false";
}
template<>
inline core::String toString(const core::String& v) {
return v;
}
template<>
inline core::String toString(const double& v) {
return core::String::format("%f", v);

View File

@ -85,6 +85,7 @@ SceneGraphNode* SceneGraph::findNodeByName(const core::String& name) {
}
int SceneGraph::emplace(SceneGraphNode &&node, int parent) {
core_assert_msg((int)node.type() >= 0 && (int)node.type() < (int)voxel::SceneGraphNodeType::Max, "%i", (int)node.type());
if (node.type() == SceneGraphNodeType::Root && _nextNodeId != 0) {
Log::error("No second root node is allowed in the scene graph");
node.release();

View File

@ -121,9 +121,4 @@ void SceneGraphNode::addProperties(const core::StringMap<core::String>& map) {
}
}
void SceneGraphNode::setProperty(const core::String& key, const core::String& value) {
_properties.put(key, value);
}
} // namespace voxel

View File

@ -5,6 +5,7 @@
#pragma once
#include "core/String.h"
#include "core/StringUtil.h"
#include "core/collection/Buffer.h"
#include "core/collection/StringMap.h"
#include "voxel/Region.h"
@ -135,7 +136,11 @@ public:
core::StringMap<core::String> &properties();
core::String property(const core::String& key) const;
void addProperties(const core::StringMap<core::String>& map);
void setProperty(const core::String& key, const core::String& value);
template<typename T>
void setProperty(const core::String& key, const T& value) {
_properties.put(key, core::string::toString(value));
}
};
inline int SceneGraphNode::referencedNodeId() const {

View File

@ -220,74 +220,68 @@ bool VXMFormat::loadGroups(const core::String &filename, io::SeekableReadStream&
return false;
}
bool foundPivot = false;
glm::ivec3 ipivot { 0 };
glm::vec3 pivot{0.5f, 0.0f, 0.5f};
glm::uvec3 size(0);
Log::debug("Found vxm%i", version);
if (version >= 6) {
wrap(stream.readUInt32(size.x));
wrap(stream.readUInt32(size.y));
wrap(stream.readUInt32(size.z));
}
if (version >= 5) {
if (version >= 6) {
wrap(stream.readUInt32(size.x));
wrap(stream.readUInt32(size.y));
wrap(stream.readUInt32(size.z));
}
glm::vec3 pivot;
wrap(stream.readFloat(pivot.x));
wrap(stream.readFloat(pivot.y));
wrap(stream.readFloat(pivot.z));
ipivot.x = (int)pivot.x;
ipivot.y = (int)pivot.y;
ipivot.z = (int)pivot.z;
foundPivot = true;
if (version >= 9) {
uint8_t surface;
wrap(stream.readUInt8(surface))
if (surface) {
uint32_t skipWidth = 0u;
uint32_t skipHeight = 0u;
uint32_t startx, starty, startz;
uint32_t endx, endy, endz;
uint32_t normal;
// since version 10 the start and end values are floats
// but for us this fact doesn't matter
wrap(stream.readUInt32(startx))
wrap(stream.readUInt32(starty))
wrap(stream.readUInt32(startz))
wrap(stream.readUInt32(endx))
wrap(stream.readUInt32(endy))
wrap(stream.readUInt32(endz))
wrap(stream.readUInt32(normal))
if (version >= 10) {
wrap(stream.readUInt32(skipWidth))
wrap(stream.readUInt32(skipHeight))
} else {
switch (normal) {
case 0:
case 1:
skipWidth = endz - startz;
skipHeight = endy - starty;
break;
case 2:
case 3:
skipWidth = endx - startx;
skipHeight = endz - startz;
break;
case 4:
case 5:
skipWidth = endx - startx;
skipHeight = endy - starty;
break;
}
}
if (version >= 9) {
uint8_t surface;
wrap(stream.readUInt8(surface))
if (surface) {
uint32_t skipWidth = 0u;
uint32_t skipHeight = 0u;
uint32_t startx, starty, startz;
uint32_t endx, endy, endz;
uint32_t normal;
// since version 10 the start and end values are floats
// but for us this fact doesn't matter
wrap(stream.readUInt32(startx))
wrap(stream.readUInt32(starty))
wrap(stream.readUInt32(startz))
wrap(stream.readUInt32(endx))
wrap(stream.readUInt32(endy))
wrap(stream.readUInt32(endz))
wrap(stream.readUInt32(normal))
if (version >= 10) {
wrap(stream.readUInt32(skipWidth))
wrap(stream.readUInt32(skipHeight))
} else {
switch (normal) {
case 0:
case 1:
skipWidth = endz - startz;
skipHeight = endy - starty;
break;
case 2:
case 3:
skipWidth = endx - startx;
skipHeight = endz - startz;
break;
case 4:
case 5:
skipWidth = endx - startx;
skipHeight = endy - starty;
break;
}
stream.skip(skipWidth * skipHeight);
}
stream.skip(skipWidth * skipHeight);
}
if (version >= 8) {
float dummy; // since version 'A'
wrap(stream.readFloat(dummy)); // lod scale
wrap(stream.readFloat(dummy)); // lod pivot x
wrap(stream.readFloat(dummy)); // lod pivot y
wrap(stream.readFloat(dummy)); // lod pivot z
}
}
if (version >= 8) {
float dummy; // since version 'A'
wrap(stream.readFloat(dummy)); // lod scale
wrap(stream.readFloat(dummy)); // lod pivot x
wrap(stream.readFloat(dummy)); // lod pivot y
wrap(stream.readFloat(dummy)); // lod pivot z
}
uint32_t lodLevels = 1;
@ -421,10 +415,6 @@ bool VXMFormat::loadGroups(const core::String &filename, io::SeekableReadStream&
const Region region(glm::ivec3(0), glm::ivec3(size) - 1);
if (!foundPivot) {
ipivot = region.getCenter();
}
uint8_t maxLayers = 1;
if (version >= 12) {
wrap(stream.readUInt8(maxLayers));
@ -439,7 +429,7 @@ bool VXMFormat::loadGroups(const core::String &filename, io::SeekableReadStream&
wrapBool(stream.readString(sizeof(layerName), layerName, true))
visible = stream.readBool();
} else {
core::string::formatBuf(layerName, sizeof(layerName), "Main");
core::string::formatBuf(layerName, sizeof(layerName), "Layer %i", layer);
}
for (;;) {
uint8_t length;
@ -477,7 +467,7 @@ bool VXMFormat::loadGroups(const core::String &filename, io::SeekableReadStream&
node.setName(layerName);
node.setVisible(visible);
node.setProperty("version", core::string::toString(version));
node.setPivot(ipivot);
node.setPivot(pivot);
sceneGraph.emplace(core::move(node));
}
@ -496,7 +486,7 @@ bool VXMFormat::loadGroups(const core::String &filename, io::SeekableReadStream&
wrap(stream.readUInt32(endz))
wrap(stream.readUInt32(normal))
}
// here might another byte - but it isn't written everytime
// here might be another byte - but it isn't written everytime
}
return true;

View File

@ -81,7 +81,7 @@ bool VXRFormat::saveGroups(const SceneGraph& sceneGraph, const core::String &fil
return true;
}
static inline glm::vec4 transform(const glm::mat4x4 &mat, const glm::ivec3 &pos, const glm::vec4 &pivot) {
static inline glm::vec4 transform(const glm::mat4x4 &mat, const glm::ivec3 &pos, const glm::vec3 &pivot) {
#if 0
glm::vec3 v(pos);
v *= 2.0f;
@ -95,13 +95,11 @@ static inline glm::vec4 transform(const glm::mat4x4 &mat, const glm::ivec3 &pos,
#endif
}
static voxel::RawVolume* transformVolume(const glm::mat4 &mat, const voxel::RawVolume *in) {
static voxel::RawVolume* transformVolume(const glm::mat4 &mat, const voxel::RawVolume *in, const glm::vec3 &pivot) {
const voxel::Region &inRegion = in->region();
const glm::ivec3 inMins(inRegion.getLowerCorner());
const glm::ivec3 inMaxs(inRegion.getUpperCorner());
const glm::ivec3 size = inRegion.getDimensionsInCells();
const glm::vec4 pivot((float)size.x / 2.0f + 0.5f, (float)size.y / 2.0f + 0.5f, (float)size.z / 2.0f + 0.5f, 0.0f);
const glm::vec4 outMins(transform(mat, inMins, pivot));
const glm::vec4 outMaxs(transform(mat, inMaxs, pivot));
const voxel::Region outRegion(glm::min(outMins, outMaxs), glm::max(outMins, outMaxs));
@ -117,35 +115,35 @@ static voxel::RawVolume* transformVolume(const glm::mat4 &mat, const voxel::RawV
return v;
}
int VXRFormat::loadChildVXM(const core::String& vxmPath, SceneGraph& sceneGraph, int parent, voxel::SceneGraphNode &node) {
bool VXRFormat::loadChildVXM(const core::String& vxmPath, SceneGraph& sceneGraph, int parent, voxel::SceneGraphNode &node) {
const io::FilePtr& file = io::filesystem()->open(vxmPath);
if (!file->validHandle()) {
Log::error("Could not open file '%s'", vxmPath.c_str());
return -1;
return false;
}
io::FileStream stream(file.get());
VXMFormat f;
SceneGraph newSceneGraph;
if (!f.loadGroups(vxmPath, stream, newSceneGraph)) {
Log::error("Failed to load '%s'", vxmPath.c_str());
return -1;
return false;
}
const int modelCount = (int)newSceneGraph.size(voxel::SceneGraphNodeType::Model);
if (modelCount > 1) {
Log::warn("Unexpected scene graph found in vxm file - only use the first one");
} else if (modelCount != 1) {
Log::error("No models found in vxm file: %i", modelCount);
return -1;
return false;
}
voxel::SceneGraphNode* modelNode = newSceneGraph[0];
core_assert_always(modelNode != nullptr);
voxel::RawVolume *v = transformVolume(node.matrix(), modelNode->volume());
voxel::RawVolume *v = transformVolume(node.matrix(), modelNode->volume(), modelNode->pivot());
node.setVolume(v, true);
node.setVisible(modelNode->visible());
node.setLocked(modelNode->locked());
node.addProperties(modelNode->properties());
return sceneGraph.emplace(core::move(node), parent);
return true;
}
bool VXRFormat::importChildOld(const core::String &filename, io::SeekableReadStream& stream, SceneGraph& sceneGraph, uint32_t version, int parent) {
@ -223,30 +221,8 @@ bool VXRFormat::importChildOld(const core::String &filename, io::SeekableReadStr
return true;
}
static void addProperty(voxel::SceneGraphNode* node, const char *name, float value) {
if (node == nullptr) {
return;
}
node->setProperty(name, core::string::toString(value));
}
static void addProperty(voxel::SceneGraphNode* node, const char *name, bool value) {
if (node == nullptr) {
return;
}
node->setProperty(name, value ? "true" : "false");
}
static void addProperty(voxel::SceneGraphNode* node, const char *name, const char *value) {
if (node == nullptr) {
return;
}
node->setProperty(name, value);
}
bool VXRFormat::importChild(const core::String& vxmPath, io::SeekableReadStream& stream, SceneGraph& sceneGraph, uint32_t version, int parent) {
voxel::SceneGraphNode node(voxel::SceneGraphNodeType::Model);
int nodeId = -1;
char id[1024];
wrapBool(stream.readString(sizeof(id), id, true))
node.setName(id);
@ -258,45 +234,40 @@ bool VXRFormat::importChild(const core::String& vxmPath, io::SeekableReadStream&
modelPath.append("/");
}
modelPath.append(filename);
nodeId = loadChildVXM(modelPath, sceneGraph, parent, node);
if (nodeId == -1) {
if (!loadChildVXM(modelPath, sceneGraph, parent, node)) {
Log::warn("Failed to attach model for id '%s' with filename %s (%s)", id, filename, modelPath.c_str());
}
} else {
voxel::SceneGraphNode node(voxel::SceneGraphNodeType::Unknown);
node.setName(id);
nodeId = sceneGraph.emplace(core::move(node), parent);
}
addProperty(&node, "id", id);
addProperty(&node, "filename", filename);
node.setProperty("id", id);
node.setProperty("filename", filename);
if (version > 4) {
if (version >= 9) {
addProperty(&node, "collidable", stream.readBool());
addProperty(&node, "decorative", stream.readBool());
node.setProperty("collidable", stream.readBool());
node.setProperty("decorative", stream.readBool());
}
uint32_t dummy;
if (version >= 6) {
wrap(stream.readUInt32(dummy)) // color
addProperty(&node, "favorite", stream.readBool());
addProperty(&node, "visible", stream.readBool());
node.setProperty("favorite", stream.readBool());
node.setProperty("visible", stream.readBool());
}
addProperty(&node, "mirror x axis", stream.readBool());
addProperty(&node, "mirror y axis", stream.readBool());
addProperty(&node, "mirror z axis", stream.readBool());
addProperty(&node, "preview mirror x axis", stream.readBool());
addProperty(&node, "preview mirror y axis", stream.readBool());
addProperty(&node, "preview mirror z axis", stream.readBool());
addProperty(&node, "ikAnchor", stream.readBool());
node.setProperty("mirror x axis", stream.readBool());
node.setProperty("mirror y axis", stream.readBool());
node.setProperty("mirror z axis", stream.readBool());
node.setProperty("preview mirror x axis", stream.readBool());
node.setProperty("preview mirror y axis", stream.readBool());
node.setProperty("preview mirror z axis", stream.readBool());
node.setProperty("ikAnchor", stream.readBool());
float dummyf;
if (version >= 9) {
char effectorId[1024];
wrapBool(stream.readString(sizeof(effectorId), effectorId, true))
addProperty(&node, "effectorId", effectorId);
addProperty(&node, "constraints visible", stream.readBool());
node.setProperty("effectorId", effectorId);
node.setProperty("constraints visible", stream.readBool());
wrap(stream.readFloat(dummyf)) // rollmin
addProperty(&node, "rollmin", dummyf);
node.setProperty("rollmin", dummyf);
wrap(stream.readFloat(dummyf)) // rollmax
addProperty(&node, "rollmax", dummyf);
node.setProperty("rollmax", dummyf);
int32_t constraints;
wrap(stream.readInt32(constraints))
for (int32_t i = 0; i < constraints; ++i) {
@ -314,6 +285,7 @@ bool VXRFormat::importChild(const core::String& vxmPath, io::SeekableReadStream&
stream.readBool(); // ???
}
}
const int nodeId = sceneGraph.emplace(core::move(node), parent);
if (version >= 4) {
int32_t children = 0;
wrap(stream.readInt32(children))
@ -353,21 +325,13 @@ bool VXRFormat::loadGroups(const core::String &filename, io::SeekableReadStream&
return false;
}
int parentNodeId;
{
voxel::SceneGraphNode groupNode(voxel::SceneGraphNodeType::Group);
groupNode.setName("VXR");
parentNodeId = sceneGraph.emplace(core::move(groupNode), sceneGraph.root().id());
}
const int rootNode = sceneGraph.root().id();
voxel::SceneGraphNode *node = nullptr;
if (sceneGraph.hasNode(parentNodeId)) {
node = &sceneGraph.node(parentNodeId);
}
voxel::SceneGraphNode &node = sceneGraph.node(rootNode);
if (version >= 7) {
char defaultAnim[1024];
wrapBool(stream.readString(sizeof(defaultAnim), defaultAnim, true))
addProperty(node, "defaultanim", defaultAnim);
node.setProperty("defaultanim", defaultAnim);
}
if (version <= 3) {
uint32_t dummy;
@ -375,7 +339,7 @@ bool VXRFormat::loadGroups(const core::String &filename, io::SeekableReadStream&
uint32_t children = 0;
wrap(stream.readUInt32(children))
for (uint32_t i = 0; i < children; ++i) {
wrapBool(importChildOld(filename, stream, sceneGraph, version, parentNodeId))
wrapBool(importChildOld(filename, stream, sceneGraph, version, rootNode))
}
int32_t modelCount;
wrap(stream.readInt32(modelCount))
@ -395,7 +359,7 @@ bool VXRFormat::loadGroups(const core::String &filename, io::SeekableReadStream&
modelPath.append("/");
}
modelPath.append(vxmFilename);
if (!loadChildVXM(modelPath, sceneGraph, parentNodeId, *node)) {
if (!loadChildVXM(modelPath, sceneGraph, rootNode, *node)) {
Log::warn("Failed to attach model for %s with filename %s", nodeId, modelPath.c_str());
}
}
@ -409,9 +373,9 @@ bool VXRFormat::loadGroups(const core::String &filename, io::SeekableReadStream&
if (version >= 8) {
char baseTemplate[1024];
wrapBool(stream.readString(sizeof(baseTemplate), baseTemplate, true))
addProperty(node, "basetemplate", baseTemplate);
node.setProperty("basetemplate", baseTemplate);
const bool isStatic = stream.readBool();
addProperty(node, "static", isStatic);
node.setProperty("static", isStatic);
if (isStatic) {
int32_t lodLevels;
wrap(stream.readInt32(lodLevels))
@ -446,7 +410,7 @@ bool VXRFormat::loadGroups(const core::String &filename, io::SeekableReadStream&
Log::debug("Found %i children (%i)", children, (int)sceneGraph.size());
for (int32_t i = 0; i < children; ++i) {
wrapBool(importChild(filename, stream, sceneGraph, version, parentNodeId))
wrapBool(importChild(filename, stream, sceneGraph, version, rootNode))
}
// some files since version 6 still have stuff here

View File

@ -13,7 +13,7 @@ namespace voxel {
*/
class VXRFormat : public Format {
private:
int loadChildVXM(const core::String& vxmPath, SceneGraph& sceneGraph, int parent, voxel::SceneGraphNode &node);
bool loadChildVXM(const core::String& vxmPath, SceneGraph& sceneGraph, int parent, voxel::SceneGraphNode &node);
bool importChild(const core::String& vxmPath, io::SeekableReadStream& stream, SceneGraph& sceneGraph, uint32_t version, int parent);
bool importChildOld(const core::String &filename, io::SeekableReadStream& stream, SceneGraph& sceneGraph, uint32_t version, int parent);
bool saveRecursiveNode(const core::String &name, const voxel::SceneGraphNode& node, const core::String &filename, io::SeekableWriteStream& stream);