Skip to content

Commit

Permalink
Make VoxelBlockyModelCube rotation behave the same as VoxelBlockyMode…
Browse files Browse the repository at this point in the history
…lMesh
  • Loading branch information
Zylann committed Sep 14, 2024
1 parent ddc3323 commit 01f8a1e
Show file tree
Hide file tree
Showing 9 changed files with 169 additions and 90 deletions.
2 changes: 2 additions & 0 deletions doc/source/changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ Semver is not yet in place, so each version can have breaking changes, although

Primarily developped with Godot 4.3.

- `VoxelBlockyModelCube`: Added support for mesh rotation like `VoxelBlockyMesh` (prior to that, rotation buttons in the editor only swapped tiles around)

- Fixes
- Fixed potential deadlock when using detail rendering and various editing features (thanks to lenesxy, issue #693)
- `VoxelInstanceLibrary`: Editor: reworked the way items are exposed as a Blender-style list. Now removing an item while the library is open as a sub-inspector is no longer problematic
Expand Down
38 changes: 33 additions & 5 deletions meshers/blocky/voxel_blocky_model.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -506,14 +506,35 @@ void VoxelBlockyModel::rotate_collision_boxes_ortho(math::OrthoBasis ortho_basis
}
}

void VoxelBlockyModel::set_mesh_ortho_rotation_index(int i) {
ZN_ASSERT_RETURN(i >= 0 && i < math::ORTHOGONAL_BASIS_COUNT);
if (i != int(_mesh_ortho_rotation)) {
_mesh_ortho_rotation = i;
}
}

int VoxelBlockyModel::get_mesh_ortho_rotation_index() const {
return _mesh_ortho_rotation;
}

void VoxelBlockyModel::rotate_90(math::Axis axis, bool clockwise) {
ZN_PRINT_ERROR("Not implemented");
// Implemented in child classes
math::OrthoBasis ortho_basis = math::get_ortho_basis_from_index(_mesh_ortho_rotation);
ortho_basis.rotate_90(axis, clockwise);
_mesh_ortho_rotation = math::get_index_from_ortho_basis(ortho_basis);

rotate_collision_boxes_90(axis, clockwise);

emit_changed();
}

