From 6402c5c2464f95e9a0f8644fa353c684a909a9ae Mon Sep 17 00:00:00 2001 From: Perttu Ahola Date: Mon, 13 Oct 2014 16:14:29 +0300 Subject: [PATCH] builtin/voxelworld: WIP --- builtin/voxelworld/voxelworld.cpp | 17 ++-- games/digger/main/client_lua/init.lua | 7 +- games/digger/main/main.cpp | 5 + src/impl/mesh.cpp | 128 ++++++++++++++++++++++++++ src/interface/mesh.h | 8 ++ src/lua_bindings/voxel.cpp | 13 ++- 6 files changed, 166 insertions(+), 12 deletions(-) diff --git a/builtin/voxelworld/voxelworld.cpp b/builtin/voxelworld/voxelworld.cpp index 561aee9..0cc5c00 100644 --- a/builtin/voxelworld/voxelworld.cpp +++ b/builtin/voxelworld/voxelworld.cpp @@ -529,10 +529,10 @@ struct Module: public interface::Module, public voxelworld::Interface n->SetVar(StringHash("buildat_voxel_data"), Variant( PODVector((const uint8_t*)data.c_str(), data.size()))); - // There is no collision shape initially, but add the components now + // There are no collision shapes initially, but add the rigid body now RigidBody *body = n->CreateComponent(LOCAL); body->SetFriction(0.75f); - CollisionShape *shape = n->CreateComponent(LOCAL); + //CollisionShape *shape = n->CreateComponent(LOCAL); } void create_section(Section §ion) @@ -752,11 +752,14 @@ struct Module: public interface::Module, public voxelworld::Interface // TODO: Create multiple box collision shapes insteade of one mesh; // vertical voxel sectors should work well enough maybe - SharedPtr model(interface:: - create_voxel_physics_model(context, *volume, - m_voxel_reg.get())); + CollisionShape *shape = n->CreateComponent(); + shape->SetBox(Vector3(10, 0, 10)); - CollisionShape *shape = n->GetComponent(); + /*SharedPtr model(interface:: + create_voxel_physics_model(context, *volume, + m_voxel_reg.get()));*/ + + /*CollisionShape *shape = n->GetComponent(); if(model){ log_v(MODULE, "Chunk " PV3I_FORMAT " has collision shape", PV3I_PARAMS(chunk_p)); @@ -767,7 +770,7 @@ struct Module: public interface::Module, public voxelworld::Interface log_v(MODULE, "Chunk " PV3I_FORMAT " does not have collision shape", PV3I_PARAMS(chunk_p)); shape->ReleaseShape(); - } + }*/ }); } diff --git a/games/digger/main/client_lua/init.lua b/games/digger/main/client_lua/init.lua index 24fcc36..39d330f 100644 --- a/games/digger/main/client_lua/init.lua +++ b/games/digger/main/client_lua/init.lua @@ -28,6 +28,7 @@ zone.fogEnd = 300 -- Add a node that the player can use to walk around with local player_node = scene:CreateChild("Player") +--player_node.position = magic.Vector3(0, 30, 0) player_node.position = magic.Vector3(55, 30, 40) ---[[ local body = player_node:CreateComponent("RigidBody") @@ -129,10 +130,10 @@ magic.SubscribeToEvent("Update", function(event_type, event_data) --if magic.input:GetKeyPress(magic.KEY_SPACE) then if magic.input:GetKeyDown(magic.KEY_SPACE) then - if player_touches_ground and - math.abs(body.linearVelocity.y) < JUMP_SPEED then + --if player_touches_ground and + -- math.abs(body.linearVelocity.y) < JUMP_SPEED then wanted_v.y = wanted_v.y + JUMP_SPEED - end + --end end if magic.input:GetKeyDown(magic.KEY_SHIFT) then wanted_v.y = wanted_v.y - MOVE_SPEED diff --git a/games/digger/main/main.cpp b/games/digger/main/main.cpp index 34cf5a7..965feda 100644 --- a/games/digger/main/main.cpp +++ b/games/digger/main/main.cpp @@ -204,6 +204,11 @@ struct Module: public interface::Module ivoxelworld->set_voxel(p, VoxelInstance(1)); continue; } + if(x > 18 && x < 25 && z >= 32 && z <= 37 && + y > 20 && y < 25){ + ivoxelworld->set_voxel(p, VoxelInstance(1)); + continue; + } double a = interface::NoisePerlin2D(&np, x, z, 0); if(y < a+5){ ivoxelworld->set_voxel(p, VoxelInstance(2)); diff --git a/src/impl/mesh.cpp b/src/impl/mesh.cpp index 3e80686..4cae1d0 100644 --- a/src/impl/mesh.cpp +++ b/src/impl/mesh.cpp @@ -21,7 +21,9 @@ #include #include #include // Allows cast to Texture +#include #pragma GCC diagnostic pop +#include #define MODULE "mesh" namespace magic = Urho3D; @@ -524,5 +526,131 @@ void set_voxel_geometry(CustomGeometry *cg, Context *context, cg->Commit(); } +void set_voxel_physics_boxes(Node *node, Context *context, + pv::RawVolume &volume_orig, + VoxelRegistry *voxel_reg) +{ + PODVector previous_shapes; + node->GetComponents(previous_shapes); + for(size_t i = 0; i < previous_shapes.Size(); i++){ + node->RemoveComponent(previous_shapes[i]); + } + + int w = volume_orig.getWidth() - 2; + int h = volume_orig.getHeight() - 2; + int d = volume_orig.getDepth() - 2; + + auto region = volume_orig.getEnclosingRegion(); + auto &lc = region.getLowerCorner(); + auto &uc = region.getUpperCorner(); + + // Create a new volume which only holds the solidity of the voxels + pv::RawVolume volume(region); + for(int x = lc.getX(); x <= uc.getX(); x++){ + for(int y = lc.getY(); y <= uc.getY(); y++){ + for(int z = lc.getZ(); z <= uc.getZ(); z++){ + VoxelInstance v_orig = volume_orig.getVoxelAt(x, y, z); + const interface::CachedVoxelDefinition *def = + voxel_reg->get_cached(v_orig); + uint8_t v = (def && def->physically_solid); + volume.setVoxelAt(x, y, z, v); + } + } + } + + // Create minimal number of boxes to fill the solid voxels. Boxes can + // overlap. When a box is added, its voxels are set to value 2 in the + // temporary volume. + + for(int z0 = lc.getZ(); z0 <= uc.getZ(); z0++){ + // Loop until this z0 plane is done, then handle the next one + for(;;){ + // Find a solid non-covered voxel (v=1) on the z0 plane + int x0 = INT_MAX; + int y0 = INT_MAX; + for(int x = lc.getX(); x <= uc.getX(); x++){ + for(int y = lc.getY(); y <= uc.getY(); y++){ + uint8_t v = volume.getVoxelAt(x, y, z0); + if(v == 1){ + x0 = x; + y0 = y; + goto found_non_covered_voxel; + } + } + } + break; // Done +found_non_covered_voxel: + // Stretch this box first in x, then y and then z to be as large as + // possible without covering any non-solid voxels + int x1 = x0; + int y1 = y0; + int z1 = z0; + for(;;){ + x1++; + for(int y = y0; y <= y1; y++){ + for(int z = z0; z <= z1; z++){ + uint8_t v = volume.getVoxelAt(x1, y, z); + if(v == 0) + goto x_plane_does_not_fit; + } + } + continue; // Fits +x_plane_does_not_fit: + x1--; + break; + } + for(;;){ + y1++; + for(int x = x0; x <= x1; x++){ + for(int z = z0; z <= z1; z++){ + uint8_t v = volume.getVoxelAt(x, y1, z); + if(v == 0) + goto y_plane_does_not_fit; + } + } + continue; // Fits +y_plane_does_not_fit: + y1--; + break; + } + for(;;){ + z1++; + for(int x = x0; x <= x1; x++){ + for(int y = y0; y <= y1; y++){ + uint8_t v = volume.getVoxelAt(x, y, z1); + if(v == 0) + goto z_plane_does_not_fit; + } + } + continue; // Fits +z_plane_does_not_fit: + z1--; + break; + } + // Now we have a box; set the voxels to 2 + for(int x = x0; x <= x1; x++){ + for(int y = y0; y <= y1; y++){ + for(int z = z0; z <= z1; z++){ + volume.setVoxelAt(x, y, z, 2); + } + } + } + // Create the box + CollisionShape *shape = + node->CreateComponent(); + shape->SetBox(Vector3( + x1 - x0 + 1, + y1 - y0 + 1, + z1 - z0 + 1 + )); + shape->SetPosition(Vector3( + (x0 + x1)/2.0f - w/2 - 0.5f, + (y0 + y1)/2.0f - h/2 - 0.5f, + (z0 + z1)/2.0f - d/2 - 0.5f + )); + } + } +} + } // namespace interface // vim: set noet ts=4 sw=4: diff --git a/src/interface/mesh.h b/src/interface/mesh.h index b640eb5..028d307 100644 --- a/src/interface/mesh.h +++ b/src/interface/mesh.h @@ -10,6 +10,7 @@ namespace Urho3D class Context; class Model; class CustomGeometry; + class Node; } namespace interface @@ -20,12 +21,14 @@ namespace interface // Create a model from a string; eg. (2, 2, 2, "11101111") Model* create_simple_voxel_model(Context *context, int w, int h, int d, const ss_ &source_data); + // Create a model from 8-bit voxel data, using a voxel registry, without // textures or normals, based on the physically_solid flag. // Returns nullptr if there is no geometry Model* create_8bit_voxel_physics_model(Context *context, int w, int h, int d, const ss_ &source_data, VoxelRegistry *voxel_reg); + // Set custom geometry from 8-bit voxel data, using a voxel registry void set_8bit_voxel_geometry(CustomGeometry *cg, Context *context, int w, int h, int d, const ss_ &source_data, @@ -39,11 +42,16 @@ namespace interface Model* create_voxel_physics_model(Context *context, pv::RawVolume &volume, VoxelRegistry *voxel_reg); + // Set custom geometry from voxel volume, using a voxel registry // Volume should be padded by one voxel on each edge // NOTE: volume is non-const due to PolyVox deficiency void set_voxel_geometry(CustomGeometry *cg, Context *context, pv::RawVolume &volume, VoxelRegistry *voxel_reg); + + void set_voxel_physics_boxes(Node *node, Context *context, + pv::RawVolume &volume, + VoxelRegistry *voxel_reg); } // vim: set noet ts=4 sw=4: diff --git a/src/lua_bindings/voxel.cpp b/src/lua_bindings/voxel.cpp index 9786cc5..205ce51 100644 --- a/src/lua_bindings/voxel.cpp +++ b/src/lua_bindings/voxel.cpp @@ -162,7 +162,7 @@ static int l_set_voxel_geometry(lua_State *L) cg->SetCastShadows(true); // TODO: Don't do this here; allow caller to do this explicitly - SharedPtr model(interface:: + /*SharedPtr model(interface:: create_voxel_physics_model(context, *volume, voxel_reg)); RigidBody *body = node->GetOrCreateComponent(LOCAL); body->SetFriction(0.7); @@ -173,7 +173,16 @@ static int l_set_voxel_geometry(lua_State *L) //log_w(MODULE, "CollisionShape disabled"); } else { shape->ReleaseShape(); - } + }*/ + /*RigidBody *body = node->GetOrCreateComponent(LOCAL); + body->SetFriction(0.7); + CollisionShape *shape = node->CreateComponent(); + shape->SetBox(Vector3(10, 0, 10));*/ + + // TODO: Don't do this here; allow caller to do this explicitly + RigidBody *body = node->GetOrCreateComponent(LOCAL); + body->SetFriction(0.7); + interface::set_voxel_physics_boxes(node, context, *volume, voxel_reg); return 0; }