Cellular automata implementation

This commit is contained in:
2024-10-21 19:54:07 +03:00
parent 997b66b7f9
commit 7bac24d34e
14 changed files with 8414 additions and 76 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

506
godot/astream/automata.conf Normal file
View File

@@ -0,0 +1,506 @@
[automata]
automata = {
"walls" : [
; corners
;corner
{
"match": [ ["empty", -1], ["empty", -1], ["empty", -1],
["empty", -1], ["normal_floor", -1], ["normal_floor", -1],
["empty", -1], ["normal_floor", -1], ["normal_floor", -1] ],
"cell": ["corner", 3, 0, 1, 2]
},
{
"match": [
["normal_floor", -1], ["normal_floor", -1], ["normal_floor", -1],
["empty", -1], ["normal_floor", -1], ["normal_floor", -1],
["empty", -1], ["empty", -1], ["normal_floor", -1]
],
"cell": ["corner", 0, 1, 2, 3]
},
{
"match": [
["empty", -1], ["normal_floor", -1], ["normal_floor", -1],
["empty", -1], ["normal_floor", -1], ["normal_floor", -1],
["empty", -1], ["empty", -1], ["normal_floor", -1]
],
"cell": ["corner", 0, 1, 2, 3]
},
; corner depends on corner
{
"match": [
["empty", -1], ["corner", 3], ["normal_floor", -1],
["empty", -1], ["normal_floor", -1], ["normal_floor", -1],
["empty", -1], ["empty", -1], ["empty", -1]
],
"cell": ["corner", 0, 1, 2, 3]
},
{
"match": [
["corner", 0], ["normal_floor", -1], ["normal_floor", -1],
["empty", -1], ["normal_floor", -1], ["normal_floor", -1],
["empty", -1], ["empty", -1], ["normal_floor", -1]
],
"cell": ["corner", 0, 1, 2, 3]
},
{
"match": [
["corner", 0], ["normal_floor", -1], ["normal_floor", -1],
["empty", -1], ["normal_floor", -1], ["corner", 1],
["empty", -1], ["empty", -1], ["empty", -1]
],
"cell": ["corner", 0, 1, 2, 3]
},
{
"match": [
["empty", -1], ["normal_floor", -1], ["normal_floor", -1],
["empty", -1], ["normal_floor", -1], ["normal_floor", -1],
["empty", -1], ["empty", -1], ["corner", 0]
],
"cell": ["corner", 0, 1, 2, 3]
},
{
"match": [
["empty", -1], ["corner", 3], ["normal_floor", -1],
["empty", -1], ["normal_floor", -1], ["normal_floor", -1],
["empty", -1], ["empty", -1], ["normal_floor", -1]
],
"cell": ["corner", 0, 1, 2, 3]
},
{
"match": [
["normal_floor", -1], ["normal_floor", -1], ["normal_floor", -1],
["empty", -1], ["normal_floor", -1], ["corner", 1],
["empty", -1], ["empty", -1], ["empty", -1]
],
"cell": ["corner", 0, 1, 2, 3]
},
{
"match": [
["normal_floor", -1], ["normal_floor", -1], ["normal_floor", -1],
["empty", -1], ["normal_floor", -1], ["normal_floor", -1],
["empty", -1], ["empty", -1], ["empty", -1]
],
"cell": ["corner", 0, 1, 2, 3]
},
; internal corner
{
"match": [
["normal_floor", -1], ["normal_floor", -1], ["normal_floor", -1],
["normal_floor", -1], ["normal_floor", -1], ["normal_floor", -1],
["empty", -1], ["normal_floor", -1], ["normal_floor", -1]
],
"cell": ["corner_internal", 0, 1, 2, 3]
},
; internal corner depends on corner_internal
{
"match": [
["normal_floor", -1], ["corner_internal", -1], ["normal_floor", -1],
["normal_floor", -1], ["normal_floor", -1], ["normal_floor", -1],
["empty", -1], ["normal_floor", -1], ["normal_floor", -1]
],
"cell": ["corner_internal", 0, 1, 2, 3]
},
{
"match": [
["corner_internal", 0], ["normal_floor", -1], ["normal_floor", -1],
["normal_floor", -1], ["normal_floor", -1], ["normal_floor", -1],
["empty", -1], ["normal_floor", -1], ["normal_floor", -1]
],
"cell": ["corner_internal", 0, 1, 2, 3]
},
; internal corner depends on corner
{
"match": [
["corner_internal", 0], ["normal_floor", -1], ["normal_floor", -1],
["corner", 0], ["normal_floor", -1], ["normal_floor", -1],
["empty", -1], ["corner", 0], ["normal_floor", -1]
],
"cell": ["corner_internal", 0, 1, 2, 3]
},
{
"match": [
["normal_floor", -1], ["normal_floor", -1], ["normal_floor", -1],
["corner", 0], ["normal_floor", -1], ["normal_floor", -1],
["empty", -1], ["corner", 0], ["corner", 1]
],
"cell": ["corner_internal", 0, 1, 2, 3]
},
{
"match": [
["normal_floor", -1], ["normal_floor", -1], ["normal_floor", -1],
["corner", 0], ["normal_floor", -1], ["normal_floor", -1],
["empty", -1], ["corner", 0], ["corner", 1]
],
"cell": ["corner_internal", 0, 1, 2, 3]
},
{
"match": [
["normal_floor", -1], ["normal_floor", -1], ["normal_floor", -1],
["corner", 0], ["normal_floor", -1], ["normal_floor", -1],
["empty", -1], ["corner", 0], ["corner_internal", 0]
],
"cell": ["corner_internal", 0, 1, 2, 3]
},
{
"match": [
["normal_floor", -1], ["normal_floor", -1], ["normal_floor", -1],
["corner", 0], ["normal_floor", -1], ["normal_floor", -1],
["empty", -1], ["normal_floor", -1], ["normal_floor", -1]
],
"cell": ["corner_internal", 0, 1, 2, 3]
},
{
"match": [
["normal_floor", -1], ["normal_floor", -1], ["normal_floor", -1],
["normal_floor", -1], ["normal_floor", -1], ["normal_floor", -1],
["empty", -1], ["corner", 0], ["corner", 1]
],
"cell": ["corner_internal", 0, 1, 2, 3]
},
{
"match": [
["corner", 3], ["normal_floor", -1], ["normal_floor", -1],
["corner", 0], ["normal_floor", -1], ["normal_floor", -1],
["empty", -1], ["normal_floor", -1], ["normal_floor", -1]
],
"cell": ["corner_internal", 0, 1, 2, 3]
},
{
"match": [
["normal_floor", -1], ["normal_floor", -1], ["normal_floor", -1],
["normal_floor", -1], ["normal_floor", -1], ["normal_floor", -1],
["empty", -1], ["corner", 0], ["normal_floor", -1]
],
"cell": ["corner_internal", 0, 1, 2, 3]
},
; walls
{
"match": [
["normal_floor", -1], ["normal_floor", -1], ["normal_floor", -1],
["corner", 0], ["normal_floor", -1], ["normal_floor", -1],
["empty", -1], ["empty", -1], ["empty", -1]
],
"cell": ["side_wall", 0, 1, 2, 3]
},
{
"match": [
["normal_floor", -1], ["normal_floor", -1], ["corner_internal", 1],
["normal_floor", -1], ["normal_floor", -1], ["corner", 1],
["empty", -1], ["empty", -1], ["empty", -1]
],
"cell": ["side_wall", 0, 1, 2, 3]
},
{
"match": [
["normal_floor", -1], ["normal_floor", -1], ["normal_floor", -1],
["side_wall", 0], ["normal_floor", -1], ["side_wall", 0],
["empty", -1], ["empty", -1], ["empty", -1]
],
"cell": ["side_wall", 0, 1, 2, 3]
},
{
"match": [
["normal_floor", -1], ["normal_floor", -1], ["corner_internal", 1],
["corner_internal", 1], ["normal_floor", -1], ["corner", 1],
["corner", 1], ["empty", -1], ["empty", -1]
],
"cell": ["side_wall", 0, 1, 2, 3]
},
{
"match": [
["corner_internal", 0], ["normal_floor", -1], ["side_wall", 1],
["corner", 0], ["normal_floor", -1], ["corner", 1],
["empty", -1], ["empty", -1], ["empty", -1]
],
"cell": ["side_wall", 0, 1, 2, 3]
},
{
"match": [
["normal_floor", -1], ["corner_internal", 2], ["corner", 2],
["normal_floor", -1], ["normal_floor", -1], ["corner", 1],
["empty", -1], ["empty", -1], ["empty", -1]
],
"cell": ["side_wall", 0, 1, 2, 3]
},
{
"match": [
["normal_floor", -1], ["normal_floor", -1], ["corner_internal", 2],
["corner_internal", 1], ["normal_floor", -1], ["side_wall", 0],
["normal_floor", -1], ["empty", -1], ["empty", -1]
],
"cell": ["side_wall", 0, 1, 2, 3]
},
{
"match": [
["normal_floor", -1], ["normal_floor", -1], ["normal_floor", -1],
["corner_internal", 1], ["normal_floor", -1], ["corner_internal", 0],
["corner", 1], ["empty", -1], ["corner", 0]
],
"cell": ["side_wall", 0, 1, 2, 3]
},
{
"match": [
["corner", 3], ["corner_internal", 3], ["normal_floor", -1],
["corner", 0], ["normal_floor", -1], ["normal_floor", -1],
["empty", -1], ["empty", -1], ["empty", -1]
],
"cell": ["side_wall", 0, 1, 2, 3]
},
{
"match": [
["corner_internal", 3], ["normal_floor", -1], ["normal_floor", -1],
["side_wall", 0], ["normal_floor", -1], ["corner_internal", 0],
["empty", -1], ["empty", -1], ["side_wall", 3]
],
"cell": ["side_wall", 0, 1, 2, 3]
},
{
"match": [
["corner_internal", 3], ["normal_floor", -1], ["corner_internal", 1],
["side_wall", 0], ["normal_floor", -1], ["corner", 1],
["empty", -1], ["empty", -1], ["empty", -1]
],
"cell": ["side_wall", 0, 1, 2, 3]
},
{
"match": [
["normal_floor", -1], ["normal_floor", -1], ["normal_floor", -1],
["normal_floor", -1], ["normal_floor", -1], ["corner_internal", 0],
["empty", -1], ["empty", -1], ["corner", 0]
],
"cell": ["side_wall", 0, 1, 2, 3]
},
{
"match": [
["normal_floor", -1], ["normal_floor", -1], ["normal_floor", -1],
["corner_internal", 1], ["normal_floor", -1], ["side_wall", 0],
["corner", 1], ["empty", -1], ["empty", -1]
],
"cell": ["side_wall", 0, 1, 2, 3]
},
; {
; "match": [
; ["normal_floor", -1], ["normal_floor", -1], ["normal_floor", -1],
; ["corner", 0], ["normal_floor", -1], ["corner", 1],
; ["empty", -1], ["empty", -1], ["empty", -1]
; ],
; "cell": ["side_wall", 0, 1, 2, 3]
; },
; {
; "match": [
; ["normal_floor", -1], ["normal_floor", -1], ["normal_floor", -1],
; ["corner", 0], ["normal_floor", -1], ["normal_floor", -1],
; ["empty", -1], ["empty", -1], ["empty", -1]
; ],
; "cell": ["side_wall", 0, 1, 2, 3]
; },
; {
; "match": [
; ["normal_floor", -1], ["normal_floor", -1], ["normal_floor", -1],
; ["normal_floor", -1], ["normal_floor", -1], ["corner", 1],
; ["empty", -1], ["empty", -1], ["empty", -1]
; ],
; "cell": ["side_wall", 0, 1, 2, 3]
; },
; {
; "match": [
; ["normal_floor", -1], ["normal_floor", -1], ["normal_floor", -1],
; ["corner", 0], ["normal_floor", -1], ["side_wall", 0],
; ["empty", -1], ["empty", -1], ["empty", -1]
; ],
; "cell": ["side_wall", 0, 1, 2, 3]
; },
; {
; "match": [
; ["side_wall", 3], ["normal_floor", -1], ["normal_floor", -1],
; ["corner", 0], ["normal_floor", -1], ["side_wall", 0],
; ["empty", -1], ["empty", -1], ["empty", -1]
; ],
; "cell": ["side_wall", 0, 1, 2, 3]
; },
; {
; "match": [
; ["normal_floor", -1], ["normal_floor", -1], ["side_wall", 1],
; ["side_wall", 0], ["normal_floor", -1], ["corner", 1],
; ["empty", -1], ["empty", -1], ["empty", -1]
; ],
; "cell": ["side_wall", 0, 1, 2, 3]
; },
; {
; "match": [
; ["normal_floor", -1], ["normal_floor", -1], ["side_wall", 1],
; ["normal_floor", -1], ["normal_floor", -1], ["corner", 1],
; ["empty", -1], ["empty", -1], ["empty", -1]
; ],
; "cell": ["side_wall", 0, 1, 2, 3]
; },
; {
; "match": [
; ["normal_floor", -1], ["normal_floor", -1], ["normal_floor", -1],
; ["side_wall", 0], ["normal_floor", -1], ["side_wall", 0],
; ["empty", -1], ["empty", -1], ["empty", -1]
; ],
; "cell": ["side_wall", 0, 1, 2, 3]
; },
; {
; "match": [
; ["normal_floor", -1], ["normal_floor", -1], ["normal_floor", -1],
; ["side_wall", 0], ["normal_floor", -1], ["normal_floor", -1],
; ["empty", -1], ["empty", -1], ["empty", -1]
; ],
; "cell": ["side_wall", 0, 1, 2, 3]
; },
; {
; "match": [
; ["normal_floor", -1], ["normal_floor", -1], ["normal_floor", -1],
; ["normal_floor", -1], ["normal_floor", -1], ["side_wall", 0],
; ["empty", -1], ["empty", -1], ["empty", -1]
; ],
; "cell": ["side_wall", 0, 1, 2, 3]
; },
; {
; "match": [
; ["normal_floor", -1], ["normal_floor", -1], ["normal_floor", -1],
; ["normal_floor", -1], ["normal_floor", -1], ["corner_internal", 0],
; ["empty", -1], ["empty", -1], ["empty", -1]
; ],
; "cell": ["side_wall", 0, 1, 2, 3]
; },
; {
; "match": [
; ["side_wall", 3], ["normal_floor", -1], ["normal_floor", -1],
; ["corner", 0], ["normal_floor", -1], ["normal_floor", -1],
; ["empty", -1], ["empty", -1], ["empty", -1]
; ],
; "cell": ["side_wall", 0, 1, 2, 3]
; },
; {
; "match": [
; ["normal_floor", -1], ["normal_floor", -1], ["normal_floor", -1],
; ["side_wall", 0], ["normal_floor", -1], ["corner_internal", -1],
; ["empty", -1], ["empty", -1], ["side_wall", 3]
; ],
; "cell": ["side_wall", 0, 1, 2, 3]
; },
; {
; "match": [
; ["normal_floor", -1], ["normal_floor", -1], ["normal_floor", -1],
; ["corner_internal", -1], ["normal_floor", -1], ["side_wall", 0],
; ["side_wall", 1], ["empty", -1], ["empty", -1]
; ],
; "cell": ["side_wall", 0, 1, 2, 3]
; },
; {
; "match": [
; ["corner_internal", 0], ["normal_floor", -1], ["normal_floor", -1],
; ["corner", 0], ["normal_floor", -1], ["corner_internal", 0],
; ["empty", -1], ["empty", -1], ["side_wall", 3]
; ],
; "cell": ["side_wall", 0, 1, 2, 3]
; },
; {
; "match": [
; ["corner_internal", 0], ["normal_floor", -1], ["normal_floor", -1],
; ["corner", 0], ["normal_floor", -1], ["corner_internal", 0],
; ["empty", -1], ["empty", -1], ["normal_floor", -1]
; ],
; "cell": ["side_wall", 0, 1, 2, 3]
; },
; {
; "match": [
; ["normal_floor", -1], ["normal_floor", -1], ["normal_floor", -1],
; ["corner_internal", 1], ["normal_floor", -1], ["side_wall", 0],
; ["normal_floor", -1], ["empty", -1], ["empty", -1]
; ],
; "cell": ["side_wall", 0, 1, 2, 3]
; },
; {
; "match": [
; ["corner_internal", -1], ["normal_floor", -1], ["normal_floor", -1],
; ["corner", -1], ["normal_floor", -1], ["corner_internal", -1],
; ["empty", -1], ["empty", -1], ["side_wall", 3]
; ],
; "cell": ["side_wall", 0, 1, 2, 3]
; },
; {
; "match": [
; ["empty", -1], ["normal_floor", -1], ["normal_floor", -1],
; ["empty", -1], ["normal_floor", -1], ["normal_floor", -1],
; ["empty", -1], ["corner", 0], ["corner", 1]
; ],
; "cell": ["side_wall", 3, 0, 1, 2]
; },
; {
; "match": [
; ["corner_internal", 2], ["normal_floor", -1], ["normal_floor", -1],
; ["corner_internal", 1], ["normal_floor", -1], ["side_wall", 0],
; ["side_wall", 1], ["empty", -1], ["empty", -1]
; ],
; "cell": ["side_wall", 0, 1, 2, 3]
; },
; {
; "match": [
; ["side_wall", 2], ["side_wall", 2], ["corner_internal", 3],
; ["normal_floor", -1], ["normal_floor", -1], ["corner_internal", 0],
; ["empty", -1], ["empty", -1], ["side_wall", 3]
; ],
; "cell": ["side_wall", 0, 1, 2, 3]
; },
; {
; "match": [
; ["corner", 3], ["side_wall", 2], ["side_wall", 2],
; ["corner", 0], ["normal_floor", -1], ["side_wall", 0],
; ["empty", -1], ["empty", -1], ["empty", -1]
; ],
; "cell": ["side_wall", 0, 1, 2, 3]
; },
; {
; "match": [
; ["normal_floor", -1], ["normal_floor", -1], ["corner", 2],
; ["corner_internal", 1], ["normal_floor", -1], ["corner", 1],
; ["corner", 1], ["empty", -1], ["empty", -1]
; ],
; "cell": ["side_wall", 0, 1, 2, 3]
; },
; {
; "match": [
; ["corner", 3], ["side_wall", 2], ["corner_internal", 3],
; ["corner", 0], ["normal_floor", -1], ["normal_floor", -1],
; ["empty", -1], ["empty", -1], ["empty", -1]
; ],
; "cell": ["side_wall", 0, 1, 2, 3]
; },
; {
; "match": [
; ["side_wall", 2], ["corner_internal", 3], ["normal_floor", -1],
; ["side_wall", 0], ["normal_floor", -1], ["corner_internal", 0],
; ["empty", -1], ["empty", -1], ["side_wall", 3]
; ],
; "cell": ["side_wall", 0, 1, 2, 3]
; },
; {
; "match": [
; ["normal_floor", -1], ["normal_floor", -1], ["normal_floor", -1],
; ["corner_internal", 1], ["normal_floor", -1], ["corner", 1],
; ["corner", 1], ["empty", -1], ["empty", -1]
; ],
; "cell": ["side_wall", 0, 1, 2, 3]
; },
; {
; "match": [
; ["side_wall", 3], ["normal_floor", -1], ["normal_floor", -1],
; ["corner", 0], ["normal_floor", -1], ["normal_floor", -1],
; ["empty", -1], ["empty", -1], ["normal_floor", -1]
; ],
; "cell": ["side_wall", 0, 1, 2, 3]
; },
; {
; "match": [
; ["normal_floor", -1], ["normal_floor", -1], ["corner", 2],
; ["corner_internal", 1], ["normal_floor", -1], ["corner", 1],
; ["side_wall", 1], ["empty", -1], ["empty", -1]
; ],
; "cell": ["side_wall", 0, 1, 2, 3]
; },
]
}

