add variants (WIP)
This commit is contained in:
@@ -44,7 +44,7 @@ void BlockWrapsRenderer::draw(const BlockWrapper& wrapper) {
|
||||
}
|
||||
if (vox->id != BLOCK_VOID) {
|
||||
const auto& def = level.content.getIndices()->blocks.require(vox->id);
|
||||
switch (def.model.type) {
|
||||
switch (def.getModel(vox->state.userbits).type) {
|
||||
case BlockModelType::BLOCK:
|
||||
batch->cube(
|
||||
glm::vec3(wrapper.position) + glm::vec3(0.5f),
|
||||
|
||||
@@ -27,12 +27,12 @@ std::unique_ptr<ImageData> BlocksPreview::draw(
|
||||
){
|
||||
display::clear();
|
||||
blockid_t id = def.rt.id;
|
||||
const UVRegion texfaces[6]{cache.getRegion(id, 0), cache.getRegion(id, 1),
|
||||
cache.getRegion(id, 2), cache.getRegion(id, 3),
|
||||
cache.getRegion(id, 4), cache.getRegion(id, 5)};
|
||||
const UVRegion texfaces[6]{cache.getRegion(id, 0, 0), cache.getRegion(id, 0, 1),
|
||||
cache.getRegion(id, 0, 2), cache.getRegion(id, 0, 3),
|
||||
cache.getRegion(id, 0, 4), cache.getRegion(id, 0, 5)};
|
||||
|
||||
glm::vec3 offset(0.1f, 0.5f, 0.1f);
|
||||
switch (def.model.type) {
|
||||
switch (def.defaults.model.type) {
|
||||
case BlockModelType::NONE:
|
||||
// something went wrong...
|
||||
break;
|
||||
|
||||
@@ -292,21 +292,22 @@ static bool is_aligned(const glm::vec3& v, float e = 1e-6f) {
|
||||
}
|
||||
|
||||
void BlocksRenderer::blockCustomModel(
|
||||
const glm::ivec3& icoord, const Block* block, ubyte rotation, bool lights, bool ao
|
||||
const glm::ivec3& icoord, const Block& block, blockstate states, bool lights, bool ao
|
||||
) {
|
||||
const auto& variant = block.getVariant(states.userbits);
|
||||
glm::vec3 X(1, 0, 0);
|
||||
glm::vec3 Y(0, 1, 0);
|
||||
glm::vec3 Z(0, 0, 1);
|
||||
glm::vec3 coord(icoord);
|
||||
if (block->rotatable) {
|
||||
auto& rotations = block->rotations;
|
||||
CoordSystem orient = rotations.variants[rotation];
|
||||
if (block.rotatable) {
|
||||
auto& rotations = block.rotations;
|
||||
CoordSystem orient = rotations.variants[states.rotation];
|
||||
X = orient.axes[0];
|
||||
Y = orient.axes[1];
|
||||
Z = orient.axes[2];
|
||||
}
|
||||
|
||||
const auto& model = cache.getModel(block->rt.id);
|
||||
const auto& model = cache.getModel(block.rt.id);
|
||||
for (const auto& mesh : model.meshes) {
|
||||
if (vertexCount + mesh.vertices.size() >= capacity) {
|
||||
overflow = true;
|
||||
@@ -328,7 +329,7 @@ void BlocksRenderer::blockCustomModel(
|
||||
0.5f;
|
||||
vp = vp.x * X + vp.y * Y + vp.z * Z;
|
||||
|
||||
if (!isOpen(glm::floor(coord + vp + 0.5f + n * 1e-3f), *block) && is_aligned(n)) {
|
||||
if (!isOpen(glm::floor(coord + vp + 0.5f + n * 1e-3f), block, variant) && is_aligned(n)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -369,6 +370,7 @@ void BlocksRenderer::blockCube(
|
||||
bool lights,
|
||||
bool ao
|
||||
) {
|
||||
const auto& variant = block.getVariant(states.userbits);
|
||||
glm::ivec3 X(1, 0, 0);
|
||||
glm::ivec3 Y(0, 1, 0);
|
||||
glm::ivec3 Z(0, 0, 1);
|
||||
@@ -382,41 +384,41 @@ void BlocksRenderer::blockCube(
|
||||
}
|
||||
|
||||
if (ao) {
|
||||
if (isOpen(coord + Z, block)) {
|
||||
if (isOpen(coord + Z, block, variant)) {
|
||||
faceAO(coord, X, Y, Z, texfaces[5], lights);
|
||||
}
|
||||
if (isOpen(coord - Z, block)) {
|
||||
if (isOpen(coord - Z, block, variant)) {
|
||||
faceAO(coord, -X, Y, -Z, texfaces[4], lights);
|
||||
}
|
||||
if (isOpen(coord + Y, block)) {
|
||||
if (isOpen(coord + Y, block, variant)) {
|
||||
faceAO(coord, X, -Z, Y, texfaces[3], lights);
|
||||
}
|
||||
if (isOpen(coord - Y, block)) {
|
||||
if (isOpen(coord - Y, block, variant)) {
|
||||
faceAO(coord, X, Z, -Y, texfaces[2], lights);
|
||||
}
|
||||
if (isOpen(coord + X, block)) {
|
||||
if (isOpen(coord + X, block, variant)) {
|
||||
faceAO(coord, -Z, Y, X, texfaces[1], lights);
|
||||
}
|
||||
if (isOpen(coord - X, block)) {
|
||||
if (isOpen(coord - X, block, variant)) {
|
||||
faceAO(coord, Z, Y, -X, texfaces[0], lights);
|
||||
}
|
||||
} else {
|
||||
if (isOpen(coord + Z, block)) {
|
||||
if (isOpen(coord + Z, block, variant)) {
|
||||
face(coord, X, Y, Z, texfaces[5], pickLight(coord + Z), lights);
|
||||
}
|
||||
if (isOpen(coord - Z, block)) {
|
||||
if (isOpen(coord - Z, block, variant)) {
|
||||
face(coord, -X, Y, -Z, texfaces[4], pickLight(coord - Z), lights);
|
||||
}
|
||||
if (isOpen(coord + Y, block)) {
|
||||
if (isOpen(coord + Y, block, variant)) {
|
||||
face(coord, X, -Z, Y, texfaces[3], pickLight(coord + Y), lights);
|
||||
}
|
||||
if (isOpen(coord - Y, block)) {
|
||||
if (isOpen(coord - Y, block, variant)) {
|
||||
face(coord, X, Z, -Y, texfaces[2], pickLight(coord - Y), lights);
|
||||
}
|
||||
if (isOpen(coord + X, block)) {
|
||||
if (isOpen(coord + X, block, variant)) {
|
||||
face(coord, -Z, Y, X, texfaces[1], pickLight(coord + X), lights);
|
||||
}
|
||||
if (isOpen(coord - X, block)) {
|
||||
if (isOpen(coord - X, block, variant)) {
|
||||
face(coord, Z, Y, -X, texfaces[0], pickLight(coord - X), lights);
|
||||
}
|
||||
}
|
||||
@@ -486,21 +488,26 @@ void BlocksRenderer::render(
|
||||
blockid_t id = vox.id;
|
||||
blockstate state = vox.state;
|
||||
const auto& def = *blockDefsCache[id];
|
||||
if (id == 0 || def.drawGroup != drawGroup || state.segment) {
|
||||
const auto& variant = def.getVariant(state.userbits);
|
||||
uint8_t variantId = state.userbits;
|
||||
if (id == 0 || variant.drawGroup != drawGroup || state.segment) {
|
||||
continue;
|
||||
}
|
||||
if (def.translucent) {
|
||||
continue;
|
||||
}
|
||||
const UVRegion texfaces[6] {
|
||||
cache.getRegion(id, 0), cache.getRegion(id, 1),
|
||||
cache.getRegion(id, 2), cache.getRegion(id, 3),
|
||||
cache.getRegion(id, 4), cache.getRegion(id, 5)
|
||||
cache.getRegion(id, variantId, 0),
|
||||
cache.getRegion(id, variantId, 1),
|
||||
cache.getRegion(id, variantId, 2),
|
||||
cache.getRegion(id, variantId, 3),
|
||||
cache.getRegion(id, variantId, 4),
|
||||
cache.getRegion(id, variantId, 5)
|
||||
};
|
||||
int x = i % CHUNK_W;
|
||||
int y = i / (CHUNK_D * CHUNK_W);
|
||||
int z = (i / CHUNK_D) % CHUNK_W;
|
||||
switch (def.model.type) {
|
||||
switch (def.getModel(state.userbits).type) {
|
||||
case BlockModelType::BLOCK:
|
||||
blockCube({x, y, z}, texfaces, def, vox.state, !def.shadeless,
|
||||
def.ambientOcclusion);
|
||||
@@ -516,8 +523,13 @@ void BlocksRenderer::render(
|
||||
break;
|
||||
}
|
||||
case BlockModelType::CUSTOM: {
|
||||
blockCustomModel({x, y, z}, &def, vox.state.rotation,
|
||||
!def.shadeless, def.ambientOcclusion);
|
||||
blockCustomModel(
|
||||
{x, y, z},
|
||||
def,
|
||||
vox.state,
|
||||
!def.shadeless,
|
||||
def.ambientOcclusion
|
||||
);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
@@ -549,21 +561,26 @@ SortingMeshData BlocksRenderer::renderTranslucent(
|
||||
blockid_t id = vox.id;
|
||||
blockstate state = vox.state;
|
||||
const auto& def = *blockDefsCache[id];
|
||||
if (id == 0 || def.drawGroup != drawGroup || state.segment) {
|
||||
uint8_t variantId = state.userbits;
|
||||
const auto& variant = def.getVariant(variantId);
|
||||
if (id == 0 || variant.drawGroup != drawGroup || state.segment) {
|
||||
continue;
|
||||
}
|
||||
if (!def.translucent) {
|
||||
continue;
|
||||
}
|
||||
const UVRegion texfaces[6] {
|
||||
cache.getRegion(id, 0), cache.getRegion(id, 1),
|
||||
cache.getRegion(id, 2), cache.getRegion(id, 3),
|
||||
cache.getRegion(id, 4), cache.getRegion(id, 5)
|
||||
cache.getRegion(id, variantId, 0),
|
||||
cache.getRegion(id, variantId, 1),
|
||||
cache.getRegion(id, variantId, 2),
|
||||
cache.getRegion(id, variantId, 3),
|
||||
cache.getRegion(id, variantId, 4),
|
||||
cache.getRegion(id, variantId, 5)
|
||||
};
|
||||
int x = i % CHUNK_W;
|
||||
int y = i / (CHUNK_D * CHUNK_W);
|
||||
int z = (i / CHUNK_D) % CHUNK_W;
|
||||
switch (def.model.type) {
|
||||
switch (def.getModel(state.userbits).type) {
|
||||
case BlockModelType::BLOCK:
|
||||
blockCube({x, y, z}, texfaces, def, vox.state, !def.shadeless,
|
||||
def.ambientOcclusion);
|
||||
@@ -579,7 +596,7 @@ SortingMeshData BlocksRenderer::renderTranslucent(
|
||||
break;
|
||||
}
|
||||
case BlockModelType::CUSTOM: {
|
||||
blockCustomModel({x, y, z}, &def, vox.state.rotation,
|
||||
blockCustomModel({x, y, z}, def, vox.state,
|
||||
!def.shadeless, def.ambientOcclusion);
|
||||
break;
|
||||
}
|
||||
@@ -670,11 +687,12 @@ void BlocksRenderer::build(const Chunk* chunk, const Chunks* chunks) {
|
||||
const voxel& vox = voxels[i];
|
||||
blockid_t id = vox.id;
|
||||
const auto& def = *blockDefsCache[id];
|
||||
const auto& variant = def.getVariant(vox.state.userbits);
|
||||
|
||||
if (beginEnds[def.drawGroup][0] == 0) {
|
||||
beginEnds[def.drawGroup][0] = i+1;
|
||||
if (beginEnds[variant.drawGroup][0] == 0) {
|
||||
beginEnds[variant.drawGroup][0] = i+1;
|
||||
}
|
||||
beginEnds[def.drawGroup][1] = i;
|
||||
beginEnds[variant.drawGroup][1] = i;
|
||||
}
|
||||
cancelled = false;
|
||||
|
||||
|
||||
@@ -113,8 +113,8 @@ class BlocksRenderer {
|
||||
);
|
||||
void blockCustomModel(
|
||||
const glm::ivec3& icoord,
|
||||
const Block* block,
|
||||
ubyte rotation,
|
||||
const Block& block,
|
||||
blockstate states,
|
||||
bool lights,
|
||||
bool ao
|
||||
);
|
||||
@@ -122,24 +122,25 @@ class BlocksRenderer {
|
||||
bool isOpenForLight(int x, int y, int z) const;
|
||||
|
||||
// Does block allow to see other blocks sides (is it transparent)
|
||||
inline bool isOpen(const glm::ivec3& pos, const Block& def) const {
|
||||
auto id = voxelsBuffer->pickBlockId(
|
||||
inline bool isOpen(const glm::ivec3& pos, const Block& def, const Variant& variant) const {
|
||||
auto vox = voxelsBuffer->pickBlock(
|
||||
chunk->x * CHUNK_W + pos.x, pos.y, chunk->z * CHUNK_D + pos.z
|
||||
);
|
||||
if (id == BLOCK_VOID) {
|
||||
if (vox.id == BLOCK_VOID) {
|
||||
return false;
|
||||
}
|
||||
const auto& block = *blockDefsCache[id];
|
||||
if (((block.drawGroup != def.drawGroup) && block.drawGroup) || !block.rt.solid) {
|
||||
const auto& block = *blockDefsCache[vox.id];
|
||||
uint8_t otherDrawGroup = block.getVariant(vox.state.userbits).drawGroup;
|
||||
if ((otherDrawGroup && (otherDrawGroup != variant.drawGroup)) || !block.rt.solid) {
|
||||
return true;
|
||||
}
|
||||
if ((def.culling == CullingMode::DISABLED ||
|
||||
(def.culling == CullingMode::OPTIONAL &&
|
||||
if ((variant.culling == CullingMode::DISABLED ||
|
||||
(variant.culling == CullingMode::OPTIONAL &&
|
||||
settings.graphics.denseRender.get())) &&
|
||||
id == def.rt.id) {
|
||||
vox.id == def.rt.id) {
|
||||
return true;
|
||||
}
|
||||
return !id;
|
||||
return !vox.id;
|
||||
}
|
||||
|
||||
glm::vec4 pickLight(int x, int y, int z) const;
|
||||
|
||||
@@ -11,8 +11,8 @@ static debug::Logger logger("models-generator");
|
||||
|
||||
static void configure_textures(
|
||||
model::Model& model,
|
||||
const Block& blockDef,
|
||||
const Assets& assets
|
||||
const Assets& assets,
|
||||
const std::array<std::string, 6>& textureFaces
|
||||
) {
|
||||
for (auto& mesh : model.meshes) {
|
||||
auto& texture = mesh.texture;
|
||||
@@ -21,7 +21,7 @@ static void configure_textures(
|
||||
}
|
||||
try {
|
||||
int index = std::stoi(texture.substr(1));
|
||||
texture = "blocks:"+blockDef.textureFaces.at(index);
|
||||
texture = "blocks:" + textureFaces.at(index);
|
||||
} catch (const std::invalid_argument& err) {
|
||||
} catch (const std::runtime_error& err) {
|
||||
logger.error() << err.what();
|
||||
@@ -48,35 +48,43 @@ static inline UVRegion get_region_for(
|
||||
return texreg.region;
|
||||
}
|
||||
|
||||
void ModelsGenerator::prepare(Content& content, Assets& assets) {
|
||||
for (auto& [name, def] : content.blocks.getDefs()) {
|
||||
if (def->model.type == BlockModelType::CUSTOM) {
|
||||
if (def->model.name.empty()) {
|
||||
assets.store(
|
||||
std::make_unique<model::Model>(
|
||||
loadCustomBlockModel(
|
||||
def->model.customRaw, assets, !def->shadeless
|
||||
)
|
||||
),
|
||||
name + ".model"
|
||||
);
|
||||
def->model.name = def->name + ".model";
|
||||
} else {
|
||||
auto srcModel = assets.get<model::Model>(def->model.name);
|
||||
if (srcModel) {
|
||||
auto model = std::make_unique<model::Model>(*srcModel);
|
||||
for (auto& mesh : model->meshes) {
|
||||
if (mesh.texture.length() && mesh.texture[0] == '$') {
|
||||
int index = std::stoll(mesh.texture.substr(1));
|
||||
mesh.texture = "blocks:" + def->textureFaces[index];
|
||||
}
|
||||
void ModelsGenerator::prepareModel(
|
||||
Assets& assets, const Block& def, Variant& variant, uint8_t variantId
|
||||
) {
|
||||
BlockModel& blockModel = variant.model;
|
||||
if (blockModel.type == BlockModelType::CUSTOM) {
|
||||
std::string modelName = def.name + ".model" + (variantId == 0 ? "" : "$" + std::to_string(variantId));
|
||||
if (blockModel.name.empty()) {
|
||||
assets.store(
|
||||
std::make_unique<model::Model>(
|
||||
loadCustomBlockModel(
|
||||
blockModel.customRaw, assets, !def.shadeless
|
||||
)
|
||||
),
|
||||
modelName
|
||||
);
|
||||
blockModel.name = modelName;
|
||||
} else {
|
||||
auto srcModel = assets.get<model::Model>(blockModel.name);
|
||||
if (srcModel) {
|
||||
auto model = std::make_unique<model::Model>(*srcModel);
|
||||
for (auto& mesh : model->meshes) {
|
||||
if (mesh.texture.length() && mesh.texture[0] == '$') {
|
||||
int index = std::stoll(mesh.texture.substr(1));
|
||||
mesh.texture = "blocks:" + variant.textureFaces[index];
|
||||
}
|
||||
def->model.name = name + ".model";
|
||||
assets.store(std::move(model), def->model.name);
|
||||
}
|
||||
blockModel.name = modelName;
|
||||
assets.store(std::move(model), blockModel.name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ModelsGenerator::prepare(Content& content, Assets& assets) {
|
||||
for (auto& [name, def] : content.blocks.getDefs()) {
|
||||
prepareModel(assets, *def, def->defaults, 0);
|
||||
}
|
||||
for (auto& [name, def] : content.items.getDefs()) {
|
||||
assets.store(
|
||||
std::make_unique<model::Model>(
|
||||
@@ -151,12 +159,14 @@ model::Model ModelsGenerator::generate(
|
||||
if (def.iconType == ItemIconType::BLOCK) {
|
||||
auto model = assets.require<model::Model>("block");
|
||||
const auto& blockDef = content.blocks.require(def.icon);
|
||||
if (blockDef.model.type == BlockModelType::XSPRITE) {
|
||||
const auto& variant = blockDef.defaults;
|
||||
const auto& blockModel = variant.model;
|
||||
if (blockModel.type == BlockModelType::XSPRITE) {
|
||||
return create_flat_model(
|
||||
"blocks:" + blockDef.textureFaces.at(0), assets
|
||||
"blocks:" + blockDef.defaults.textureFaces.at(0), assets
|
||||
);
|
||||
} else if (blockDef.model.type == BlockModelType::CUSTOM) {
|
||||
model = assets.require<model::Model>(blockDef.model.name);
|
||||
} else if (blockModel.type == BlockModelType::CUSTOM) {
|
||||
model = assets.require<model::Model>(blockModel.name);
|
||||
for (auto& mesh : model.meshes) {
|
||||
mesh.scale(glm::vec3(0.2f));
|
||||
}
|
||||
@@ -164,7 +174,7 @@ model::Model ModelsGenerator::generate(
|
||||
}
|
||||
for (auto& mesh : model.meshes) {
|
||||
mesh.shading = !blockDef.shadeless;
|
||||
switch (blockDef.model.type) {
|
||||
switch (blockModel.type) {
|
||||
case BlockModelType::AABB: {
|
||||
glm::vec3 size = blockDef.hitboxes.at(0).size();
|
||||
float m = glm::max(size.x, glm::max(size.y, size.z));
|
||||
@@ -176,7 +186,7 @@ model::Model ModelsGenerator::generate(
|
||||
}
|
||||
mesh.scale(glm::vec3(0.2f));
|
||||
}
|
||||
configure_textures(model, blockDef, assets);
|
||||
configure_textures(model, assets, blockDef.defaults.textureFaces);
|
||||
return model;
|
||||
} else if (def.iconType == ItemIconType::SPRITE) {
|
||||
return create_flat_model(def.icon, assets);
|
||||
|
||||
@@ -8,6 +8,7 @@ struct ItemDef;
|
||||
class Assets;
|
||||
class Content;
|
||||
class Block;
|
||||
struct Variant;
|
||||
|
||||
class ModelsGenerator {
|
||||
public:
|
||||
@@ -28,4 +29,8 @@ public:
|
||||
static model::Model loadCustomBlockModel(
|
||||
const dv::value& primitives, const Assets& assets, bool lighting
|
||||
);
|
||||
|
||||
static void prepareModel(
|
||||
Assets& assets, const Block& def, Variant& variant, uint8_t variantId
|
||||
);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user