Toast Engine
Loading...
Searching...
No Matches
voxel_node.hpp
Go to the documentation of this file.
1
7
8#pragma once
9#include "voxel.hpp"
10
11#include <algorithm>
12#include <cstdint>
13#include <memory>
14#include <optional>
18#include <toast/voxel/stamp.hpp>
20#include <vector>
21
22namespace assets {
23class VoxelModel;
24class VoxelPalette;
25class PhysicsMaterial;
26}
27
28namespace physics {
29class Simulator;
30}
31
32namespace toast {
33
34namespace _detail {
35
37[[nodiscard]]
38inline auto toVoxel(glm::vec3 pos) noexcept -> glm::ivec3 {
39 return {glm::floor(pos)};
40}
41
43[[nodiscard]]
44inline auto toId(int id) noexcept -> uint8_t {
45 return static_cast<uint8_t>(std::clamp(id, 0, 255));
46}
47
48}
49
54enum class SimulationType : uint8_t {
55 static_body = 0,
57 dynamic = 2,
58};
59
72class [[ToastNode, Icon("BoxMesh")]] TOAST_API VoxelNode : public Voxel {
73 friend class physics::Simulator;
74
75public:
77 VoxelNode() = default;
78
80 VoxelNode(assets::Handle<assets::VoxelModel> model) : m_model(std::move(model)) { }
81
82 // Where the shape comes from
83
85 [[nodiscard, Reflect]]
86 auto getModel() const -> const assets::Handle<assets::VoxelModel>&;
87
89 [[nodiscard]]
90 auto getModel() -> assets::Handle<assets::VoxelModel>&;
91
93 [[Reflect]]
94 void setModel(assets::Handle<assets::VoxelModel> model);
95
97 [[nodiscard, Reflect]]
98 auto getPalette() const -> const assets::Handle<assets::VoxelPalette>&;
99
101 [[Reflect]]
102 void setPalette(assets::Handle<assets::VoxelPalette> palette);
103
108 [[nodiscard, Reflect]]
109 auto paletteUid() const -> uint64_t;
110
112 [[nodiscard]]
113 auto resolvedModel() const -> const assets::VoxelModel*;
114
116 [[nodiscard]]
117 auto resolvedPalette() -> const voxel::Palette*;
118
120 [[nodiscard]]
121 auto resolvedMaterialLibrary() -> const voxel::MaterialLibrary*;
122
123 // Building the shape
124
131 // [[Reflect]]
132 // void editShape() { }
133
134 // Reading voxels
135
139 [[Reflect]]
140 auto getVoxel(glm::vec3 pos) -> int;
141
145 [[Reflect]]
146 auto getSize() -> glm::vec3;
147
152 [[Reflect]]
153 auto getBounds() -> std::vector<glm::vec3>;
154
158 [[Reflect]]
159 auto getVoxelCount() -> int;
160
164 [[Reflect]]
165 auto worldToVoxel(glm::vec3 pos) -> glm::vec3;
166
170 [[Reflect]]
171 auto voxelToWorld(glm::vec3 pos) -> glm::vec3;
172
173 // Writing voxels
174 //
175 // Adding voxels grows the shape on its own
176 // Writes with a mode use it to pick what they may overwrite
177 // - replace: Just replaces every voxel
178 // - empty_only: Doesn't touch voxels with a Palette ID different than 0
179 // - solid_only: Doesn't touch empty voxels
180 // - match: Passing an extra palette ID (match_id), it replaces every voxel of that ID
181
183 [[Reflect]]
184 void setVoxel(glm::vec3 pos, int id);
185
187 [[Reflect]]
188 void removeVoxel(glm::vec3 pos);
189
195 [[Reflect]]
196 void fillBox(glm::vec3 min, glm::vec3 max, int id, voxel::WriteMode mode = voxel::WriteMode::replace, int match_id = 0);
197
199 [[Reflect]]
200 void fillSphere(glm::vec3 center, float radius, int id, voxel::WriteMode mode = voxel::WriteMode::replace, int match_id = 0);
201
203 [[Reflect]]
204 void fillCylinder(
205 glm::vec3 a, glm::vec3 b, float radius, int id, voxel::WriteMode mode = voxel::WriteMode::replace, int match_id = 0
206 );
207
209 [[Reflect]]
210 void fillLine(
211 glm::vec3 a, glm::vec3 b, float radius, int id, voxel::WriteMode mode = voxel::WriteMode::replace, int match_id = 0
212 );
213
215 [[Reflect]]
216 void carveBox(glm::vec3 min, glm::vec3 max);
217
219 [[Reflect]]
220 void carveSphere(glm::vec3 center, float radius);
221
222 [[Reflect]]
223 void setLayers(int included_layers, int excluded_layers);
224
225 [[Reflect]]
226 void includeLayer(int layer, bool value = true);
227
228 [[Reflect]]
229 void excludeLayer(int layer, bool value = true);
230
232 [[Reflect]]
233 void carveCylinder(glm::vec3 a, glm::vec3 b, float radius);
234
236 [[Reflect]]
237 void carveLine(glm::vec3 a, glm::vec3 b, float radius);
238
240 [[Reflect]]
241 void paintBox(glm::vec3 min, glm::vec3 max, int id);
242
244 [[Reflect]]
245 void paintSphere(glm::vec3 center, float radius, int id);
246
248 [[Reflect]]
249 void replaceId(int from, int to);
250
255 [[Reflect]]
256 void slice(glm::vec3 point, glm::vec3 normal, int side);
257
262 [[Reflect]]
263 void extrudeFace(glm::vec3 pos, glm::vec3 normal, int distance);
264
270 [[Reflect]]
271 void stamp(
272 const assets::Handle<assets::VoxelModel>& asset, glm::vec3 pos, glm::quat rotation = glm::quat(1.0f, 0.0f, 0.0f, 0.0f),
273 voxel::WriteMode mode = voxel::WriteMode::replace, int match_id = 0
274 );
275
280 [[Reflect]]
281 auto copy(glm::vec3 min, glm::vec3 max) -> int;
282
287 [[Reflect]]
288 void paste(int region, glm::vec3 pos, voxel::WriteMode mode = voxel::WriteMode::replace, int match_id = 0);
289
291 [[Reflect]]
292 void clearRegions();
293
294 // Shape signals
295
296 signals::Signal<> rebuilt_shape;
297 signals::Signal<int, glm::vec3> damaged;
298 signals::Signal<int> broke_apart;
299 signals::Signal<> emptied;
300
301 // Physics
302
303 signals::Signal<toast::Box<toast::Node>> contact_begin;
304 signals::Signal<toast::Box<toast::Node>> contact_end;
305 signals::Signal<> went_to_sleep;
306 signals::Signal<> woke_up;
307
309 [[Reflect]]
310 void sleep();
311
313 [[Reflect]]
314 void wake();
315
316 // Editor
317
321 [[Reflect, Button("Edit Voxel"), EditorAction("voxel_editor.open")]]
322 void editVoxel() { }
323
324 // Backend
325
326 [[nodiscard]]
327 auto volume() -> voxel::Volume*;
328
329 [[nodiscard]]
330 auto revision() const noexcept -> uint32_t {
331 return m_revision;
332 }
333
334 [[nodiscard]]
335 auto voxelOrigin() const noexcept -> glm::ivec3 {
336 return m_voxel_origin;
337 }
338
339 [[nodiscard]]
340 auto volumeLocalTransform() const -> glm::mat4;
341
342 [[nodiscard, Reflect]]
343 auto localBoundingSphere() const -> glm::vec4;
344
345 [[nodiscard]]
346 auto latticePlacement() const -> std::optional<voxel::LatticePlacement>;
347
348 [[nodiscard]]
349 auto renderOnly() const noexcept -> bool {
350 return render_only;
351 }
352
353protected:
357 virtual void buildShape() { }
358
362 [[nodiscard]]
363 virtual auto shapeKey() -> uint64_t {
364 return 0;
365 }
366
368 void requestRebuild() noexcept { m_rebuild_requested = true; }
369
374 [[nodiscard]]
375 virtual auto buildsAsync() -> bool {
376 return false;
377 }
378
379 virtual void tickAsyncBuild() { }
380
381 void finishShape();
382
383 void init();
384 void begin();
385 void end();
386 void destroy();
387 void onEnable();
388 void onDisable();
389 void editorTick();
390 void earlyTick();
391 void postPhysics();
392 void onReflectedFieldChanged(std::string_view field_name) override;
393 void onScriptsReloaded() override;
394 void updateInspectorMessages() override;
395 void onEditorTransformChanged() override;
396 virtual void drawDebug();
397
398 void refreshVolume();
399 void releaseVolume();
400 void retireVolume();
401 void recordDamage(uint32_t count, glm::vec3 index_sum);
402
407 auto ensureContains(const voxel::EditBounds& bounds) -> voxel::Volume*;
408
413 auto replaceVolume(const voxel::EditBounds& bounds) -> voxel::Volume*;
414
416 template<typename Kernel>
417 void edit(const voxel::EditBounds& local_bounds, bool grows, std::string_view operation, Kernel&& kernel);
418
420 void commitEdit(const voxel::EditResult& result, std::string_view operation);
421
422 [[nodiscard]]
423 auto toIndex(glm::ivec3 local) const noexcept -> glm::ivec3 {
424 return local - m_voxel_origin;
425 }
426
427 [[nodiscard]]
428 auto toIndex(glm::vec3 local) const noexcept -> glm::vec3 {
429 return local - glm::vec3(m_voxel_origin);
430 }
431
432 [[nodiscard]]
433 auto toIndex(const voxel::EditBounds& local) const noexcept -> voxel::EditBounds {
434 return {local.min - m_voxel_origin, local.max - m_voxel_origin};
435 }
436
438 physics::BodyID other_body;
439 toast::Box<toast::Node> other_node;
440 uint32_t shape_pair_count = 0;
441 };
442
443 [[nodiscard]]
444 auto physicsBound() const noexcept -> bool {
445 return m_body != physics::BodyID {};
446 }
447
448 void assignBody(physics::BodyID body) noexcept { m_body = body; }
449
450 void assignShape(physics::ShapeID shape) noexcept { m_shape = shape; }
451
452 [[nodiscard]]
453 auto bodyID() const noexcept -> physics::BodyID {
454 return m_body;
455 }
456
457 [[nodiscard]]
458 auto shapeID() const noexcept -> physics::ShapeID {
459 return m_shape;
460 }
461
462 void handleContactBegin(const physics::BroadPhasePair& pair);
463 void handleContactEnd(const physics::BroadPhasePair& pair);
464
465 void applyPhysicsTransform(const glm::vec3& position, const glm::quat& rotation);
466 void publishPhysicsState(bool is_awake, const glm::vec3& current_linear_velocity, const glm::vec3& current_angular_velocity);
467
468 // Inspector
469
470 [[Reflect]]
471 assets::Handle<assets::VoxelModel> m_model;
472
473 [[Reflect, Name("Palette Override")]]
474 assets::Handle<assets::VoxelPalette> m_palette;
475
480 [[Reflect, Name("Simulation Type"), Enum("Static", "Kinematic", "Dynamic")]]
482
483 [[Reflect, ReadOnly, Unit("kg")]]
484 float mass = 0.0f;
485
487 [[Reflect, Group("Physics")]]
488 bool render_only = false;
489
490 [[Reflect, Group("Physics"), Layers("excluded"), Name("Layers")]]
491 uint32_t included = 1; // Default
492
493 [[Reflect, Group("Physics"), LayersExcluded]]
494 uint32_t excluded = 0;
495
496 [[Reflect, Group("Physics")]]
497 bool allow_sleep = true;
498
499 [[Reflect, Group("Physics"), ReadOnly]]
500 bool awake = true;
501
502 [[Reflect, Group("Physics")]]
503 float gravity_scale = 1.0f;
504
506 [[Reflect, Group("Physics")]]
507 bool auto_mass_center = true;
508
509 [[Reflect, Group("Physics"), Unit("m"), ReadOnly("auto_mass_center")]]
510 glm::vec3 center_of_mass = {};
511
512 [[Reflect, Group("Physics"), Unit("kg•m²"), ReadOnly("auto_mass_center")]]
513 glm::vec3 inertia = {};
514
515 [[Reflect, Group("Physics"), Subgroup("Drag"), Unit("1/s")]]
516 float linear_damping = 0.0f;
517 [[Reflect, Group("Physics"), Subgroup("Drag"), Unit("1/s")]]
518 float angular_damping = 0.0f;
519 [[Reflect, Group("Physics"), Subgroup("Drag")]]
520 float drag_scale = 1.0f;
521
522 [[Reflect, Group("Physics"), Subgroup("Velocities"), Unit("m/s"), ReadOnly]]
523 glm::vec3 linear_velocity = {};
524 [[Reflect, Group("Physics"), Subgroup("Velocities"), Unit("rad/s"), ReadOnly]]
525 glm::vec3 angular_velocity = {};
526
527 [[Reflect, Group("Physics"), Subgroup("Constant Forces"), Unit("N"), ReadOnly]]
528 glm::vec3 constant_force = {};
529 [[Reflect, Group("Physics"), Subgroup("Constant Forces"), Unit("N•m"), ReadOnly]]
530 glm::vec3 constant_torque = {};
531
532 [[Reflect, Name("Lock X"), Group("Physics"), Subgroup("Position Locks"), ReadOnly]]
533 bool lock_pos_x = false;
534 [[Reflect, Name("Lock Y"), Group("Physics"), Subgroup("Position Locks"), ReadOnly]]
535 bool lock_pos_y = false;
536 [[Reflect, Name("Lock Z"), Group("Physics"), Subgroup("Position Locks"), ReadOnly]]
537 bool lock_pos_z = false;
538 [[Reflect, Name("Lock X"), Group("Physics"), Subgroup("Rotation Locks"), ReadOnly]]
539 bool lock_rot_x = false;
540 [[Reflect, Name("Lock Y"), Group("Physics"), Subgroup("Rotation Locks"), ReadOnly]]
541 bool lock_rot_y = false;
542 [[Reflect, Name("Lock Z"), Group("Physics"), Subgroup("Rotation Locks"), ReadOnly]]
543 bool lock_rot_z = false;
544
545 [[Reflect, Name("Show AABB"), Group("AABB")]]
546 bool show_aabb = false;
547
548 [[Reflect, Color, Name("AABB Color"), Group("AABB")]]
549 glm::vec4 aabb_color = glm::vec4(1.0f, 0.75f, 0.15f, 0.6f);
550
552 [[Reflect, Name("Fill Shape"), Group("AABB")]]
553 bool aabb_fill = false;
554
555 std::unique_ptr<voxel::Volume> m_volume;
556 std::vector<std::unique_ptr<voxel::Volume>> m_retired_volumes;
557 glm::ivec3 m_voxel_origin {0};
558 uint32_t m_revision = 0;
559 const assets::VoxelModel* m_instanced_from = nullptr;
561 std::vector<std::optional<voxel::Region>> m_regions;
562
563 bool m_volume_stale = false;
564 bool m_rebuild_requested = false;
565 bool m_edit_shape_pending = false;
566 bool m_split_pending = false;
567 bool m_building_shape = false;
568
570 uint32_t damaged_voxels = 0;
571 glm::vec3 damaged_sum {0.0f};
572 std::vector<int> broken_pieces;
573 bool emptied = false;
574 };
575
576 PendingEvents m_pending_events;
577
578 physics::BodyID m_body;
579 physics::ShapeID m_shape;
580 std::vector<ActiveContact> m_active_contacts;
581 bool m_registration_requested = false;
582
583 bool m_registered_proxy = false;
584 bool m_debug_visible = false;
585 uint64_t m_shape_key = 0;
586
587 uint64_t m_reported_wrong_model = 0;
588 uint64_t m_reported_wrong_palette = 0;
589};
590
591}
Body identifiers, creation data, and copied runtime state.
Type-safe smart pointer for assets.
Definition core_types.hpp:149
Definition physics_material.hpp:14
Definition voxel_model.hpp:43
Definition voxel_palette.hpp:40
Definition simulator.hpp:57
Intrusive reference-counted handle to a Node.
Definition box.hpp:35
Definition node.hpp:81
Definition reflect.hpp:244
virtual void buildShape()
Definition voxel_node.hpp:357
signals::Signal emptied
Sent when the last voxel is gone.
Definition voxel_node.hpp:299
signals::Signal< int, glm::vec3 > damaged
Sent when hits remove voxels with how many and where in the world.
Definition voxel_node.hpp:297
VoxelNode()=default
void sleep()
Definition voxel_node.cpp:630
bool render_only
Read when the game starts.
Definition voxel_node.hpp:488
signals::Signal< toast::Box< toast::Node > > contact_end
Sent when it stops touching another body.
Definition voxel_node.hpp:304
virtual auto shapeKey() -> uint64_t
Definition voxel_node.hpp:363
signals::Signal woke_up
Sent when the body wakes up.
Definition voxel_node.hpp:306
signals::Signal rebuilt_shape
Sent after a rebuild once editShape is done.
Definition voxel_node.hpp:296
bool auto_mass_center
Definition voxel_node.hpp:507
signals::Signal< toast::Box< toast::Node > > contact_begin
Sent when it starts touching another body.
Definition voxel_node.hpp:303
void editVoxel()
Definition voxel_node.hpp:322
void requestRebuild() noexcept
Definition voxel_node.hpp:368
signals::Signal< int > broke_apart
Sent when a piece breaks off with how many voxels it took.
Definition voxel_node.hpp:298
SimulationType simulation_type
Definition voxel_node.hpp:481
VoxelNode(assets::Handle< assets::VoxelModel > model)
Definition voxel_node.hpp:80
signals::Signal went_to_sleep
Sent when the body falls asleep.
Definition voxel_node.hpp:305
virtual auto buildsAsync() -> bool
Definition voxel_node.hpp:375
bool aabb_fill
Definition voxel_node.hpp:553
void wake()
Definition voxel_node.cpp:643
Definition voxel.hpp:14
Definition voxel_volume.hpp:21
Canonical collision-pair records shared by broad and narrow phases.
Member-robber pattern used by the generated reflection code.
Definition defer.hpp:16
auto toVoxel(glm::vec3 pos) noexcept -> glm::ivec3
Definition voxel_node.hpp:38
auto toId(int id) noexcept -> uint8_t
Definition voxel_node.hpp:44
Definition body.hpp:20
Definition shape.hpp:29
Definition voxel_node.hpp:437
Definition voxel_node.hpp:569
Definition voxel_edit.hpp:49
Definition voxel_edit.hpp:59
Concrete asset types for the Toast engine.
Common base of every voxel node.
Functions that allow the editing of Voxel Volumes.
SimulationType
Definition voxel_node.hpp:54
@ kinematic
Follows the node transform and pushes other bodies.
Definition voxel_node.hpp:56
@ dynamic
Fully simulated.
Definition voxel_node.hpp:57