add vcm format loader
This commit is contained in:
parent
9a0f6b23b0
commit
ec85260ec4
5
res/models/stairs.xml
Normal file
5
res/models/stairs.xml
Normal file
@ -0,0 +1,5 @@
|
||||
<model>
|
||||
<box from="0,0,0" to="1,0.5,1" delete="top"/>
|
||||
<box from="0,0.5,0.5" to="1,1,1" delete="bottom"/>
|
||||
<rect from="0,0.5,0" right="1,0,0" up="0,0,0.5"/>
|
||||
</model>
|
||||
@ -10,6 +10,7 @@
|
||||
#include "coders/imageio.hpp"
|
||||
#include "coders/json.hpp"
|
||||
#include "coders/obj.hpp"
|
||||
#include "coders/vcm.hpp"
|
||||
#include "coders/vec3.hpp"
|
||||
#include "constants.hpp"
|
||||
#include "debug/Logger.hpp"
|
||||
@ -300,7 +301,8 @@ assetload::postfunc assetload::sound(
|
||||
|
||||
static void request_textures(AssetsLoader* loader, const model::Model& model) {
|
||||
for (auto& mesh : model.meshes) {
|
||||
if (mesh.texture.find('$') == std::string::npos) {
|
||||
if (mesh.texture.find('$') == std::string::npos &&
|
||||
mesh.texture.find(':') == std::string::npos) {
|
||||
auto filename = TEXTURES_FOLDER + "/" + mesh.texture;
|
||||
loader->add(
|
||||
AssetType::TEXTURE, filename, mesh.texture, nullptr
|
||||
@ -337,6 +339,7 @@ assetload::postfunc assetload::model(
|
||||
};
|
||||
}
|
||||
path = paths.find(file + ".obj");
|
||||
if (io::exists(path)) {
|
||||
auto text = io::read_string(path);
|
||||
try {
|
||||
auto model = obj::parse(path.string(), text).release();
|
||||
@ -348,6 +351,22 @@ assetload::postfunc assetload::model(
|
||||
std::cerr << err.errorLog() << std::endl;
|
||||
throw;
|
||||
}
|
||||
}
|
||||
path = paths.find(file + ".xml");
|
||||
if (io::exists(path)) {
|
||||
auto text = io::read_string(path);
|
||||
try {
|
||||
auto model = vcm::parse(path.string(), text).release();
|
||||
return [=](Assets* assets) {
|
||||
request_textures(loader, *model);
|
||||
assets->store(std::unique_ptr<model::Model>(model), name);
|
||||
};
|
||||
} catch (const parsing_error& err) {
|
||||
std::cerr << err.errorLog() << std::endl;
|
||||
throw;
|
||||
}
|
||||
}
|
||||
throw std::runtime_error("could not to find model " + util::quote(file));
|
||||
}
|
||||
|
||||
static void read_anim_file(
|
||||
|
||||
143
src/coders/vcm.cpp
Normal file
143
src/coders/vcm.cpp
Normal file
@ -0,0 +1,143 @@
|
||||
#include "vcm.hpp"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include "xml.hpp"
|
||||
#include "util/stringutil.hpp"
|
||||
#include "graphics/commons/Model.hpp"
|
||||
|
||||
using namespace vcm;
|
||||
using namespace xml;
|
||||
|
||||
static const std::unordered_map<std::string, int> side_indices {
|
||||
{"east", 0},
|
||||
{"west", 1},
|
||||
{"top", 2},
|
||||
{"bottom", 3},
|
||||
{"back", 4},
|
||||
{"front", 5},
|
||||
};
|
||||
|
||||
static void perform_rect(const xmlelement& root, model::Model& model) {
|
||||
auto from = root.attr("from").asVec3();
|
||||
auto right = root.attr("right").asVec3();
|
||||
auto up = root.attr("up").asVec3();
|
||||
|
||||
right *= -1;
|
||||
from -= right;
|
||||
|
||||
UVRegion region {};
|
||||
if (root.has("region")) {
|
||||
region.set(root.attr("region").asVec4());
|
||||
} else {
|
||||
region.scale(glm::length(right), glm::length(up));
|
||||
}
|
||||
|
||||
auto flip = root.attr("flip", "").getText();
|
||||
if (flip == "h") {
|
||||
std::swap(region.u1, region.u2);
|
||||
right *= -1;
|
||||
from -= right;
|
||||
} else if (flip == "v") {
|
||||
std::swap(region.v1, region.v2);
|
||||
up *= -1;
|
||||
from -= up;
|
||||
}
|
||||
std::string texture = root.attr("texture", "$0").getText();
|
||||
auto& mesh = model.addMesh(texture);
|
||||
|
||||
auto normal = glm::cross(glm::normalize(right), glm::normalize(up));
|
||||
mesh.addRect(
|
||||
from + right * 0.5f + up * 0.5f,
|
||||
right * 0.5f,
|
||||
up * 0.5f,
|
||||
normal,
|
||||
region
|
||||
);
|
||||
}
|
||||
|
||||
static void perform_box(const xmlelement& root, model::Model& model) {
|
||||
auto from = root.attr("from").asVec3();
|
||||
auto to = root.attr("to").asVec3();
|
||||
|
||||
UVRegion regions[6] {};
|
||||
regions[0].scale(to.x - from.x, to.y - from.y);
|
||||
regions[1].scale(from.x - to.x, to.y - from.y);
|
||||
regions[2].scale(to.x - from.x, to.z - from.z);
|
||||
regions[3].scale(from.x - to.x, to.z - from.z);
|
||||
regions[4].scale(to.z - from.z, to.y - from.y);
|
||||
regions[5].scale(from.z - to.z, to.y - from.y);
|
||||
|
||||
auto center = (from + to) * 0.5f;
|
||||
auto halfsize = (to - from) * 0.5f;
|
||||
|
||||
std::string texfaces[6] {"$0","$1","$2","$3","$4","$5"};
|
||||
|
||||
for (const auto& elem : root.getElements()) {
|
||||
if (elem->getTag() == "part") {
|
||||
// todo: replace by expression parsing
|
||||
auto tags = util::split(elem->attr("tags").getText(), ',');
|
||||
for (auto& tag : tags) {
|
||||
util::trim(tag);
|
||||
const auto& found = side_indices.find(tag);
|
||||
if (found == side_indices.end()) {
|
||||
continue;
|
||||
}
|
||||
int idx = found->second;
|
||||
if (elem->has("texture")) {
|
||||
texfaces[idx] = elem->attr("texture").getText();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool deleted[6] {};
|
||||
if (root.has("delete")) {
|
||||
// todo: replace by expression parsing
|
||||
auto names = util::split(root.attr("delete").getText(), ',');
|
||||
for (auto& name : names) {
|
||||
util::trim(name);
|
||||
const auto& found = side_indices.find(name);
|
||||
if (found != side_indices.end()) {
|
||||
deleted[found->second] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < 6; i++) {
|
||||
if (deleted[i]) {
|
||||
continue;
|
||||
}
|
||||
bool enabled[6] {};
|
||||
enabled[i] = true;
|
||||
auto& mesh = model.addMesh(texfaces[i]);
|
||||
mesh.addBox(center, halfsize, regions, enabled);
|
||||
}
|
||||
}
|
||||
|
||||
static std::unique_ptr<model::Model> load_model(const xmlelement& root) {
|
||||
model::Model model;
|
||||
|
||||
for (const auto& elem : root.getElements()) {
|
||||
auto tag = elem->getTag();
|
||||
|
||||
if (tag == "rect") {
|
||||
perform_rect(*elem, model);
|
||||
} else if (tag == "box") {
|
||||
perform_box(*elem, model);
|
||||
}
|
||||
}
|
||||
|
||||
return std::make_unique<model::Model>(std::move(model));
|
||||
}
|
||||
|
||||
std::unique_ptr<model::Model> vcm::parse(std::string_view file, std::string_view src) {
|
||||
auto doc = xml::parse(file, src);
|
||||
const auto& root = *doc->getRoot();
|
||||
if (root.getTag() != "model") {
|
||||
throw std::runtime_error(
|
||||
"'model' tag expected as root, got '" + root.getTag() + "'"
|
||||
);
|
||||
}
|
||||
return load_model(root);
|
||||
}
|
||||
12
src/coders/vcm.hpp
Normal file
12
src/coders/vcm.hpp
Normal file
@ -0,0 +1,12 @@
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
namespace model {
|
||||
struct Model;
|
||||
}
|
||||
|
||||
namespace vcm {
|
||||
std::unique_ptr<model::Model> parse(std::string_view file, std::string_view src);
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user