Now layout build works fine

This commit is contained in:
2024-12-01 04:12:25 +03:00
parent 34bded906c
commit 42dc811cf6
28 changed files with 4040 additions and 2640 deletions

View File

@@ -33,7 +33,7 @@ entries=[ {
"order": 4,
"type": "layout"
}, {
"children": [ 18, 19 ],
"children": [ 18, 19, 20 ],
"commands": [ [ 3, [ ] ], [ 4, [ ] ] ],
"index": 4,
"name": "zone_0",
@@ -41,7 +41,7 @@ entries=[ {
"type": "zone",
"zone_type": 1
}, {
"children": [ 20, 21, 22 ],
"children": [ 21, 22, 23 ],
"commands": [ [ 4, [ ] ] ],
"index": 5,
"name": "zone_1",
@@ -49,7 +49,7 @@ entries=[ {
"type": "zone",
"zone_type": 0
}, {
"children": [ 23, 24, 25, 26 ],
"children": [ 24, 25, 26, 27 ],
"commands": [ [ 3, [ ] ], [ 4, [ ] ] ],
"index": 6,
"name": "zone_1",
@@ -57,7 +57,7 @@ entries=[ {
"type": "zone",
"zone_type": 1
}, {
"children": [ 27, 28, 29 ],
"children": [ 28, 29, 30 ],
"commands": [ [ 3, [ ] ], [ 4, [ ] ] ],
"index": 7,
"name": "zone_0",
@@ -65,14 +65,14 @@ entries=[ {
"type": "zone",
"zone_type": 0
}, {
"children": [ 30, 31 ],
"children": [ 31, 32 ],
"commands": [ [ 3, [ ] ], [ 4, [ ] ] ],
"index": 8,
"name": "unit_0",
"order": 3,
"type": "unit"
}, {
"children": [ 32, 33 ],
"children": [ 33, 34 ],
"commands": [ [ 3, [ ] ], [ 4, [ ] ] ],
"index": 9,
"name": "zone_0",
@@ -80,35 +80,35 @@ entries=[ {
"type": "zone",
"zone_type": 1
}, {
"children": [ 34, 35 ],
"children": [ 35, 36 ],
"commands": [ [ 3, [ ] ], [ 4, [ ] ] ],
"index": 10,
"name": "unit_0",
"order": 0,
"type": "unit"
}, {
"children": [ 36, 37 ],
"children": [ 37, 38 ],
"commands": [ [ 3, [ ] ], [ 4, [ ] ] ],
"index": 11,
"name": "unit_1",
"order": 0,
"type": "unit"
}, {
"children": [ 38, 39 ],
"children": [ 39, 40 ],
"commands": [ [ 3, [ ] ], [ 4, [ ] ] ],
"index": 12,
"name": "unit_2",
"order": 0,
"type": "unit"
}, {
"children": [ 40, 41 ],
"children": [ 41, 42 ],
"commands": [ [ 3, [ ] ], [ 4, [ ] ] ],
"index": 13,
"name": "unit_3",
"order": 0,
"type": "unit"
}, {
"children": [ 42, 43 ],
"children": [ 43, 44 ],
"commands": [ ],
"index": 14,
"name": "zone_0",
@@ -116,7 +116,7 @@ entries=[ {
"type": "zone",
"zone_type": 0
}, {
"children": [ 44, 45 ],
"children": [ 45, 46 ],
"commands": [ ],
"index": 15,
"name": "zone_1",
@@ -124,7 +124,7 @@ entries=[ {
"type": "zone",
"zone_type": 0
}, {
"children": [ 46, 47, 48 ],
"children": [ 47, 48, 49 ],
"commands": [ ],
"index": 16,
"name": "zone_2",
@@ -132,7 +132,7 @@ entries=[ {
"type": "zone",
"zone_type": 0
}, {
"children": [ 49, 50, 51, 52, 53 ],
"children": [ 50, 51, 52, 53, 54 ],
"commands": [ ],
"index": 17,
"name": "zone_3",
@@ -161,8 +161,18 @@ entries=[ {
"window": true
}, {
"children": [ ],
"commands": [ [ 5, [ ] ] ],
"commands": [ ],
"index": 20,
"name": "office_0",
"order": 3,
"room_area": 16.0,
"room_type": 309,
"type": "room",
"window": true
}, {
"children": [ ],
"commands": [ [ 5, [ ] ] ],
"index": 21,
"name": "wc_0",
"order": 0,
"room_area": 16.0,
@@ -172,7 +182,7 @@ entries=[ {
}, {
"children": [ ],
"commands": [ [ 5, [ ] ], [ 3, [ ] ] ],
"index": 21,
"index": 22,
"name": "bathroom_0",
"order": 1,
"room_area": 16.0,
@@ -182,7 +192,7 @@ entries=[ {
}, {
"children": [ ],
"commands": [ [ 5, [ ] ] ],
"index": 22,
"index": 23,
"name": "bedroom_0",
"order": 2,
"room_area": 64.0,
@@ -192,7 +202,7 @@ entries=[ {
}, {
"children": [ ],
"commands": [ [ 5, [ ] ] ],
"index": 23,
"index": 24,
"name": "living_room_0",
"order": 0,
"room_area": 144.0,
@@ -202,7 +212,7 @@ entries=[ {
}, {
"children": [ ],
"commands": [ [ 5, [ ] ] ],
"index": 24,
"index": 25,
"name": "kitchen_0",
"order": 1,
"room_area": 64.0,
@@ -212,7 +222,7 @@ entries=[ {
}, {
"children": [ ],
"commands": [ [ 5, [ ] ] ],
"index": 25,
"index": 26,
"name": "storage_room_0",
"order": 2,
"room_area": 16.0,
@@ -222,7 +232,7 @@ entries=[ {
}, {
"children": [ ],
"commands": [ [ 5, [ ] ], [ 4, [ ] ] ],
"index": 26,
"index": 27,
"name": "enterance_0",
"order": 3,
"room_area": 16.0,
@@ -232,7 +242,7 @@ entries=[ {
}, {
"children": [ ],
"commands": [ [ 5, [ ] ] ],
"index": 27,
"index": 28,
"name": "wc_0",
"order": 0,
"room_area": 16.0,
@@ -242,7 +252,7 @@ entries=[ {
}, {
"children": [ ],
"commands": [ [ 5, [ ] ] ],
"index": 28,
"index": 29,
"name": "bathroom_0",
"order": 1,
"room_area": 16.0,
@@ -252,7 +262,7 @@ entries=[ {
}, {
"children": [ ],
"commands": [ [ 5, [ ] ] ],
"index": 29,
"index": 30,
"name": "bedroom_0",
"order": 2,
"room_area": 64.0,
@@ -260,17 +270,17 @@ entries=[ {
"type": "room",
"window": true
}, {
"children": [ 54, 55, 56 ],
"children": [ 55, 56, 57 ],
"commands": [ [ 3, [ ] ], [ 4, [ ] ] ],
"index": 30,
"index": 31,
"name": "zone_0",
"order": 0,
"type": "zone",
"zone_type": 0
}, {
"children": [ 57, 58 ],
"children": [ 58, 59 ],
"commands": [ [ 3, [ ] ], [ 4, [ ] ] ],
"index": 31,
"index": 32,
"name": "zone_1",
"order": 0,
"type": "zone",
@@ -278,7 +288,7 @@ entries=[ {
}, {
"children": [ ],
"commands": [ [ 5, [ ] ] ],
"index": 32,
"index": 33,
"name": "enterance_0",
"order": 0,
"room_area": 64.0,
@@ -286,9 +296,9 @@ entries=[ {
"type": "room",
"window": true
}, {
"children": [ 59 ],
"children": [ 60 ],
"commands": [ [ 5, [ ] ] ],
"index": 33,
"index": 34,
"name": "stair_0",
"order": 0,
"room_area": 16.0,
@@ -296,65 +306,65 @@ entries=[ {
"type": "room",
"window": true
}, {
"children": [ 60, 61, 62 ],
"commands": [ [ 3, [ ] ], [ 4, [ ] ] ],
"index": 34,
"name": "zone_0",
"order": 0,
"type": "zone",
"zone_type": 0
}, {
"children": [ 63, 64 ],
"children": [ 61, 62, 63 ],
"commands": [ [ 3, [ ] ], [ 4, [ ] ] ],
"index": 35,
"name": "zone_1",
"name": "zone_0",
"order": 0,
"type": "zone",
"zone_type": 1
"zone_type": 0
}, {
"children": [ 65 ],
"children": [ 64, 65 ],
"commands": [ [ 3, [ ] ], [ 4, [ ] ] ],
"index": 36,
"name": "zone_0",
"order": 0,
"type": "zone",
"zone_type": 0
}, {
"children": [ 66, 67 ],
"commands": [ [ 3, [ ] ], [ 4, [ ] ] ],
"index": 37,
"name": "zone_1",
"order": 0,
"type": "zone",
"zone_type": 1
}, {
"children": [ 68 ],
"children": [ 66 ],
"commands": [ [ 3, [ ] ], [ 4, [ ] ] ],
"index": 38,
"index": 37,
"name": "zone_0",
"order": 0,
"type": "zone",
"zone_type": 0
}, {
"children": [ 67, 68 ],
"commands": [ [ 3, [ ] ], [ 4, [ ] ] ],
"index": 38,
"name": "zone_1",
"order": 0,
"type": "zone",
"zone_type": 1
}, {
"children": [ 69 ],
"commands": [ [ 3, [ ] ], [ 4, [ ] ] ],
"index": 39,
"name": "zone_1",
"order": 1,
"type": "zone",
"zone_type": 1
}, {
"children": [ 70 ],
"commands": [ [ 3, [ ] ], [ 4, [ ] ] ],
"index": 40,
"name": "zone_0",
"order": 0,
"type": "zone",
"zone_type": 0
}, {
"children": [ 70 ],
"commands": [ [ 3, [ ] ], [ 4, [ ] ] ],
"index": 40,
"name": "zone_1",
"order": 1,
"type": "zone",
"zone_type": 1
}, {
"children": [ 71 ],
"commands": [ [ 3, [ ] ], [ 4, [ ] ] ],
"index": 41,
"name": "zone_0",
"order": 0,
"type": "zone",
"zone_type": 0
}, {
"children": [ 72 ],
"commands": [ [ 3, [ ] ], [ 4, [ ] ] ],
"index": 42,
"name": "zone_1",
"order": 1,
"type": "zone",
@@ -362,7 +372,7 @@ entries=[ {
}, {
"children": [ ],
"commands": [ ],
"index": 42,
"index": 43,
"name": "wc_0",
"order": 1,
"room_area": 16.0,
@@ -372,27 +382,7 @@ entries=[ {
}, {
"children": [ ],
"commands": [ ],
"index": 43,
"name": "bedroom_0",
"order": 2,
"room_area": 64.0,
"room_type": 202,
"type": "room",
"window": true
}, {
"children": [ ],
"commands": [ ],
"index": 44,
"name": "wc_0",
"order": 1,
"room_area": 16.0,
"room_type": 200,
"type": "room",
"window": false
}, {
"children": [ ],
"commands": [ ],
"index": 45,
"name": "bedroom_0",
"order": 2,
"room_area": 64.0,
@@ -402,7 +392,7 @@ entries=[ {
}, {
"children": [ ],
"commands": [ ],
"index": 46,
"index": 45,
"name": "wc_0",
"order": 1,
"room_area": 16.0,
@@ -412,7 +402,27 @@ entries=[ {
}, {
"children": [ ],
"commands": [ ],
"index": 46,
"name": "bedroom_0",
"order": 2,
"room_area": 64.0,
"room_type": 202,
"type": "room",
"window": true
}, {
"children": [ ],
"commands": [ ],
"index": 47,
"name": "wc_0",
"order": 1,
"room_area": 16.0,
"room_type": 200,
"type": "room",
"window": false
}, {
"children": [ ],
"commands": [ ],
"index": 48,
"name": "bathroom_0",
"order": 2,
"room_area": 16.0,
@@ -422,7 +432,7 @@ entries=[ {
}, {
"children": [ ],
"commands": [ ],
"index": 48,
"index": 49,
"name": "bathroom_1",
"order": 3,
"room_area": 144.0,
@@ -432,7 +442,7 @@ entries=[ {
}, {
"children": [ ],
"commands": [ ],
"index": 49,
"index": 50,
"name": "living_room_0",
"order": 1,
"room_area": 144.0,
@@ -442,7 +452,7 @@ entries=[ {
}, {
"children": [ ],
"commands": [ ],
"index": 50,
"index": 51,
"name": "kitchen_0",
"order": 2,
"room_area": 64.0,
@@ -452,7 +462,7 @@ entries=[ {
}, {
"children": [ ],
"commands": [ ],
"index": 51,
"index": 52,
"name": "dining_room_0",
"order": 3,
"room_area": 144.0,
@@ -462,7 +472,7 @@ entries=[ {
}, {
"children": [ ],
"commands": [ ],
"index": 52,
"index": 53,
"name": "enterance_0",
"order": 4,
"room_area": 16.0,
@@ -472,7 +482,7 @@ entries=[ {
}, {
"children": [ ],
"commands": [ ],
"index": 53,
"index": 54,
"name": "enterance_1",
"order": 5,
"room_area": 16.0,
@@ -482,7 +492,7 @@ entries=[ {
}, {
"children": [ ],
"commands": [ [ 5, [ ] ] ],
"index": 54,
"index": 55,
"name": "bathroom_0",
"order": 0,
"room_area": 16.0,
@@ -492,7 +502,7 @@ entries=[ {
}, {
"children": [ ],
"commands": [ [ 5, [ ] ] ],
"index": 55,
"index": 56,
"name": "wc_0",
"order": 1,
"room_area": 16.0,
@@ -502,7 +512,7 @@ entries=[ {
}, {
"children": [ ],
"commands": [ [ 5, [ ] ] ],
"index": 56,
"index": 57,
"name": "bedroom_0",
"order": 2,
"room_area": 36.0,
@@ -512,7 +522,7 @@ entries=[ {
}, {
"children": [ ],
"commands": [ [ 5, [ ] ] ],
"index": 57,
"index": 58,
"name": "living_room_0",
"order": 0,
"room_area": 36.0,
@@ -522,7 +532,7 @@ entries=[ {
}, {
"children": [ ],
"commands": [ [ 5, [ ] ] ],
"index": 58,
"index": 59,
"name": "kitchen_0",
"order": 1,
"room_area": 16.0,
@@ -530,17 +540,17 @@ entries=[ {
"type": "room",
"window": true
}, {
"children": [ 72, 73 ],
"children": [ 73, 74 ],
"commands": [ ],
"floor_index": 1,
"index": 59,
"index": 60,
"name": "floor_0",
"order": 0,
"type": "floor"
}, {
"children": [ ],
"commands": [ [ 5, [ ] ] ],
"index": 60,
"index": 61,
"name": "wc_0",
"order": 0,
"room_area": 16.0,
@@ -550,7 +560,7 @@ entries=[ {
}, {
"children": [ ],
"commands": [ [ 5, [ ] ] ],
"index": 61,
"index": 62,
"name": "bathroom_0",
"order": 1,
"room_area": 16.0,
@@ -560,7 +570,7 @@ entries=[ {
}, {
"children": [ ],
"commands": [ [ 5, [ ] ] ],
"index": 62,
"index": 63,
"name": "bedroom_0",
"order": 2,
"room_area": 64.0,
@@ -570,7 +580,7 @@ entries=[ {
}, {
"children": [ ],
"commands": [ [ 5, [ ] ] ],
"index": 63,
"index": 64,
"name": "kitchen_0",
"order": 0,
"room_area": 16.0,
@@ -580,7 +590,7 @@ entries=[ {
}, {
"children": [ ],
"commands": [ [ 5, [ ] ] ],
"index": 64,
"index": 65,
"name": "living_room_0",
"order": 1,
"room_area": 144.0,
@@ -590,7 +600,7 @@ entries=[ {
}, {
"children": [ ],
"commands": [ [ 5, [ ] ] ],
"index": 65,
"index": 66,
"name": "bathroom_0",
"order": 0,
"room_area": 16.0,
@@ -600,7 +610,7 @@ entries=[ {
}, {
"children": [ ],
"commands": [ [ 5, [ ] ] ],
"index": 66,
"index": 67,
"name": "kitchen_0",
"order": 0,
"room_area": 64.0,
@@ -610,7 +620,7 @@ entries=[ {
}, {
"children": [ ],
"commands": [ [ 5, [ ] ] ],
"index": 67,
"index": 68,
"name": "living_room_0",
"order": 1,
"room_area": 64.0,
@@ -620,7 +630,7 @@ entries=[ {
}, {
"children": [ ],
"commands": [ [ 5, [ ] ] ],
"index": 68,
"index": 69,
"name": "wc_0",
"order": 0,
"room_area": 16.0,
@@ -630,7 +640,7 @@ entries=[ {
}, {
"children": [ ],
"commands": [ [ 5, [ ] ] ],
"index": 69,
"index": 70,
"name": "living_room_0",
"order": 0,
"room_area": 64.0,
@@ -640,7 +650,7 @@ entries=[ {
}, {
"children": [ ],
"commands": [ [ 5, [ ] ] ],
"index": 70,
"index": 71,
"name": "bathroom_0",
"order": 0,
"room_area": 16.0,
@@ -650,7 +660,7 @@ entries=[ {
}, {
"children": [ ],
"commands": [ [ 5, [ ] ] ],
"index": 71,
"index": 72,
"name": "living_room_0",
"order": 0,
"room_area": 64.0,
@@ -658,24 +668,24 @@ entries=[ {
"type": "room",
"window": true
}, {
"children": [ 74 ],
"children": [ 75 ],
"commands": [ ],
"index": 72,
"index": 73,
"name": "zone_0",
"order": 0,
"type": "zone",
"zone_type": 1
}, {
"children": [ 75, 76 ],
"children": [ 76, 77 ],
"commands": [ ],
"index": 73,
"index": 74,
"name": "unit_0",
"order": 0,
"type": "unit"
}, {
"children": [ ],
"commands": [ ],
"index": 74,
"index": 75,
"name": "storage_room_0",
"order": 0,
"room_area": 64.0,
@@ -683,17 +693,17 @@ entries=[ {
"type": "room",
"window": true
}, {
"children": [ 77 ],
"children": [ 78 ],
"commands": [ ],
"index": 75,
"index": 76,
"name": "zone_0",
"order": 0,
"type": "zone",
"zone_type": 0
}, {
"children": [ 78 ],
"children": [ 79 ],
"commands": [ ],
"index": 76,
"index": 77,
"name": "zone_1",
"order": 0,
"type": "zone",
@@ -701,7 +711,7 @@ entries=[ {
}, {
"children": [ ],
"commands": [ ],
"index": 77,
"index": 78,
"name": "wc_0",
"order": 0,
"room_area": 16.0,
@@ -711,7 +721,7 @@ entries=[ {
}, {
"children": [ ],
"commands": [ ],
"index": 78,
"index": 79,
"name": "living_room_0",
"order": 0,
"room_area": 16.0,

View File

@@ -2,6 +2,8 @@
#include "base_data.h"
#include "world_editor.h"
#include "editor_event.h"
#include "graph_module.h"
#include "growth_module.h"
#include "building_layout_graph.h"
// TODO: allocate zones in completed units and grow them.
@@ -17,7 +19,8 @@ BuildingLayoutGraph::BuildingLayoutGraph()
flecs::log::set_level(255);
get_layout_grid_base();
get_layout_grid_base();
ecs.import <BuildingLayoutGraph::graph_module>();
ecs.import <graph_module>();
ecs.import <growth_module>();
Error err = config.load("res://astream/building_layout.conf");
assert(err == OK);
public_rooms = config.get_value("rooms", "public", Array());

View File

@@ -45,26 +45,4 @@ public:
void create_interior_tilemap(const String &layout_name);
int get_layout_count() const;
int get_children_count(flecs::entity base_e) const;
struct graph_module {
flecs::entity GraphSolve;
flecs::entity get_layout_grid_base();
flecs::entity get_layout_base();
bool have_cell(flecs::entity floor_e, int id);
void grow_cell(flecs::entity seed_e, int id);
void queue_grow_cell(flecs::entity seed_e, int id);
void growth_module(flecs::world &ecs,
const String &module_name);
void room_growth_module(flecs::world &ecs,
const String &module_name);
void zones_graph_module(flecs::world &ecs,
const String &module_name);
void create_floor_components(
flecs::entity floor_e, flecs::entity base_floor_e,
const WorldEditor::components::buildings_layout_grid_size
&size);
bool check_region(flecs::entity floor_e, int index,
const Rect2i &rect) const;
graph_module(flecs::world &ecs);
};
};

View File

@@ -899,15 +899,14 @@ void BuildingLayoutGraphUI::draw_2d_grid_view(Control *draw)
Math::randf(),
Math::randf(),
1.0f);
draw->draw_rect(
Rect2(dx + 0.1f * dsize,
dy + 0.1f * dsize,
0.8f * dsize,
0.8f * dsize),
colors[String(
re.path())],
true);
}
draw->draw_rect(
Rect2(dx + 0.3f * dsize,
dy + 0.3f * dsize,
0.6f * dsize,
0.6f * dsize),
colors[String(re.path())],
true);
mcount++;
});
print_line(
@@ -916,6 +915,8 @@ void BuildingLayoutGraphUI::draw_2d_grid_view(Control *draw)
", " + String::num(dy) + ") " +
String::num(dsize) + " " +
(colors[cell.type].operator String()));
if (mcount)
print_line("draw_cell: is a room");
});
}
pos++;

File diff suppressed because it is too large Load Diff

View File

@@ -1,235 +1,19 @@
#ifndef GRAPH_MODULE_H_
#define GRAPH_MODULE_H_
#include <core/math/vector2.h>
#include "grid_misc.h"
#include "grow_job.h"
struct RegionRect2i {
Point2i position;
Size2i size;
struct graph_module {
flecs::entity GraphSolve;
const Point2i &get_position() const
{
return position;
}
void set_position(const Point2i &p_position)
{
position = p_position;
}
const Size2i &get_size() const
{
return size;
}
void set_size(const Size2i &p_size)
{
size = p_size;
}
int get_area() const
{
return size.width * size.height;
}
_FORCE_INLINE_ Vector2i get_center() const
{
return position + (size / 2);
}
inline bool intersects(const RegionRect2i &p_rect) const
{
if (position.x > (p_rect.position.x + p_rect.size.width - 1)) {
return false;
}
if ((position.x + size.width - 1) < p_rect.position.x) {
return false;
}
if (position.y > (p_rect.position.y + p_rect.size.height - 1)) {
return false;
}
if ((position.y + size.height - 1) < p_rect.position.y) {
return false;
}
return true;
}
inline bool encloses(const RegionRect2i &p_rect) const
{
return (p_rect.position.x >= position.x) &&
(p_rect.position.y >= position.y) &&
((p_rect.position.x + p_rect.size.x) <=
(position.x + size.x)) &&
((p_rect.position.y + p_rect.size.y) <=
(position.y + size.y));
}
_FORCE_INLINE_ bool has_no_area() const
{
return (size.x <= 0 || size.y <= 0);
}
inline RegionRect2i clip(const RegionRect2i &p_rect) const
{ /// return a clipped rect
RegionRect2i new_rect = p_rect;
if (!intersects(new_rect)) {
return RegionRect2i();
}
new_rect.position.x = MAX(p_rect.position.x, position.x);
new_rect.position.y = MAX(p_rect.position.y, position.y);
Point2 p_rect_end = p_rect.position + p_rect.size;
Point2 end = position + size;
new_rect.size.x =
(int)(MIN(p_rect_end.x, end.x) - new_rect.position.x);
new_rect.size.y =
(int)(MIN(p_rect_end.y, end.y) - new_rect.position.y);
return new_rect;
}
inline RegionRect2i merge(const RegionRect2i &p_rect) const
{ ///< return a merged rect
RegionRect2i new_rect;
new_rect.position.x = MIN(p_rect.position.x, position.x);
new_rect.position.y = MIN(p_rect.position.y, position.y);
new_rect.size.x = MAX(p_rect.position.x + p_rect.size.x,
position.x + size.x);
new_rect.size.y = MAX(p_rect.position.y + p_rect.size.y,
position.y + size.y);
new_rect.size =
new_rect.size - new_rect.position; //make relative again
return new_rect;
};
bool has_point(const Point2 &p_point) const
{
if (p_point.x < position.x) {
return false;
}
if (p_point.y < position.y) {
return false;
}
if (p_point.x >= (position.x + size.x)) {
return false;
}
if (p_point.y >= (position.y + size.y)) {
return false;
}
return true;
}
bool operator==(const RegionRect2i &p_rect) const
{
return position == p_rect.position && size == p_rect.size;
}
bool operator!=(const RegionRect2i &p_rect) const
{
return position != p_rect.position || size != p_rect.size;
}
RegionRect2i grow(int p_by) const
{
RegionRect2i g = *this;
g.position.x -= p_by;
g.position.y -= p_by;
g.size.width += p_by * 2;
g.size.height += p_by * 2;
return g;
}
inline RegionRect2i grow_margin(Margin p_margin, int p_amount) const
{
RegionRect2i g = *this;
g = g.grow_individual((MARGIN_LEFT == p_margin) ? p_amount : 0,
(MARGIN_TOP == p_margin) ? p_amount : 0,
(MARGIN_RIGHT == p_margin) ? p_amount : 0,
(MARGIN_BOTTOM == p_margin) ? p_amount :
0);
return g;
}
inline RegionRect2i grow_individual(int p_left, int p_top, int p_right,
int p_bottom) const
{
RegionRect2i g = *this;
g.position.x -= p_left;
g.position.y -= p_top;
g.size.width += p_left + p_right;
g.size.height += p_top + p_bottom;
return g;
}
_FORCE_INLINE_ RegionRect2i expand(const Vector2i &p_vector) const
{
RegionRect2i r = *this;
r.expand_to(p_vector);
return r;
}
inline void expand_to(const Point2i &p_vector)
{
Point2i begin = position;
Point2i end = position + size;
if (p_vector.x < begin.x) {
begin.x = p_vector.x;
}
if (p_vector.y < begin.y) {
begin.y = p_vector.y;
}
if (p_vector.x > end.x) {
end.x = p_vector.x;
}
if (p_vector.y > end.y) {
end.y = p_vector.y;
}
position = begin;
size = end - begin;
}
operator String() const
{
return String(position) + ", " + String(size);
}
operator Rect2() const
{
return Rect2(position, size);
}
RegionRect2i(const Rect2 &p_r2)
: position(p_r2.position)
, size(p_r2.size)
{
}
RegionRect2i(const Rect2i &p_r2)
: position(p_r2.position)
, size(p_r2.size)
{
}
RegionRect2i()
{
}
RegionRect2i(int p_x, int p_y, int p_width, int p_height)
: position(Point2(p_x, p_y))
, size(Size2(p_width, p_height))
{
}
RegionRect2i(const Point2 &p_pos, const Size2 &p_size)
: position(p_pos)
, size(p_size)
{
}
bool have_cell(flecs::entity floor_e, int id);
void queue_grow_cell(flecs::entity seed_e, int id);
void zones_graph_module(flecs::world &ecs, const String &module_name);
void create_floor_components(
flecs::entity floor_e, flecs::entity base_floor_e,
const WorldEditor::components::buildings_layout_grid_size &size);
bool check_region(flecs::entity floor_e, int index,
const Rect2i &rect) const;
graph_module(flecs::world &ecs);
};
#endif

View File

@@ -49,302 +49,3 @@ struct grid_calc {
assert(grid_size > 0);
}
};
void BuildingLayoutGraph::graph_module::growth_module(flecs::world &ecs,
const String &module_name)
{
ecs.component<growth_regions>();
ecs.component<region_tree>();
flecs::entity GraphFilter = ecs.entity("GraphFilter")
.add(flecs::Phase)
.depends_on(flecs::OnUpdate);
GraphFilter.disable();
flecs::entity GraphGridPrepare = ecs.entity("GraphGridPrepare")
.add(flecs::Phase)
.depends_on(GraphSolve);
#if 0
ecs.system<const WorldEditor::components::buildings_layout_grid_size>(
"CreateGrid")
.kind(GraphSolve)
.write<WorldEditor::components::buildings_layout_grid>()
.each([this](flecs::iter &it, size_t count,
const WorldEditor::components::
buildings_layout_grid_size &size) {
struct grid_misc grid;
flecs::entity graph_e = it.entity(count);
graph_e.world().defer_suspend();
flecs::log::warn("creating grid for: %s",
graph_e.path().c_str());
flecs::entity grid_base_e = get_layout_grid_base();
flecs::entity grid_e =
grid_base_e.lookup(graph_e.name());
assert(grid_e.is_valid());
flecs::log::warn("creating grid for: %s: %s",
graph_e.path().c_str(),
grid_e.path().c_str());
/* starting at grid center */
const List<Pair<int, flecs::entity_t> >::Element *me =
size.floors.front();
while (me) {
flecs::query<const WorldEditor::components::
buildings_layout_area>
q = graph_e.world()
.query_builder<
const WorldEditor::components::
buildings_layout_area>()
.with(flecs::ChildOf,
me->get().second)
.scope_open()
.with<WorldEditor::components::
buildings_layout_zone>()
.or_()
.with<WorldEditor::components::
buildings_layout_unit>()
.scope_close()
.build();
q.each([size,
&grid](flecs::entity ce,
const WorldEditor::components::
buildings_layout_area
&area) {
flecs::log::warn(
"generating positions for: %s",
ce.path().c_str());
grid.filter_candidates(ce, area.area,
size);
});
flecs::entity base_floor_e =
grid_e.world().entity(me->get().second);
flecs::entity grid_floor_e =
grid.get_grid_floor(grid_e,
base_floor_e);
create_floor_components(grid_floor_e,
base_floor_e, size);
grid.place_regions(grid_floor_e);
me = me->next();
}
graph_e.world().defer_resume();
});
#endif
ecs.system("AssembleSkeletonEnd")
.kind(GraphSolve)
.run([module_name](flecs::iter &it) {
print_line("Assembling skeleton done...");
it.world()
.lookup((module_name + "::GraphSolveZones")
.ascii()
.ptr())
.disable();
it.world()
.lookup((module_name + "::GraphFilter")
.ascii()
.ptr())
.enable();
EditorEvent::get_singleton()->event.emit(
"update_layout_view", varray());
// assert(false);
});
#if 0
ecs.system<WorldEditor::components::buildings_layout_grid_floor,
growth_regions>("GrowFloorRectRegions")
.kind(0)
.each([this](flecs::entity floor_e,
WorldEditor::components::buildings_layout_grid_floor
&fl,
growth_regions &g) {
struct grid_misc grid;
grid.grow_region_rects(this, floor_e, fl, g);
grid.place_region_cells(this, floor_e, fl, g);
});
#endif
#if 0
ecs.system<WorldEditor::components::buildings_layout_grid_floor>(
"GrowFloorRegions")
.kind(0)
.each([this](flecs::entity floor_e,
WorldEditor::components::buildings_layout_grid_floor
&fl) {
/* TODO: limit growth per region too */
struct grid_calc grid(fl.grid_size);
if (fl.size_left <= 0)
return;
flecs::query<const WorldEditor::components::
buildings_layout_grid_cell>
q = floor_e.world()
.query_builder<
const WorldEditor::components::
buildings_layout_grid_cell>()
.with(flecs::ChildOf, floor_e)
.without<WorldEditor::components::
final_cell>()
.build();
q.each([this, &floor_e, &fl,
&grid](flecs::entity et,
const WorldEditor::components::
buildings_layout_grid_cell &cell) {
int index = cell.index;
assert(et.is_valid());
int i;
LocalVector<int> candidates;
candidates.resize(8);
grid.get_cadidates(cell.index,
candidates.ptr());
int extended = 0;
for (i = 0; i < (int)candidates.size(); i++) {
if (have_cell(floor_e, candidates[i]))
continue;
queue_grow_cell(et, candidates[i]);
extended++;
}
if (extended == 0)
et.add<WorldEditor::components::
final_cell>();
print_line("size: " + itos(grid.grid_size) +
" index: " + itos(index));
});
});
#endif
#if 0
ecs.system<const WorldEditor::components::buildings_layout_grid_cell>(
"GrowRegions")
.kind(0)
.without<WorldEditor::components::final_cell>()
.read<WorldEditor::components::buildings_layout_grid_size>()
.write<WorldEditor::components::buildings_layout_grid_cell>()
.write<WorldEditor::components::buildings_layout_grid_floor>()
.write<WorldEditor::components::buildings_layout_grid_queue>()
.each([this](flecs::entity e,
const WorldEditor::components::
buildings_layout_grid_cell &cell) {
e.world().defer_suspend();
int index = cell.index;
assert(e.is_valid());
flecs::entity floor_e = e.parent();
assert(floor_e.is_valid());
flecs::entity grid_e = floor_e.parent();
assert(grid_e.is_valid());
String layout_name(grid_e.name());
flecs::entity base_e = get_layout_base();
flecs::entity layout_e =
base_e.lookup(layout_name.ascii().ptr());
assert(layout_e.is_valid());
struct grid_calc grid(layout_e);
int i;
LocalVector<int> candidates;
candidates.resize(8);
grid.get_cadidates(cell.index, candidates.ptr());
int extended = 0;
for (i = 0; i < (int)candidates.size(); i++) {
if (have_cell(floor_e, candidates[i]))
continue;
queue_grow_cell(e, candidates[i]);
extended++;
}
if (extended == 0)
e.add<WorldEditor::components::final_cell>();
print_line("size: " + itos(grid.grid_size) +
" index: " + itos(index));
e.world().defer_resume();
});
#endif
ecs.system<WorldEditor::components::buildings_layout_grid_floor,
WorldEditor::components::buildings_layout_grid_queue>(
"GrowCommitQueue")
.kind(0)
.each([this](flecs::entity e,
WorldEditor::components::buildings_layout_grid_floor
&fl,
WorldEditor::components::buildings_layout_grid_queue
&queue) {
List<Pair<flecs::entity_t, int> >::Element *me =
queue.queue.front();
while (me) {
flecs::entity seed_e =
e.world().entity(me->get().first);
int id = me->get().second;
if (!fl.cells.has(id)) {
grow_cell(seed_e, id);
fl.cells.insert(id);
}
me = me->next();
}
queue.queue.clear();
e.remove<WorldEditor::components::
buildings_layout_grid_queue>();
});
ecs.system("RunGrow")
.immediate()
.write<WorldEditor::components::buildings_layout_grid_floor>()
.write<WorldEditor::components::buildings_layout_grid_size>()
.write<growth_regions>()
.kind(GraphFilter)
.run([module_name, this](flecs::iter &it) {
flecs::world &&ecs = it.world();
it.world().defer_suspend();
struct queries queries(ecs);
flecs::log::dbg("Creating regions grow...");
queries.get_qp().each(
[this, &queries,
module_name](flecs::iter &it2, size_t count,
const WorldEditor::components::
buildings_layout_grid_size
&size) {
struct grid_misc grid;
// grid.subregions_init(it2.world());
flecs::entity graph_e =
it2.entity(count);
flecs::log::warn(
"creating grid for: %s",
graph_e.path().c_str());
flecs::entity grid_base_e =
get_layout_grid_base();
flecs::entity grid_e =
grid_base_e.lookup(
graph_e.name());
assert(grid_e.is_valid());
flecs::log::warn(
"creating grid for: %s: %s",
graph_e.path().c_str(),
grid_e.path().c_str());
/* starting at grid center */
queries.build_subregions(grid_e, grid,
size);
struct grow_job_queue job_queue(
grid_e, queries, size,
module_name);
job_queue.iterate();
// assert(false);
});
#if 0
assert(false);
flecs::log::dbg("Running grow...");
qr.each([this](flecs::entity grid_floor_e,
WorldEditor::components::
buildings_layout_grid_floor &fl,
growth_regions &g) {
struct grid_misc grd;
if (g.complete)
return;
grd.grow_region_rects(this, grid_floor_e, fl,
g);
grd.place_region_cells(this, grid_floor_e, fl,
g);
});
#endif
it.world()
.system(it.world().lookup(
(module_name + "::GrowCommitQueue")
.ascii()
.ptr()))
.run();
it.world()
.lookup((module_name + "::GraphFilter")
.ascii()
.ptr())
.disable();
it.world().defer_resume();
});
}

View File

@@ -1,456 +0,0 @@
#include "base_data.h"
#include "world_editor.h"
#include "building_layout_graph.h"
#include "grid_misc.h"
#include "graph_module.h"
void BuildingLayoutGraph::graph_module::room_growth_module(
flecs::world &ecs, const String &module_name)
{
flecs::entity GraphFilter =
ecs.lookup((module_name + "::GraphFilter").ascii().ptr());
assert(GraphFilter.is_valid());
flecs::entity GraphGrowUnitAreas = ecs.entity("GraphGrowUnitAreas")
.add(flecs::Phase)
.depends_on(flecs::OnUpdate);
GraphGrowUnitAreas.disable();
flecs::entity GraphMarkData = ecs.entity("GraphMarkData")
.add(flecs::Phase)
.depends_on(flecs::OnUpdate);
GraphMarkData.disable();
flecs::entity GraphProcessRooms = ecs.entity("GraphProcessRooms")
.add(flecs::Phase)
.depends_on(flecs::OnUpdate);
GraphProcessRooms.disable();
ecs.system<const WorldEditor::components::buildings_layout_unit>(
"AllocateUnitGrow")
.kind(GraphGrowUnitAreas)
.each([](flecs::entity ec,
const WorldEditor::components::buildings_layout_unit
&unit) {
ec.world()
.query_builder<const WorldEditor::components::
buildings_layout_zone>()
.build()
.each([](flecs::entity e,
const WorldEditor::components::
buildings_layout_zone &zone) {
// assert(false);
});
});
ecs.system("CheckGrow").kind(GraphFilter).run([module_name](flecs::iter &it) {
int failed_zones = 0, total_zones = 0;
it.world()
.query_builder<const WorldEditor::components::
buildings_layout_zone>()
.build()
.each([&failed_zones, &total_zones](
flecs::entity ec,
const WorldEditor::components::
buildings_layout_zone &zone) {
int count = 0;
ec.world()
.query_builder<
const WorldEditor::components::
buildings_layout_grid_cell>()
.with<WorldEditor::components::belongs>(
ec)
.build()
.each([&count](
flecs::entity e,
const WorldEditor::components::
buildings_layout_grid_cell
&cell) {
count++;
});
if (count == 0)
failed_zones++;
total_zones++;
});
if (failed_zones > 0)
flecs::log::err("failed to allocate zones: %d/%d",
failed_zones, total_zones);
flecs::query<const WorldEditor::components::
buildings_layout_grid_floor>
q = it.world()
.query_builder<
const WorldEditor::components::
buildings_layout_grid_floor>()
.build();
int count_left = 0;
int count_run = 0;
q.each([&count_left,
&count_run](flecs::entity e,
const WorldEditor::components::
buildings_layout_grid_floor &fl) {
count_run++;
count_left += MAX(0, fl.size_left);
});
// assert(false);
if (count_run > 0 && count_left <= 0 && failed_zones == 0) {
it.world()
.lookup((module_name + "::GraphFilter")
.ascii()
.ptr())
.disable();
print_line("Grow done");
it.world()
.lookup((module_name + "::GraphMarkData")
.ascii()
.ptr())
.enable();
print_line("Mark started...");
} else if (count_run > 0 && count_left <= 0 &&
failed_zones > 0) {
it.world()
.lookup((module_name + "::GraphFilter")
.ascii()
.ptr())
.disable();
print_line("Grow done");
it.world()
.lookup((module_name + "::GraphGrowUnitAreas")
.ascii()
.ptr())
.enable();
print_line("Grow unit started...");
}
});
ecs.system<const WorldEditor::components::buildings_layout_grid_cell>(
"MarkExternalWall")
.kind(GraphMarkData)
.without<WorldEditor::components::outside_wall>()
.read<WorldEditor::components::buildings_layout_grid_floor>()
.write<WorldEditor::components::outside_wall>()
.write<WorldEditor::components::final_cell>()
.each([](flecs::entity e,
const WorldEditor::components::buildings_layout_grid_cell
&cell) {
int grid_size =
e.parent()
.get<WorldEditor::components::
buildings_layout_grid_floor>()
->grid_size;
int i;
Vector2i position(cell.index % grid_size,
cell.index / grid_size);
Vector2 west(position.x - 1, position.y);
Vector2 north(position.x, position.y - 1);
Vector2 east(position.x + 1, position.y);
Vector2 south(position.x, position.y + 1);
int west_id = west.x + grid_size * west.y;
int north_id = north.x + grid_size * north.y;
int east_id = east.x + grid_size * east.y;
int south_id = south.x + grid_size * south.y;
std::vector<int> neighbors = { west_id, north_id,
east_id, south_id };
bool outside = false;
bool border = false;
for (i = 0; i < (int)neighbors.size(); i++) {
int id = neighbors[i];
print_line("id=" + itos(id));
if (!e.parent()
.get<WorldEditor::components::
buildings_layout_grid_floor>()
->cells.has(id)) {
outside = true;
break;
}
}
for (i = 0; i < (int)neighbors.size(); i++) {
int id = neighbors[i];
print_line("id=" + itos(id));
String neighbor_name = "cell_" + itos(id);
flecs::entity neighbor_e = e.parent().lookup(
neighbor_name.ascii().ptr());
if (!neighbor_e.is_valid())
continue;
const WorldEditor::components::buildings_layout_grid_cell
*neighbor_cell = neighbor_e.get<
WorldEditor::components::
buildings_layout_grid_cell>();
if (cell.type != neighbor_cell->type) {
border = true;
break;
}
}
if (outside)
e.add<WorldEditor::components::outside_wall>();
else
e.add<WorldEditor::components::final_cell>();
if (border)
e.add<WorldEditor::components::border>();
print_line("outside: " + itos(outside));
print_line("position: " + (position.operator String()));
print_line("grid size: " + itos(grid_size));
print_line("tile index: " + itos(cell.index));
});
ecs.system("CheckMark")
.kind(GraphMarkData)
.run([module_name](flecs::iter &it) {
int tile_count = 0, inside_count = 0, wall_count = 0;
it.world()
.query_builder<
const WorldEditor::components::
buildings_layout_grid_cell>()
.build()
.each([&tile_count, &inside_count, &wall_count](
flecs::entity e,
const WorldEditor::components::
buildings_layout_grid_cell
&cell) {
tile_count++;
if (e.has<WorldEditor::components::
outside_wall>())
wall_count++;
if (e.has<WorldEditor::components::
final_cell>())
inside_count++;
});
if (tile_count > 0 && wall_count > 0 &&
inside_count > 0 &&
tile_count == wall_count + inside_count) {
it.world()
.lookup((module_name +
"::GraphMarkData")
.ascii()
.ptr())
.disable();
it.world()
.lookup((module_name +
"::GraphProcessRooms")
.ascii()
.ptr())
.enable();
}
});
struct prio_queue {
HashMap<int, flecs::entity> entities;
Set<int> tile_selection[4];
Vector<int> tile_selection_array[4];
struct make_random r;
bool dirty;
prio_queue()
: r(make_random(100))
, dirty(true)
{
}
void add_tile(int prio, int id, flecs::entity ec)
{
if (!tile_selection[prio].has(id))
tile_selection[prio].insert(id);
if (!entities.has(id))
entities[id] = ec;
dirty = true;
}
void update()
{
int i, j;
for (i = 0; i < 4; i++) {
tile_selection_array[i].resize(
tile_selection[i].size());
j = 0;
Set<int>::Element *m =
tile_selection[i].front();
while (m) {
tile_selection_array[i].write[j++] =
m->get();
m = m->next();
}
}
}
void dump()
{
if (dirty) {
update();
dirty = false;
}
print_line("0: " +
itos(tile_selection_array[0].size()));
print_line("1: " +
itos(tile_selection_array[1].size()));
print_line("2: " +
itos(tile_selection_array[2].size()));
}
int get_random_tile(int prio)
{
assert(tile_selection[prio].size() > 0);
int sel = r.get() % tile_selection[prio].size();
int id = tile_selection_array[prio][sel];
assert(entities.has(id));
tile_selection_array[prio].erase(id);
tile_selection[prio].erase(id);
return id;
}
void delete_neighbors(int id)
{
int i, j;
flecs::entity selected_e = entities[id];
int grid_size =
selected_e.parent()
.get<WorldEditor::components::
buildings_layout_grid_floor>()
->grid_size;
Vector2i base(id % grid_size, id / grid_size);
for (i = -1; i < 2; i++)
for (j = -1; j < 2; j++) {
if (i == 0 && j == 0)
continue;
Vector2i neighbor =
base + Vector2i(i, j);
int neighbor_id =
neighbor.x +
grid_size * neighbor.y;
tile_selection_array[0].erase(
neighbor_id);
tile_selection[0].erase(neighbor_id);
if (!tile_selection[3].has(
neighbor_id)) {
tile_selection_array[3]
.push_back(neighbor_id);
tile_selection[3].insert(
neighbor_id);
}
}
}
int take_tile()
{
if (dirty) {
update();
dirty = false;
}
if (tile_selection[0].size() > 0) {
int id = get_random_tile(0);
delete_neighbors(id);
return id;
} else {
int prio;
flecs::log::warn(
"out of normal tiles, using outside wall and zone borders");
for (prio = 1; prio < 4; prio++) {
if (tile_selection[prio].size() > 0) {
int id = get_random_tile(prio);
return id;
}
}
}
flecs::log::err("failed to allocate room initial tile");
return -1;
}
flecs::entity get_entity(int id)
{
assert(entities.has(id));
return entities[id];
}
int get_total_size()
{
int ret = 0, i;
for (i = 0; i < 4; i++)
ret += tile_selection[i].size();
return ret;
}
};
ecs.system<const WorldEditor::components::buildings_layout_zone,
const WorldEditor::components::buildings_layout_floor_index>(
"ProcessFloor0Rooms")
.kind(GraphProcessRooms)
.read<WorldEditor::components::belongs>()
.read<WorldEditor::components::outside_wall>()
.read<WorldEditor::components::border>()
.each([](flecs::entity e,
const WorldEditor::components::buildings_layout_zone
&zone,
const WorldEditor::components::
buildings_layout_floor_index &idx) {
if (idx.index != 0)
return;
// make_random r(1001);
struct prio_queue prio;
e.world()
.query_builder<
const WorldEditor::components::
buildings_layout_grid_cell>()
.with<WorldEditor::components::belongs>(e)
.without<WorldEditor::components::outside_wall>()
.without<WorldEditor::components::border>()
.build()
.each([&prio](flecs::entity ec,
const WorldEditor::components::
buildings_layout_grid_cell
&cell) {
prio.add_tile(0, cell.index, ec);
});
e.world()
.query_builder<
const WorldEditor::components::
buildings_layout_grid_cell>()
.with<WorldEditor::components::belongs>(e)
.without<WorldEditor::components::outside_wall>()
.with<WorldEditor::components::border>()
.build()
.each([&prio](flecs::entity ec,
const WorldEditor::components::
buildings_layout_grid_cell
&cell) {
prio.add_tile(1, cell.index, ec);
});
e.world()
.query_builder<
const WorldEditor::components::
buildings_layout_grid_cell>()
.with<WorldEditor::components::belongs>(e)
.with<WorldEditor::components::outside_wall>()
.build()
.each([&prio](flecs::entity ec,
const WorldEditor::components::
buildings_layout_grid_cell
&cell) {
prio.add_tile(2, cell.index, ec);
});
prio.update();
prio.dump();
if (prio.get_total_size() == 0) {
flecs::log::err(
"no tiles allocated for zone: %s",
e.path().c_str());
return;
}
int count = 0, assigned_count = 0;
e.world()
.query_builder<const WorldEditor::components::
buildings_layout_room>()
.with(flecs::ChildOf, e)
.build()
.each([&prio, &count, &assigned_count](
flecs::entity ec,
const WorldEditor::components::
buildings_layout_room
&room) {
int id = prio.take_tile();
if (id >= 0) {
flecs::entity selected_e =
prio.get_entity(id);
int mcount = 0;
selected_e.each<
WorldEditor::components::
belongs_room>(
[&mcount](flecs::entity
e) {
mcount++;
});
assert(mcount == 0);
selected_e.add<
WorldEditor::components::
belongs_room>(
ec);
assigned_count++;
}
count++;
});
if (assigned_count < count)
flecs::log::err(
"not all rooms were assigned: %d < %d",
assigned_count, count);
});
}

View File

@@ -0,0 +1,713 @@
#include <vector>
#include <core/math/vector2.h>
#include <core/math/rect2.h>
#include "world_editor.h"
#include "graph_module.h"
#include "growth_regions.h"
#include "grid_misc.h"
void grid_misc::get_dim_candidates(const Vector2i &base, int dim,
Vector2i *candidates)
{
int i;
std::vector<Vector2i> candidates_data = {
/* clang-format off */
{ base.x + dim, base.y },
{ base.x, base.y + dim },
{ base.x - dim, base.y },
{ base.x, base.y - dim },
{ base.x + dim, base.y },
{ base.x, base.y + dim },
{ base.x - dim, base.y },
{ base.x, base.y - dim },
/* clang-format on */
};
for (i = 0; i < (int)candidates_data.size(); i++)
candidates[i] = candidates_data[i];
}
int grid_misc::get_floor_index(flecs::entity e) const
{
return e.get<WorldEditor::components::buildings_layout_floor_index>()
->index;
}
flecs::entity grid_misc::get_grid_floor(flecs::entity grid_e,
flecs::entity graph_floor_e) const
{
assert(grid_e.is_valid());
assert(graph_floor_e.is_valid());
int floor_index = get_floor_index(graph_floor_e);
String floor_name = "floor_" + itos(floor_index);
// flecs::log::dbg("floor: %s", floor_name.ascii().ptr());
flecs::entity floor_e = grid_e.lookup(floor_name.ascii().ptr());
assert(floor_e.is_valid());
return floor_e;
}
bool grid_misc::check_duplicates() const
{
int i, j;
bool result = true;
for (i = 0; i < (int)positions.size(); i++)
for (j = 0; j < (int)positions.size(); j++) {
if (i == j)
continue;
if (positions[i].second == positions[j].second) {
flecs::log::err("duplicate positions");
result = false;
goto out;
}
}
out:
return result;
}
#if 0
void grid_misc::place_regions(flecs::entity grid_floor_e)
{
int i;
int grid_size = grid_floor_e
.get<WorldEditor::components::
buildings_layout_grid_floor>()
->grid_size;
// flecs::log::dbg("###=== %s", grid_floor_e.path().c_str());
flecs::entity grid_e = grid_floor_e.parent();
assert(grid_e.is_valid());
growth_regions::region parent_reg;
parent_reg.can_grow = false;
parent_reg.complete = true;
parent_reg.rect.position = Vector2i();
parent_reg.rect.size = Vector2i(grid_size, grid_size);
parent_reg.can_grow_square = false;
growth_regions *g = grid_floor_e.get_mut<growth_regions>();
int parent_index = g->parent_regions.size();
g->parent_regions.push_back(parent_reg);
for (i = 0; i < (int)positions.size(); i++) {
int cell_id = positions[i].second.x +
grid_size * positions[i].second.y;
flecs::entity region_e =
grid_e.world().entity(positions[i].first);
assert(region_e.is_valid());
Rect2i check;
check.position = positions[i].second;
check.size = Vector2i(1, 1);
// flecs::log::dbg("%s ->region: %s cell_id %d",
// grid_floor_e.path().c_str(),
// region_e.path().c_str(), cell_id);
assert(g->check_region(-1, check));
flecs::entity cell_e =
g->create_cell(grid_floor_e, region_e, cell_id);
assert(cell_e.is_valid());
flecs::log::warn("grid cell: %s", cell_e.path().c_str());
float area = get_entity_area(region_e);
// flecs::log::dbg("region: %s: parent: %s",
// region_e.path().c_str(),
// region_e.parent().path().c_str());
g->create_region(grid_floor_e, cell_e, region_e.parent(),
region_e, positions[i].second, area,
parent_index);
flecs::log::warn("grid cell: %s", cell_e.path().c_str());
}
// flecs::log::dbg("###=== %s done", grid_floor_e.path().c_str());
}
#endif
#if 0
void grid_misc::place_regions_common(flecs::entity parent_e,
flecs::entity grid_floor_e,
int parent_index)
{
int i;
int grid_size = grid_floor_e
.get<WorldEditor::components::
buildings_layout_grid_floor>()
->grid_size;
// flecs::log::dbg("###=== %s", grid_floor_e.path().c_str());
flecs::entity grid_e = grid_floor_e.parent();
assert(grid_e.is_valid());
growth_regions *g = grid_floor_e.get_mut<growth_regions>();
for (i = 0; i < (int)positions.size(); i++) {
assert(g->parent_regions[parent_index].rect.has_point(
positions[i].second));
int cell_id = positions[i].second.x +
grid_size * positions[i].second.y;
flecs::entity region_e =
grid_e.world().entity(positions[i].first);
assert(region_e.is_valid());
RegionRect2i check;
check.position = positions[i].second;
check.size = Vector2i(1, 1);
// flecs::log::dbg("%s ->region: %s cell_id %d",
// grid_floor_e.path().c_str(),
// region_e.path().c_str(), cell_id);
assert(g->check_region(-1, check));
flecs::entity cell_e = g->update_cell(grid_floor_e, parent_e,
region_e, cell_id);
if (cell_e.is_valid()) {
float area = get_entity_area(region_e);
// flecs::log::dbg(
// "region: %s: parent: %s",
// region_e.path().c_str(),
// region_e.parent().path().c_str());
g->create_region(grid_floor_e, cell_e, parent_e,
region_e, positions[i].second, area,
parent_index);
// flecs::log::warn("grid cell: %s",
// cell_e.path().c_str());
} else {
flecs::log::err("unable to create region");
assert(false);
}
}
// flecs::log::dbg("###=== %s done", grid_floor_e.path().c_str());
}
#endif
bool grid_misc::process_candidates(flecs::entity ce, const Vector2i &base,
float area, flecs::entity_t base_et, int dim,
const RegionRect2i &clip, bool tight)
{
int j;
assert(dim > 1);
int base_radius = get_base_radius(ce.world(), base_et);
base_radius = MAX(1, base_radius);
int local_radius = (int)((Math::sqrt(area) * 1.6f) / 2.0f) /
4; /* grid conversion */
local_radius = MAX(1, local_radius);
// int dim = base_radius + local_radius;
// dim = MAX(4, dim);
Vector2i candidates[8];
assert(clip.has_point(base));
get_dim_candidates(base, dim, &candidates[0]);
for (j = 0; j < (int)(sizeof(candidates) / sizeof(candidates[0]));
j++) {
print_line("base: " + itos(base.x) + ", " + itos(base.y));
print_line("possible candidate: " + itos(candidates[j].x) +
", " + itos(candidates[j].y));
if (!clip.has_point(candidates[j])) {
print_line("clipped by grid field");
print_line(clip.operator String());
continue;
}
if (!clip.has_point(candidates[j])) {
flecs::log::dbg("clipped by clip rect");
continue;
}
if (!check_candidates_tolerance(candidates[j])) {
print_line("too close to existing positions");
continue;
}
if (!check_candidate(candidates[j])) {
// print_line(
// "too close to existing positions (rect)");
continue;
}
// print_line("valid candidate: " + itos(candidates[j].x) +
// ", " + itos(candidates[j].y));
// flecs::log::dbg(
// "accepting candidate: %s",
// (candidates[j].operator String()).ascii().ptr());
if (!tight)
accept_candidate(ce, candidates[j], area);
else
accept_candidate2(ce, candidates[j]);
}
if (accepted.size() == 0) {
Vector2i current = base;
Set<Vector2i> generated;
int candidate_count = 0;
int max_count = 1000;
for (j = 0; j < positions.size(); j++) {
assert(clip.has_point(positions[j].second));
generated.insert(positions[j].second);
}
for (j = 0;
j < (int)(sizeof(candidates) / sizeof(candidates[0]));
j++) {
do {
candidates[j] = clip.position +
Vector2i(r.get() % clip.size.x,
r.get() % clip.size.y);
max_count--;
if (max_count < 0)
break;
} while (generated.has(candidates[j]) ||
!clip.has_point(candidates[j]));
if (max_count >= 0) {
assert(!generated.has(candidates[j]));
generated.insert(candidates[j]);
flecs::log::dbg(
"candidate: %d: %s -> %s", j,
(clip.operator String()).ascii().ptr(),
(candidates[j].operator String())
.ascii()
.ptr());
candidate_count++;
}
}
for (j = 0; j < candidate_count; j++) {
print_line("!!base: " + itos(base.x) + ", " +
itos(base.y));
print_line("!!possible candidate: " +
itos(candidates[j].x) + ", " +
itos(candidates[j].y));
if (!clip.has_point(candidates[j])) {
print_line("!!clipped by grid field");
print_line(clip.operator String());
continue;
}
if (!clip.has_point(candidates[j])) {
flecs::log::dbg("!!clipped by clip rect");
continue;
}
/*
if (!check_candidate(candidates[j])) {
print_line(
"!!too close to existing positions (rect)");
continue;
}
*/
// print_line("valid candidate: " + itos(candidates[j].x) +
// ", " + itos(candidates[j].y));
// flecs::log::dbg(
// "accepting candidate: %s",
// (candidates[j].operator String()).ascii().ptr());
if (!tight)
accept_candidate(ce, candidates[j], area);
else
accept_candidate2(ce, candidates[j]);
assert(clip.has_point(candidates[j]));
}
if (accepted.size() == 0)
flecs::log::err("all candidates were rejected");
}
if (accepted.size() > 0)
return true;
else
return false;
}
void grid_misc::filter_candidates(flecs::entity ce, float area,
const RegionRect2i &clip_rect)
{
if (positions.empty()) {
/* starting at grid center */
Vector2i start_pos(clip_rect.position.x + clip_rect.size.x / 2,
clip_rect.position.y + clip_rect.size.y / 2);
positions.push_back(
Pair<flecs::entity_t, Vector2i>(ce.id(), start_pos));
return;
}
while (1) {
int which = which_position();
const Vector2i &base = positions[which].second;
flecs::entity_t base_et = positions[which].first;
int base_radius = get_base_radius(ce.world(), base_et);
base_radius = MAX(1, base_radius);
int local_radius = (int)((Math::sqrt(area) * 1.6f) / 2.0f) /
4; /* grid conversion */
local_radius = MAX(1, local_radius);
/* minimum distance between region positions */
int dim = base_radius + local_radius;
dim = MAX(2, dim);
int md = 1;
int clip_size = MIN(clip_rect.size.x, clip_rect.size.y);
assert(dim > 1);
if (clip_size > 30)
md = 8;
else if (clip_size > 20)
md = 6;
else if (clip_size > 15)
md = 4;
else if (clip_size > 10)
md = 2;
if (clip_size < 6)
md = 0;
Rect2i clip(clip_rect.position.x + md,
clip_rect.position.y + md,
clip_rect.size.x - md * 2,
clip_rect.size.y - md * 2);
#if 0
Rect2i dim_rect_min(base.x - dim, base.y - dim, dim,
dim),
dim_rect_max(base.x, base.y, dim, dim);
dim_rect_min = clip.clip(dim_rect_min);
dim_rect_max = clip.clip(dim_rect_max);
int dim_min =
MAX(dim_rect_min.size.x, dim_rect_min.size.y);
int dim_max =
MAX(dim_rect_max.size.x, dim_rect_max.size.y);
int avg_dim = (dim_min + dim_max) / 2;
dim = MIN(dim, avg_dim - 1);
#endif
// flecs::log::dbg("dim=%d", dim);
assert(dim > 1);
assert(clip.has_point(base));
// flecs::log::warn(
// "filter_candidates: %d %d / %s / %s",
// clip_size, dim,
// (base.operator String()).ascii().ptr(),
// (clip.operator String()).ascii().ptr());
// flecs::log::warn("clip: %s base: %s dim: %d",
// (clip.operator String()).ascii().ptr(),
// (base.operator String()).ascii().ptr(),
// dim);
if (!(clip.has_point(base + Vector2i(dim, dim)) ||
clip.has_point(base + Vector2i(dim, 0)) ||
clip.has_point(base + Vector2i(0, dim)) ||
clip.has_point(base + Vector2i(-dim, -dim)) ||
clip.has_point(base + Vector2i(-dim, 0)) ||
clip.has_point(base + Vector2i(0, -dim))))
dim = MIN(2, dim);
assert(clip.has_point(base));
assert(clip.has_point(base + Vector2i(dim, dim)) ||
clip.has_point(base + Vector2i(dim, 0)) ||
clip.has_point(base + Vector2i(0, dim)) ||
clip.has_point(base + Vector2i(-dim, -dim)) ||
clip.has_point(base + Vector2i(-dim, 0)) ||
clip.has_point(base + Vector2i(0, -dim)));
if (dim < 4)
process_candidates(ce, base, area, base_et, dim, clip,
true);
else
process_candidates(ce, base, area, base_et, dim, clip,
false);
if (accepted.size() > 0) {
assert(accepted.size() > 0);
const Vector2i &selected = accepted[which_selected()];
assert(check_candidates_tolerance(selected));
Pair<flecs::entity_t, Vector2i> m(ce.id(), selected);
check_candidate(selected);
assert(clip_rect.encloses(
Rect2i(m.second, Vector2i(1, 1))));
positions.push_back(m);
flecs::log::warn("add position: %d, %d", selected.x,
selected.y);
accepted.clear();
break;
} else {
assert(positions.size() > 0);
continue;
}
}
}
#if 0
void grid_misc::place_region_cells(
flecs::entity grid_floor_e,
const WorldEditor::components::buildings_layout_grid_floor &fl,
growth_regions &g)
{
int i;
for (i = 0; i < g.regions.size(); i++) {
int x, y;
RegionRect2i rect = g.regions[i].rect;
for (x = rect.position.x; x <= rect.position.x + rect.size.x;
x++)
for (y = rect.position.y;
y <= rect.position.y + rect.size.y; y++) {
int id = x + fl.grid_size * y;
if (!fl.cells.has(id)) {
flecs::entity seed_e =
grid_floor_e.world().entity(
g.regions[i].seed_et);
assert(seed_e.is_valid());
assert(seed_e.parent().is_valid());
assert(seed_e.parent().id() ==
grid_floor_e.id());
queue_grow_cell(seed_e, id);
}
}
}
}
#endif
void grid_misc::queue_grow_cell(flecs::entity seed_e, int id)
{
assert(seed_e.is_valid());
flecs::entity floor_e = seed_e.parent();
if (!floor_e.is_valid())
flecs::log::err("the parent of %s is not grid floor",
seed_e.path().c_str());
assert(floor_e.is_valid());
if (!floor_e.has<WorldEditor::components::buildings_layout_grid_floor>())
flecs::log::err("the parent of %s is not grid floor %s",
seed_e.path().c_str(), floor_e.path().c_str());
assert(floor_e.has<
WorldEditor::components::buildings_layout_grid_floor>());
Pair<flecs::entity_t, int> m(seed_e.id(), id);
if (!floor_e.has<
WorldEditor::components::buildings_layout_grid_queue>()) {
List<Pair<flecs::entity_t, int> > queue;
queue.push_back(m);
floor_e.set<WorldEditor::components::buildings_layout_grid_queue>(
{ queue });
} else {
floor_e.get_mut<WorldEditor::components::
buildings_layout_grid_queue>()
->queue.push_back(m);
floor_e.modified<
WorldEditor::components::buildings_layout_grid_queue>();
}
}
#if 0
void grid_misc::print_can_grow(int state, growth_regions &g, int index,
const char *what)
{
const growth_regions::region &region = g.regions[index];
bool can = false;
if (!strcmp(what, "square"))
can = region.can_grow_square;
else if (!strcmp(what, "rect"))
can = region.can_grow;
if (can)
flecs::log::dbg(
"state: %d: index %d: region can still grow %s %d",
state, index, what, region.remains_area);
else
flecs::log::dbg("state: %d: index %d: region can't grow %s %d",
state, index, what, region.remains_area);
if (region.can_grow_region())
flecs::log::dbg("state %d: index %d: region can still continue",
state, index);
}
bool grid_misc::grow_state0(growth_regions &g, int index,
const RegionRect2i &clip)
{
bool ok = true, ret = false;
RegionRect2i mrect;
growth_regions::region &region = g.regions.write[index];
mrect = region.rect;
assert(g.check_region(index, mrect));
mrect = mrect.grow(1);
ok = clip.encloses(mrect);
// if (!ok)
// flecs::log::dbg("state: %d: index %d: out of clip area",
// 0, index);
if (ok) {
ok = g.check_region(index, mrect);
// if (!ok)
// flecs::log::dbg(
// "state: %d: index %d: check_region failed",
// 0, index);
}
if (ok) {
ret = region.update_region_size(mrect);
// if (!ret)
// flecs::log::dbg(
// "state: %d: index %d: update_region_size failed",
// 0, index);
}
print_can_grow(0, g, index, "square");
// if (!ret)
// flecs::log::dbg("state %d could not grow region %d: %d",
// 0, index, region.remains_area);
// else
// flecs::log::dbg("state %d could grow region %d: %d", 0,
// index, region.remains_area);
return ret;
}
#if 0
bool grid_misc::grow_state1(growth_regions &g, int index,
const RegionRect2i &clip)
{
int d;
bool ret = false;
RegionRect2i mrect;
growth_regions::region &region = g.regions.write[index];
int count = 0;
for (d = 0; d < 4; d++) {
bool ok;
mrect = region.rect;
assert(g.check_region(index, mrect));
switch (d) {
case 0:
mrect.position.y -= 1;
mrect.size.y += 1;
break;
case 1:
mrect.size.y += 1;
break;
case 2:
mrect.position.x -= 1;
mrect.size.x += 1;
break;
case 3:
mrect.size.x += 1;
break;
}
ok = g.parent_regions[region.parent_region].rect.encloses(
mrect);
if (ok)
ok = clip.encloses(mrect);
if (ok) {
ok = false;
if (mrect.size.y > 0 && mrect.size.x > 0) {
float aspect = (float)mrect.size.x /
(float)mrect.size.y;
ok = (aspect > 0.2f && aspect < 5.0f);
}
}
if (ok)
ok = g.check_region(index, mrect);
if (ok) {
bool result = region.update_region_size(mrect);
if (result)
count++;
}
}
if (count > 0) {
ret = true;
// flecs::log::dbg(
// "state %d could grow region %d: %d - %d out of %d times",
// 0, index, region.remains_area, count, 4);
}
print_can_grow(1, g, index, "rect");
// if (!ret)
// flecs::log::dbg(
// "state %d could not grow region rect %d: %d", 0,
// index, region.remains_area);
return ret;
}
#endif
#endif
#if 0
void grid_misc::grow_region_rects(
flecs::entity floor_e,
WorldEditor::components::buildings_layout_grid_floor &fl,
growth_regions &g)
{
int i;
bool grown = true;
int state = 0;
if (g.complete)
return;
Rect2i clip(0, 0, fl.grid_size, fl.grid_size);
state = 0;
// flecs::log::dbg("growing square");
while (grown) {
grown = false;
int count = 0;
for (i = 0; i < g.regions.size(); i++) {
growth_regions::region &region = g.regions.write[i];
RegionRect2i mrect = region.rect;
// flecs::log::dbg("grow_region_rects: region %d",
// i);
if (!region.can_grow_region()) {
// flecs::log::dbg(
// "grow_region_rects: skip %d",
// i);
continue;
}
mrect = region.rect;
bool result = false;
result = grow_state0(g, i, clip);
if (result)
count++;
}
if (count > 0) {
grown = true;
// flecs::log::dbg("grown squares %d times of %d",
// count, g.regions.size());
}
// if (!grown)
// flecs::log::dbg(
// "grow_region_rects: could not grow more squares");
}
state = 1;
grown = true;
// flecs::log::dbg("growing rect");
while (grown) {
grown = false;
int count = 0;
for (i = 0; i < g.regions.size(); i++) {
growth_regions::region &region = g.regions.write[i];
RegionRect2i mrect = region.rect;
// flecs::log::dbg("grow_region_rects: region %d",
// i);
if (!region.can_grow_region()) {
// flecs::log::dbg(
// "grow_region_rects: skip %d",
// i);
continue;
}
mrect = region.rect;
bool result = false;
result = grow_state1(g, i, clip);
if (result)
count++;
// if (!result)
// flecs::log::dbg(
// "state %d could not grow region %d",
// state, i);
// else
// flecs::log::dbg(
// "state %d could grow region %d: %d",
// state, i, region.remains_area);
}
if (count > 0) {
grown = true;
// flecs::log::dbg("grown rects %d times of %d",
// count, g.regions.size());
}
// if (!grown)
// flecs::log::dbg(
// "grow_region_rects: could not grow any more rects");
}
flecs::log::dbg("grow_region_rects: complete");
g.complete = true;
flecs::log::dbg("grow_region_rects: %s: done", floor_e.path().c_str());
}
void grid_misc::subregions_init(flecs::world w)
{
flecs::query<const WorldEditor::components::buildings_layout_area> qprep =
w.query_builder<
const WorldEditor::components::buildings_layout_area>()
.scope_open()
.with<WorldEditor::components::buildings_layout_zone>()
.or_()
.with<WorldEditor::components::buildings_layout_unit>()
.scope_close()
.build();
qprep.each([this](flecs::entity ce,
const WorldEditor::components::buildings_layout_area
&area) {
all_items.push_back({ ce, ce.parent().id() });
});
}
void grid_misc::get_subregions(flecs::entity parent,
List<Pair<flecs::entity, float> > *subregions)
{
flecs::query<const WorldEditor::components::buildings_layout_area> qprep =
parent.world()
.query_builder<const WorldEditor::components::
buildings_layout_area>()
.with(flecs::ChildOf, parent)
.scope_open()
.with<WorldEditor::components::buildings_layout_zone>()
.or_()
.with<WorldEditor::components::buildings_layout_unit>()
.or_()
.with<WorldEditor::components::buildings_layout_room>()
.scope_close()
.build();
qprep.each([&subregions](
flecs::entity ce,
const WorldEditor::components::buildings_layout_area
&area) {
subregions->push_back({ ce, area.area });
});
}
#endif

View File

@@ -0,0 +1,196 @@
#ifndef GRID_MISC_H
#define GRID_MISC_H
#include <core/vector.h>
#include <core/pair.h>
#include "world_editor.h"
struct RegionRect2i;
struct growth_regions;
struct make_random {
int seed;
int next;
make_random(int seed)
: seed(seed)
, next(seed)
{
}
int get()
{
next = next * 1103515245 + 12345;
return (int)((unsigned)next >> 16) % 32768;
}
};
struct grid_misc {
Vector<Pair<flecs::entity_t, Vector2i> > positions;
Vector<Vector2i> accepted;
struct make_random r;
grid_misc()
: r(100)
{
}
void get_dim_candidates(const Vector2i &base, int dim,
Vector2i *candidates);
int get_floor_index(flecs::entity e) const;
flecs::entity get_grid_floor(flecs::entity grid_e,
flecs::entity graph_floor_e) const;
bool check_duplicates() const;
void place_regions(flecs::entity grid_floor_e);
void place_regions_common(flecs::entity parent_e,
flecs::entity grid_floor_e, int parent_index);
float get_entity_area(flecs::entity e) const
{
return e.get<WorldEditor::components::buildings_layout_area>()
->area;
}
float get_entity_area(flecs::world &&ecs, flecs::entity_t et) const
{
flecs::entity e = ecs.entity(et);
return e.get<WorldEditor::components::buildings_layout_area>()
->area;
}
float get_entity_area(flecs::world &ecs, flecs::entity_t et) const
{
flecs::entity e = ecs.entity(et);
return e.get<WorldEditor::components::buildings_layout_area>()
->area;
}
int get_base_radius(flecs::world &&ecs, flecs::entity_t et) const
{
float base_area = get_entity_area(ecs, et);
int base_radius = (int)((Math::sqrt(base_area) * 1.6f) / 2.0f) /
4; /* grid conversion */
return base_radius;
}
int get_base_radius(flecs::world &ecs, flecs::entity_t et) const
{
float base_area = get_entity_area(ecs, et);
int base_radius = (int)((Math::sqrt(base_area) * 1.6f) / 2.0f) /
4; /* grid conversion */
return base_radius;
}
int distance_squared(const Vector2i &p1, const Vector2i &p2) const
{
int lx = p2.x - p1.x;
int ly = p2.y - p1.y;
return lx * lx + ly * ly;
}
bool check_candidates_tolerance(const Vector2i check)
{
int i;
bool ret = true;
for (i = 0; i < (int)positions.size(); i++)
if (distance_squared(check, positions[i].second) < 1) {
ret = false;
break;
}
return ret;
}
bool check_candidate(const Vector2i &candidate)
{
int m;
bool bad = false;
for (m = 0; m < (int)positions.size(); m++)
if (positions[m].second == candidate) {
bad = true;
break;
}
return !bad;
}
bool accept_candidate(flecs::entity ce, const Vector2i &candidate,
float area)
{
int k;
int local_radius = (int)((Math::sqrt(area) * 1.6f) / 2.0f) /
4; /* grid conversion */
local_radius = MAX(1, local_radius);
bool ok = false;
for (k = 0; k < (int)positions.size(); k++) {
assert(k < (int)positions.size());
flecs::entity_t pbase_et = positions[k].first;
float parea = get_entity_area(ce.world(), pbase_et);
int pdim = (int)((Math::sqrt(parea) * 1.5f) / 2.0f) /
4; /* radius converted to grid 4x4*/
int radius = pdim + local_radius;
int radius_sq = radius * radius;
if (distance_squared(positions[k].second, candidate) <
radius_sq) {
// flecs::log::dbg(
// "too close to positions %d < %d",
// distance_squared(positions[k].second,
// candidate),
// radius_sq);
continue;
}
assert(check_candidates_tolerance(candidate));
accepted.push_back(candidate);
ok = true;
}
return ok;
}
bool accept_candidate2(flecs::entity ce, const Vector2i &candidate)
{
int k;
bool ok = false;
for (k = 0; k < (int)positions.size(); k++) {
assert(k < (int)positions.size());
flecs::entity_t pbase_et = positions[k].first;
int radius_sq = 4;
if (distance_squared(positions[k].second, candidate) <
radius_sq) {
// flecs::log::dbg(
// "too close to positions %d < %d",
// distance_squared(positions[k].second,
// candidate),
// radius_sq);
continue;
}
assert(check_candidates_tolerance(candidate));
accepted.push_back(candidate);
ok = true;
}
return ok;
}
bool process_candidates(flecs::entity ce, const Vector2i &base,
float area, flecs::entity_t base_et, int dim,
const RegionRect2i &clip, bool tight);
void filter_candidates(flecs::entity ce, float area,
const RegionRect2i &clip_rect);
int which_position()
{
int which;
if (positions.size() == 0)
return -1;
which = r.get() % positions.size();
assert(which < (int)positions.size());
return which;
}
int which_selected()
{
int which;
if (accepted.size() == 0)
return -1;
which = r.get() % accepted.size();
assert(which < (int)accepted.size());
return which;
}
void place_region_cells(
flecs::entity grid_floor_e,
const WorldEditor::components::buildings_layout_grid_floor &fl,
growth_regions &g);
void queue_grow_cell(flecs::entity seed_e, int id);
void print_can_grow(int state, growth_regions &g, int index,
const char *what);
bool grow_state0(growth_regions &g, int index,
const RegionRect2i &clip);
bool grow_state1(growth_regions &g, int index,
const RegionRect2i &clip);
void grow_region_rects(
flecs::entity floor_e,
WorldEditor::components::buildings_layout_grid_floor &fl,
growth_regions &g);
Vector<Pair<flecs::entity, flecs::entity_t> > all_items;
void subregions_init(flecs::world w);
void get_subregions(flecs::entity parent,
List<Pair<flecs::entity, float> > *subregions);
};
#endif

View File

@@ -0,0 +1,735 @@
#include "base_data.h"
#include "world_editor.h"
#include "grid_misc.h"
#include "graph_module.h"
#include "queries.h"
#include "region_tree.h"
#include "grow_job.h"
static inline int get_floor_index(flecs::entity e)
{
return e.get<WorldEditor::components::buildings_layout_floor_index>()
->index;
}
static inline flecs::entity get_grid_floor(flecs::entity grid_e,
flecs::entity graph_floor_e)
{
assert(grid_e.is_valid());
assert(graph_floor_e.is_valid());
int floor_index = get_floor_index(graph_floor_e);
String floor_name = "floor_" + itos(floor_index);
// flecs::log::dbg("floor: %s", floor_name.ascii().ptr());
flecs::entity floor_e = grid_e.lookup(floor_name.ascii().ptr());
assert(floor_e.is_valid());
return floor_e;
}
grow_job_queue::grow_job_queue(
flecs::entity grid_e, struct subregions &subregions,
const WorldEditor::components::buildings_layout_grid_size &size,
const String &module_name)
: grid_e(grid_e)
, grid_size(size.grid_size)
, subregions(subregions)
, module_name(module_name)
{
const List<Pair<int, flecs::entity_t> >::Element *me;
List<Pair<flecs::entity_t, flecs::entity_t> > job_create_queue;
me = size.floors.front();
while (me) {
// graph entity
job_create_queue.push_back(
{ me->get().second, me->get().second });
flecs::entity_t base_floor_et =
job_create_queue.front()->get().second;
flecs::entity base_floor_e =
grid_e.world().entity(base_floor_et);
flecs::entity grid_floor_e =
get_grid_floor(grid_e, base_floor_e);
grid_floor_e.get_mut<growth_regions>()->job_list =
List<grow_job>();
me = me->next();
}
while (!job_create_queue.empty()) {
// graph entity
flecs::entity_t et = job_create_queue.front()->get().first;
// parent graph entity
flecs::entity_t base_floor_et =
job_create_queue.front()->get().second;
job_create_queue.pop_front();
flecs::entity base_floor_e =
grid_e.world().entity(base_floor_et);
flecs::log::dbg("job_queue: base_floor: %s",
base_floor_e.path().c_str());
flecs::entity grid_floor_e =
get_grid_floor(grid_e, base_floor_e);
flecs::log::dbg("job_queue: grid_floor: %s",
grid_floor_e.path().c_str());
assert(!subregions.sub_subregions.empty());
if (subregions.sub_subregions.has(et) &&
!subregions.sub_subregions[et].empty()) {
flecs::log::dbg(
"subregions for: %s",
grid_e.world().entity(et).path().c_str());
struct grow_job job;
if (grid_floor_e.get<growth_regions>()->job_list.empty())
job.job_type = grow_job::INITIAL;
else
job.job_type = grow_job::COMMON;
job.parent_id = et;
job.base_floor_id = base_floor_et;
job.grid_floor_id = grid_floor_e.id();
job.subregions =
subregions.sub_subregions[job.parent_id];
grid_floor_e.get_mut<growth_regions>()
->job_list.push_back(job);
List<Pair<flecs::entity, float> >::Element *se =
job.subregions.front();
while (se) {
job_create_queue.push_back(
{ se->get().first.id(),
base_floor_et });
se = se->next();
}
grid_floor_e.modified<growth_regions>();
} else
flecs::log::dbg(
"no subregions for: %s",
grid_e.world().entity(et).path().c_str());
}
}
void grow_job_queue::job_initial(struct grow_job *job)
{
int i, j;
flecs::entity base_floor_e = grid_e.world().entity(job->base_floor_id);
flecs::entity grid_floor_e = grid_e.world().entity(job->grid_floor_id);
flecs::log::dbg("create: base_floor: %s", base_floor_e.path().c_str());
flecs::log::dbg("create: grid_floor: %s", grid_floor_e.path().c_str());
growth_regions *g = grid_floor_e.get_mut<growth_regions>();
RegionRect2i clip_rect(1, 1, grid_size - 2, grid_size - 2);
const List<Pair<flecs::entity, float> > &subregions = job->subregions;
List<struct region> initial_regions;
#if 0
assert(g->regions.size() == 0);
#endif
if (subregions.size() == 0) {
flecs::log::err("nothing to do");
return;
}
grid_floor_e.set<region_tree>(
{ { job->base_floor_id, job->base_floor_id, job->base_floor_id,
clip_rect.grow(-1), grid_size * grid_size, false, false,
true },
Vector<struct region_tree *>(),
nullptr });
struct region_tree *rtree = grid_floor_e.get_mut<region_tree>();
create_region_list(rtree, subregions, initial_regions);
grid_floor_e.modified<region_tree>();
grid_floor_e.get_mut<region_tree>()->split(grid_floor_e,
initial_regions);
assert(rtree->check(grid_floor_e));
grid_floor_e.modified<region_tree>();
grid_floor_e.get<region_tree>()->dump(grid_floor_e);
grid_floor_e.get_mut<region_tree>()->grow(grid_floor_e);
grid_floor_e.modified<region_tree>();
grid_floor_e.get<region_tree>()->dump(grid_floor_e);
// grid_floor_e.get<region_tree>()->place(grid_floor_e);
List<RegionRect2i> rects;
List<RegionRect2i>::Element *e, *e1;
grid_floor_e.get<region_tree>()->get_rects(&rects);
e = rects.front();
bool ok = true;
while (e) {
e1 = rects.front();
while (e1) {
if (e->get() == e1->get()) {
e1 = e1->next();
continue;
}
if (e->get().intersects(e1->get()))
ok = false;
if (e->get().encloses(e1->get()))
ok = false;
if (e1->get().intersects(e->get()))
ok = false;
if (e1->get().encloses(e->get()))
ok = false;
if (!ok)
break;
e1 = e1->next();
}
e = e->next();
}
#if 0
while (fe) {
flecs::entity ce = fe->get().first;
float area = fe->get().second;
flecs::log::warn("generating positions for: %s",
ce.path().c_str());
job->grid.filter_candidates(ce, area, clip_rect);
fe = fe->next();
}
#endif
#if 0
job->grid.place_regions(grid_floor_e);
flecs::log::dbg("Running grow...");
queries.get_qr().each(
[this](flecs::entity grid_floor_e,
WorldEditor::components::buildings_layout_grid_floor &fl,
growth_regions &g) {
struct grid_misc grd;
if (g.complete)
return;
grd.grow_region_rects(grid_floor_e, fl, g);
grd.place_region_cells(grid_floor_e, fl, g);
});
queries.get_qr().each(
[](flecs::entity grid_floor_e,
WorldEditor::components::buildings_layout_grid_floor &fl,
growth_regions &g) {
int i;
for (i = 0; i < (int)g.regions.size(); i++)
g.regions.write[i].complete = true;
g.complete = true;
});
grid_e.world()
.system(grid_e.world().lookup(
(module_name + "::GrowCommitQueue").ascii().ptr()))
.run();
queries.get_mark_cells().each([](flecs::entity e,
const WorldEditor::components::
buildings_layout_grid_cell
&cell) {
int grid_size =
e.parent()
.get<WorldEditor::components::
buildings_layout_grid_floor>()
->grid_size;
int i;
Vector2i position(cell.index % grid_size,
cell.index / grid_size);
Vector2 west(position.x - 1, position.y);
Vector2 north(position.x, position.y - 1);
Vector2 east(position.x + 1, position.y);
Vector2 south(position.x, position.y + 1);
int west_id = west.x + grid_size * west.y;
int north_id = north.x + grid_size * north.y;
int east_id = east.x + grid_size * east.y;
int south_id = south.x + grid_size * south.y;
std::vector<int> neighbors = { west_id, north_id, east_id,
south_id };
bool outside = false;
bool border = false;
for (i = 0; i < (int)neighbors.size(); i++) {
int id = neighbors[i];
print_line("id=" + itos(id));
if (!e.parent()
.get<WorldEditor::components::
buildings_layout_grid_floor>()
->cells.has(id)) {
outside = true;
break;
}
}
for (i = 0; i < (int)neighbors.size(); i++) {
int id = neighbors[i];
print_line("id=" + itos(id));
String neighbor_name = "cell_" + itos(id);
flecs::entity neighbor_e =
e.parent().lookup(neighbor_name.ascii().ptr());
if (!neighbor_e.is_valid())
continue;
const WorldEditor::components::buildings_layout_grid_cell
*neighbor_cell = neighbor_e.get<
WorldEditor::components::
buildings_layout_grid_cell>();
if (cell.type != neighbor_cell->type) {
border = true;
break;
}
}
if (outside)
e.add<WorldEditor::components::outside_wall>();
else
e.add<WorldEditor::components::final_cell>();
if (border)
e.add<WorldEditor::components::border>();
print_line("outside: " + itos(outside));
print_line("position: " + (position.operator String()));
print_line("grid size: " + itos(grid_size));
print_line("tile index: " + itos(cell.index));
});
flecs::log::dbg("initial: region count: %d", g->regions.size());
assert(g->regions.size() > 0);
#endif
assert(rtree->check(grid_floor_e));
}
void grow_job_queue::job_common(struct grow_job *job)
{
int i, j;
make_random r(172);
flecs::entity base_floor_e = grid_e.world().entity(job->base_floor_id);
flecs::entity grid_floor_e = grid_e.world().entity(job->grid_floor_id);
flecs::log::dbg("create: base_floor: %s", base_floor_e.path().c_str());
flecs::log::dbg("create: grid_floor: %s", grid_floor_e.path().c_str());
flecs::entity parent_e = grid_e.world().entity(job->parent_id);
growth_regions *g = grid_floor_e.get_mut<growth_regions>();
const List<Pair<flecs::entity, float> > &subregions = job->subregions;
const List<Pair<flecs::entity, float> >::Element *fe =
subregions.front();
struct region_tree *base_rtree = grid_floor_e.get_mut<region_tree>(),
*rtree;
List<struct region> region_list;
base_rtree->dump(grid_floor_e);
flecs::log::warn("search for: %s %lx", parent_e.path().c_str(),
job->parent_id);
rtree = base_rtree->find(job->parent_id);
if (!rtree) {
g->job_list.push_back(*job);
flecs::log::warn("delay job fo %s (%d jobs)",
parent_e.path().c_str(), g->job_list.size());
return;
}
create_region_list(rtree, subregions, region_list);
assert(base_rtree->check(grid_floor_e));
rtree->split(grid_floor_e, region_list);
assert(base_rtree->check(grid_floor_e));
grid_floor_e.modified<region_tree>();
rtree->dump(grid_floor_e);
assert(base_rtree->check(grid_floor_e));
rtree->grow(grid_floor_e);
assert(base_rtree->check(grid_floor_e));
rtree->dump(grid_floor_e);
grid_floor_e.modified<region_tree>();
#if 0
flecs::log::dbg("common: region count: %d", g->regions.size());
assert(g->regions.size() > 0);
bool restart = false, found = false;
RegionRect2i clip_rect(0, 0, grid_size, grid_size);
for (i = 0; i < (int)g->regions.size(); i++) {
flecs::log::dbg("region %d: %s", i,
grid_e.world()
.entity(g->regions[i].region_et)
.path()
.c_str());
}
int region_index = -1;
for (i = 0; i < (int)g->regions.size(); i++) {
if (g->regions[i].region_et == job->parent_id) {
flecs::log::warn("parent is in regions %d", i);
region_index = i;
if (!g->regions[i].complete) {
g->job_list.push_back(*job);
restart = true;
flecs::log::err(
"parent is in regions %d incomplete",
i);
flecs::log::warn("delay job fo %s (%d jobs)",
grid_e.world()
.entity(job->parent_id)
.path()
.c_str(),
g->job_list.size());
}
found = true;
break;
}
}
if (!found) {
// no parent region yet
g->job_list.push_back(*job);
flecs::log::warn("delay job fo %s (%d jobs)",
parent_e.path().c_str(), g->job_list.size());
restart = true;
}
if (restart)
return;
#endif
#if 0
for (i = 0; i < g->regions.size(); i++)
flecs::log::warn(
"before: region %d: %s", i,
(g->regions[i].rect.operator String()).ascii().ptr());
// growth_regions::region parent_region = g->regions[region_index];
// const List<Pair<flecs::entity, float> >::Element *fe =
// subregions.front();
List<Pair<flecs::entity, float> > region_list = subregions;
g->split_region(grid_floor_e, region_index, region_list);
#endif
// g->regions.remove(region_index);
// clip_rect = parent_region.rect;
// int parent_region_index = g->parent_regions.size();
// g->parent_regions.push_back(parent_region);
/*
while (fe) {
flecs::entity ce = fe->get().first;
float area = fe->get().second;
flecs::log::warn("generating positions for: %s",
ce.path().c_str());
job->grid.filter_candidates(ce, area, clip_rect);
fe = fe->next();
}
job->grid.place_regions_common(parent_e, grid_floor_e,
parent_region_index);
*/
#if 0
for (i = 0; i < g->regions.size(); i++)
flecs::log::warn(
"after: region %d: %s", i,
(g->regions[i].rect.operator String()).ascii().ptr());
flecs::log::dbg("Running grow...");
g->grow_regions(grid_floor_e);
#endif
#if 0
// FIXME: fix this
queries.get_qr().each(
[this, parent_e](
flecs::entity grid_floor_e,
WorldEditor::components::buildings_layout_grid_floor &fl,
growth_regions &g) {
if (g.complete)
return;
g.grow_regions(grid_floor_e);
});
#endif
#if 0
for (i = 0; i < g->regions.size(); i++)
flecs::log::warn(
"after2: region %d: %s", i,
(g->regions[i].rect.operator String()).ascii().ptr());
#endif
#if 0
queries.get_qr().each(
[this, parent_e](
flecs::entity grid_floor_e,
WorldEditor::components::buildings_layout_grid_floor &fl,
growth_regions &g) {
struct grid_misc grd;
// if (g.complete)
// return;
//grd.grow_region_rects(grid_floor_e, fl, g);
grd.update_region_cells(grid_floor_e, parent_e, fl, g);
assert(false);
});
#endif
#if 0
update_region_cells(grid_floor_e);
for (i = 0; i < (int)g->regions.size(); i++)
g->regions.write[i].complete = true;
g->complete = true;
#endif
commit_common_queue();
// assert(false);
}
void grow_job_queue::commit_common_queue()
{
grid_e.world()
.query_builder<
WorldEditor::components::buildings_layout_grid_floor,
WorldEditor::components::buildings_layout_grid_queue>()
.each([this](flecs::entity e,
WorldEditor::components::buildings_layout_grid_floor
&fl,
WorldEditor::components::buildings_layout_grid_queue
&queue) {
List<Pair<flecs::entity_t, int> >::Element *me =
queue.queue.front();
while (me) {
flecs::entity seed_e =
e.world().entity(me->get().first);
int id = me->get().second;
if (!fl.cells.has(id)) {
flecs::log::err("bad cell %d", id);
assert(false);
}
// fl.cells.insert(id);
flecs::entity floor_e = seed_e.parent();
String c_name = "cell_" + itos(id);
flecs::entity c_e =
floor_e.lookup(c_name.ascii().ptr());
if (c_e.is_valid() &&
c_e.has<WorldEditor::components::
buildings_layout_grid_cell>()) {
// flecs::log::dbg("cell: %s: %s",
// e.path().c_str(),
// c_e.path().c_str());
String type =
seed_e.get<WorldEditor::components::
buildings_layout_grid_cell>()
->type;
c_e.set<WorldEditor::components::
buildings_layout_grid_cell>(
{ type, id });
seed_e.each<
WorldEditor::components::belongs>(
[&c_e](flecs::entity second) {
c_e.add<WorldEditor::components::
belongs>(
second);
});
seed_e.each<WorldEditor::components::
belongs_room>(
[&c_e](flecs::entity second) {
c_e.add<WorldEditor::components::
belongs_room>(
second);
});
floor_e.modified<
WorldEditor::components::
buildings_layout_grid_floor>();
} else {
flecs::log::err("bad cell %s",
c_name.ascii().ptr());
assert(false);
}
me = me->next();
}
queue.queue.clear();
e.remove<WorldEditor::components::
buildings_layout_grid_queue>();
});
}
void grow_job_queue::create_region_list(
region_tree *rtree, const List<Pair<flecs::entity, float> > &subregions,
List<struct region> &region_list)
{
int i, j;
const List<Pair<flecs::entity, float> >::Element *fe =
subregions.front();
bool restart = false, found = false;
make_random r(172);
RegionRect2i clip_rect = rtree->region.rect;
Vector2i current_position = clip_rect.get_center();
Vector2i velocity;
Vector<flecs::entity> regions;
LocalVector<Vector2i> positions;
Vector<int> distances;
LocalVector<float> areas;
// Drunk walk implementation
int speed = MAX(1, grid_size * grid_size / 2 / subregions.size());
int bad_count = 0;
while (fe) {
Vector<Vector2i> position_candidates;
if (positions.empty()) {
int target_distance =
(int)(Math::sqrt(fe->get().second) * 0.7f) + 1;
positions.push_back(current_position);
distances.push_back(target_distance);
regions.push_back(fe->get().first);
areas.push_back(fe->get().second);
fe = fe->next();
if (!fe)
break;
}
for (i = 0; i < (int)positions.size(); i++) {
int which = r.get() % 12;
switch (which) {
case 1:
velocity = { 0, 1 };
break;
case 3:
velocity = { 1, 0 };
break;
case 5:
velocity = { 0, -1 };
break;
case 7:
velocity = { -1, 0 };
break;
}
if (clip_rect.has_point(current_position + velocity)) {
position_candidates.push_back(current_position +
velocity);
current_position += velocity;
}
}
int target_distance =
(int)(Math::sqrt(fe->get().second) * 0.7f) + 1;
assert(fe);
if (bad_count > 100)
target_distance = 1;
bool any_match = false;
for (i = 0; i < position_candidates.size(); i++) {
bool bad = false;
assert(fe);
for (j = 0; j < (int)positions.size(); j++) {
Vector2i l =
position_candidates[i] - positions[j];
int distance =
l.x * l.x + l.y * l.y - distances[j];
if (distance < target_distance) {
bad = true;
break;
}
}
assert(fe);
if (!bad) {
assert(fe);
positions.push_back(position_candidates[i]);
distances.push_back(target_distance);
regions.push_back(fe->get().first);
areas.push_back(fe->get().second);
any_match = true;
bad_count = 0;
if (fe) {
fe = fe->next();
if (fe)
target_distance =
(int)(Math::sqrt(
fe->get()
.second) *
0.7f) +
1;
}
}
if (!fe)
break;
}
if (!any_match) {
flecs::log::err(
"No match found: %s: %s",
(clip_rect.operator String()).ascii().ptr(),
(current_position.operator String())
.ascii()
.ptr());
bad_count++;
}
if (bad_count >= 100) {
position_candidates.clear();
int x, y;
for (x = clip_rect.position.x;
x < clip_rect.position.x + clip_rect.size.x; x++)
for (y = clip_rect.position.y;
y <
clip_rect.position.y + clip_rect.size.y;
y++) {
position_candidates.push_back(
Vector2i(x, y));
}
bad_count = 0;
for (i = 0; i < position_candidates.size(); i++) {
bool bad = false;
assert(fe);
for (j = 0; j < (int)positions.size(); j++) {
Vector2i l = position_candidates[i] -
positions[j];
int distance = l.x * l.x + l.y * l.y -
distances[j];
if (distance > 0) {
bad = true;
break;
}
}
assert(fe);
if (!bad) {
assert(fe);
positions.push_back(
position_candidates[i]);
distances.push_back(target_distance);
regions.push_back(fe->get().first);
areas.push_back(fe->get().second);
any_match = true;
bad_count = 0;
if (fe)
fe = fe->next();
}
if (!fe)
break;
}
}
assert(bad_count < 2000);
}
flecs::log::dbg("grid_size %d", grid_size);
for (i = 0; i < (int)positions.size(); i++) {
struct region region;
flecs::log::dbg("region: %s", regions[i].path().c_str());
flecs::log::dbg("position: %d, %d", positions[i].x,
positions[i].y);
region.complete = false;
region.can_grow = true;
region.can_grow_square = true;
region.parent = rtree->region.region_et;
region.rect = RegionRect2i(positions[i], Vector2i(1, 1));
region.region_et = regions[i].id();
region.remains_area = MAX(1, (areas[i] / 16));
/* setting seed uninitialized */
region_list.push_back(region);
}
}
void grow_job_queue::iterate()
{
assert(grid_e.is_valid());
assert(this);
flecs::query<growth_regions> q =
grid_e.world().query_builder<growth_regions>().build();
q.each([this](flecs::entity e, growth_regions &g) {
flecs::log::warn("pre floor: %s", e.path().c_str());
});
q.each([this](flecs::entity e, growth_regions &g) {
flecs::log::warn("floor: %s", e.path().c_str());
flecs::log::warn("job count: %d", g.job_list.size());
while (!g.job_list.empty()) {
List<struct grow_job>::Element *job_e =
g.job_list.front();
assert(job_e);
flecs::entity base_floor_e = grid_e.world().entity(
job_e->get().base_floor_id);
assert(base_floor_e.is_valid());
flecs::entity grid_floor_e = grid_e.world().entity(
job_e->get().grid_floor_id);
assert(grid_floor_e.is_valid());
flecs::log::dbg("inerate: create: base_floor: %s",
base_floor_e.path().c_str());
flecs::log::dbg("iterate: create: grid_floor: %s",
grid_floor_e.path().c_str());
switch (job_e->get().job_type) {
case grow_job::INITIAL:
flecs::log::dbg("initial");
job_initial(&job_e->get());
{
const region_tree *rtree =
e.get<region_tree>();
assert(!rtree ||
(rtree &&
rtree->check(grid_floor_e)));
}
break;
case grow_job::COMMON:
flecs::log::dbg("common");
job_common(&job_e->get());
{
const region_tree *rtree =
e.get<region_tree>();
assert(!rtree ||
(rtree &&
rtree->check(grid_floor_e)));
}
break;
default:
assert(false);
break;
}
g.job_list.pop_front();
// if (common_count > 0)
// break;
}
g.job_list.clear();
flecs::query<region_tree> qm =
grid_e.world().query_builder<region_tree>().build();
qm.each([this](flecs::entity em, region_tree &rt) {
assert(rt.check(em));
});
qm.each([this](flecs::entity em, region_tree &rt) {
rt.place(em);
});
flecs::log::dbg(
"processed jobs (created region initial positions): %d",
g.job_list.size());
});
}

View File

@@ -0,0 +1,31 @@
#ifndef GROW_JOB_H
#define GROW_JOB_H
struct grow_job {
enum { INITIAL, COMMON };
int job_type;
flecs::entity_t parent_id;
flecs::entity_t base_floor_id;
flecs::entity_t grid_floor_id;
List<Pair<flecs::entity, float> > subregions;
struct grid_misc grid;
};
struct grow_job_queue {
flecs::entity grid_e;
int grid_size;
struct subregions &subregions;
const String &module_name;
grow_job_queue(
flecs::entity grid_e, struct subregions &subregions,
const WorldEditor::components::buildings_layout_grid_size &size,
const String &module_name);
void iterate();
void job_initial(struct grow_job *job);
void job_common(struct grow_job *job);
void commit_common_queue();
void
create_region_list(struct region_tree *rtree,
const List<Pair<flecs::entity, float> > &subregions,
List<struct region> &region_list);
};
#endif

View File

@@ -0,0 +1,242 @@
#include "growth_regions.h"
#include "region_tree.h"
#include "editor_event.h"
#include "queries.h"
#include "growth_module.h"
growth_module::growth_module(flecs::world &ecs)
{
ecs.module<growth_module>();
ecs.component<growth_regions>();
ecs.component<region_tree>();
const String &module_name = "::growth_module";
flecs::entity GraphFilter = ecs.entity("GraphFilter")
.add(flecs::Phase)
.depends_on(flecs::OnUpdate);
flecs::entity GraphSolve = ecs.lookup("::graph_module::GraphSolve");
assert(GraphSolve.is_valid());
GraphFilter.disable();
#if 0
flecs::entity GraphGridPrepare = ecs.entity("GraphGridPrepare")
.add(flecs::Phase)
.depends_on(GraphSolve);
#endif
ecs.system("RunGrow")
.immediate()
.write<WorldEditor::components::buildings_layout_grid_floor>()
.write<WorldEditor::components::buildings_layout_grid_size>()
.write<growth_regions>()
.kind(GraphSolve)
.run([module_name, this, GraphFilter](flecs::iter &it) {
flecs::world &&ecs_ = it.world();
it.world().defer_suspend();
flecs::log::dbg("Assembling skeleton done...");
flecs::entity GraphSolveZones = it.world().lookup(
"::graph_module::GraphSolveZones");
assert(GraphSolveZones.is_valid());
GraphSolveZones.disable();
assert(GraphFilter.is_valid());
GraphFilter.enable();
EditorEvent::get_singleton()->event.emit(
"update_layout_view", varray());
// assert(false);
struct subregions subregions(ecs_);
struct queries queries(ecs_);
flecs::log::dbg("Creating regions grow...");
queries.get_qp().each(
[this, &subregions, &queries,
module_name](flecs::iter &it2, size_t count,
const WorldEditor::components::
buildings_layout_grid_size
&size) {
struct grid_misc grid;
// grid.subregions_init(it2.world());
flecs::entity graph_e =
it2.entity(count);
flecs::log::warn(
"creating grid for: %s",
graph_e.path().c_str());
flecs::entity grid_base_e =
queries.get_layout_grid_base();
flecs::entity grid_e =
grid_base_e.lookup(
graph_e.name());
assert(grid_e.is_valid());
flecs::log::warn(
"creating grid for: %s: %s",
graph_e.path().c_str(),
grid_e.path().c_str());
/* starting at grid center */
subregions.build_subregions(grid_e,
grid, size);
struct grow_job_queue job_queue(
grid_e, subregions, size,
module_name);
job_queue.iterate();
});
commit_growth_queue(it.world());
queries.get_mark_cells().each([](flecs::entity e,
const WorldEditor::
components::buildings_layout_grid_cell
&cell) {
int grid_size =
e.parent()
.get<WorldEditor::components::
buildings_layout_grid_floor>()
->grid_size;
int i;
Vector2i position(cell.index % grid_size,
cell.index / grid_size);
Vector2 west(position.x - 1, position.y);
Vector2 north(position.x, position.y - 1);
Vector2 east(position.x + 1, position.y);
Vector2 south(position.x, position.y + 1);
int west_id = west.x + grid_size * west.y;
int north_id = north.x + grid_size * north.y;
int east_id = east.x + grid_size * east.y;
int south_id = south.x + grid_size * south.y;
std::vector<int> neighbors = {
west_id, north_id, east_id, south_id
};
bool outside = false;
#if 0
bool border = false;
#endif
for (i = 0; i < (int)neighbors.size(); i++) {
int id = neighbors[i];
print_line("id=" + itos(id));
String neighbor_cell =
"cell_" + itos(id);
flecs::entity neighbor_e =
e.parent().lookup(
neighbor_cell.ascii()
.ptr());
if (!neighbor_e.is_valid()) {
outside = true;
break;
}
if (!e.parent()
.get<WorldEditor::components::
buildings_layout_grid_floor>()
->cells.has(id)) {
outside = true;
break;
}
}
flecs::log::dbg("outside: %d", outside);
#if 0
for (i = 0; i < (int)neighbors.size(); i++) {
int id = neighbors[i];
print_line("id=" + itos(id));
String neighbor_name = "cell_" + itos(id);
flecs::entity neighbor_e =
e.parent().lookup(neighbor_name.ascii().ptr());
if (!neighbor_e.is_valid())
continue;
const WorldEditor::components::buildings_layout_grid_cell
*neighbor_cell = neighbor_e.get<
WorldEditor::components::
buildings_layout_grid_cell>();
if (cell.type != neighbor_cell->type) {
border = true;
break;
}
}
#endif
if (outside) {
e.add<WorldEditor::components::
outside_wall>();
flecs::log::dbg("outside wall cell %s",
e.path().c_str());
} else
e.add<WorldEditor::components::
final_cell>();
#if 0
if (border)
e.add<WorldEditor::components::border>();
#endif
print_line("outside: " + itos(outside));
print_line("position: " +
(position.operator String()));
print_line("grid size: " + itos(grid_size));
print_line("tile index: " + itos(cell.index));
});
it.world()
.lookup("::growth_module::GraphFilter")
.disable();
it.world().defer_resume();
});
}
void growth_module::grow_cell(flecs::entity seed_e, int id)
{
flecs::entity floor_e = seed_e.parent();
String c_name = "cell_" + itos(id);
flecs::entity c_e = floor_e.lookup(c_name.ascii().ptr());
if (!c_e.is_valid()) {
c_e = seed_e.world()
.entity(c_name.ascii().ptr())
.child_of(floor_e);
assert(c_e.is_valid());
String type = seed_e.get<WorldEditor::components::
buildings_layout_grid_cell>()
->type;
c_e.set<WorldEditor::components::buildings_layout_grid_cell>(
{ type, id });
seed_e.each<WorldEditor::components::belongs>(
[&c_e](flecs::entity second) {
c_e.add<WorldEditor::components::belongs>(
second);
});
int mcount = 0;
seed_e.each<WorldEditor::components::belongs_room>(
[&c_e, &mcount](flecs::entity second) {
assert(mcount == 0);
c_e.add<WorldEditor::components::belongs_room>(
second);
mcount++;
});
floor_e.get_mut<WorldEditor::components::
buildings_layout_grid_floor>()
->size_left--;
floor_e.get_mut<WorldEditor::components::
buildings_layout_grid_floor>()
->cells.insert(id);
floor_e.modified<
WorldEditor::components::buildings_layout_grid_floor>();
}
}
void growth_module::commit_growth_queue(flecs::world &&ecs)
{
flecs::query<WorldEditor::components::buildings_layout_grid_floor,
WorldEditor::components::buildings_layout_grid_queue>
grow_commit_queue =
ecs.query_builder<WorldEditor::components::
buildings_layout_grid_floor,
WorldEditor::components::
buildings_layout_grid_queue>()
.build();
grow_commit_queue.each(
[this](flecs::entity e,
WorldEditor::components::buildings_layout_grid_floor &fl,
WorldEditor::components::buildings_layout_grid_queue
&queue) {
List<Pair<flecs::entity_t, int> >::Element *me =
queue.queue.front();
while (me) {
flecs::entity seed_e =
e.world().entity(me->get().first);
int id = me->get().second;
if (!fl.cells.has(id)) {
grow_cell(seed_e, id);
fl.cells.insert(id);
}
me = me->next();
}
queue.queue.clear();
e.remove<WorldEditor::components::
buildings_layout_grid_queue>();
});
}

View File

@@ -0,0 +1,12 @@
/* ~/godot-projects/streaming_world/src/modules/stream/ui/growth_module.h */
#ifndef GROWTH_MODULE_H_
#define GROWTH_MODULE_H_
#include "base_data.h"
struct growth_module {
void grow_cell(flecs::entity seed_e, int id);
void commit_growth_queue(flecs::world &&world);
growth_module(flecs::world &ecs);
};
#endif // GROWTH_MODULE_H_

View File

@@ -0,0 +1,213 @@
#include "growth_regions.h"
#if 0
static void print_can_grow(int state, growth_regions &g, int index,
const char *what)
{
const growth_regions::region &region = g.regions[index];
bool can = false;
if (!strcmp(what, "square"))
can = region.can_grow_square;
else if (!strcmp(what, "rect"))
can = region.can_grow;
if (can)
flecs::log::dbg(
"state: %d: index %d: region can still grow %s %d",
state, index, what, region.remains_area);
else
flecs::log::dbg("state: %d: index %d: region can't grow %s %d",
state, index, what, region.remains_area);
if (region.can_grow_region())
flecs::log::dbg("state %d: index %d: region can still continue",
state, index);
}
bool growth_regions::grow_state0(int index, const RegionRect2i &clip)
{
bool ok = true, ret = false;
RegionRect2i mrect;
growth_regions::region &region = regions.write[index];
mrect = region.rect;
assert(check_region(index, mrect));
mrect = mrect.grow(1);
ok = clip.encloses(mrect);
// if (!ok)
// flecs::log::dbg("state: %d: index %d: out of clip area",
// 0, index);
if (ok) {
ok = check_region(index, mrect);
// if (!ok)
// flecs::log::dbg(
// "state: %d: index %d: check_region failed",
// 0, index);
}
if (ok) {
ret = region.update_region_size(mrect);
// if (!ret)
// flecs::log::dbg(
// "state: %d: index %d: update_region_size failed",
// 0, index);
}
print_can_grow(0, *this, index, "square");
// if (!ret)
// flecs::log::dbg("state %d could not grow region %d: %d",
// 0, index, region.remains_area);
// else
// flecs::log::dbg("state %d could grow region %d: %d", 0,
// index, region.remains_area);
return ret;
}
bool growth_regions::grow_state1(int index, const RegionRect2i &clip)
{
int d;
bool ret = false;
RegionRect2i mrect;
growth_regions::region &region = regions.write[index];
int count = 0;
for (d = 0; d < 4; d++) {
bool ok;
mrect = region.rect;
assert(check_region(index, mrect));
switch (d) {
case 0:
mrect.position.y -= 1;
mrect.size.y += 1;
break;
case 1:
mrect.size.y += 1;
break;
case 2:
mrect.position.x -= 1;
mrect.size.x += 1;
break;
case 3:
mrect.size.x += 1;
break;
}
ok = parent_regions[region.parent_region].rect.encloses(mrect);
if (ok)
ok = clip.encloses(mrect);
if (ok) {
ok = false;
if (mrect.size.y > 0 && mrect.size.x > 0) {
float aspect = (float)mrect.size.x /
(float)mrect.size.y;
ok = (aspect > 0.2f && aspect < 5.0f);
}
}
if (ok)
ok = check_region(index, mrect);
if (ok) {
bool result = region.update_region_size(mrect);
if (result)
count++;
}
}
if (count > 0) {
ret = true;
// flecs::log::dbg(
// "state %d could grow region %d: %d - %d out of %d times",
// 0, index, region.remains_area, count, 4);
}
print_can_grow(1, *this, index, "rect");
// if (!ret)
// flecs::log::dbg(
// "state %d could not grow region rect %d: %d", 0,
// index, region.remains_area);
return ret;
}
#endif
#if 0
void growth_regions::grow_regions(flecs::entity grid_floor_e)
{
int i;
bool grown = true;
int state = 0;
if (complete)
return;
#if 0
int grid_size = grid_floor_e
.get<WorldEditor::components::
buildings_layout_grid_floor>()
->grid_size;
#endif
state = 0;
flecs::log::dbg("growing square");
while (grown) {
grown = false;
int count = 0;
for (i = 0; i < regions.size(); i++) {
growth_regions::region &region = regions.write[i];
const RegionRect2i &clip =
parent_regions[region.parent_region].rect;
RegionRect2i mrect = region.rect;
flecs::log::dbg("grow_region_rects: region %d", i);
if (!region.can_grow_region()) {
flecs::log::dbg("grow_region_rects: skip %d",
i);
continue;
}
mrect = region.rect;
bool result = false;
result = grow_state0(i, clip);
if (result)
count++;
}
if (count > 0) {
grown = true;
flecs::log::dbg("grown squares %d times of %d", count,
regions.size());
}
if (!grown)
flecs::log::dbg(
"grow_region_rects: could not grow more squares");
}
state = 1;
grown = true;
flecs::log::dbg("growing rect");
while (grown) {
grown = false;
int count = 0;
for (i = 0; i < regions.size(); i++) {
growth_regions::region &region = regions.write[i];
const RegionRect2i &clip =
parent_regions[region.parent_region].rect;
RegionRect2i mrect = region.rect;
flecs::log::dbg("grow_region_rects: region %d", i);
if (!region.can_grow_region()) {
flecs::log::dbg("grow_region_rects: skip %d",
i);
continue;
}
mrect = region.rect;
bool result = false;
result = grow_state1(i, clip);
if (result)
count++;
if (!result)
flecs::log::dbg(
"state %d could not grow region %d",
state, i);
else
flecs::log::dbg(
"state %d could grow region %d: %d",
state, i, region.remains_area);
}
if (count > 0) {
grown = true;
flecs::log::dbg("grown rects %d times of %d", count,
regions.size());
}
if (!grown)
flecs::log::dbg(
"grow_region_rects: could not grow any more rects");
}
flecs::log::dbg("grow_region_rects: complete");
complete = true;
flecs::log::dbg("grow_region_rects: %s: done",
grid_floor_e.path().c_str());
}
#endif

View File

@@ -0,0 +1,99 @@
#ifndef GROWTH_REGIONS_H
#define GROWTH_REGIONS_H
#include <core/vector.h>
#include <core/list.h>
#include <core/pair.h>
#include <core/math/vector2.h>
#include "base_data.h"
#include "region_rect2.h"
#include "graph_module.h"
struct region {
flecs::entity_t parent;
flecs::entity_t seed_et;
flecs::entity_t region_et;
RegionRect2i rect;
int remains_area;
bool can_grow_square;
bool can_grow;
bool complete;
bool can_grow_region() const
{
bool ret = can_grow;
if (remains_area <= 0)
ret = false;
return ret;
}
bool update_region_size(RegionRect2i &mrect)
{
bool ret = false;
int old_area = rect.get_area();
int new_area = mrect.get_area();
int area_diff = new_area - old_area;
if (area_diff > 0) {
rect = mrect;
remains_area -= area_diff;
ret = true;
}
if (remains_area <= 0) {
can_grow_square = false;
can_grow = false;
}
flecs::log::dbg("update_region_size %d -> %d", area_diff, ret);
return ret;
}
};
struct growth_regions {
List<struct grow_job> job_list;
bool complete;
bool check_region(int index, const RegionRect2i &rect) const;
#if 0
bool check_region(int index, const RegionRect2i &rect) const
{
int i;
bool ret = true;
for (i = 0; i < regions.size(); i++) {
if (i == index)
continue;
if (rect.intersects(regions[i].rect)) {
ret = false;
flecs::log::dbg(
"%d: %s intersects %s", i,
(rect.operator String()).ascii().ptr(),
(regions[i].rect.operator String())
.ascii()
.ptr());
break;
}
}
flecs::log::dbg("check_region: %d -> %d", index, ret);
return ret;
}
#endif
bool update_region_size(int index, RegionRect2i &mrect);
#if 0
bool update_region_size(int index, RegionRect2i &mrect)
{
bool ret = false;
bool ok = check_region(index, mrect);
if (ok)
ret = regions.write[index].update_region_size(mrect);
flecs::log::dbg("update_region_size %d -> %d", index, ret);
return ret;
}
#endif
void create_region(flecs::entity floor_e, flecs::entity seed_e,
flecs::entity parent_e, flecs::entity region_e,
const Vector2i &position, float area,
int parent_index);
flecs::entity create_cell(flecs::entity floor_e, flecs::entity region_e,
int id);
flecs::entity update_cell(flecs::entity floor_e, flecs::entity parent_e,
flecs::entity region_e, int id);
void split_region(flecs::entity grid_floor_e, int region_index,
const List<Pair<flecs::entity, float> > &region_list);
void grow_regions(flecs::entity grid_floor_e);
bool grow_state0(int index, const RegionRect2i &clip);
bool grow_state1(int index, const RegionRect2i &clip);
};
#endif

View File

@@ -0,0 +1,204 @@
#ifndef QUERIES_H
#define QUERIES_H
#include "base_data.h"
#include "world_editor.h"
#include "growth_regions.h"
#include "graph_module.h"
struct queries {
flecs::query_builder<WorldEditor::components::buildings_layout_grid_size>
qp;
flecs::query_builder<WorldEditor::components::buildings_layout_grid_floor,
growth_regions>
qr;
flecs::query_builder<
const WorldEditor::components::buildings_layout_grid_cell>
mark_cells;
flecs::query<WorldEditor::components::buildings_layout_grid_size>
get_qp()
{
return qp.build();
}
flecs::query<WorldEditor::components::buildings_layout_grid_floor,
growth_regions>
get_qr()
{
return qr.build();
}
flecs::query<const WorldEditor::components::buildings_layout_grid_cell>
get_mark_cells()
{
return mark_cells.build();
}
queries(flecs::world &w)
: qp(w.query_builder<WorldEditor::components::
buildings_layout_grid_size>()
.write<WorldEditor::components::
buildings_layout_grid>())
, qr(w.query_builder<
WorldEditor::components::buildings_layout_grid_floor,
growth_regions>())
, mark_cells(
w.query_builder<const WorldEditor::components::
buildings_layout_grid_cell>()
.without<WorldEditor::components::outside_wall>()
.read<WorldEditor::components::
buildings_layout_grid_floor>()
.write<WorldEditor::components::outside_wall>()
.write<WorldEditor::components::final_cell>())
{
}
int get_floor_index(flecs::entity e) const
{
return e.get<WorldEditor::components::
buildings_layout_floor_index>()
->index;
}
flecs::entity get_grid_floor(flecs::entity grid_e,
flecs::entity graph_floor_e)
{
assert(grid_e.is_valid());
assert(graph_floor_e.is_valid());
int floor_index = get_floor_index(graph_floor_e);
String floor_name = "floor_" + itos(floor_index);
flecs::log::dbg("floor: %s", floor_name.ascii().ptr());
flecs::entity floor_e = grid_e.lookup(floor_name.ascii().ptr());
assert(floor_e.is_valid());
return floor_e;
}
void create_floor_components(
flecs::entity floor_e, flecs::entity base_floor_e,
const WorldEditor::components::buildings_layout_grid_size &size)
const
{
assert(!floor_e.has<
WorldEditor::components::buildings_layout_grid_floor>());
assert(!floor_e.has<growth_regions>());
floor_e.set<WorldEditor::components::buildings_layout_grid_floor>(
{ Set<int>(), size.grid_size, size.growth_size });
floor_e.set<growth_regions>({ List<struct grow_job>(), false });
floor_e.add<WorldEditor::components::belongs>(base_floor_e);
}
flecs::entity get_layout_grid_base()
{
const String &layout_grid_name = "buildings_layout_grid_v2";
flecs::world ecs = BaseData::get_singleton()->get();
flecs::entity layout_base_e =
ecs.lookup(layout_grid_name.ascii().ptr());
if (layout_base_e.is_valid()) {
assert(layout_base_e.has<
WorldEditor::components::
buildings_layout_grid_base>());
return layout_base_e;
} else {
layout_base_e =
ecs.entity(layout_grid_name.ascii().ptr());
assert(layout_base_e.is_valid());
layout_base_e.add<WorldEditor::components::
buildings_layout_grid_base>();
assert(layout_base_e.has<
WorldEditor::components::
buildings_layout_grid_base>());
return layout_base_e;
}
}
flecs::entity get_layout_base()
{
const String &layout_base_name = "buildings_layout_graph";
flecs::world ecs = BaseData::get_singleton()->get();
flecs::entity layout_base_e =
ecs.lookup(layout_base_name.ascii().ptr());
if (layout_base_e.is_valid()) {
assert(layout_base_e.has<
WorldEditor::components::buildings_layout_base>());
return layout_base_e;
} else {
layout_base_e =
ecs.entity(layout_base_name.ascii().ptr());
assert(layout_base_e.is_valid());
layout_base_e.add<
WorldEditor::components::buildings_layout_base>();
return layout_base_e;
}
}
};
struct subregions {
HashMap<flecs::entity_t, List<Pair<flecs::entity, float> > >
sub_subregions;
struct queries queries;
subregions(flecs::world &ecs)
: queries(ecs)
{
}
void get_subregions(flecs::entity parent,
List<Pair<flecs::entity, float> > *subregions)
{
flecs::query<const WorldEditor::components::buildings_layout_area>
qprep = parent.world()
.query_builder<
const WorldEditor::components::
buildings_layout_area>()
.with(flecs::ChildOf, parent)
.scope_open()
.with<WorldEditor::components::
buildings_layout_zone>()
.or_()
.with<WorldEditor::components::
buildings_layout_unit>()
.or_()
.with<WorldEditor::components::
buildings_layout_room>()
.scope_close()
.build();
qprep.each([&subregions](flecs::entity ce,
const WorldEditor::components::
buildings_layout_area &area) {
subregions->push_back({ ce, area.area });
});
}
void build_subregions(
flecs::entity grid_e, struct grid_misc &grid,
const WorldEditor::components::buildings_layout_grid_size &size)
{
const List<Pair<int, flecs::entity_t> >::Element *me =
size.floors.front();
List<flecs::entity_t> subregions_queue;
while (me) {
subregions_queue.push_back(me->get().second);
flecs::entity_t base_floor_et = me->get().second;
flecs::entity base_floor_e =
grid_e.world().entity(base_floor_et);
flecs::log::dbg("job_queue: base_floor: %s",
base_floor_e.path().c_str());
flecs::entity grid_floor_e =
queries.get_grid_floor(grid_e, base_floor_e);
flecs::log::dbg("job_queue: grid_floor: %s",
grid_floor_e.path().c_str());
if (!grid_floor_e
.has<WorldEditor::components::
buildings_layout_grid_floor>())
queries.create_floor_components(
grid_floor_e, base_floor_e, size);
me = me->next();
}
while (!subregions_queue.empty()) {
// eid is graph entity
flecs::entity_t eid = subregions_queue.front()->get();
subregions_queue.pop_front();
List<Pair<flecs::entity, float> > subregions;
flecs::entity item_e = grid_e.world().entity(eid);
get_subregions(grid_e.world().entity(eid), &subregions);
if (subregions.empty())
flecs::log::dbg("!no subregions for: %s",
item_e.path().c_str());
sub_subregions[eid] = subregions;
List<Pair<flecs::entity, float> >::Element *fe =
subregions.front();
while (fe) {
subregions_queue.push_back(
fe->get().first.id());
fe = fe->next();
}
}
}
};
#endif

View File

@@ -0,0 +1,235 @@
/* ~/godot-projects/streaming_world/src/modules/stream/ui/region_rect2.h */
#ifndef REGION_RECT2_H_
#define REGION_RECT2_H_
#include <core/math/vector2.h>
#include <core/math/rect2.h>
struct RegionRect2i {
Point2i position;
Size2i size;
const Point2i &get_position() const
{
return position;
}
void set_position(const Point2i &p_position)
{
position = p_position;
}
const Size2i &get_size() const
{
return size;
}
void set_size(const Size2i &p_size)
{
size = p_size;
}
int get_area() const
{
return size.width * size.height;
}
_FORCE_INLINE_ Vector2i get_center() const
{
return position + (size / 2);
}
inline bool intersects(const RegionRect2i &p_rect) const
{
if (position.x > (p_rect.position.x + p_rect.size.width - 1)) {
return false;
}
if ((position.x + size.width - 1) < p_rect.position.x) {
return false;
}
if (position.y > (p_rect.position.y + p_rect.size.height - 1)) {
return false;
}
if ((position.y + size.height - 1) < p_rect.position.y) {
return false;
}
return true;
}
inline bool encloses(const RegionRect2i &p_rect) const
{
return (p_rect.position.x >= position.x) &&
(p_rect.position.y >= position.y) &&
((p_rect.position.x + p_rect.size.x) <=
(position.x + size.x)) &&
((p_rect.position.y + p_rect.size.y) <=
(position.y + size.y));
}
_FORCE_INLINE_ bool has_no_area() const
{
return (size.x <= 0 || size.y <= 0);
}
inline RegionRect2i clip(const RegionRect2i &p_rect) const
{ /// return a clipped rect
RegionRect2i new_rect = p_rect;
if (!intersects(new_rect)) {
return RegionRect2i();
}
new_rect.position.x = MAX(p_rect.position.x, position.x);
new_rect.position.y = MAX(p_rect.position.y, position.y);
Point2 p_rect_end = p_rect.position + p_rect.size;
Point2 end = position + size;
new_rect.size.x =
(int)(MIN(p_rect_end.x, end.x) - new_rect.position.x);
new_rect.size.y =
(int)(MIN(p_rect_end.y, end.y) - new_rect.position.y);
return new_rect;
}
inline RegionRect2i merge(const RegionRect2i &p_rect) const
{ ///< return a merged rect
RegionRect2i new_rect;
new_rect.position.x = MIN(p_rect.position.x, position.x);
new_rect.position.y = MIN(p_rect.position.y, position.y);
new_rect.size.x = MAX(p_rect.position.x + p_rect.size.x,
position.x + size.x);
new_rect.size.y = MAX(p_rect.position.y + p_rect.size.y,
position.y + size.y);
new_rect.size =
new_rect.size - new_rect.position; //make relative again
return new_rect;
};
bool has_point(const Point2 &p_point) const
{
if (p_point.x < position.x) {
return false;
}
if (p_point.y < position.y) {
return false;
}
if (p_point.x >= (position.x + size.x)) {
return false;
}
if (p_point.y >= (position.y + size.y)) {
return false;
}
return true;
}
bool operator==(const RegionRect2i &p_rect) const
{
return position == p_rect.position && size == p_rect.size;
}
bool operator!=(const RegionRect2i &p_rect) const
{
return position != p_rect.position || size != p_rect.size;
}
RegionRect2i grow(int p_by) const
{
RegionRect2i g = *this;
g.position.x -= p_by;
g.position.y -= p_by;
g.size.width += p_by * 2;
g.size.height += p_by * 2;
return g;
}
inline RegionRect2i grow_margin(Margin p_margin, int p_amount) const
{
RegionRect2i g = *this;
g = g.grow_individual((MARGIN_LEFT == p_margin) ? p_amount : 0,
(MARGIN_TOP == p_margin) ? p_amount : 0,
(MARGIN_RIGHT == p_margin) ? p_amount : 0,
(MARGIN_BOTTOM == p_margin) ? p_amount :
0);
return g;
}
inline RegionRect2i grow_individual(int p_left, int p_top, int p_right,
int p_bottom) const
{
RegionRect2i g = *this;
g.position.x -= p_left;
g.position.y -= p_top;
g.size.width += p_left + p_right;
g.size.height += p_top + p_bottom;
return g;
}
_FORCE_INLINE_ RegionRect2i expand(const Vector2i &p_vector) const
{
RegionRect2i r = *this;
r.expand_to(p_vector);
return r;
}
inline void expand_to(const Point2i &p_vector)
{
Point2i begin = position;
Point2i end = position + size;
if (p_vector.x < begin.x) {
begin.x = p_vector.x;
}
if (p_vector.y < begin.y) {
begin.y = p_vector.y;
}
if (p_vector.x > end.x) {
end.x = p_vector.x;
}
if (p_vector.y > end.y) {
end.y = p_vector.y;
}
position = begin;
size = end - begin;
}
operator String() const
{
return String(position) + ", " + String(size);
}
operator Rect2() const
{
return Rect2(position, size);
}
RegionRect2i(const Rect2 &p_r2)
: position(p_r2.position)
, size(p_r2.size)
{
}
RegionRect2i(const Rect2i &p_r2)
: position(p_r2.position)
, size(p_r2.size)
{
}
RegionRect2i()
{
}
RegionRect2i(int p_x, int p_y, int p_width, int p_height)
: position(Point2(p_x, p_y))
, size(Size2(p_width, p_height))
{
}
RegionRect2i(const Point2 &p_pos, const Size2 &p_size)
: position(p_pos)
, size(p_size)
{
}
};
#endif // REGION_RECT2_H_

View File

@@ -2,17 +2,40 @@
#include <cassert>
#include <core/ustring.h>
#include <core/list.h>
#include <core/hashfuncs.h>
#include <core/hash_map.h>
#include "region_tree.h"
void region_tree::split(const List<struct region> &regions)
void region_tree::split(flecs::entity grid_floor_e,
const List<struct region> &regions)
{
assert(children.size() == 0);
const region_tree *base_rtree = grid_floor_e.get<region_tree>();
const List<struct region>::Element *e = regions.front();
int count = 0;
assert(base_rtree->check(grid_floor_e));
while (e) {
flecs::log::warn(
"%lx: %s -> %s", region.region_et,
(region.rect.operator String()).ascii().ptr(),
(e->get().rect.operator String()).ascii().ptr());
assert(region.rect.encloses(e->get().rect));
struct region_tree *child = memnew(struct region_tree);
child->parent = this;
child->region = e->get();
children.push_back(child);
base_rtree->dump(grid_floor_e);
flecs::log::dbg(
"added region: %d: %s", count,
(child->region.rect.operator String()).ascii().ptr());
if (!base_rtree->check(grid_floor_e))
flecs::log::err(
"bad region %d: %s: %s", count,
(region.rect.operator String()).ascii().ptr(),
(e->get().rect.operator String()).ascii().ptr());
base_rtree->dump(grid_floor_e);
assert(base_rtree->check(grid_floor_e));
count++;
e = e->next();
}
}
@@ -40,6 +63,8 @@ region_tree *region_tree::find(flecs::entity_t which)
queue.push_back(this);
while (!queue.empty()) {
struct region_tree *item = queue.front()->get();
flecs::log::dbg("check %lx == %lx", item->region.region_et,
which);
if (item->region.region_et == which)
return item;
queue.pop_front();
@@ -62,11 +87,12 @@ void region_tree::dump(flecs::entity grid_floor_e) const
int i;
for (i = 0; i < tabs; i++)
stabs += "\t";
flecs::log::warn("%sregion: %s", stabs.ascii().ptr(),
flecs::log::warn("%sregion: %s: %lx", stabs.ascii().ptr(),
grid_floor_e.world()
.entity(item->region.region_et)
.path()
.c_str());
.c_str(),
item->region.region_et);
flecs::log::warn(
"%srect: %s", stabs.ascii().ptr(),
(item->region.rect.operator String()).ascii().ptr());
@@ -76,13 +102,20 @@ void region_tree::dump(flecs::entity grid_floor_e) const
}
}
void region_tree::grow()
void region_tree::grow(flecs::entity grid_floor_e)
{
List<struct region_tree *> grow_list;
List<struct region_tree *> queue;
List<struct region_tree *>::Element *e, *e1;
const struct region_tree *base_rtree = grid_floor_e.get<region_tree>();
assert(base_rtree);
#ifdef TESTS
flecs::log::warn("grow");
#endif
if (region.complete)
queue.push_back(this);
else
flecs::log::warn("incomplete");
while (!queue.empty()) {
int i;
struct region_tree *item = queue.front()->get();
@@ -95,26 +128,65 @@ void region_tree::grow()
queue.push_back(item->children[i]);
}
}
assert(base_rtree->check(grid_floor_e));
flecs::log::warn("grow list: %d", grow_list.size());
int grow_count = 0;
queue.clear();
struct pointer_hasher {
static _FORCE_INLINE_ uint32_t hash(void *ptr)
{
return hash_one_uint64((uint64_t)ptr);
}
};
HashMap<struct region_tree *, int, pointer_hasher> state;
while (1) {
e = grow_list.front();
int amount = 0;
while (e) {
struct region_tree *item = e->get();
flecs::log::warn(
"item: %s",
(item->region.rect.operator String()).ascii().ptr());
flecs::log::warn("item: %s",
(item->region.rect.operator String())
.ascii()
.ptr());
if (!item->region.can_grow) {
e = e->next();
flecs::log::err("can't grow");
continue;
}
RegionRect2i candidate = item->region.rect.grow(1);
if (!state.has(item))
state[item] = 0;
RegionRect2i candidate = item->region.rect;
switch (state[item]) {
case 0:
candidate = item->region.rect.grow(1);
break;
case 1:
candidate = item->region.rect;
candidate.size.x += 1;
break;
case 2:
candidate = item->region.rect;
candidate.size.y += 1;
break;
case 3:
candidate = item->region.rect;
candidate.position.x -= 1;
candidate.size.x += 1;
break;
case 4:
candidate = item->region.rect;
candidate.position.y -= 1;
candidate.size.y += 1;
break;
default:
state[item]++;
}
e1 = grow_list.front();
bool ok = true;
while (e1) {
struct region_tree *check_item = e1->get();
if (item != check_item) {
flecs::log::warn("check item: %s candidate: %s",
flecs::log::warn(
"check item: %s candidate: %s",
(check_item->region.rect
.operator String())
.ascii()
@@ -122,7 +194,8 @@ void region_tree::grow()
(candidate.operator String())
.ascii()
.ptr());
if (!check_item->check_candidate(candidate)) {
if (!check_item->check_candidate(
candidate)) {
ok = false;
flecs::log::err("check failed");
break;
@@ -131,180 +204,153 @@ void region_tree::grow()
e1 = e1->next();
}
if (ok) {
struct region backup = item->region;
item->update_candidate(candidate);
amount++;
if (!base_rtree->check(grid_floor_e)) {
item->region = backup;
flecs::log::err(
"can't update candidate (after checking all rects)");
if (state[item] == 0)
item->region.can_grow_square =
false;
state[item]++;
}
assert(base_rtree->check(grid_floor_e));
} else {
flecs::log::err("can't update candidate");
if (state[item] == 0)
item->region.can_grow_square = false;
state[item]++;
}
if (item->region.remains_area < -2) {
item->region.can_grow = false;
item->region.can_grow_square = false;
item->region.complete = true;
}
grow_count++;
if (item->region.can_grow && state[item] < 5)
queue.push_back(item);
else {
item->region.can_grow = false;
item->region.complete = true;
}
e = e->next();
assert(base_rtree->check(grid_floor_e));
}
#if 0
assert(false);
if (region.complete)
if (queue.empty())
break;
while (!queue.empty()) {
grow_list.push_back(queue.front()->get());
queue.pop_front();
}
queue.clear();
assert(base_rtree->check(grid_floor_e));
}
}
bool region_tree::check(flecs::entity grid_floor_e) const
{
List<const struct region_tree *> queue;
assert(!parent);
Vector<RegionRect2i> check_regions;
Vector<RegionRect2i> root_regions;
int i, j;
if (children.size() == 0)
return true;
int grid_size = grid_floor_e
.get<WorldEditor::components::
buildings_layout_grid_floor>()
->grid_size;
for (i = 0; i < children.size(); i++)
root_regions.push_back(children[i]->region.rect);
flecs::log::dbg("root regions count: %d", root_regions.size());
queue.push_back(this);
while (!queue.empty()) {
struct region_tree *item = queue.front()->get();
const struct region_tree *item = queue.front()->get();
queue.pop_front();
if (item->region.can_grow || item->region.can_grow_square)
continue;
int i, j;
int amount = 0;
amount = 0;
for (i = 0; i < (int)item->children.size(); i++) {
if (item->children[i]->region.can_grow_square) {
RegionRect2i candidate =
item->children[i]->region.rect.grow(1);
if (!item->region.rect.encloses(candidate)) {
item->children.write[i]
->region.can_grow_square =
false;
continue;
if (item->is_leaf()) {
const RegionRect2i &rect = item->region.rect;
check_regions.push_back(rect);
}
bool ok = item->check_candidate(i, candidate);
if (ok) {
item->children.write[i]
->update_candidate(candidate);
amount++;
} else
item->children.write[i]
->region.can_grow_square =
false;
}
}
if (amount > 0) /* try again later */
queue.push_back(item);
#if 0
for (i = 0; i < (int)item->children.size(); i++) {
if (!can_grow_square)
item->children.write[i]
->region.can_grow_square =
false;
}
while (can_grow) {
amount = 0;
for (i = 0; i < (int)item->children.size();
i++) {
if (!item->children[i]->region.can_grow)
continue;
int orig_area =
item->children[i]
->region.rect.get_area();
RegionRect2i candidate =
item->children[i]->region.rect;
candidate.size.x += 1;
if (!item->region.rect.encloses(
candidate))
continue;
bool ok = item->check_candidate(
i, candidate);
if (ok) {
item->children.write[i]
->update_candidate(
candidate);
amount++;
}
}
for (i = 0; i < (int)item->children.size();
i++) {
if (!item->children[i]->region.can_grow)
continue;
int orig_area =
item->children[i]
->region.rect.get_area();
RegionRect2i candidate =
item->children[i]->region.rect;
candidate.size.x += 1;
candidate.position.x -= 1;
if (!item->region.rect.encloses(
candidate))
continue;
bool ok = item->check_candidate(
i, candidate);
if (ok) {
item->children.write[i]
->update_candidate(
candidate);
amount++;
}
}
for (i = 0; i < (int)item->children.size();
i++) {
if (!item->children[i]->region.can_grow)
continue;
int orig_area =
item->children[i]
->region.rect.get_area();
RegionRect2i candidate =
item->children[i]->region.rect;
candidate.size.y += 1;
if (!item->region.rect.encloses(
candidate))
continue;
bool ok = item->check_candidate(
i, candidate);
if (ok) {
item->children.write[i]
->update_candidate(
candidate);
amount++;
}
}
for (i = 0; i < (int)item->children.size();
i++) {
if (!item->children[i]->region.can_grow)
continue;
int orig_area =
item->children[i]
->region.rect.get_area();
RegionRect2i candidate =
item->children[i]->region.rect;
candidate.size.y += 1;
candidate.position.y -= 1;
if (!item->region.rect.encloses(
candidate))
continue;
bool ok = item->check_candidate(
i, candidate);
if (ok) {
item->children.write[i]
->update_candidate(
candidate);
amount++;
}
}
for (i = 0; i < (int)item->children.size();
i++) {
if (item->children[i]
->region.remains_area <
-100) {
item->children[i]
->region.can_grow =
false;
item->children[i]
->region.complete =
true;
}
}
if (amount == 0)
can_grow = false;
}
#endif
for (i = 0; i < (int)item->children.size(); i++) {
queue.push_back(item->children[i]);
}
}
flecs::log::dbg("regions to check: %d", check_regions.size());
for (i = 0; i < (int)root_regions.size(); i++)
flecs::log::dbg(
"root region: %d %s", i,
(root_regions[i].operator String()).ascii().ptr());
for (i = 0; i < (int)check_regions.size(); i++)
flecs::log::dbg(
"check region: %d %s", i,
(check_regions[i].operator String()).ascii().ptr());
int ok = true;
for (i = 0; i < (int)check_regions.size(); i++) {
if (!region.rect.encloses(check_regions[i])) {
flecs::log::err("region is not inside parent");
ok = false;
break;
}
#endif
}
if (root_regions.size() > 0) {
for (i = 0; i < (int)check_regions.size(); i++) {
int count = 0;
if (root_regions.find(check_regions[i]) >= 0)
continue;
for (j = 0; j < (int)root_regions.size(); j++)
if (root_regions[j].encloses(check_regions[i]))
count++;
if (count == 0) {
flecs::log::err(
"region is out of root regions");
ok = false;
break;
}
}
}
if (!ok)
return ok;
for (i = 0; i < (int)check_regions.size(); i++) {
for (j = 0; j < (int)check_regions.size(); j++) {
if (i == j)
continue;
if (check_regions[i].intersects(check_regions[j]))
ok = false;
if (check_regions[i].encloses(check_regions[j]))
ok = false;
if (check_regions[j].encloses(check_regions[i]))
ok = false;
if (!ok)
break;
}
if (!ok)
break;
}
if (!ok)
flecs::log::err(
"some leaf regions intersect other leaf regions");
return ok;
}
void region_tree::place(flecs::entity grid_floor_e) const
{
int i, j;
int i, j, k;
assert(!parent);
List<const struct region_tree *> queue;
int grid_size = grid_floor_e
.get<WorldEditor::components::
buildings_layout_grid_floor>()
->grid_size;
LocalVector<flecs::entity> delete_cells;
grid_floor_e.children([&delete_cells](flecs::entity e) {
if (e.has<WorldEditor::components::buildings_layout_grid_cell>())
delete_cells.push_back(e);
});
for (i = 0; i < (int)delete_cells.size(); i++)
delete_cells[i].destruct();
delete_cells.clear();
#if 0
for (i = region.rect.position.x;
i < region.rect.position.x + region.rect.size.x; i++)
for (j = region.rect.position.y;
@@ -316,6 +362,39 @@ void region_tree::place(flecs::entity grid_floor_e) const
if (cell_e.is_valid())
cell_e.destruct();
}
#endif
queue.push_back(this);
bool result = true;
while (!queue.empty()) {
const struct region_tree *item = queue.front()->get();
queue.pop_front();
if (item->is_leaf()) {
const RegionRect2i &rect = item->region.rect;
for (i = rect.position.x;
i < rect.position.x + rect.size.x; i++) {
for (j = rect.position.y;
j < rect.position.y + rect.size.y; j++) {
int cell_id = i + grid_size * j;
result = check_cell(
grid_floor_e,
item->region.parent,
item->region.region_et,
cell_id);
if (!result)
break;
}
if (!result)
break;
}
}
if (!result)
break;
for (i = 0; i < (int)item->children.size(); i++) {
queue.push_back(item->children[i]);
}
}
assert(result);
queue.clear();
queue.push_back(this);
while (!queue.empty()) {
const struct region_tree *item = queue.front()->get();
@@ -324,8 +403,8 @@ void region_tree::place(flecs::entity grid_floor_e) const
const RegionRect2i &rect = item->region.rect;
for (i = rect.position.x;
i < rect.position.x + rect.size.x; i++)
for (j = rect.position.x;
j < rect.position.x + rect.size.x; j++) {
for (j = rect.position.y;
j < rect.position.y + rect.size.y; j++) {
int cell_id = i + grid_size * j;
update_cell(grid_floor_e,
item->region.parent,
@@ -337,6 +416,31 @@ void region_tree::place(flecs::entity grid_floor_e) const
queue.push_back(item->children[i]);
}
}
for (i = 0; i < children.size(); i++) {
for (j = children[i]->region.rect.position.x;
j < children[i]->region.rect.position.x +
children[i]->region.rect.size.x;
j++)
for (k = children[i]->region.rect.position.y;
k < children[i]->region.rect.position.y +
children[i]->region.rect.size.y;
k++) {
int id = j + grid_size * k;
String cname("cell_" + itos(id));
flecs::entity cell_e = grid_floor_e.lookup(
cname.ascii().ptr());
if (cell_e.is_valid())
continue;
#if 0
update_cell(grid_floor_e,
grid_floor_e.parent().id(),
grid_floor_e.id(), id);
#endif
create_corridoor_cell(
grid_floor_e,
grid_floor_e.parent().id(), id);
}
}
}
void region_tree::get_rects(List<RegionRect2i> *rect_list) const
@@ -451,6 +555,63 @@ flecs::entity region_tree::update_cell(flecs::entity grid_floor_e,
return cell_e;
}
flecs::entity region_tree::create_corridoor_cell(flecs::entity grid_floor_e,
flecs::entity_t parent_et,
int id) const
{
// flecs::entity region_e = grid_floor_e.world().entity(region_et);
flecs::entity parent_e = grid_floor_e.world().entity(parent_et);
String pname("cell_" + itos(id));
flecs::entity cell_e = grid_floor_e.lookup(pname.ascii().ptr());
if (!cell_e.is_valid()) {
flecs::log::warn("creating new cell %s", pname.ascii().ptr());
cell_e = grid_floor_e.world()
.entity(pname.ascii().ptr())
.child_of(grid_floor_e);
assert(cell_e.is_valid());
}
// assert(cell_e.has<WorldEditor::components::belongs>(parent_e));
/* already there */
grid_floor_e
.get_mut<WorldEditor::components::buildings_layout_grid_floor>()
->cells.insert(id);
grid_floor_e.modified<
WorldEditor::components::buildings_layout_grid_floor>();
cell_e.set<WorldEditor::components::buildings_layout_grid_cell>(
{ "corridoor", id });
cell_e.add<WorldEditor::components::corridoor>();
return cell_e;
}
bool region_tree::check_cell(flecs::entity grid_floor_e,
flecs::entity_t parent_et,
flecs::entity_t region_et, int id) const
{
flecs::entity region_e = grid_floor_e.world().entity(region_et);
flecs::entity parent_e = grid_floor_e.world().entity(parent_et);
flecs::log::dbg("check_cell: %s %d", region_e.path().c_str(), id);
String pname("cell_" + itos(id));
flecs::entity cell_e = grid_floor_e.lookup(pname.ascii().ptr());
if (!cell_e.is_valid())
return true;
int mcount = 0;
if (region_e.has<WorldEditor::components::buildings_layout_room>()) {
cell_e.each<WorldEditor::components::belongs_room>(
[&mcount, region_e, cell_e](flecs::entity e) {
flecs::log::err(
"while adding region %s to cell %s",
region_e.path().c_str(),
cell_e.path().c_str());
flecs::log::err("already belongs to %s",
e.path().c_str());
mcount++;
});
}
if (mcount == 0)
return true;
return false;
}
void region_tree::update_candidate(const RegionRect2i &candidate)
{
int orig_area = region.rect.get_area();

View File

@@ -6,7 +6,8 @@ struct region_tree {
struct region region;
Vector<struct region_tree *> children;
struct region_tree *parent;
void split(const List<struct region> &regions);
void split(flecs::entity grid_floor_e,
const List<struct region> &regions);
const struct region_tree *find(flecs::entity_t which) const;
struct region_tree *find(flecs::entity_t which);
bool is_leaf() const
@@ -14,7 +15,8 @@ struct region_tree {
return children.size() == 0;
}
void dump(flecs::entity grid_floor_e) const;
void grow();
void grow(flecs::entity grid_floor_e);
bool check(flecs::entity grid_floor_e) const;
void place(flecs::entity grid_floor_e) const;
void get_rects(List<RegionRect2i> *rect_list) const;
@@ -24,6 +26,11 @@ private:
flecs::entity update_cell(flecs::entity grid_floor_e,
flecs::entity_t parent_et,
flecs::entity_t region_et, int id) const;
flecs::entity create_corridoor_cell(flecs::entity grid_floor_e,
flecs::entity_t parent_et,
int id) const;
bool check_cell(flecs::entity grid_floor_e, flecs::entity_t parent_et,
flecs::entity_t region_et, int id) const;
void update_candidate(const RegionRect2i &candidate);
};
#endif // REGION_TREE_H_

View File

@@ -123,6 +123,7 @@ public:
struct border {};
struct belongs_room {};
struct outside_wall {};
struct corridoor {};
struct buildings_layout_grid_floor {
Set<int> cells;
int grid_size;

View File

@@ -1,9 +1,12 @@
all: graph_test entity_test rect2i regions
LIBS=
SDL_LIBS=$(shell pkg-config sdl2 --libs)
SDL_CFLAGS=$(shell pkg-config sdl2 --cflags)
IMGUI_OBJS= ./imgui/imgui.o ./imgui/imgui_draw.o ./imgui/imgui_tables.o ./imgui/imgui_widgets.o ./imgui/imgui_impl_sdlrenderer2.o ./imgui/imgui_impl_sdl2.o
# LIBS= ./godot_mockery/libgodot-mockery.a
CFLAGS = -I../src/flecs/distr -g
CXXFLAGS = -I../src/flecs/distr -I../src/modules/stream/ui -I./godot_mockery -I../src/godot -I../src/godot/platform/x11 -I. -I../src/modules/stream -g
CFLAGS = -I../src/flecs/distr $(SDL_CFLAGS) -I./cglm/include -I./flecs-game/include -g
CXXFLAGS = -I../src/flecs/distr -I../src/modules/stream/ui -I./godot_mockery -I../src/godot -I../src/godot/platform/x11 -I. -I../src/modules/stream -I./imgui $(SDL_CFLAGS) -g
#CXXFLAGS = -I../src/flecs/distr -I../src/modules/stream/ui -I../src/godot -I../src/godot/platform/x11 -I. -I../src/modules/stream -g
graph_test: graph_module.o flecs.o $(LIBS)
@@ -20,8 +23,14 @@ rect2i: rect2i.o $(LIBS)
region_tree.o: ../src/modules/stream/ui/region_tree.cpp
$(CC) $(CFLAGS) $(CXXFLAGS) -DTESTS -o $@ -c $<
regions: regions.o flecs.o region_tree.o godot_mockery/core/os/memory.o godot_mockery/core/ustring.o $(LIBS)
$(CXX) -o $@ regions.o flecs.o region_tree.o godot_mockery/core/os/memory.o godot_mockery/core/ustring.o $(LIBS)
#graph_module_growth.o: ../src/modules/stream/ui/graph_module_growth.cpp
# $(CC) $(CFLAGS) $(CXXFLAGS) -DTESTS -o $@ -c $<
#
#graph_module_core.o: ../src/modules/stream/ui/graph_module.cpp
# $(CC) $(CFLAGS) $(CXXFLAGS) -DTESTS -o $@ -c $<
regions: regions.o flecs.o region_tree.o godot_mockery/core/os/memory.o godot_mockery/core/ustring.o $(SDL_LIBS) $(IMGUI_OBJS) $(LIBS)
$(CXX) -o $@ regions.o flecs.o region_tree.o godot_mockery/core/os/memory.o godot_mockery/core/ustring.o $(IMGUI_OBJS) $(LIBS) $(SDL_LIBS)
MOCK_OBJS=godot_mockery/core/os/memory.o godot_mockery/core/error_macros.o \
godot_mockery/core/ustring.o godot_mockery/core/array.o \
@@ -58,7 +67,7 @@ godot_mockery/core/math/%.o: ../src/godot/core/math/%.cpp
$(CC) $(CFLAGS) $(CXXFLAGS) -DTESTS -o $@ -c $<
clean:
rm -f godot_mockery/core/*.o godot_mockery/core/os/*.o *.o graph_test entity_test rect2i regions
rm -f godot_mockery/core/*.o godot_mockery/core/os/*.o *.o graph_test entity_test rect2i regions $(FLECS_OBJS)
.PHONY: all clean

View File

@@ -460,4 +460,72 @@ String String::num_int64(int64_t p_num, int base, bool capitalize_hex) {
return s;
}
uint32_t String::hash(const char *p_cstr) {
uint32_t hashv = 5381;
uint32_t c;
while ((c = *p_cstr++)) {
hashv = ((hashv << 5) + hashv) + c; /* hash * 33 + c */
}
return hashv;
}
uint32_t String::hash(const char *p_cstr, int p_len) {
uint32_t hashv = 5381;
for (int i = 0; i < p_len; i++) {
hashv = ((hashv << 5) + hashv) + p_cstr[i]; /* hash * 33 + c */
}
return hashv;
}
uint32_t String::hash(const CharType *p_cstr, int p_len) {
uint32_t hashv = 5381;
for (int i = 0; i < p_len; i++) {
hashv = ((hashv << 5) + hashv) + p_cstr[i]; /* hash * 33 + c */
}
return hashv;
}
uint32_t String::hash(const CharType *p_cstr) {
uint32_t hashv = 5381;
uint32_t c;
while ((c = *p_cstr++)) {
hashv = ((hashv << 5) + hashv) + c; /* hash * 33 + c */
}
return hashv;
}
uint32_t String::hash() const {
/* simple djb2 hashing */
const CharType *chr = c_str();
uint32_t hashv = 5381;
uint32_t c;
while ((c = *chr++)) {
hashv = ((hashv << 5) + hashv) + c; /* hash * 33 + c */
}
return hashv;
}
uint64_t String::hash64() const {
/* simple djb2 hashing */
const CharType *chr = c_str();
uint64_t hashv = 5381;
uint64_t c;
while ((c = *chr++)) {
hashv = ((hashv << 5) + hashv) + c; /* hash * 33 + c */
}
return hashv;
}

View File

@@ -1,18 +1,45 @@
#include "../src/modules/stream/ui/region_tree.h"
#include "../src/modules/stream/ui/grid_misc.h"
#include "../src/modules/stream/world_editor.h"
#include "../src/modules/stream/ui/queries.h"
#include "../src/modules/stream/ui/building_layout_graph.h"
#include "imgui.h"
#include "imgui_impl_sdl2.h"
#include "imgui_impl_sdlrenderer2.h"
#include <SDL.h>
#include <SDL_opengl.h>
using graph_module = BuildingLayoutGraph::graph_module;
int main()
{
int i;
SDL_Window *window = NULL;
SDL_Surface *screenSurface = NULL;
SDL_Renderer *renderer;
SDL_WindowFlags window_flags;
ImVec4 clear_color = ImVec4(0.45f, 0.55f, 0.60f, 1.00f);
HashMap<String, Color> colors;
make_random r(172);
flecs::world ecs;
ecs.component<WorldEditor::components::buildings_layout_grid_floor>();
ecs.component<WorldEditor::components::buildings_layout_grid_cell>();
flecs::log::set_level(1);
flecs::entity graph_base_e = ecs.entity("graph");
flecs::entity graph_e = ecs.entity("v1").child_of(graph_base_e);
flecs::entity grid_base_e = ecs.entity("grid");
flecs::entity grid_e = ecs.entity("v1").child_of(grid_base_e);
flecs::entity grid_floor_e = ecs.entity("floor_0").child_of(grid_e);
int grid_size = 27;
grid_floor_e.set<WorldEditor::components::buildings_layout_grid_floor>({.grid_size = grid_size, .size_left = grid_size * grid_size});
List<struct region> region_list;
struct region region;
region.region_et = graph_e.id();
region.rect = RegionRect2i(0, 0, 25, 25);
region.rect = RegionRect2i(1, 1, grid_size - 2, grid_size - 2);
region.complete = true;
region.can_grow = false;
region.can_grow_square = false;
struct region_tree regions;
regions.region = region;
regions.dump(grid_floor_e);
@@ -20,9 +47,32 @@ int main()
zone2_e = ecs.entity("zone2").child_of(graph_e),
zone3_e = ecs.entity("zone3").child_of(graph_e);
struct region region_data[] = {
{.region_et = zone1_e.id(), .rect = {0, 0, 1, 1}},
{.region_et = zone2_e.id(), .rect = {2, 2, 1, 1}},
{.region_et = zone3_e.id(), .rect = {4, 4, 1 ,1}}
{
.parent = graph_e.id(),
.region_et = zone1_e.id(),
.rect = {4, 4, 1, 1},
.remains_area = 140,
.can_grow_square = true,
.can_grow = true,
.complete = false
},
{
.parent = graph_e.id(),
.region_et = zone2_e.id(),
.rect = {4, 9, 1, 1},
.remains_area = 80,
.can_grow_square = true,
.can_grow = true,
.complete = false},
{
.parent = graph_e.id(),
.region_et = zone3_e.id(),
.rect = {20, 15, 1 ,1},
.remains_area = 50,
.can_grow_square = true,
.can_grow = true,
.complete = false
}
};
for (i = 0; i < sizeof(region_data) / sizeof(region_data[0]); i++)
region_list.push_back(region_data[i]);
@@ -30,6 +80,109 @@ int main()
regions.dump(grid_floor_e);
regions.grow();
regions.dump(grid_floor_e);
regions.place(grid_floor_e);
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER | SDL_INIT_GAMECONTROLLER) < 0)
goto out;
#ifdef SDL_HINT_IME_SHOW_UI
SDL_SetHint(SDL_HINT_IME_SHOW_UI, "1");
#endif
window_flags = (SDL_WindowFlags)(SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI);
window = SDL_CreateWindow("RegionTest", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 1280, 1024, window_flags);
if (window == NULL)
goto out;
renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_PRESENTVSYNC | SDL_RENDERER_ACCELERATED);
if (!renderer)
goto out;
// screenSurface = SDL_GetWindowSurface(window);
// if (!screenSurface)
// goto out;
IMGUI_CHECKVERSION();
ImGui::CreateContext();
{
ImGuiIO& io = ImGui::GetIO(); (void)io;
io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls
io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls
}
// Setup Dear ImGui style
ImGui::StyleColorsDark();
//ImGui::StyleColorsLight();
// Setup Platform/Renderer backends
ImGui_ImplSDL2_InitForSDLRenderer(window, renderer);
ImGui_ImplSDLRenderer2_Init(renderer);
// SDL_FillRect(screenSurface, NULL, SDL_MapRGB(screenSurface->format, 0xFF, 0xFF, 0xFF));
// SDL_UpdateWindowSurface(window);
SDL_Event event;
while(1) {
SDL_PollEvent(&event);
ImGui_ImplSDL2_ProcessEvent(&event);
switch(event.type) {
case SDL_QUIT:
goto shutdown;
break;
case SDL_WINDOWEVENT:
if (event.window.event == SDL_WINDOWEVENT_CLOSE && event.window.windowID == SDL_GetWindowID(window))
goto shutdown;
break;
default:
break;
}
ecs.progress();
if (SDL_GetWindowFlags(window) & SDL_WINDOW_MINIMIZED) {
SDL_Delay(10);
continue;
}
ImGui_ImplSDLRenderer2_NewFrame();
ImGui_ImplSDL2_NewFrame();
ImGui::NewFrame();
{
ImGui::Begin("Hello, world!"); // Create a window called "Hello, world!" and append into it.
ImGui::Text("This is some useful text."); // Display some text (you can use a format strings too)
ImGui::End();
}
ImGui::Render();
{
ImGuiIO& io = ImGui::GetIO(); (void)io;
SDL_RenderSetScale(renderer, io.DisplayFramebufferScale.x, io.DisplayFramebufferScale.y);
}
SDL_SetRenderDrawColor(renderer, (Uint8)(clear_color.x * 255), (Uint8)(clear_color.y * 255), (Uint8)(clear_color.z * 255), (Uint8)(clear_color.w * 255));
SDL_RenderClear(renderer);
ecs.query_builder<const WorldEditor::components::buildings_layout_grid_cell>()
.build().each([grid_size, renderer, &colors, &r](flecs::entity e, const WorldEditor::components::buildings_layout_grid_cell &cell)
{
// flecs::log::warn("cell: %s: %s: %d", e.path().c_str(), cell.type.ascii().ptr(), cell.index);
int x = cell.index % grid_size;
int y = cell.index / grid_size;
int px = 1280 * x / grid_size;
int py = 1024 * y / grid_size;
int w = 1280 / grid_size;
int h = 1024 / grid_size;
// flecs::log::warn("position: %d %d", x, y);
if (!colors.has(cell.type))
colors[cell.type] = Color((float)(r.get() % 256) / 256.0f, (float)(r.get() % 256) / 256.0f, (float)(r.get() % 256) / 256.0f, 1.0f);
const Color &c = colors[cell.type];
SDL_SetRenderDrawColor(renderer, (uint8_t)(c.r * 255), (uint8_t)(c.g * 255), (uint8_t)(c.b * 255), 255);
SDL_Rect rect = {px, py, w, h};
SDL_RenderFillRect(renderer, &rect);
SDL_SetRenderDrawColor(renderer, 255, 15, 15, 255);
SDL_RenderDrawRect(renderer, &rect);
});
ImGui_ImplSDLRenderer2_RenderDrawData(ImGui::GetDrawData(), renderer);
SDL_RenderPresent(renderer);
}
shutdown:
ImGui_ImplSDLRenderer2_Shutdown();
ImGui_ImplSDL2_Shutdown();
ImGui::DestroyContext();
SDL_DestroyRenderer(renderer);
SDL_DestroyWindow(window);
SDL_Quit();
out:
return 0;
}