File diff suppressed because it is too large Load Diff

View File

@@ -19,7 +19,7 @@ nodes/storage=0
nodes/use_legacy_names=false
materials/location=1
materials/storage=1
materials/keep_on_reimport=true
materials/keep_on_reimport=false
meshes/compress=4286
meshes/ensure_tangents=true
meshes/octahedral_compression=true

Binary file not shown.

View File

@@ -65,6 +65,14 @@ focus_mode = 2
text = "Interior"
switch_on_hover = true
[node name="Automata" type="MenuButton" parent="menu_panel"]
margin_left = 237.0
margin_right = 311.0
margin_bottom = 20.0
focus_mode = 2
text = "Automata"
switch_on_hover = true
[node name="bg_floor" type="Spatial" parent="."]
unique_name_in_owner = true
@@ -339,13 +347,13 @@ columns = 2
unique_name_in_owner = true
margin_top = 771.0
margin_right = 314.0
margin_bottom = 1107.0
margin_bottom = 1135.0
[node name="VBoxContainer" type="VBoxContainer" parent="VBoxContainer/layout_editor"]
margin_left = 7.0
margin_top = 7.0
margin_right = 307.0
margin_bottom = 329.0
margin_bottom = 357.0
[node name="GridContainer" type="GridContainer" parent="VBoxContainer/layout_editor/VBoxContainer"]
margin_right = 300.0
@@ -505,11 +513,49 @@ margin_top = 274.0
margin_right = 300.0
margin_bottom = 298.0
[node name="layout_selector" type="OptionButton" parent="VBoxContainer/layout_editor/VBoxContainer"]
unique_name_in_owner = true
[node name="g" type="GridContainer" parent="VBoxContainer/layout_editor/VBoxContainer"]
margin_top = 302.0
margin_right = 300.0
margin_bottom = 322.0
margin_bottom = 350.0
columns = 2
[node name="Label2" type="Label" parent="VBoxContainer/layout_editor/VBoxContainer/g"]
margin_top = 3.0
margin_right = 82.0
margin_bottom = 17.0
text = "Select layout"
[node name="layout_selector" type="OptionButton" parent="VBoxContainer/layout_editor/VBoxContainer/g"]
unique_name_in_owner = true
margin_left = 86.0
margin_right = 300.0
margin_bottom = 20.0
size_flags_horizontal = 3
[node name="Label" type="Label" parent="VBoxContainer/layout_editor/VBoxContainer/g"]
margin_top = 29.0
margin_right = 82.0
margin_bottom = 43.0
text = "New layout"
[node name="HBoxContainer" type="HBoxContainer" parent="VBoxContainer/layout_editor/VBoxContainer/g"]
margin_left = 86.0
margin_top = 24.0
margin_right = 300.0
margin_bottom = 48.0
[node name="layout_create_new" type="LineEdit" parent="VBoxContainer/layout_editor/VBoxContainer/g/HBoxContainer"]
unique_name_in_owner = true
margin_right = 157.0
margin_bottom = 24.0
size_flags_horizontal = 3
[node name="layout_create_new_button" type="Button" parent="VBoxContainer/layout_editor/VBoxContainer/g/HBoxContainer"]
unique_name_in_owner = true
margin_left = 161.0
margin_right = 214.0
margin_bottom = 24.0
text = "Create"
[node name="BuildingLayoutEditor" type="BuildingLayoutEditor" parent="."]
source = ExtResource( 2 )

