Cellular automata implementation
This commit is contained in:
Binary file not shown.
BIN
assets/blender/buildings/textures/Atlas_73934.png
Normal file
BIN
assets/blender/buildings/textures/Atlas_73934.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.3 KiB |
506
godot/astream/automata.conf
Normal file
506
godot/astream/automata.conf
Normal 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
Binary file not shown.
@@ -19,7 +19,7 @@ nodes/storage=0
|
|||||||
nodes/use_legacy_names=false
|
nodes/use_legacy_names=false
|
||||||
materials/location=1
|
materials/location=1
|
||||||
materials/storage=1
|
materials/storage=1
|
||||||
materials/keep_on_reimport=true
|
materials/keep_on_reimport=false
|
||||||
meshes/compress=4286
|
meshes/compress=4286
|
||||||
meshes/ensure_tangents=true
|
meshes/ensure_tangents=true
|
||||||
meshes/octahedral_compression=true
|
meshes/octahedral_compression=true
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
@@ -65,6 +65,14 @@ focus_mode = 2
|
|||||||
text = "Interior"
|
text = "Interior"
|
||||||
switch_on_hover = true
|
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="."]
|
[node name="bg_floor" type="Spatial" parent="."]
|
||||||
unique_name_in_owner = true
|
unique_name_in_owner = true
|
||||||
|
|
||||||
@@ -339,13 +347,13 @@ columns = 2
|
|||||||
unique_name_in_owner = true
|
unique_name_in_owner = true
|
||||||
margin_top = 771.0
|
margin_top = 771.0
|
||||||
margin_right = 314.0
|
margin_right = 314.0
|
||||||
margin_bottom = 1107.0
|
margin_bottom = 1135.0
|
||||||
|
|
||||||
[node name="VBoxContainer" type="VBoxContainer" parent="VBoxContainer/layout_editor"]
|
[node name="VBoxContainer" type="VBoxContainer" parent="VBoxContainer/layout_editor"]
|
||||||
margin_left = 7.0
|
margin_left = 7.0
|
||||||
margin_top = 7.0
|
margin_top = 7.0
|
||||||
margin_right = 307.0
|
margin_right = 307.0
|
||||||
margin_bottom = 329.0
|
margin_bottom = 357.0
|
||||||
|
|
||||||
[node name="GridContainer" type="GridContainer" parent="VBoxContainer/layout_editor/VBoxContainer"]
|
[node name="GridContainer" type="GridContainer" parent="VBoxContainer/layout_editor/VBoxContainer"]
|
||||||
margin_right = 300.0
|
margin_right = 300.0
|
||||||
@@ -505,11 +513,49 @@ margin_top = 274.0
|
|||||||
margin_right = 300.0
|
margin_right = 300.0
|
||||||
margin_bottom = 298.0
|
margin_bottom = 298.0
|
||||||
|
|
||||||
[node name="layout_selector" type="OptionButton" parent="VBoxContainer/layout_editor/VBoxContainer"]
|
[node name="g" type="GridContainer" parent="VBoxContainer/layout_editor/VBoxContainer"]
|
||||||
unique_name_in_owner = true
|
|
||||||
margin_top = 302.0
|
margin_top = 302.0
|
||||||
margin_right = 300.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="."]
|
[node name="BuildingLayoutEditor" type="BuildingLayoutEditor" parent="."]
|
||||||
source = ExtResource( 2 )
|
source = ExtResource( 2 )
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -3,6 +3,7 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
#include <main/main.h>
|
#include <main/main.h>
|
||||||
#include <core/engine.h>
|
#include <core/engine.h>
|
||||||
|
#include <core/io/marshalls.h>
|
||||||
#include <core/os/input.h>
|
#include <core/os/input.h>
|
||||||
#include <scene/resources/packed_scene.h>
|
#include <scene/resources/packed_scene.h>
|
||||||
#include <scene/resources/surface_tool.h>
|
#include <scene/resources/surface_tool.h>
|
||||||
@@ -20,6 +21,7 @@
|
|||||||
#include <flecs/flecs.h>
|
#include <flecs/flecs.h>
|
||||||
namespace meshoptimizer
|
namespace meshoptimizer
|
||||||
{
|
{
|
||||||
|
#define MESHOPTIMIZER_EXPERIMENTAL static
|
||||||
#define MESHOPTIMIZER_API static
|
#define MESHOPTIMIZER_API static
|
||||||
#include <meshoptimizer.h>
|
#include <meshoptimizer.h>
|
||||||
#include <simplifier.cpp>
|
#include <simplifier.cpp>
|
||||||
@@ -62,6 +64,12 @@ public:
|
|||||||
"select_grid_rotation");
|
"select_grid_rotation");
|
||||||
get_as_node<Button>("%grow_cell_button")
|
get_as_node<Button>("%grow_cell_button")
|
||||||
->connect("pressed", this, "grow_cell");
|
->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()
|
virtual ~LayoutEditor()
|
||||||
{
|
{
|
||||||
@@ -102,7 +110,7 @@ public:
|
|||||||
Vector3(-14, 23, 32));
|
Vector3(-14, 23, 32));
|
||||||
List<String> element_keys;
|
List<String> element_keys;
|
||||||
List<String>::Element *e;
|
List<String>::Element *e;
|
||||||
ElementData::get_singleton()->get_element_key_list(
|
ElementData::get_singleton()->get_selectable_element_key_list(
|
||||||
&element_keys);
|
&element_keys);
|
||||||
e = element_keys.front();
|
e = element_keys.front();
|
||||||
get_as_node<OptionButton>(grid_elements)->clear();
|
get_as_node<OptionButton>(grid_elements)->clear();
|
||||||
@@ -112,6 +120,17 @@ public:
|
|||||||
print_line("Added item: " + e->get());
|
print_line("Added item: " + e->get());
|
||||||
e = e->next();
|
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(
|
EditorEvent::get_singleton()->event.add_listener(
|
||||||
this, &LayoutEditor::event_signal_handler);
|
this, &LayoutEditor::event_signal_handler);
|
||||||
}
|
}
|
||||||
@@ -209,6 +228,11 @@ public:
|
|||||||
} else if (event == "elements_update_all") {
|
} else if (event == "elements_update_all") {
|
||||||
print_line(event);
|
print_line(event);
|
||||||
editor->update_element_meshes();
|
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)
|
void set_current_floor(float value)
|
||||||
@@ -222,6 +246,7 @@ public:
|
|||||||
ElementData::get_singleton()->ensure_floor(
|
ElementData::get_singleton()->ensure_floor(
|
||||||
current_layout, is_exterior, current_floor);
|
current_layout, is_exterior, current_floor);
|
||||||
print_line("visualize: " + itos(current_floor));
|
print_line("visualize: " + itos(current_floor));
|
||||||
|
clear_vis(current_layout, is_exterior);
|
||||||
visualize_below_and_current(current_layout, is_exterior);
|
visualize_below_and_current(current_layout, is_exterior);
|
||||||
Transform xform = editor->get_viewport()
|
Transform xform = editor->get_viewport()
|
||||||
->get_camera()
|
->get_camera()
|
||||||
@@ -259,6 +284,10 @@ public:
|
|||||||
ElementData::get_singleton()->set_grid_rotation(
|
ElementData::get_singleton()->set_grid_rotation(
|
||||||
current_layout, is_exterior, current_floor,
|
current_layout, is_exterior, current_floor,
|
||||||
current_cell, index);
|
current_cell, index);
|
||||||
|
ElementData::get_singleton()->clear_grid_node(current_layout,
|
||||||
|
is_exterior,
|
||||||
|
current_floor,
|
||||||
|
current_cell);
|
||||||
editor->visualize_element_at(
|
editor->visualize_element_at(
|
||||||
element, ElementData::get_singleton()->get_grid_node(
|
element, ElementData::get_singleton()->get_grid_node(
|
||||||
current_layout, is_exterior,
|
current_layout, is_exterior,
|
||||||
@@ -289,6 +318,43 @@ public:
|
|||||||
}
|
}
|
||||||
print_line("grow_cell");
|
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()
|
static void _bind_methods()
|
||||||
{
|
{
|
||||||
@@ -301,6 +367,12 @@ public:
|
|||||||
ClassDB::bind_method(D_METHOD("grow_cell"),
|
ClassDB::bind_method(D_METHOD("grow_cell"),
|
||||||
&LayoutEditor::grow_cell);
|
&LayoutEditor::grow_cell);
|
||||||
ClassDB::bind_method(D_METHOD("update"), &LayoutEditor::update);
|
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)
|
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(
|
ElementData::get_singleton()->get_grid_element(
|
||||||
layout, exterior, fl, i);
|
layout, exterior, fl, i);
|
||||||
assert(element.length() > 0);
|
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 =
|
Ref<Mesh> src =
|
||||||
ElementData::get_singleton()->get_element_mesh(
|
ElementData::get_singleton()->get_element_mesh(
|
||||||
element);
|
element);
|
||||||
@@ -1232,20 +1318,29 @@ Ref<Mesh> BuildingLayoutEditor::get_layout_exterior_mesh(const String &layout,
|
|||||||
src->set_storage_mode(Mesh::STORAGE_MODE_GPU);
|
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();
|
Array arr = sf.commit_to_arrays();
|
||||||
print_line("optimizing for lod: " + itos(lod));
|
print_line("optimizing for lod: " + itos(lod));
|
||||||
|
Ref<SpatialMaterial> spmat = mat;
|
||||||
|
assert(spmat.is_valid());
|
||||||
if (lod > 0) {
|
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<Vector2> &uvs = arr[Mesh::ARRAY_TEX_UV];
|
||||||
const PoolVector<int> &index_array = arr[Mesh::ARRAY_INDEX];
|
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;
|
LocalVector<Color> colors;
|
||||||
colors.resize(uvs.size());
|
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();
|
Ref<Image> img_data = albedo_texture->get_data();
|
||||||
assert(img_data.is_valid());
|
assert(img_data.is_valid());
|
||||||
img_data->lock();
|
img_data->lock();
|
||||||
@@ -1254,6 +1349,7 @@ Ref<Mesh> BuildingLayoutEditor::get_layout_exterior_mesh(const String &layout,
|
|||||||
uvs[i] * img_data->get_size());
|
uvs[i] * img_data->get_size());
|
||||||
img_data->unlock();
|
img_data->unlock();
|
||||||
}
|
}
|
||||||
|
#if 0
|
||||||
HashMap<Color, int> map_colors;
|
HashMap<Color, int> map_colors;
|
||||||
HashMap<int, int[3]> base_uvs;
|
HashMap<int, int[3]> base_uvs;
|
||||||
Set<Color> seen_colors;
|
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];
|
uv_remap.write()[idx] = uvs[uv_idx];
|
||||||
}
|
}
|
||||||
arr[Mesh::ARRAY_TEX_UV] = uv_remap;
|
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;
|
LocalVector<float> vertices;
|
||||||
const PoolVector<Vector3> &vertex_array =
|
|
||||||
arr[Mesh::ARRAY_VERTEX];
|
|
||||||
lodv.resize(index_array.size());
|
|
||||||
vertices.resize(vertex_array.size() * 3);
|
vertices.resize(vertex_array.size() * 3);
|
||||||
for (i = 0; i < vertex_array.size(); i++) {
|
for (i = 0; i < vertex_array.size(); i++) {
|
||||||
vertices[i * 3 + 0] = vertex_array[i].x;
|
vertices[i * 3 + 0] = vertex_array[i].x;
|
||||||
vertices[i * 3 + 1] = vertex_array[i].y;
|
vertices[i * 3 + 1] = vertex_array[i].y;
|
||||||
vertices[i * 3 + 2] = vertex_array[i].z;
|
vertices[i * 3 + 2] = vertex_array[i].z;
|
||||||
}
|
}
|
||||||
|
PoolVector<int> lodv;
|
||||||
|
lodv.resize(index_array.size());
|
||||||
float error = 0.f;
|
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 threshold = 1.0f;
|
||||||
float target_error = 0.01f;
|
float target_error = 0.01f;
|
||||||
bool sloppy = false;
|
bool sloppy = false;
|
||||||
switch (lod) {
|
switch (lod) {
|
||||||
case 1:
|
case 1:
|
||||||
threshold = 0.6f;
|
threshold = 0.6f;
|
||||||
target_error = 0.01f;
|
target_error = FLT_MAX;
|
||||||
sloppy = false;
|
sloppy = false;
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
threshold = 0.3f;
|
threshold = 0.3f;
|
||||||
target_error = 0.01f;
|
target_error = FLT_MAX;
|
||||||
sloppy = false;
|
sloppy = false;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
threshold = 1.0f / (float(lod + 1));
|
threshold = 1.0f / (float(lod + 1));
|
||||||
target_error = 0.01;
|
target_error = FLT_MAX;
|
||||||
sloppy = true;
|
sloppy = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -1400,6 +1585,309 @@ Ref<Mesh> BuildingLayoutEditor::get_layout_exterior_mesh(const String &layout,
|
|||||||
assert(ret.is_valid());
|
assert(ret.is_valid());
|
||||||
return ret;
|
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()
|
void BuildingLayoutEditor::update_element_meshes()
|
||||||
{
|
{
|
||||||
List<String> keys;
|
List<String> keys;
|
||||||
@@ -1432,11 +1920,13 @@ void BuildingLayoutEditor::update_layout_meshes()
|
|||||||
while (e) {
|
while (e) {
|
||||||
print_line("update_layout_meshes: " + e->get());
|
print_line("update_layout_meshes: " + e->get());
|
||||||
for (lod = 0; lod < 4; lod++) {
|
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);
|
String item_name = e->get() + "_lod" + itos(lod);
|
||||||
int id = ml->get_last_unused_item_id();
|
int id = ml->get_last_unused_item_id();
|
||||||
ml->create_item(id);
|
ml->create_item(id);
|
||||||
Ref<Mesh> mesh =
|
|
||||||
get_layout_exterior_mesh(e->get(), lod);
|
|
||||||
assert(mesh.is_valid());
|
assert(mesh.is_valid());
|
||||||
Ref<Shape> shape = mesh->create_trimesh_shape();
|
Ref<Shape> shape = mesh->create_trimesh_shape();
|
||||||
assert(shape.is_valid());
|
assert(shape.is_valid());
|
||||||
@@ -1468,6 +1958,7 @@ void BuildingLayoutEditor::update_layout_meshes()
|
|||||||
static ElementTypeEditor *etype_editor;
|
static ElementTypeEditor *etype_editor;
|
||||||
static ElementEditor *element_editor;
|
static ElementEditor *element_editor;
|
||||||
static LayoutEditor *layout_editor;
|
static LayoutEditor *layout_editor;
|
||||||
|
static HashMap<int, String> automata_id;
|
||||||
|
|
||||||
void BuildingLayoutEditor::_notification(int which)
|
void BuildingLayoutEditor::_notification(int which)
|
||||||
{
|
{
|
||||||
@@ -1489,6 +1980,29 @@ void BuildingLayoutEditor::_notification(int which)
|
|||||||
}
|
}
|
||||||
select_mode(0);
|
select_mode(0);
|
||||||
set_process_unhandled_input(true);
|
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;
|
} break;
|
||||||
case NOTIFICATION_EXIT_TREE:
|
case NOTIFICATION_EXIT_TREE:
|
||||||
for (i = 0; i < (int)editors.size(); i++)
|
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();
|
get_as_node<Control>("%socket_editor")->hide();
|
||||||
select_mode(2);
|
select_mode(2);
|
||||||
break;
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -32,6 +32,11 @@ public:
|
|||||||
Ref<Mesh> get_element_mesh(const String &element) const;
|
Ref<Mesh> get_element_mesh(const String &element) const;
|
||||||
Ref<Mesh> get_layout_exterior_mesh(const String &layout, int lod) 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_element_meshes();
|
||||||
void update_layout_meshes();
|
void update_layout_meshes();
|
||||||
|
|
||||||
|
|||||||
@@ -421,6 +421,8 @@ void ElementData::ensure_floor(const String &key, bool exterior, int fl)
|
|||||||
flecs::entity floor_e =
|
flecs::entity floor_e =
|
||||||
ecs.entity(("floor_" + itos(fl)).ascii().ptr()).child_of(base);
|
ecs.entity(("floor_" + itos(fl)).ascii().ptr()).child_of(base);
|
||||||
assert(floor_e.is_valid());
|
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++) {
|
for (i = 0; i < grid_size * grid_size; i++) {
|
||||||
flecs::entity item =
|
flecs::entity item =
|
||||||
ecs.entity(("item_" + itos(i)).ascii().ptr())
|
ecs.entity(("item_" + itos(i)).ascii().ptr())
|
||||||
@@ -434,6 +436,7 @@ void ElementData::load_data()
|
|||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
ConfigFile config;
|
ConfigFile config;
|
||||||
|
ConfigFile automata_conf;
|
||||||
Dictionary conf_element_types;
|
Dictionary conf_element_types;
|
||||||
Dictionary conf_elements;
|
Dictionary conf_elements;
|
||||||
Dictionary conf_grid_layouts;
|
Dictionary conf_grid_layouts;
|
||||||
@@ -469,6 +472,7 @@ void ElementData::load_data()
|
|||||||
assert(item.has("type"));
|
assert(item.has("type"));
|
||||||
assert(item.has("mesh_names"));
|
assert(item.has("mesh_names"));
|
||||||
String type = item["type"];
|
String type = item["type"];
|
||||||
|
String base = item.get("base", "");
|
||||||
print_line("loading element: " + key + " type: " + type);
|
print_line("loading element: " + key + " type: " + type);
|
||||||
if (key == "empty") {
|
if (key == "empty") {
|
||||||
e = e->next();
|
e = e->next();
|
||||||
@@ -478,12 +482,265 @@ void ElementData::load_data()
|
|||||||
Array mesh_names = item["mesh_names"];
|
Array mesh_names = item["mesh_names"];
|
||||||
for (i = 0; i < mesh_names.size(); i++)
|
for (i = 0; i < mesh_names.size(); i++)
|
||||||
set_element_mesh_name(key, i, mesh_names[i]);
|
set_element_mesh_name(key, i, mesh_names[i]);
|
||||||
|
set_element_base(key, base);
|
||||||
e = e->next();
|
e = e->next();
|
||||||
}
|
}
|
||||||
unserialize_layouts(conf_grid_layouts);
|
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",
|
EditorEvent::get_singleton()->event.emit("elements_update_all",
|
||||||
varray());
|
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()
|
void ElementData::save_data()
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
@@ -529,6 +786,7 @@ void ElementData::save_data()
|
|||||||
for (i = 0; i < ELEMENT_SOCKETS; i++)
|
for (i = 0; i < ELEMENT_SOCKETS; i++)
|
||||||
mesh_names[i] = g.mesh_names[i];
|
mesh_names[i] = g.mesh_names[i];
|
||||||
item["mesh_names"] = mesh_names;
|
item["mesh_names"] = mesh_names;
|
||||||
|
item["base"] = g.base;
|
||||||
|
|
||||||
conf_elements[e->get()] = item;
|
conf_elements[e->get()] = item;
|
||||||
e = e->next();
|
e = e->next();
|
||||||
|
|||||||
@@ -84,6 +84,7 @@ public:
|
|||||||
String type;
|
String type;
|
||||||
String mesh_names[ELEMENT_SOCKETS];
|
String mesh_names[ELEMENT_SOCKETS];
|
||||||
Ref<Mesh> element_mesh;
|
Ref<Mesh> element_mesh;
|
||||||
|
String base;
|
||||||
};
|
};
|
||||||
int grid_step{ 4 };
|
int grid_step{ 4 };
|
||||||
int grid_size{ 9 };
|
int grid_size{ 9 };
|
||||||
@@ -110,6 +111,16 @@ public:
|
|||||||
Spatial *node;
|
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:
|
protected:
|
||||||
ElementData()
|
ElementData()
|
||||||
{
|
{
|
||||||
@@ -145,6 +156,10 @@ protected:
|
|||||||
.event(flecs::OnSet)
|
.event(flecs::OnSet)
|
||||||
.each([](flecs::entity em,
|
.each([](flecs::entity em,
|
||||||
struct grid_floor_item_node &s) {
|
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 =
|
em.parent().get_mut<struct grid_floor>()->dirty =
|
||||||
true;
|
true;
|
||||||
});
|
});
|
||||||
@@ -248,10 +263,20 @@ public:
|
|||||||
{
|
{
|
||||||
int ch;
|
int ch;
|
||||||
Spatial *node = get_grid_node(key, exterior, fl, i);
|
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++) {
|
for (ch = 0; ch < node->get_child_count(); ch++) {
|
||||||
Node *child = node->get_child(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);
|
node->remove_child(child);
|
||||||
child->queue_delete();
|
child->queue_delete();
|
||||||
|
e = e->next();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
int get_closest_node_on_floor(const String &key, bool exterior, int fl,
|
int get_closest_node_on_floor(const String &key, bool exterior, int fl,
|
||||||
@@ -372,6 +397,18 @@ public:
|
|||||||
{
|
{
|
||||||
elements.get_key_list(keys);
|
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
|
inline bool has_element(const String &key) const
|
||||||
{
|
{
|
||||||
return elements.has(key);
|
return elements.has(key);
|
||||||
@@ -384,6 +421,19 @@ public:
|
|||||||
{
|
{
|
||||||
elements[element].element_mesh = mesh;
|
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 save_data();
|
||||||
void load_data();
|
void load_data();
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user