void VoxelBlockyModel::rotate_ortho(math::OrthoBasis ortho_basis) {
ZN_PRINT_ERROR("Not implemented");
// Implemented in child classes
void VoxelBlockyModel::rotate_ortho(math::OrthoBasis p_ortho_basis) {
math::OrthoBasis ortho_basis = math::get_ortho_basis_from_index(_mesh_ortho_rotation);
ortho_basis = p_ortho_basis * ortho_basis;
_mesh_ortho_rotation = math::get_index_from_ortho_basis(ortho_basis);

rotate_collision_boxes_ortho(p_ortho_basis);

emit_changed();
}

void VoxelBlockyModel::_b_rotate_90(Vector3i::Axis axis, bool clockwise) {
Expand Down Expand Up @@ -560,6 +581,11 @@ void VoxelBlockyModel::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_collision_mask", "mask"), &VoxelBlockyModel::set_collision_mask);
ClassDB::bind_method(D_METHOD("get_collision_mask"), &VoxelBlockyModel::get_collision_mask);

ClassDB::bind_method(
D_METHOD("set_mesh_ortho_rotation_index", "i"), &VoxelBlockyModel::set_mesh_ortho_rotation_index
);
ClassDB::bind_method(D_METHOD("get_mesh_ortho_rotation_index"), &VoxelBlockyModel::get_mesh_ortho_rotation_index);

// Bound for editor purposes
ClassDB::bind_method(D_METHOD("rotate_90", "axis", "clockwise"), &VoxelBlockyModel::_b_rotate_90);

Expand All @@ -586,6 +612,8 @@ void VoxelBlockyModel::_bind_methods() {
"get_collision_mask"
);

ADD_GROUP("Rotation", "");

BIND_ENUM_CONSTANT(SIDE_NEGATIVE_X);
BIND_ENUM_CONSTANT(SIDE_POSITIVE_X);
BIND_ENUM_CONSTANT(SIDE_NEGATIVE_Y);
Expand Down
8 changes: 6 additions & 2 deletions meshers/blocky/voxel_blocky_model.h
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,9 @@ class VoxelBlockyModel : public Resource {
void set_random_tickable(bool rt);
bool is_random_tickable() const;

void set_mesh_ortho_rotation_index(int i);
int get_mesh_ortho_rotation_index() const;

//------------------------------------------
// Properties for internal usage only

Expand Down Expand Up @@ -204,8 +207,8 @@ class VoxelBlockyModel : public Resource {

virtual Ref<Mesh> get_preview_mesh() const;

virtual void rotate_90(math::Axis axis, bool clockwise);
virtual void rotate_ortho(math::OrthoBasis ortho_basis);
void rotate_90(math::Axis axis, bool clockwise);
void rotate_ortho(math::OrthoBasis ortho_basis);

static Ref<Mesh> make_mesh_from_baked_data(const BakedData &baked_data, bool tangents_enabled);

Expand Down Expand Up @@ -252,6 +255,7 @@ class VoxelBlockyModel : public Resource {
// can be useful for denser transparent voxels, such as foliage.
bool _culls_neighbors = true;
bool _random_tickable = false;
uint8_t _mesh_ortho_rotation = 0;

Color _color;

Expand Down
52 changes: 48 additions & 4 deletions meshers/blocky/voxel_blocky_model_cube.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#include "voxel_blocky_model_cube.h"
#include "../../util/containers/container_funcs.h"
#include "../../util/math/conv.h"
#include "voxel_blocky_model_mesh.h"

namespace zylann::voxel {

Expand Down Expand Up @@ -115,6 +116,46 @@ float VoxelBlockyModelCube::get_height() const {

namespace {

Cube::Side get_rotated_side(const Cube::Side src_side, const math::OrthoBasis ortho_basis) {
const Vector3i dir = ortho_basis.xform(Cube::g_side_normals[src_side]);
return Cube::dir_to_side(dir);
}

void add(Span<Vector3f> vecs, Vector3f a) {
for (Vector3f &v : vecs) {
v += a;
}
}

void rotate_ortho(
FixedArray<VoxelBlockyModel::BakedData::SideSurface, Cube::SIDE_COUNT> &sides,
const unsigned int ortho_rotation_index
) {
const math::OrthoBasis ortho_basis = math::get_ortho_basis_from_index(ortho_rotation_index);
const Basis3f basis(to_vec3f(ortho_basis.x), to_vec3f(ortho_basis.y), to_vec3f(ortho_basis.z));

FixedArray<VoxelBlockyModel::BakedData::SideSurface, Cube::SIDE_COUNT> rotated_sides;

for (unsigned int side = 0; side < Cube::SIDE_COUNT; ++side) {
VoxelBlockyModel::BakedData::SideSurface &side_surface = sides[side];

FixedArray<Vector3f, 4> normals;
for (Vector3f &n : normals) {
n = to_vec3f(Cube::g_side_normals[side]);
}

// Move mesh to origin for easier rotation, since the baked mesh spans 0..1 instead of -0.5..0.5
add(to_span(side_surface.positions), Vector3f(-0.5));
rotate_mesh_arrays(to_span(side_surface.positions), to_span(normals), to_span(side_surface.tangents), basis);
add(to_span(side_surface.positions), Vector3f(0.5));

const Cube::Side dst_side = get_rotated_side(static_cast<Cube::Side>(side), ortho_basis);
rotated_sides[dst_side] = std::move(side_surface);
}

sides = std::move(rotated_sides);
}

void bake_cube_geometry(
const VoxelBlockyModelCube &config,
VoxelBlockyModel::BakedData &baked_data,
Expand Down Expand Up @@ -195,6 +236,10 @@ void bake_cube_geometry(
}
}

if (config.get_mesh_ortho_rotation_index() != 0) {
rotate_ortho(surface.sides, config.get_mesh_ortho_rotation_index());
}

baked_data.empty = false;
}

Expand Down Expand Up @@ -229,7 +274,7 @@ Ref<Mesh> VoxelBlockyModelCube::get_preview_mesh() const {
return mesh;
}

void VoxelBlockyModelCube::rotate_90(math::Axis axis, bool clockwise) {
void VoxelBlockyModelCube::rotate_tiles_90(const math::Axis axis, const bool clockwise) {
FixedArray<Vector2i, Cube::SIDE_COUNT> rotated_tiles;

for (unsigned int src_side = 0; src_side < Cube::SIDE_COUNT; ++src_side) {
Expand All @@ -250,12 +295,11 @@ void VoxelBlockyModelCube::rotate_90(math::Axis axis, bool clockwise) {
emit_changed();
}

void VoxelBlockyModelCube::rotate_ortho(math::OrthoBasis ortho_basis) {
void VoxelBlockyModelCube::rotate_tiles_ortho(const math::OrthoBasis ortho_basis) {
FixedArray<Vector2i, Cube::SIDE_COUNT> rotated_tiles;

for (unsigned int src_side = 0; src_side < Cube::SIDE_COUNT; ++src_side) {
const Vector3i dir = ortho_basis.xform(Cube::g_side_normals[src_side]);
Cube::Side dst_side = Cube::dir_to_side(dir);
Cube::Side dst_side = get_rotated_side(static_cast<Cube::Side>(src_side), ortho_basis);
rotated_tiles[dst_side] = _tiles[src_side];
}

Expand Down
6 changes: 4 additions & 2 deletions meshers/blocky/voxel_blocky_model_cube.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@ class VoxelBlockyModelCube : public VoxelBlockyModel {

Ref<Mesh> get_preview_mesh() const override;

void rotate_90(math::Axis axis, bool clockwise) override;
void rotate_ortho(math::OrthoBasis ortho_basis) override;
void rotate_tiles_90(const math::Axis axis, const bool clockwise);
void rotate_tiles_ortho(const math::OrthoBasis ortho_basis);

private:
bool _set(const StringName &p_name, const Variant &p_value);
Expand All @@ -45,6 +45,8 @@ class VoxelBlockyModelCube : public VoxelBlockyModel {
float _height = 1.f;

Vector2i _atlas_size_in_tiles;

uint8_t _mesh_ortho_rotation = 0;
};

} // namespace zylann::voxel
Expand Down
4 changes: 0 additions & 4 deletions meshers/blocky/voxel_blocky_model_empty.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,6 @@ void VoxelBlockyModelEmpty::bake(BakedData &baked_data, bool bake_tangents, Mate
VoxelBlockyModel::bake(baked_data, bake_tangents, materials);
}

void VoxelBlockyModelEmpty::rotate_90(math::Axis axis, bool clockwise) {
rotate_collision_boxes_90(axis, clockwise);
}

Ref<Mesh> VoxelBlockyModelEmpty::get_preview_mesh() const {
return Ref<Mesh>();
}
Expand Down
1 change: 0 additions & 1 deletion meshers/blocky/voxel_blocky_model_empty.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ class VoxelBlockyModelEmpty : public VoxelBlockyModel {
VoxelBlockyModelEmpty();

void bake(BakedData &baked_data, bool bake_tangents, MaterialIndexer &materials) const override;
void rotate_90(math::Axis axis, bool clockwise) override;
Ref<Mesh> get_preview_mesh() const override;
bool is_empty() const override;

Expand Down
Loading

0 comments on commit 01f8a1e

Please sign in to comment.