feat: new block custom models implementation (WIP)

This commit is contained in:
MihailRis 2024-11-05 19:28:40 +03:00
parent c95c97430a
commit 5e0bcf8ec0
14 changed files with 189 additions and 149 deletions

View File

@ -224,9 +224,9 @@ void ContentLoader::loadBlock(
if (auto model = BlockModel_from(modelName)) {
if (*model == BlockModel::custom) {
if (root.has("model-primitives")) {
loadCustomBlockModel(def, root["model-primitives"]);
def.customModelRaw = root["model-primitives"];
} else {
logger.error() << name << ": no 'model-primitives' found";
throw std::runtime_error(name + ": no 'model-primitives' found");
}
}
def.model = *model;
@ -277,8 +277,6 @@ void ContentLoader::loadBlock(
);
aabb.b += aabb.a;
def.hitboxes = {aabb};
} else if (!def.modelBoxes.empty()) {
def.hitboxes = def.modelBoxes;
} else {
def.hitboxes = {AABB()};
}
@ -350,61 +348,6 @@ void ContentLoader::loadBlock(
}
}
void ContentLoader::loadCustomBlockModel(Block& def, const dv::value& primitives) {
if (primitives.has("aabbs")) {
const auto& modelboxes = primitives["aabbs"];
for (uint i = 0; i < modelboxes.size(); i++) {
// Parse aabb
const auto& boxarr = modelboxes[i];
AABB modelbox;
modelbox.a = glm::vec3(
boxarr[0].asNumber(), boxarr[1].asNumber(), boxarr[2].asNumber()
);
modelbox.b = glm::vec3(
boxarr[3].asNumber(), boxarr[4].asNumber(), boxarr[5].asNumber()
);
modelbox.b += modelbox.a;
def.modelBoxes.push_back(modelbox);
if (boxarr.size() == 7) {
for (uint j = 6; j < 12; j++) {
def.modelTextures.emplace_back(boxarr[6].asString());
}
} else if (boxarr.size() == 12) {
for (uint j = 6; j < 12; j++) {
def.modelTextures.emplace_back(boxarr[j].asString());
}
} else {
for (uint j = 6; j < 12; j++) {
def.modelTextures.emplace_back("notfound");
}
}
}
}
if (primitives.has("tetragons")) {
const auto& modeltetragons = primitives["tetragons"];
for (uint i = 0; i < modeltetragons.size(); i++) {
// Parse tetragon to points
const auto& tgonobj = modeltetragons[i];
glm::vec3 p1(
tgonobj[0].asNumber(), tgonobj[1].asNumber(), tgonobj[2].asNumber()
);
glm::vec3 xw(
tgonobj[3].asNumber(), tgonobj[4].asNumber(), tgonobj[5].asNumber()
);
glm::vec3 yh(
tgonobj[6].asNumber(), tgonobj[7].asNumber(), tgonobj[8].asNumber()
);
def.modelExtraPoints.push_back(p1);
def.modelExtraPoints.push_back(p1 + xw);
def.modelExtraPoints.push_back(p1 + xw + yh);
def.modelExtraPoints.push_back(p1 + yh);
def.modelTextures.emplace_back(tgonobj[9].asString());
}
}
}
void ContentLoader::loadItem(
ItemDef& def, const std::string& name, const fs::path& file
) {

View File

@ -42,7 +42,6 @@ class ContentLoader {
GeneratorDef& def, const std::string& full, const std::string& name
);
static void loadCustomBlockModel(Block& def, const dv::value& primitives);
static void loadBlockMaterial(BlockMaterial& def, const fs::path& file);
void loadBlock(
Block& def, const std::string& name, const fs::path& file

View File

@ -286,6 +286,18 @@ void Engine::loadAssets() {
assets = std::move(new_assets);
if (content) {
for (auto& [name, def] : content->blocks.getDefs()) {
if (def->model == BlockModel::custom) {
assets->store(
std::make_unique<model::Model>(
ModelsGenerator::loadCustomBlockModel(
def->customModelRaw, *assets, !def->shadeless
)
),
name + ".model"
);
}
}
for (auto& [name, def] : content->items.getDefs()) {
assets->store(
std::make_unique<model::Model>(

View File

@ -1,24 +1,25 @@
#include "ContentGfxCache.hpp"
#include "UiDocument.hpp"
#include <string>
#include "UiDocument.hpp"
#include "assets/Assets.hpp"
#include "content/Content.hpp"
#include "content/ContentPack.hpp"
#include "core_defs.hpp"
#include "graphics/commons/Model.hpp"
#include "graphics/core/Atlas.hpp"
#include "maths/UVRegion.hpp"
#include "voxels/Block.hpp"
#include <string>
ContentGfxCache::ContentGfxCache(const Content* content, Assets* assets) : content(content) {
ContentGfxCache::ContentGfxCache(const Content* content, Assets* assets)
: content(content) {
auto indices = content->getIndices();
sideregions = std::make_unique<UVRegion[]>(indices->blocks.count() * 6);
auto atlas = assets->get<Atlas>("blocks");
const auto& blocks = indices->blocks.getIterable();
for (uint i = 0; i < blocks.size(); i++) {
for (blockid_t i = 0; i < blocks.size(); i++) {
auto def = blocks[i];
for (uint side = 0; side < 6; side++) {
const std::string& tex = def->textureFaces[side];
@ -28,13 +29,9 @@ ContentGfxCache::ContentGfxCache(const Content* content, Assets* assets) : conte
sideregions[i * 6 + side] = atlas->get(TEXTURE_NOTFOUND);
}
}
for (uint side = 0; side < def->modelTextures.size(); side++) {
const std::string& tex = def->modelTextures[side];
if (atlas->has(tex)) {
def->modelUVs.push_back(atlas->get(tex));
} else if (atlas->has(TEXTURE_NOTFOUND)) {
def->modelUVs.push_back(atlas->get(TEXTURE_NOTFOUND));
}
if (def->model == BlockModel::custom) {
models[def->rt.id] =
assets->require<model::Model>(def->name + ".model");
}
}
}
@ -44,3 +41,11 @@ ContentGfxCache::~ContentGfxCache() = default;
const Content* ContentGfxCache::getContent() const {
return content;
}
const model::Model& ContentGfxCache::getModel(blockid_t id) const {
const auto& found = models.find(id);
if (found == models.end()) {
throw std::runtime_error("model not found");
}
return found->second;
}

View File

@ -3,15 +3,22 @@
#include "typedefs.hpp"
#include <memory>
#include <stdexcept>
#include <unordered_map>
class Content;
class Assets;
struct UVRegion;
namespace model {
struct Model;
}
class ContentGfxCache {
const Content* content;
// array of block sides uv regions (6 per block)
std::unique_ptr<UVRegion[]> sideregions;
std::unordered_map<blockid_t, model::Model> models;
public:
ContentGfxCache(const Content* content, Assets* assets);
~ContentGfxCache();
@ -19,6 +26,8 @@ public:
inline const UVRegion& getRegion(blockid_t id, int side) const {
return sideregions[id * 6 + side];
}
const model::Model& getModel(blockid_t id) const;
const Content* getContent() const;
};

View File

@ -36,7 +36,7 @@ void Mesh::addPlane(
vertices.push_back({pos-right-up, {uv.u1, uv.v1}, norm});
vertices.push_back({pos+right+up, {uv.u2, uv.v2}, norm});
vertices.push_back({pos-right+up, {uv.u1, uv.u2}, norm});
vertices.push_back({pos-right+up, {uv.u1, uv.v2}, norm});
}
void Mesh::addBox(const glm::vec3& pos, const glm::vec3& size) {

View File

@ -64,41 +64,41 @@ std::unique_ptr<ImageData> BlocksPreview::draw(
{
glm::vec3 pmul = glm::vec3(size * 0.63f);
glm::vec3 hitbox = glm::vec3();
for (const auto& box : def.modelBoxes) {
hitbox = glm::max(hitbox, box.size());
}
// for (const auto& box : def.modelBoxes) {
// hitbox = glm::max(hitbox, box.size());
// }
offset.y += (1.0f - hitbox).y * 0.5f;
shader->uniformMatrix("u_apply", glm::translate(glm::mat4(1.0f), offset));
for (size_t i = 0; i < def.modelBoxes.size(); i++) {
const UVRegion (&boxtexfaces)[6] = {
def.modelUVs[i * 6],
def.modelUVs[i * 6 + 1],
def.modelUVs[i * 6 + 2],
def.modelUVs[i * 6 + 3],
def.modelUVs[i * 6 + 4],
def.modelUVs[i * 6 + 5]
};
batch->cube(
def.modelBoxes[i].a * glm::vec3(1.0f, 1.0f, -1.0f) * pmul,
def.modelBoxes[i].size() * pmul,
boxtexfaces, glm::vec4(1.0f), !def.rt.emissive
);
}
// for (size_t i = 0; i < def.modelBoxes.size(); i++) {
// const UVRegion (&boxtexfaces)[6] = {
// def.modelUVs[i * 6],
// def.modelUVs[i * 6 + 1],
// def.modelUVs[i * 6 + 2],
// def.modelUVs[i * 6 + 3],
// def.modelUVs[i * 6 + 4],
// def.modelUVs[i * 6 + 5]
// };
// batch->cube(
// def.modelBoxes[i].a * glm::vec3(1.0f, 1.0f, -1.0f) * pmul,
// def.modelBoxes[i].size() * pmul,
// boxtexfaces, glm::vec4(1.0f), !def.rt.emissive
// );
// }
auto& points = def.modelExtraPoints;
glm::vec3 poff = glm::vec3(0.0f, 0.0f, 1.0f);
// auto& points = def.modelExtraPoints;
// glm::vec3 poff = glm::vec3(0.0f, 0.0f, 1.0f);
for (size_t i = 0; i < def.modelExtraPoints.size() / 4; i++) {
const UVRegion& reg = def.modelUVs[def.modelBoxes.size() * 6 + i];
// for (size_t i = 0; i < def.modelExtraPoints.size() / 4; i++) {
// const UVRegion& reg = def.modelUVs[def.modelBoxes.size() * 6 + i];
batch->vertex((points[i * 4 + 0] - poff) * pmul, glm::vec2(reg.u1, reg.v1), glm::vec4(1.0));
batch->vertex((points[i * 4 + 1] - poff) * pmul, glm::vec2(reg.u2, reg.v1), glm::vec4(1.0));
batch->vertex((points[i * 4 + 2] - poff) * pmul, glm::vec2(reg.u2, reg.v2), glm::vec4(1.0));
batch->vertex((points[i * 4 + 0] - poff) * pmul, glm::vec2(reg.u1, reg.v1), glm::vec4(1.0));
batch->vertex((points[i * 4 + 2] - poff) * pmul, glm::vec2(reg.u2, reg.v2), glm::vec4(1.0));
batch->vertex((points[i * 4 + 3] - poff) * pmul, glm::vec2(reg.u1, reg.v2), glm::vec4(1.0));
}
batch->flush();
// batch->vertex((points[i * 4 + 0] - poff) * pmul, glm::vec2(reg.u1, reg.v1), glm::vec4(1.0));
// batch->vertex((points[i * 4 + 1] - poff) * pmul, glm::vec2(reg.u2, reg.v1), glm::vec4(1.0));
// batch->vertex((points[i * 4 + 2] - poff) * pmul, glm::vec2(reg.u2, reg.v2), glm::vec4(1.0));
// batch->vertex((points[i * 4 + 0] - poff) * pmul, glm::vec2(reg.u1, reg.v1), glm::vec4(1.0));
// batch->vertex((points[i * 4 + 2] - poff) * pmul, glm::vec2(reg.u2, reg.v2), glm::vec4(1.0));
// batch->vertex((points[i * 4 + 3] - poff) * pmul, glm::vec2(reg.u1, reg.v2), glm::vec4(1.0));
// }
// batch->flush();
}
break;
case BlockModel::xsprite: {

View File

@ -1,6 +1,7 @@
#include "BlocksRenderer.hpp"
#include "graphics/core/Mesh.hpp"
#include "graphics/commons/Model.hpp"
#include "maths/UVRegion.hpp"
#include "constants.hpp"
#include "content/Content.hpp"
@ -303,6 +304,7 @@ void BlocksRenderer::blockAABB(
}
}
#include <iostream>
void BlocksRenderer::blockCustomModel(
const glm::ivec3& icoord, const Block* block, ubyte rotation, bool lights, bool ao
) {
@ -319,29 +321,31 @@ void BlocksRenderer::blockCustomModel(
Z = orient.axisZ;
}
for (size_t i = 0; i < block->modelBoxes.size(); i++) {
AABB box = block->modelBoxes[i];
auto size = box.size();
if (block->rotatable) {
orient.transform(box);
const auto& model = cache->getModel(block->rt.id);
for (const auto& mesh : model.meshes) {
if (vertexOffset + BlocksRenderer::VERTEX_SIZE * mesh.vertices.size() > capacity) {
overflow = true;
return;
}
int i = 0;
for (const auto& vertex : mesh.vertices) {
if ((i++) % 6 < 3) {
// continue;
}
float d = glm::dot(glm::normalize(vertex.normal), SUN_VECTOR);
d = 0.8f + d * 0.2f;
const auto& n = vertex.normal;
vertexAO(
coord + vertex.coord - 0.5f,
vertex.uv.x,
vertex.uv.y,
glm::vec4(1, 1, 1, 0),
glm::vec3(n.x, -n.z, n.y),
glm::vec3(0, 1, 0),
n
);
indexBuffer[indexSize++] = indexOffset++;
}
glm::vec3 center_coord = coord - glm::vec3(0.5f) + box.center();
faceAO(center_coord, X * size.x, Y * size.y, Z * size.z, block->modelUVs[i * 6 + 5], lights); // north
faceAO(center_coord, -X * size.x, Y * size.y, -Z * size.z, block->modelUVs[i * 6 + 4], lights); // south
faceAO(center_coord, X * size.x, -Z * size.z, Y * size.y, block->modelUVs[i * 6 + 3], lights); // top
faceAO(center_coord, -X * size.x, -Z * size.z, -Y * size.y, block->modelUVs[i * 6 + 2], lights); // bottom
faceAO(center_coord, -Z * size.z, Y * size.y, X * size.x, block->modelUVs[i * 6 + 1], lights); // west
faceAO(center_coord, Z * size.z, Y * size.y, -X * size.x, block->modelUVs[i * 6 + 0], lights); // east
}
for (size_t i = 0; i < block->modelExtraPoints.size()/4; i++) {
tetragonicFace(coord,
block->modelExtraPoints[i * 4 + 0],
block->modelExtraPoints[i * 4 + 1],
block->modelExtraPoints[i * 4 + 2],
block->modelExtraPoints[i * 4 + 3],
X, Y, Z,
block->modelUVs[block->modelBoxes.size()*6 + i], lights);
}
}

View File

@ -59,13 +59,14 @@ model::Model ModelsGenerator::fromCustom(
for (size_t i = 0; i < modelBoxes.size(); i++) {
auto& mesh = model.addMesh("blocks:" + modelTextures[i * 6]);
mesh.lighting = lighting;
const UVRegion(&boxtexfaces)[6] = {
const UVRegion boxtexfaces[6] = {
get_region_for(modelTextures[i * 6], assets),
get_region_for(modelTextures[i * 6 + 1], assets),
get_region_for(modelTextures[i * 6 + 2], assets),
get_region_for(modelTextures[i * 6 + 3], assets),
get_region_for(modelTextures[i * 6 + 4], assets),
get_region_for(modelTextures[i * 6 + 5], assets)};
get_region_for(modelTextures[i * 6 + 5], assets)
};
mesh.addBox(
modelBoxes[i].center(), modelBoxes[i].size() * 0.5f, boxtexfaces
);
@ -112,13 +113,7 @@ model::Model ModelsGenerator::generate(
"blocks:" + blockDef.textureFaces.at(0), assets
);
} else if (blockDef.model == BlockModel::custom) {
model = fromCustom(
assets,
blockDef.modelBoxes,
blockDef.modelTextures,
blockDef.modelExtraPoints,
!blockDef.shadeless
);
model = assets.require<model::Model>(blockDef.name+".model");
for (auto& mesh : model.meshes) {
mesh.scale(glm::vec3(0.3f));
}
@ -146,3 +141,67 @@ model::Model ModelsGenerator::generate(
return model::Model();
}
}
model::Model ModelsGenerator::loadCustomBlockModel(
const dv::value& primitives, const Assets& assets, bool lighting
) {
std::vector<AABB> modelBoxes;
std::vector<std::string> modelTextures;
std::vector<glm::vec3> modelExtraPoints;
if (primitives.has("aabbs")) {
const auto& modelboxes = primitives["aabbs"];
for (uint i = 0; i < modelboxes.size(); i++) {
// Parse aabb
const auto& boxarr = modelboxes[i];
AABB modelbox;
modelbox.a = glm::vec3(
boxarr[0].asNumber(), boxarr[1].asNumber(), boxarr[2].asNumber()
);
modelbox.b = glm::vec3(
boxarr[3].asNumber(), boxarr[4].asNumber(), boxarr[5].asNumber()
);
modelbox.b += modelbox.a;
modelBoxes.push_back(modelbox);
if (boxarr.size() == 7) {
for (uint j = 6; j < 12; j++) {
modelTextures.emplace_back(boxarr[6].asString());
}
} else if (boxarr.size() == 12) {
for (uint j = 6; j < 12; j++) {
modelTextures.emplace_back(boxarr[j].asString());
}
} else {
for (uint j = 6; j < 12; j++) {
modelTextures.emplace_back("notfound");
}
}
}
}
if (primitives.has("tetragons")) {
const auto& modeltetragons = primitives["tetragons"];
for (uint i = 0; i < modeltetragons.size(); i++) {
// Parse tetragon to points
const auto& tgonobj = modeltetragons[i];
glm::vec3 p1(
tgonobj[0].asNumber(), tgonobj[1].asNumber(), tgonobj[2].asNumber()
);
glm::vec3 xw(
tgonobj[3].asNumber(), tgonobj[4].asNumber(), tgonobj[5].asNumber()
);
glm::vec3 yh(
tgonobj[6].asNumber(), tgonobj[7].asNumber(), tgonobj[8].asNumber()
);
modelExtraPoints.push_back(p1);
modelExtraPoints.push_back(p1 + xw);
modelExtraPoints.push_back(p1 + xw + yh);
modelExtraPoints.push_back(p1 + yh);
modelTextures.emplace_back(tgonobj[9].asString());
}
}
return fromCustom(
assets, modelBoxes, modelTextures, modelExtraPoints, lighting
);
}

View File

@ -2,10 +2,12 @@
#include "graphics/commons/Model.hpp"
#include "maths/aabb.hpp"
#include "data/dv.hpp"
struct ItemDef;
class Assets;
class Content;
struct Block;
class ModelsGenerator {
public:
@ -20,4 +22,8 @@ public:
const std::vector<glm::vec3>& points,
bool lighting
);
static model::Model loadCustomBlockModel(
const dv::value& primitives, const Assets& assets, bool lighting
);
};

View File

@ -1,6 +1,7 @@
#pragma once
#include <cmath>
#include <glm/vec2.hpp>
struct UVRegion {
float u1;
@ -33,4 +34,10 @@ struct UVRegion {
u2 = u1 + uvw * w;
v2 = v1 + uvh * h;
}
inline glm::vec2 apply(const glm::vec2& uv) {
float w = getWidth();
float h = getHeight();
return glm::vec2(u1 + uv.x / w, v1 + uv.y / h);
}
};

View File

@ -114,12 +114,8 @@ Block::Block(std::string name, const std::string& texture)
void Block::cloneTo(Block& dst) {
dst.caption = caption;
for (int i = 0; i < 6; i++) {
dst.textureFaces[i] = textureFaces[i];
dst.textureFaces[i] = textureFaces[i];
}
dst.modelTextures = modelTextures;
dst.modelBoxes = modelBoxes;
dst.modelExtraPoints = modelExtraPoints;
dst.modelUVs = modelUVs;
dst.material = material;
std::copy(&emission[0], &emission[3], dst.emission);
dst.size = size;
@ -143,7 +139,10 @@ void Block::cloneTo(Block& dst) {
dst.inventorySize = inventorySize;
dst.tickInterval = tickInterval;
dst.overlayTexture = overlayTexture;
dst.particles = std::make_unique<ParticlesPreset>(*particles);
if (particles) {
dst.particles = std::make_unique<ParticlesPreset>(*particles);
}
dst.customModelRaw = customModelRaw;
}
static std::set<std::string, std::less<>> RESERVED_BLOCK_FIELDS {

View File

@ -6,6 +6,7 @@
#include <vector>
#include <array>
#include "data/dv.hpp"
#include "maths/UVRegion.hpp"
#include "maths/aabb.hpp"
#include "typedefs.hpp"
@ -116,12 +117,6 @@ public:
/// @brief Textures set applied to block sides
std::array<std::string, 6> textureFaces; // -x,x, -y,y, -z,z
std::vector<std::string> modelTextures = {};
std::vector<BoxModel> modelBoxes = {};
// initially made for tetragons
std::vector<glm::vec3> modelExtraPoints = {};
std::vector<UVRegion> modelUVs = {}; // boxes' tex-UVs also there
/// @brief id of used BlockMaterial, may specify non-existing material
std::string material = DEFAULT_MATERIAL;
@ -137,6 +132,9 @@ public:
/// @brief Block model type
BlockModel model = BlockModel::block;
/// @brief Custom model raw data
dv::value customModelRaw = nullptr;
/// @brief Does the block passing lights into itself
bool lightPassing = false;

View File

@ -597,8 +597,7 @@ glm::vec3 Chunks::rayCastToObstacle(
if (def.obstacle) {
if (!def.rt.solid) {
const std::vector<AABB>& hitboxes =
def.rotatable ? def.rt.hitboxes[voxel->state.rotation]
: def.modelBoxes;
def.rt.hitboxes[voxel->state.rotation];
scalar_t distance;
glm::ivec3 norm;