File diff suppressed because one or more lines are too long

View File

@@ -3,6 +3,7 @@
#include <vector>
#include <main/main.h>
#include <core/engine.h>
#include <core/io/marshalls.h>
#include <core/os/input.h>
#include <scene/resources/packed_scene.h>
#include <scene/resources/surface_tool.h>
@@ -20,6 +21,7 @@
#include <flecs/flecs.h>
namespace meshoptimizer
{
#define MESHOPTIMIZER_EXPERIMENTAL static
#define MESHOPTIMIZER_API static
#include <meshoptimizer.h>
#include <simplifier.cpp>
@@ -62,6 +64,12 @@ public:
"select_grid_rotation");
get_as_node<Button>("%grow_cell_button")
->connect("pressed", this, "grow_cell");
get_as_node<OptionButton>("%layout_selector")
->connect("item_selected", this, "select_layout");
get_as_node<LineEdit>("%layout_create_new")
->connect("text_entered", this, "create_new_layout");
get_as_node<Button>("%layout_create_new_button")
->connect("pressed", this, "create_new_layout_button");
}
virtual ~LayoutEditor()
{
@@ -102,7 +110,7 @@ public:
Vector3(-14, 23, 32));
List<String> element_keys;
List<String>::Element *e;
ElementData::get_singleton()->get_element_key_list(
ElementData::get_singleton()->get_selectable_element_key_list(
&element_keys);
e = element_keys.front();
get_as_node<OptionButton>(grid_elements)->clear();
@@ -112,6 +120,17 @@ public:
print_line("Added item: " + e->get());
e = e->next();
}
List<String> layout_keys;
get_as_node<OptionButton>("%layout_selector")->clear();
ElementData::get_singleton()->get_grid_layouts_key_list(
&layout_keys);
e = layout_keys.front();
while (e) {
get_as_node<OptionButton>("%layout_selector")
->add_item(e->get());
e = e->next();
}
EditorEvent::get_singleton()->event.add_listener(
this, &LayoutEditor::event_signal_handler);
}
@@ -209,6 +228,11 @@ public:
} else if (event == "elements_update_all") {
print_line(event);
editor->update_element_meshes();
} else if (event == "run_cellular_automata_start") {
String name = args[0];
ElementData::get_singleton()->run_cellular_automata(
name, current_layout, is_exterior,
current_floor);
}
}
void set_current_floor(float value)
@@ -222,6 +246,7 @@ public:
ElementData::get_singleton()->ensure_floor(
current_layout, is_exterior, current_floor);
print_line("visualize: " + itos(current_floor));
clear_vis(current_layout, is_exterior);
visualize_below_and_current(current_layout, is_exterior);
Transform xform = editor->get_viewport()
->get_camera()
@@ -259,6 +284,10 @@ public:
ElementData::get_singleton()->set_grid_rotation(
current_layout, is_exterior, current_floor,
current_cell, index);
ElementData::get_singleton()->clear_grid_node(current_layout,
is_exterior,
current_floor,
current_cell);
editor->visualize_element_at(
element, ElementData::get_singleton()->get_grid_node(
current_layout, is_exterior,
@@ -289,6 +318,43 @@ public:
}
print_line("grow_cell");
}
void select_layout(int index)
{
const String &item =
get_as_node<OptionButton>("%layout_selector")
->get_item_text(index);
if (item.length() > 0) {
current_layout = item;
clear_vis(current_layout, is_exterior);
visualize_whole(current_layout, is_exterior);
ElementData::get_singleton()->ensure_floor(
item, is_exterior, 0);
set_current_floor(0);
}
}
void create_new_layout(const String &name)
{
print_line(name);
ElementData::get_singleton()->create_new_layout(name);
List<String> layout_keys;
List<String>::Element *e;
get_as_node<OptionButton>("%layout_selector")->clear();
ElementData::get_singleton()->get_grid_layouts_key_list(
&layout_keys);
e = layout_keys.front();
while (e) {
get_as_node<OptionButton>("%layout_selector")
->add_item(e->get());
e = e->next();
}
}
void create_new_layout_button()
{
const String &text =
get_as_node<LineEdit>("%layout_create_new")->get_text();
create_new_layout(text);
}
static void _bind_methods()
{
@@ -301,6 +367,12 @@ public:
ClassDB::bind_method(D_METHOD("grow_cell"),
&LayoutEditor::grow_cell);
ClassDB::bind_method(D_METHOD("update"), &LayoutEditor::update);
ClassDB::bind_method(D_METHOD("select_layout", "index"),
&LayoutEditor::select_layout);
ClassDB::bind_method(D_METHOD("create_new_layout", "name"),
&LayoutEditor::create_new_layout);
ClassDB::bind_method(D_METHOD("create_new_layout_button"),
&LayoutEditor::create_new_layout_button);
}
void clear_vis(const String &key, bool exterior)
{
@@ -1180,6 +1252,20 @@ Ref<Mesh> BuildingLayoutEditor::get_layout_exterior_mesh(const String &layout,
ElementData::get_singleton()->get_grid_element(
layout, exterior, fl, i);
assert(element.length() > 0);
if (ElementData::get_singleton()->has_element(element +
"-lod"))
element = element + "-lod";
else {
String base =
ElementData::get_singleton()
->get_element_base(element);
if (base.length() > 0) {
if (ElementData::get_singleton()
->has_element(base +
"-lod"))
element = base + "-lod";
}
}
Ref<Mesh> src =
ElementData::get_singleton()->get_element_mesh(
element);
@@ -1232,20 +1318,29 @@ Ref<Mesh> BuildingLayoutEditor::get_layout_exterior_mesh(const String &layout,
src->set_storage_mode(Mesh::STORAGE_MODE_GPU);
}
}
if (!mat.is_valid()) {
print_error("no data to save");
return Ref<Mesh>();
}
Array arr = sf.commit_to_arrays();
print_line("optimizing for lod: " + itos(lod));
Ref<SpatialMaterial> spmat = mat;
assert(spmat.is_valid());
if (lod > 0) {
Ref<Texture> albedo_texture =
spmat->get_texture(SpatialMaterial::TEXTURE_ALBEDO);
assert(albedo_texture.is_valid());
// deduplicate_index(arr, albedo_texture, lod);
const PoolVector<Vector2> &uvs = arr[Mesh::ARRAY_TEX_UV];
const PoolVector<int> &index_array = arr[Mesh::ARRAY_INDEX];
const PoolVector<Vector3> &vertex_array =
arr[Mesh::ARRAY_VERTEX];
const PoolVector<Vector3> &normal_array =
arr[Mesh::ARRAY_NORMAL];
LocalVector<Color> colors;
colors.resize(uvs.size());
{
Ref<SpatialMaterial> spmat = mat;
assert(spmat.is_valid());
Ref<Texture> albedo_texture = spmat->get_texture(
SpatialMaterial::TEXTURE_ALBEDO);
assert(albedo_texture.is_valid());
Ref<Image> img_data = albedo_texture->get_data();
assert(img_data.is_valid());
img_data->lock();
@@ -1254,6 +1349,7 @@ Ref<Mesh> BuildingLayoutEditor::get_layout_exterior_mesh(const String &layout,
uvs[i] * img_data->get_size());
img_data->unlock();
}
#if 0
HashMap<Color, int> map_colors;
HashMap<int, int[3]> base_uvs;
Set<Color> seen_colors;
@@ -1319,36 +1415,125 @@ Ref<Mesh> BuildingLayoutEditor::get_layout_exterior_mesh(const String &layout,
uv_remap.write()[idx] = uvs[uv_idx];
}
arr[Mesh::ARRAY_TEX_UV] = uv_remap;
PoolVector<int> lodv;
#endif
#if 0
{
meshoptimizer::meshopt_Stream streams[] = {
{ &vertex_array.read().ptr()->x,
sizeof(float) * 3, sizeof(float) * 3 },
{ &normal_array.read().ptr()->x,
sizeof(float) * 3, sizeof(float) * 3 },
{ &uv_remap.read().ptr()->x, sizeof(float) * 2,
sizeof(float) * 2 },
};
LocalVector<unsigned int> remap;
remap.resize(index_array.size());
PoolVector<int> new_index_array;
new_index_array.resize(index_array.size());
int vertex_count =
meshoptimizer::meshopt_generateVertexRemapMulti(
remap.ptr(), index_array.read().ptr(),
index_array.size(), vertex_array.size(),
streams,
sizeof(streams) / sizeof(streams[0]));
for (i = 0; i < Mesh::ARRAY_MAX; i++) {
if (arr[i].get_type() == Variant::NIL)
continue;
switch (i) {
case Mesh::ARRAY_VERTEX:
case Mesh::ARRAY_NORMAL: {
PoolVector<Vector3> data = arr[i];
assert(data.size() > 0);
meshoptimizer::meshopt_remapVertexBuffer(
&data.write().ptr()->x,
&data.read().ptr()->x,
vertex_count, sizeof(float) * 3,
remap.ptr());
data.resize(vertex_count);
arr[i] = data;
} break;
case Mesh::ARRAY_TANGENT: {
PoolVector<float> data = arr[i];
assert(data.size() > 0);
meshoptimizer::meshopt_remapVertexBuffer(
data.write().ptr(),
data.read().ptr(), vertex_count,
sizeof(float) * 4, remap.ptr());
data.resize(vertex_count * 4);
arr[i] = data;
} break;
case Mesh::ARRAY_COLOR: {
PoolVector<Color> data = arr[i];
assert(data.size() > 0);
meshoptimizer::meshopt_remapVertexBuffer(
&data.write().ptr()->r,
&data.read().ptr()->r,
vertex_count, sizeof(float) * 4,
remap.ptr());
data.resize(vertex_count);
arr[i] = data;
} break;
case Mesh::ARRAY_TEX_UV:
case Mesh::ARRAY_TEX_UV2: {
PoolVector<Vector2> data = arr[i];
assert(data.size() > 0);
meshoptimizer::meshopt_remapVertexBuffer(
&data.write().ptr()->x,
&data.read().ptr()->x,
vertex_count, sizeof(float) * 2,
remap.ptr());
data.resize(vertex_count);
arr[i] = data;
} break;
case Mesh::ARRAY_BONES:
case Mesh::ARRAY_WEIGHTS: {
arr[i] = Variant();
} break;
case Mesh::ARRAY_INDEX: {
PoolVector<int> data = arr[i];
assert(data.size() > 0);
meshoptimizer::meshopt_remapIndexBuffer(
(unsigned int *)data.write()
.ptr(),
(const unsigned int *)data
.read()
.ptr(),
data.size(), remap.ptr());
arr[i] = data;
} break;
}
}
}
#endif
LocalVector<float> vertices;
const PoolVector<Vector3> &vertex_array =
arr[Mesh::ARRAY_VERTEX];
lodv.resize(index_array.size());
vertices.resize(vertex_array.size() * 3);
for (i = 0; i < vertex_array.size(); i++) {
vertices[i * 3 + 0] = vertex_array[i].x;
vertices[i * 3 + 1] = vertex_array[i].y;
vertices[i * 3 + 2] = vertex_array[i].z;
}
PoolVector<int> lodv;
lodv.resize(index_array.size());
float error = 0.f;
const int simplify_options = 1; /* lock border */
// const int simplify_options = 1; /* lock border */
const int simplify_options = 1; /* ... */
float threshold = 1.0f;
float target_error = 0.01f;
bool sloppy = false;
switch (lod) {
case 1:
threshold = 0.6f;
target_error = 0.01f;
target_error = FLT_MAX;
sloppy = false;
break;
case 2:
threshold = 0.3f;
target_error = 0.01f;
target_error = FLT_MAX;
sloppy = false;
break;
default:
threshold = 1.0f / (float(lod + 1));
target_error = 0.01;
target_error = FLT_MAX;
sloppy = true;
break;
}
@@ -1400,6 +1585,309 @@ Ref<Mesh> BuildingLayoutEditor::get_layout_exterior_mesh(const String &layout,
assert(ret.is_valid());
return ret;
}
static Vector<float> vector3_to_float32_array(const Vector3 *vecs, size_t count)
{
// We always allocate a new array, and we don't memcpy.
// We also don't consider returning a pointer to the passed vectors when sizeof(real_t) == 4.
// One reason is that we could decide to put a 4th component in Vector3 for SIMD/mobile performance,
// which would cause trouble with these optimizations.
Vector<float> floats;
if (count == 0) {
return floats;
}
floats.resize(count * 3);
float *floats_w = floats.ptrw();
for (size_t i = 0; i < count; ++i) {
const Vector3 v = vecs[i];
floats_w[0] = v.x;
floats_w[1] = v.y;
floats_w[2] = v.z;
floats_w += 3;
}
return floats;
}
static void fixup_uvs(Array &arr, const Ref<Texture> &albedo_texture)
{
int i;
PoolVector<Vector2> uvs = arr[Mesh::ARRAY_TEX_UV];
PoolVector<int> index_array = arr[Mesh::ARRAY_INDEX];
const PoolVector<Vector3> &vertex_array = arr[Mesh::ARRAY_VERTEX];
const PoolVector<Vector3> &normal_array = arr[Mesh::ARRAY_NORMAL];
const PoolVector<float> &tangent_array = arr[Mesh::ARRAY_TANGENT];
const Vector3 *vertices_ptr = vertex_array.read().ptr();
const Vector3 *normals_ptr = normal_array.read().ptr();
const Vector2 *uvs_ptr = uvs.read().ptr();
int *index_ptrw = index_array.write().ptr();
const float *tangents_ptr = tangent_array.read().ptr();
int vertex_count = vertex_array.size();
int index_count = index_array.size();
LocalVector<Color> colors;
assert(albedo_texture.is_valid());
Ref<Image> img_data = albedo_texture->get_data();
assert(img_data.is_valid());
colors.resize(uvs.size());
img_data->lock();
for (i = 0; i < uvs.size(); i++)
colors[i] = img_data->get_pixelv(uvs[i] * img_data->get_size());
img_data->unlock();
Color *colors_ptr = colors.ptr();
float normal_merge_angle = 5.0f;
float normal_merge_threshold =
Math::cos(normal_merge_angle * Math_PI / 180.0f);
Vector2 *uvs_ptrw = uvs.write().ptr();
HashMap<int, int> remap_verts;
for (i = 0; i < vertex_count; i++) {
int j;
const Vector3 &v = vertices_ptr[i];
const Vector3 &n = normals_ptr[i];
const Color &c = colors_ptr[i];
if (uvs_ptr[i].x >= 0.75f && uvs_ptr[i].y >= 0.75f)
/* do not remap UVs for texture area */
continue;
for (j = 0; j < vertex_count; j++) {
if (i == j)
continue;
bool is_vertices_close =
v.distance_squared_to(vertices_ptr[j]) <
CMP_EPSILON2;
bool is_normals_close = normals_ptr[j].dot(n) >
normal_merge_threshold;
bool is_tang_aligned =
!tangents_ptr ||
(tangents_ptr[i * 4 + 3] < 0) ==
(tangents_ptr[j * 4 + 3] < 0);
bool is_colors_close =
c.is_equal_approx(colors_ptr[j]) &&
(uvs_ptr[j].x < 0.75f || uvs_ptr[j].y < 0.75f);
if (is_vertices_close && is_normals_close &&
is_tang_aligned && is_colors_close) {
uvs_ptrw[j] = uvs_ptr[i];
remap_verts[j] = i;
}
}
}
PoolVector<int> new_indices;
new_indices.resize(index_count);
int *new_indices_ptrw = new_indices.write().ptr();
for (i = 0; i < index_count; i++) {
int idx = index_ptrw[i];
if (remap_verts.has(idx))
index_ptrw[i] = remap_verts[idx];
}
int new_index_count = 0;
for (i = 0; i < index_count; i += 3) {
int i1 = index_ptrw[i];
int i2 = index_ptrw[i + 1];
int i3 = index_ptrw[i + 2];
if (i1 == i2 || i2 == i3 || i1 == i3)
continue;
new_indices_ptrw[new_index_count++] = i1;
new_indices_ptrw[new_index_count++] = i2;
new_indices_ptrw[new_index_count++] = i3;
}
new_indices.resize(new_index_count);
arr[Mesh::ARRAY_INDEX] = new_indices;
arr[Mesh::ARRAY_TEX_UV] = uvs;
print_line("index before: " + itos(index_array.size()));
print_line("index after: " + itos(new_indices.size()));
}
void BuildingLayoutEditor::deduplicate_index(Array &arr,
const Ref<Texture> &albedo_texture,
int lod) const
{
int i;
const PoolVector<Vector2> &uvs = arr[Mesh::ARRAY_TEX_UV];
const PoolVector<int> &index_array = arr[Mesh::ARRAY_INDEX];
const PoolVector<Vector3> &vertex_array = arr[Mesh::ARRAY_VERTEX];
const PoolVector<Vector3> &normal_array = arr[Mesh::ARRAY_NORMAL];
const PoolVector<float> &tangent_array = arr[Mesh::ARRAY_TANGENT];
float normal_split_angle = 45.0f;
float normal_merge_angle = 5.0f;
float normal_merge_threshold =
Math::cos(normal_merge_angle * Math_PI / 180.0f);
float normal_pre_split_threshold = Math::cos(
(MIN(180.0f, normal_split_angle * 2.0f)) * Math_PI / 180.0f);
float normal_split_threshold =
Math::cos(normal_split_angle * Math_PI / 180.0f);
HashMap<Vector3, LocalVector<Pair<int, int> > > unique_vertices;
const Vector3 *vertices_ptr = vertex_array.read().ptr();
const Vector3 *normals_ptr = normal_array.read().ptr();
const Vector2 *uvs_ptr = uvs.read().ptr();
const float *tangents_ptr = tangent_array.read().ptr();
int vertex_count = vertex_array.size();
int index_count = index_array.size();
LocalVector<int> vertex_remap;
LocalVector<int> vertex_inverse_remap;
LocalVector<Vector3> merged_vertices;
LocalVector<Vector3> merged_normals;
LocalVector<int> merged_normals_counts;
assert(albedo_texture.is_valid());
fixup_uvs(arr, albedo_texture);
for (i = 0; i < vertex_count; i++) {
const Vector3 &v = vertices_ptr[i];
const Vector3 &n = normals_ptr[i];
if (unique_vertices.has(v)) {
const LocalVector<Pair<int, int> > &close_verts =
unique_vertices[v];
bool found = false;
int k;
for (k = 0; k < close_verts.size(); k++) {
const Pair<int, int> &idx = close_verts[k];
assert(idx.second < normal_array.size());
bool is_uvs_close =
(!uvs_ptr ||
uvs_ptr[i].distance_squared_to(
uvs_ptr[idx.second]) <
CMP_EPSILON2);
/* bool is_uv2s_close = (!uv2s_ptr || uv2s_ptr[j].distance_squared_to(uv2s_ptr[idx.second]) < CMP_EPSILON2); */
bool is_tang_aligned =
!tangents_ptr ||
(tangents_ptr[i * 4 + 3] < 0) ==
(tangents_ptr[idx.second * 4 +
3] < 0);
bool is_normals_close =
normals_ptr[idx.second].dot(n) >
normal_merge_threshold;
if (is_uvs_close &&
/* is_uv2s_close && */ is_normals_close &&
is_tang_aligned) {
/* vertex_remap contains indices of vertices which
are remapped onto other vertices */
vertex_remap.push_back(idx.first);
assert(idx.first < vertex_count);
assert(idx.second < vertex_count);
/* adding normal vectors and counts to normalize later */
merged_normals[idx.first] +=
normals_ptr[idx.second];
merged_normals_counts[idx.first]++;
found = true;
break;
}
}
if (!found) {
/* add to array as we did not find similar vertex */
int vcount = merged_vertices.size();
unique_vertices[v].push_back(
Pair<int, int>(vcount, i));
vertex_inverse_remap.push_back(i);
merged_vertices.push_back(v);
/* index in merged vertices */
vertex_remap.push_back(vcount);
merged_normals.push_back(normals_ptr[i]);
merged_normals_counts.push_back(1);
}
} else {
/* add to array as we did not find vertex
with such coordinates */
int vcount = merged_vertices.size();
unique_vertices[v] = LocalVector<Pair<int, int> >();
unique_vertices[v].push_back(Pair<int, int>(vcount, i));
vertex_inverse_remap.push_back(i);
merged_vertices.push_back(v);
vertex_remap.push_back(vcount);
merged_normals.push_back(normals_ptr[i]);
merged_normals_counts.push_back(1);
}
}
LocalVector<int> merged_indices;
merged_indices.resize(index_count);
for (i = 0; i < index_count; i++)
merged_indices[i] = vertex_remap[index_array[i]];
int merged_vertex_count = merged_vertices.size();
const Vector3 *merged_vertices_ptr = merged_vertices.ptr();
const int32_t *merged_indices_ptr = merged_indices.ptr();
/* normalize merged normals */
{
const int *counts_ptr = merged_normals_counts.ptr();
Vector3 *merged_normals_ptrw = merged_normals.ptr();
for (i = 0; i < merged_vertex_count; i++)
merged_normals_ptrw[i] /= counts_ptr[i];
}
const float normal_weights[3] = {
// Give some weight to normal preservation, may be worth exposing as an import setting
2.0f, 2.0f, 2.0f
};
Vector<float> merged_vertices_f32 = vector3_to_float32_array(
merged_vertices_ptr, merged_vertex_count);
float scale = meshoptimizer::meshopt_simplifyScale(
merged_vertices_f32.ptr(), merged_vertex_count,
sizeof(float) * 3);
unsigned int index_target = 12, last_index_count = 0;
const float max_mesh_error =
FLT_MAX; // We don't want to limit by error, just by index target
float mesh_error = 0.0f;
int counter = lod;
while (index_target < index_count) {
PoolVector<int> new_indices;
new_indices.resize(index_count);
Vector<float> merged_normals_f32 = vector3_to_float32_array(
merged_normals.ptr(), merged_normals.size());
const int simplify_options = 1;
size_t new_index_count =
meshoptimizer::meshopt_simplifyWithAttributes(
(unsigned int *)new_indices.write().ptr(),
(const uint32_t *)merged_indices_ptr,
index_count, merged_vertices_f32.ptr(),
merged_vertex_count,
sizeof(float) * 3 /* vertex stride */,
merged_normals_f32.ptr(),
sizeof(float) * 3 /* attribute stride */,
normal_weights, 3, NULL, index_target,
max_mesh_error, simplify_options, &mesh_error);
if (new_index_count < last_index_count * 1.5f) {
index_target = index_target * 1.5f;
continue;
}
if (new_index_count == 0 ||
(new_index_count >= (index_count * 0.75f)))
break;
if (new_index_count > 5000000)
break;
new_indices.resize(new_index_count);
{
int *ptrw = new_indices.write().ptr();
for (unsigned int j = 0; j < new_index_count; j++) {
ptrw[j] = vertex_inverse_remap[ptrw[j]];
}
}
print_line("index_count: " + itos(new_indices.size()));
index_target = MAX(new_index_count, index_target) * 2;
last_index_count = new_index_count;
if (mesh_error == 0.0f) {
if (new_indices.size() > 0)
arr[Mesh::ARRAY_INDEX] = new_indices;
break;
}
if (counter == 0) {
arr[Mesh::ARRAY_INDEX] = new_indices;
break;
}
counter--;
}
#if 0
for (i = 0; i < vertex_count; i++) {
for (j = 0; j < vertex_count; j++) {
if (i == j)
continue;
if (vertex_array[i].is_equal_approx(
vertex_array[j] &&
normal_array[i].dot(normal_array[j]) >))
}
}
#endif
}
void BuildingLayoutEditor::update_element_meshes()
{
List<String> keys;
@@ -1432,11 +1920,13 @@ void BuildingLayoutEditor::update_layout_meshes()
while (e) {
print_line("update_layout_meshes: " + e->get());
for (lod = 0; lod < 4; lod++) {
Ref<Mesh> mesh =
get_layout_exterior_mesh(e->get(), lod);
if (!mesh.is_valid())
continue;
String item_name = e->get() + "_lod" + itos(lod);
int id = ml->get_last_unused_item_id();
ml->create_item(id);
Ref<Mesh> mesh =
get_layout_exterior_mesh(e->get(), lod);
assert(mesh.is_valid());
Ref<Shape> shape = mesh->create_trimesh_shape();
assert(shape.is_valid());
@@ -1468,6 +1958,7 @@ void BuildingLayoutEditor::update_layout_meshes()
static ElementTypeEditor *etype_editor;
static ElementEditor *element_editor;
static LayoutEditor *layout_editor;
static HashMap<int, String> automata_id;
void BuildingLayoutEditor::_notification(int which)
{
@@ -1489,6 +1980,29 @@ void BuildingLayoutEditor::_notification(int which)
}
select_mode(0);
set_process_unhandled_input(true);
ConfigFile automata_conf;
Error res = automata_conf.load("res://astream/automata.conf");
assert(res == OK);
Dictionary automata =
automata_conf.get_value("automata", "automata");
List<Variant> akeys;
automata.get_key_list(&akeys);
int automata_index = 10000;
List<Variant>::Element *e = akeys.front();
Node *menu_panel = get_as_node<Node>("%menu_panel");
MenuButton *automata_menu = Object::cast_to<MenuButton>(
menu_panel->get_node(NodePath("Automata")));
assert(automata_menu);
automata_menu->get_popup()->clear();
while (e) {
String aname = e->get();
automata_menu->get_popup()->add_item(aname,
automata_index);
automata_id[automata_index] = aname;
automata_index++;
e = e->next();
}
} break;
case NOTIFICATION_EXIT_TREE:
for (i = 0; i < (int)editors.size(); i++)
@@ -1679,6 +2193,14 @@ void BuildingLayoutEditor::menu_control(int id)
get_as_node<Control>("%socket_editor")->hide();
select_mode(2);
break;
default:
if (id >= 10000 && id < 20000) {
EditorEvent::get_singleton()->event.emit(
"run_cellular_automata_start",
varray(automata_id[id]));
// ElementData::get_singleton()->run_cellular_automata(
// automata_id[id], layout_editor->get_curr);
}
}
}

View File

@@ -32,6 +32,11 @@ public:
Ref<Mesh> get_element_mesh(const String &element) const;
Ref<Mesh> get_layout_exterior_mesh(const String &layout, int lod) const;
private:
void deduplicate_index(Array &arr, const Ref<Texture> &albedo_texture,
int lod) const;
public:
void update_element_meshes();
void update_layout_meshes();

View File

@@ -421,6 +421,8 @@ void ElementData::ensure_floor(const String &key, bool exterior, int fl)
flecs::entity floor_e =
ecs.entity(("floor_" + itos(fl)).ascii().ptr()).child_of(base);
assert(floor_e.is_valid());
if (!floor_e.has<struct grid_floor>())
floor_e.set<struct grid_floor>({ true });
for (i = 0; i < grid_size * grid_size; i++) {
flecs::entity item =
ecs.entity(("item_" + itos(i)).ascii().ptr())
@@ -434,6 +436,7 @@ void ElementData::load_data()
{
int i;
ConfigFile config;
ConfigFile automata_conf;
Dictionary conf_element_types;
Dictionary conf_elements;
Dictionary conf_grid_layouts;
@@ -469,6 +472,7 @@ void ElementData::load_data()
assert(item.has("type"));
assert(item.has("mesh_names"));
String type = item["type"];
String base = item.get("base", "");
print_line("loading element: " + key + " type: " + type);
if (key == "empty") {
e = e->next();
@@ -478,12 +482,265 @@ void ElementData::load_data()
Array mesh_names = item["mesh_names"];
for (i = 0; i < mesh_names.size(); i++)
set_element_mesh_name(key, i, mesh_names[i]);
set_element_base(key, base);
e = e->next();
}
unserialize_layouts(conf_grid_layouts);
{
Error err = automata_conf.load("res://astream/automata.conf");
assert(err == OK);
Dictionary automata_dict = automata_conf.get_value(
"automata", "automata", Dictionary());
assert(automata_dict.size() > 0);
List<Variant> pkeys;
List<Variant>::Element *pe;
automata_dict.get_key_list(&pkeys);
pe = pkeys.front();
automata.clear();
while (pe) {
String name = pe->get();
print_line("automata: " + name);
assert(automata_dict.has(name));
Array at = automata_dict[name];
assert(at.size() > 0);
for (i = 0; i < at.size(); i++)
add_automata_from_dict(name, at[i]);
assert(automata.has(name));
pe = pe->next();
}
}
assert(automata.size() > 0);
EditorEvent::get_singleton()->event.emit("elements_update_all",
varray());
}
void ElementData::add_automata(const String &name,
const struct ElementData::match_field *match,
const struct ElementData::match_field &cell)
{
struct ElementData::automata_data data;
int i;
for (i = 0; i < 9; i++)
data.match[i] = match[i];
data.cell = cell;
automata[name].push_back(data);
}
void ElementData::add_automata_from_dict(const String &name,
const Dictionary &d)
{
int i;
assert(d.has("match"));
assert(d.has("cell"));
Array cell = d["cell"];
Array matches = d["match"];
assert(matches.size() == 9);
if (cell.size() == 2) {
struct ElementData::automata_data data;
for (i = 0; i < matches.size(); i++) {
Array match = matches[i];
assert(match.size() == 2);
String entry = match[0];
int rotation = match[1];
data.match[i] = { entry, rotation };
}
String n = cell[0];
int r = cell[1];
data.cell = { n, r };
if (automata.has(name))
automata[name].push_back(data);
else {
Vector<struct ElementData::automata_data> l;
l.push_back(data);
automata[name] = l;
}
} else if (cell.size() == 5) {
/*******************************************
* 0 1 2
* 3 4 5 0
* 6 7 8
*
* 2 5 8
* 1 4 7 90
* 0 3 6
*
* 8 7 6
* 5 4 3 180
* 2 1 0
*
* 6 3 0
* 7 4 1 270
* 8 5 2
*/
/* clang-format off */
int remap[9][9] = {
{
/* 0 */
0, 1, 2, /* a */
3, 4, 5, /* b */
6, 7, 8, /* c */
},
{
/* 90 */
2, 5, 8,
1, 4, 7,
0, 3, 6,
},
{
/* 180 */
8, 7, 6,
5, 4, 3,
2, 1, 0,
},
{
/* 270 */
6, 3, 0,
7, 4, 1,
8, 5, 2,
},
};
/* clang-format on */
int j;
struct ElementData::automata_data data[4];
for (j = 0; j < 4; j++) {
for (i = 0; i < matches.size(); i++) {
Array match = matches[remap[j][i]];
assert(match.size() == 2);
String entry = match[0];
int rotation = match[1];
if (rotation >= 0)
rotation = (rotation + j) % 4;
data[j].match[i] = { entry, rotation };
String n = cell[0];
int r = cell[1 + j];
data[j].cell = { n, r };
}
}
if (!automata.has(name)) {
Vector<struct ElementData::automata_data> l;
automata[name] = l;
}
for (j = 0; j < 4; j++)
automata[name].push_back(data[j]);
}
}
void ElementData::run_cellular_automata(const String &name, const String &key,
bool exterior, int fl)
{
int i, j, k;
print_line("automata: " + name);
assert(automata.size() > 0);
assert(automata.has(name));
flecs::entity base = get_base(key, exterior);
flecs::entity floor_e =
base.lookup(("floor_" + itos(fl)).ascii().ptr());
assert(floor_e.is_valid());
bool changed = true;
while (changed) {
changed = false;
for (k = 0; k < automata[name].size(); k++) {
for (i = 0; i < grid_size * grid_size; i++) {
flecs::entity item = floor_e.lookup(
("item_" + itos(i)).ascii().ptr());
const struct grid_floor_item *floor_item =
item.get<struct grid_floor_item>();
int index = floor_item->index;
// print_line("automata: processing: " + itos(index));
assert(index == i);
int neighbor_indices[9] = {
/* a */ index - grid_size - 1,
index - grid_size,
index - grid_size + 1,
/* b */ index - 1,
index,
index + 1,
/* c */ index + grid_size - 1,
index + grid_size,
index + grid_size + 1
};
struct ElementData::match_field match[9];
for (j = 0; j < 9; j++) {
int idx = neighbor_indices[j];
if (idx < 0 ||
idx >= grid_size * grid_size) {
match[j].entry = "empty";
match[j].rotation = -1;
} else {
flecs::entity mitem =
floor_e.lookup(
("item_" +
itos(idx))
.ascii()
.ptr());
const struct ElementData::grid_floor_item
*fl_item = mitem.get<
struct ElementData::
grid_floor_item>();
match[j].entry =
fl_item->element;
match[j].rotation =
fl_item->rotation;
}
// print_line("automata: processing: " +
// itos(index) + " " + match[j].entry +
// " " + itos(match[j].rotation));
}
// print_line("match created: " +
// itos(automata[name].size()));
bool matched = true;
for (j = 0; j < 9; j++) {
if (match[j].entry !=
automata[name][k].match[j].entry) {
matched = false;
break;
}
if (automata[name][k].match[j].rotation >=
0 &&
match[j].rotation >= 0 &&
match[j].rotation !=
automata[name][k]
.match[j]
.rotation) {
matched = false;
break;
}
}
if (matched) {
for (j = 0; j < 9; j++) {
print_line(
"matched: " +
match[j].entry + " " +
itos(match[j].rotation) +
" => " +
automata[name][k]
.match[j]
.entry +
" " +
itos(automata[name][k]
.match[j]
.rotation));
}
}
if (matched) {
struct grid_floor_item *floor_item_rw =
item.get_mut<
struct grid_floor_item>();
assert(has_element(
automata[name][k].cell.entry));
floor_item_rw->element =
automata[name][k].cell.entry;
changed = true;
print_line("matched, " +
floor_item->element);
if (automata[name][k].cell.rotation >=
0)
floor_item_rw->rotation =
automata[name][k]
.cell.rotation;
}
}
}
}
}
void ElementData::save_data()
{
int i;
@@ -529,6 +786,7 @@ void ElementData::save_data()
for (i = 0; i < ELEMENT_SOCKETS; i++)
mesh_names[i] = g.mesh_names[i];
item["mesh_names"] = mesh_names;
item["base"] = g.base;
conf_elements[e->get()] = item;
e = e->next();

View File

@@ -84,6 +84,7 @@ public:
String type;
String mesh_names[ELEMENT_SOCKETS];
Ref<Mesh> element_mesh;
String base;
};
int grid_step{ 4 };
int grid_size{ 9 };
@@ -110,6 +111,16 @@ public:
Spatial *node;
};
struct match_field {
String entry;
int rotation;
};
struct automata_data {
struct match_field match[9];
struct match_field cell;
};
HashMap<String, Vector<struct automata_data> > automata;
protected:
ElementData()
{
@@ -145,6 +156,10 @@ protected:
.event(flecs::OnSet)
.each([](flecs::entity em,
struct grid_floor_item_node &s) {
print_line(String(em.parent().name()));
print_line(String(em.parent().path()));
/* should be floor */
assert(em.parent().has<struct grid_floor>());
em.parent().get_mut<struct grid_floor>()->dirty =
true;
});
@@ -248,10 +263,20 @@ public:
{
int ch;
Spatial *node = get_grid_node(key, exterior, fl, i);
List<Node *> remove_nodes;
List<Node *>::Element *e;
for (ch = 0; ch < node->get_child_count(); ch++) {
Node *child = node->get_child(ch);
remove_nodes.push_back(child);
}
if (remove_nodes.empty())
return;
e = remove_nodes.front();
while (e) {
Node *child = e->get();
node->remove_child(child);
child->queue_delete();
e = e->next();
}
}
int get_closest_node_on_floor(const String &key, bool exterior, int fl,
@@ -372,6 +397,18 @@ public:
{
elements.get_key_list(keys);
}
void get_selectable_element_key_list(List<String> *keys)
{
List<String> tmp;
List<String>::Element *e;
elements.get_key_list(&tmp);
e = tmp.front();
while (e) {
if (!e->get().ends_with("-lod"))
keys->push_back(e->get());
e = e->next();
}
}
inline bool has_element(const String &key) const
{
return elements.has(key);
@@ -384,6 +421,19 @@ public:
{
elements[element].element_mesh = mesh;
}
String get_element_base(const String &element) const
{
return elements[element].base;
}
void set_element_base(const String &element, const String &base)
{
elements[element].base = base;
}
void add_automata(const String &name, const struct match_field *match,
const struct match_field &cell);
void add_automata_from_dict(const String &name, const Dictionary &data);
void run_cellular_automata(const String &name, const String &key,
bool exterior, int fl);
void save_data();
void load_data();
};