Initial commit
This commit is contained in:
9
modules/meshops/SCsub
Normal file
9
modules/meshops/SCsub
Normal file
@@ -0,0 +1,9 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
Import('env')
|
||||
from compat import isbasestring
|
||||
|
||||
# Godot source files
|
||||
env.add_source_files(env.modules_sources, "*.cpp")
|
||||
|
||||
Export('env')
|
||||
BIN
modules/meshops/__pycache__/config.cpython-38.pyc
Normal file
BIN
modules/meshops/__pycache__/config.cpython-38.pyc
Normal file
Binary file not shown.
BIN
modules/meshops/__pycache__/config.cpython-39.pyc
Normal file
BIN
modules/meshops/__pycache__/config.cpython-39.pyc
Normal file
Binary file not shown.
BIN
modules/meshops/a.out
Executable file
BIN
modules/meshops/a.out
Executable file
Binary file not shown.
100
modules/meshops/city_grid.h
Normal file
100
modules/meshops/city_grid.h
Normal file
@@ -0,0 +1,100 @@
|
||||
#ifndef CITY_GRID_H
|
||||
#define CITY_GRID_H
|
||||
#include <core/hash_map.h>
|
||||
#include <modules/voxel/util/math/vector3i.h>
|
||||
class TownGridData {
|
||||
protected:
|
||||
struct shape_data {
|
||||
Ref<Shape> shape;
|
||||
Transform shape_xform;
|
||||
};
|
||||
struct cell_item {
|
||||
String name;
|
||||
AABB aabb;
|
||||
Transform xform;
|
||||
Dictionary data;
|
||||
};
|
||||
Vector<cell_item> items;
|
||||
HashMap<Vector3i, int, Vector3iHasher> grid;
|
||||
Vector3 origin;
|
||||
Vector3 scale;
|
||||
public:
|
||||
void set_origin(const Vector3 &pos)
|
||||
{
|
||||
origin = pos;
|
||||
}
|
||||
void set_scale(const Vector3 &pos)
|
||||
{
|
||||
scale = pos;
|
||||
}
|
||||
Vector3i pos_to_grid(const Vector3 &pos)
|
||||
{
|
||||
Vector3i ret;
|
||||
ret.x = (int)(((pos.x - origin.x) / + scale.x * 0.5f) / scale.x);
|
||||
ret.y = (int)(((pos.y - origin.y) / + scale.y * 0.5f) / scale.y);
|
||||
ret.z = (int)(((pos.z - origin.z) / + scale.z * 0.5f) / scale.z);
|
||||
return ret;
|
||||
}
|
||||
Vector3 grid_to_pos(int x, int y, int z)
|
||||
{
|
||||
Vector3 ret;
|
||||
ret.x = (float)x * scale.x - scale.x * 0.5f + origin.x;
|
||||
ret.y = (float)y * scale.y - scale.y * 0.5f + origin.y;
|
||||
ret.z = (float)z * scale.z - scale.z * 0.5f + origin.z;
|
||||
return ret;
|
||||
}
|
||||
bool grid_can_place(const AABB &place, const Transform &xform)
|
||||
{
|
||||
Transform xform_inv = xform.affine_inverse();
|
||||
AABB xplace = xform.xform(place);
|
||||
int i, j, k, x1, y1, z1, x2, y2, z2;
|
||||
Vector3i a = pos_to_grid(xplace.position);
|
||||
Vector3i b = pos_to_grid(xplace.position + xplace.size);
|
||||
x1 = MIN(a.x, b.x);
|
||||
y1 = MIN(a.y, b.y);
|
||||
z1 = MIN(a.z, b.z);
|
||||
x2 = MAX(a.x, b.x);
|
||||
y2 = MAX(a.y, b.y);
|
||||
z2 = MAX(a.z, b.z);
|
||||
for (i = x1; i < x2; i++)
|
||||
for (j = y1; j < y2; j++)
|
||||
for (k = z1; k < z2; k++) {
|
||||
Vector3 key(i, j, k);
|
||||
Vector3 pos = grid_to_pos(i, j, k);
|
||||
Vector3 pos_inv = xform_inv.xform(pos);
|
||||
if (place.has_point(pos_inv) && grid.has(key))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
void grid_place(const StringName &name, const AABB &place, const Transform &xform)
|
||||
{
|
||||
int id = items.size();
|
||||
struct cell_item it;
|
||||
it.name = name;
|
||||
it.aabb = place;
|
||||
it.xform = xform;
|
||||
items.push_back(it);
|
||||
Transform xform_inv = xform.affine_inverse();
|
||||
AABB xplace = xform.xform(place);
|
||||
int i, j, k, x1, y1, z1, x2, y2, z2;
|
||||
Vector3i a = pos_to_grid(xplace.position);
|
||||
Vector3i b = pos_to_grid(xplace.position + xplace.size);
|
||||
x1 = MIN(a.x, b.x);
|
||||
y1 = MIN(a.y, b.y);
|
||||
z1 = MIN(a.z, b.z);
|
||||
x2 = MAX(a.x, b.x);
|
||||
y2 = MAX(a.y, b.y);
|
||||
z2 = MAX(a.z, b.z);
|
||||
for (i = x1; i < x2; i++)
|
||||
for (j = y1; j < y2; j++)
|
||||
for (k = z1; k < z2; k++) {
|
||||
Vector3 key(i, j, k);
|
||||
Vector3 pos = grid_to_pos(i, j, k);
|
||||
Vector3 pos_inv = xform_inv.xform(pos);
|
||||
if (place.has_point(pos_inv))
|
||||
grid[key] = id;
|
||||
}
|
||||
}
|
||||
};
|
||||
#endif
|
||||
5
modules/meshops/config.py
Normal file
5
modules/meshops/config.py
Normal file
@@ -0,0 +1,5 @@
|
||||
def can_build(env, platform):
|
||||
return True
|
||||
|
||||
def configure(env):
|
||||
pass
|
||||
34
modules/meshops/functor.h
Normal file
34
modules/meshops/functor.h
Normal file
@@ -0,0 +1,34 @@
|
||||
#ifndef FUNCTOR_H
|
||||
#define FUNCTOR_H
|
||||
template <class T, class S>
|
||||
struct functor {
|
||||
void *obj;
|
||||
typedef void (T::*_memfunc)(S);
|
||||
_memfunc func;
|
||||
functor(void *obj, _memfunc func)
|
||||
{
|
||||
this->obj = obj;
|
||||
this->func = func;
|
||||
}
|
||||
functor()
|
||||
{
|
||||
obj = 0;
|
||||
}
|
||||
operator bool() const
|
||||
{
|
||||
return !!obj;
|
||||
}
|
||||
void operator()(S item)
|
||||
{
|
||||
run(*this, item);
|
||||
}
|
||||
static void run(functor &ftor, S item)
|
||||
{
|
||||
T *obj = (T *)ftor.obj;
|
||||
_memfunc func = ftor.func;
|
||||
(obj->*func)(item);
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
82
modules/meshops/meshops.cpp
Normal file
82
modules/meshops/meshops.cpp
Normal file
@@ -0,0 +1,82 @@
|
||||
#include "meshops.h"
|
||||
|
||||
MeshOps *MeshOps::get_singleton()
|
||||
{
|
||||
static MeshOps *mo = NULL;
|
||||
if (!mo)
|
||||
mo = memnew(MeshOps);
|
||||
return mo;
|
||||
}
|
||||
|
||||
Array MeshOps::merge_meshes(const Array &surfaces, const Array &xforms) const
|
||||
{
|
||||
int i;
|
||||
Array ret;
|
||||
ret.resize(Mesh::ARRAY_MAX);
|
||||
int surface_count = surfaces.size();
|
||||
PoolVector<int> cur_index;
|
||||
PoolVector<Vector3> cur_vertex;
|
||||
PoolVector<Vector3> cur_normal;
|
||||
PoolVector<Vector2> cur_uv;
|
||||
for (i = 0; i < surface_count; i++) {
|
||||
int icount, count, j, k, st;
|
||||
const Array &sts = surfaces[i];
|
||||
for (st = 0; st < sts.size(); st++) {
|
||||
const Array &s = sts[st];
|
||||
const PoolVector<int> &index = s[Mesh::ARRAY_INDEX];
|
||||
const PoolVector<Vector3> &vertex =
|
||||
s[Mesh::ARRAY_VERTEX];
|
||||
const PoolVector<Vector3> &normal =
|
||||
s[Mesh::ARRAY_NORMAL];
|
||||
const PoolVector<Vector2> &uv = s[Mesh::ARRAY_TEX_UV];
|
||||
icount = cur_index.size();
|
||||
count = cur_vertex.size();
|
||||
const Transform &xform = xforms[i];
|
||||
for (j = 0; j < Mesh::ARRAY_MAX; j++) {
|
||||
switch (j) {
|
||||
case Mesh::ARRAY_INDEX:
|
||||
cur_index.append_array(index);
|
||||
for (k = 0; k < index.size(); k++)
|
||||
cur_index.write()[k + icount] =
|
||||
cur_index.read()[k +
|
||||
icount] +
|
||||
count;
|
||||
break;
|
||||
case Mesh::ARRAY_VERTEX:
|
||||
cur_vertex.append_array(vertex);
|
||||
for (k = 0; k < vertex.size(); k++)
|
||||
cur_vertex.write()[k + count] =
|
||||
xform.xform(
|
||||
cur_vertex.read()
|
||||
[k +
|
||||
count]);
|
||||
break;
|
||||
case Mesh::ARRAY_NORMAL:
|
||||
cur_normal.append_array(normal);
|
||||
/* all sizes except index are the same */
|
||||
for (k = 0; k < vertex.size(); k++)
|
||||
cur_normal.write()[k + count] =
|
||||
xform.basis.xform(
|
||||
cur_normal.read()
|
||||
[k +
|
||||
count]);
|
||||
break;
|
||||
case Mesh::ARRAY_TEX_UV:
|
||||
cur_uv.append_array(uv);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ret[Mesh::ARRAY_INDEX] = cur_index;
|
||||
ret[Mesh::ARRAY_VERTEX] = cur_vertex;
|
||||
ret[Mesh::ARRAY_NORMAL] = cur_normal;
|
||||
ret[Mesh::ARRAY_TEX_UV] = cur_uv;
|
||||
return ret;
|
||||
}
|
||||
|
||||
void MeshOps::_bind_methods()
|
||||
{
|
||||
ClassDB::bind_method(D_METHOD("merge_meshes", "surfaces", "xforms"),
|
||||
&MeshOps::merge_meshes);
|
||||
}
|
||||
|
||||
17
modules/meshops/meshops.h
Normal file
17
modules/meshops/meshops.h
Normal file
@@ -0,0 +1,17 @@
|
||||
#ifndef MESHOPS_H
|
||||
#define MESHOPS_H
|
||||
#include <core/reference.h>
|
||||
#include <scene/resources/mesh.h>
|
||||
#include <scene/resources/material.h>
|
||||
|
||||
class MeshOps: public Reference {
|
||||
GDCLASS(MeshOps, Reference)
|
||||
protected:
|
||||
static void _bind_methods();
|
||||
public:
|
||||
static MeshOps *get_singleton();
|
||||
Array merge_meshes(const Array &surfaces, const Array &xforms) const;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
BIN
modules/meshops/meshops.x11.opt.tools.64.o
Normal file
BIN
modules/meshops/meshops.x11.opt.tools.64.o
Normal file
Binary file not shown.
96
modules/meshops/queue.cpp
Normal file
96
modules/meshops/queue.cpp
Normal file
@@ -0,0 +1,96 @@
|
||||
#include <cstdio>
|
||||
#include "queue.h"
|
||||
|
||||
DelayedQueue::DelayedQueue()
|
||||
{
|
||||
default_func = "";
|
||||
default_obj = NULL;
|
||||
}
|
||||
|
||||
void DelayedQueue::_bind_methods()
|
||||
{
|
||||
ClassDB::bind_method(D_METHOD("push_back", "item"),
|
||||
&DelayedQueue::push_back);
|
||||
ClassDB::bind_method(D_METHOD("push_front", "item"),
|
||||
&DelayedQueue::push_front);
|
||||
ClassDB::bind_method(D_METHOD("pop_front"),
|
||||
&DelayedQueue::pop_front);
|
||||
ClassDB::bind_method(D_METHOD("push_back_delayed", "item"),
|
||||
&DelayedQueue::push_back_delayed);
|
||||
ClassDB::bind_method(D_METHOD("register_callback", "item_name", "obj", "func"),
|
||||
&DelayedQueue::register_callback);
|
||||
ClassDB::bind_method(D_METHOD("register_default_callback", "obj", "func"),
|
||||
&DelayedQueue::register_default_callback);
|
||||
ClassDB::bind_method(D_METHOD("unregister_callback", "item_name"),
|
||||
&DelayedQueue::unregister_callback);
|
||||
ClassDB::bind_method(D_METHOD("process"),
|
||||
&DelayedQueue::process);
|
||||
}
|
||||
|
||||
void DelayedQueue::push_back(const Dictionary &data)
|
||||
{
|
||||
queue.push_back(data);
|
||||
}
|
||||
|
||||
void DelayedQueue::push_front(const Dictionary &data)
|
||||
{
|
||||
queue.push_front(data);
|
||||
}
|
||||
|
||||
Dictionary DelayedQueue::pop_front()
|
||||
{
|
||||
Dictionary ret = queue[0];
|
||||
queue.pop_front();
|
||||
return ret;
|
||||
}
|
||||
|
||||
void DelayedQueue::push_back_delayed(const Dictionary &data)
|
||||
{
|
||||
queue_delayed.push_back(data);
|
||||
}
|
||||
|
||||
void DelayedQueue::register_callback(const StringName &item_name, Object *obj, const StringName &func)
|
||||
{
|
||||
struct _reg r;
|
||||
r.name = item_name;
|
||||
r.obj = obj;
|
||||
r.func = func;
|
||||
reg[item_name] = r;
|
||||
}
|
||||
void DelayedQueue::register_default_callback(Object *obj, const StringName &func)
|
||||
{
|
||||
default_obj = obj;
|
||||
default_func = func;
|
||||
}
|
||||
void DelayedQueue::unregister_callback(const StringName &item_name)
|
||||
{
|
||||
reg.erase(item_name);
|
||||
}
|
||||
|
||||
void DelayedQueue::process()
|
||||
{
|
||||
while (queue.size() > 0 || queue_delayed.size() > 0) {
|
||||
if (queue.size() == 0) {
|
||||
queue.push_back(queue_delayed[0]);
|
||||
queue_delayed.pop_front();
|
||||
}
|
||||
const Dictionary &item = queue[0];
|
||||
const String &name = item["name"];
|
||||
if (callbacks.has(name)) {
|
||||
functor<Object, const Dictionary &> f = callbacks[name];
|
||||
f(item);
|
||||
}
|
||||
else if (reg.has(name))
|
||||
reg[name].obj->call(reg[name].func, item);
|
||||
else {
|
||||
if (default_callback) {
|
||||
functor<Object, const Dictionary &> f = default_callback;
|
||||
f(item);
|
||||
}
|
||||
if (default_obj)
|
||||
default_obj->call(default_func, item);
|
||||
}
|
||||
queue.pop_front();
|
||||
}
|
||||
}
|
||||
|
||||
45
modules/meshops/queue.h
Normal file
45
modules/meshops/queue.h
Normal file
@@ -0,0 +1,45 @@
|
||||
#ifndef QUEUE_H
|
||||
#define QUEUE_H
|
||||
#include <core/reference.h>
|
||||
#include <core/object.h>
|
||||
#include "functor.h"
|
||||
class DelayedQueue: public Reference {
|
||||
GDCLASS(DelayedQueue, Reference)
|
||||
protected:
|
||||
List<Dictionary> queue;
|
||||
List<Dictionary> queue_delayed;
|
||||
static void _bind_methods();
|
||||
struct _reg {
|
||||
String name;
|
||||
Object * obj;
|
||||
String func;
|
||||
};
|
||||
HashMap<String, struct _reg> reg;
|
||||
String default_func;
|
||||
Object *default_obj;
|
||||
HashMap<String, functor<Object, const Dictionary &> > callbacks;
|
||||
functor<Object, const Dictionary &> default_callback;
|
||||
|
||||
public:
|
||||
void push_back(const Dictionary &data);
|
||||
void push_front(const Dictionary &data);
|
||||
Dictionary pop_front();
|
||||
void push_back_delayed(const Dictionary &data);
|
||||
void register_callback(const StringName &item_name, Object *obj, const StringName &func);
|
||||
void register_callback_native(const StringName &item_name, Object *obj, void(Object::*func)(const Dictionary &item))
|
||||
{
|
||||
functor<Object, const Dictionary &> f(obj, func);
|
||||
callbacks[item_name] = f;
|
||||
}
|
||||
void register_default_callback_native(Object *obj, void(Object::*func)(const Dictionary& item))
|
||||
{
|
||||
functor<Object, const Dictionary &> f(obj, func);
|
||||
default_callback = f;
|
||||
}
|
||||
void register_default_callback(Object *obj, const StringName &func);
|
||||
void unregister_callback(const StringName &item_name);
|
||||
void process();
|
||||
DelayedQueue();
|
||||
};
|
||||
#endif
|
||||
|
||||
BIN
modules/meshops/queue.x11.opt.tools.64.o
Normal file
BIN
modules/meshops/queue.x11.opt.tools.64.o
Normal file
Binary file not shown.
27
modules/meshops/register_types.cpp
Normal file
27
modules/meshops/register_types.cpp
Normal file
@@ -0,0 +1,27 @@
|
||||
#include <core/engine.h>
|
||||
|
||||
#include "register_types.h"
|
||||
#include "meshops.h"
|
||||
#include "town.h"
|
||||
#include "queue.h"
|
||||
#include "town_queue.h"
|
||||
|
||||
void register_meshops_types()
|
||||
{
|
||||
ClassDB::register_class<DelayedQueue>();
|
||||
ClassDB::register_class<TownQueue>();
|
||||
ClassDB::register_class<GenExteriorSet>();
|
||||
ClassDB::register_class<GenInteriorSet>();
|
||||
ClassDB::register_class<GenBuildingSet>();
|
||||
ClassDB::register_class<GenRoadSet>();
|
||||
ClassDB::register_class<GenCitySet>();
|
||||
ClassDB::register_class<MeshItemList>();
|
||||
ClassDB::register_class<MeshOps>();
|
||||
Engine::get_singleton()->add_singleton(
|
||||
Engine::Singleton("MeshOps",
|
||||
MeshOps::get_singleton()));
|
||||
}
|
||||
void unregister_meshops_types()
|
||||
{
|
||||
}
|
||||
|
||||
6
modules/meshops/register_types.h
Normal file
6
modules/meshops/register_types.h
Normal file
@@ -0,0 +1,6 @@
|
||||
#ifndef MESHOPS_REGISTER_TYPES_H
|
||||
#define MESHOPS_REGISTER_TYPES_H
|
||||
void register_meshops_types();
|
||||
void unregister_meshops_types();
|
||||
#endif
|
||||
|
||||
BIN
modules/meshops/register_types.x11.opt.tools.64.o
Normal file
BIN
modules/meshops/register_types.x11.opt.tools.64.o
Normal file
Binary file not shown.
548
modules/meshops/town.cpp
Normal file
548
modules/meshops/town.cpp
Normal file
@@ -0,0 +1,548 @@
|
||||
#include "town.h"
|
||||
|
||||
void MeshItemList::add_item(const StringName &item_name, Ref<Mesh> mesh)
|
||||
{
|
||||
struct mesh_data item;
|
||||
int surface_count = 0, i;
|
||||
item.item_name = item_name;
|
||||
item.mesh = mesh;
|
||||
Array surfaces;
|
||||
Vector<Ref<Material> > materials;
|
||||
surface_count = mesh->get_surface_count();
|
||||
surfaces.resize(surface_count);
|
||||
materials.resize(surface_count);
|
||||
for (i = 0; i < surface_count; i++) {
|
||||
surfaces[i] = mesh->surface_get_arrays(i);
|
||||
Ref<Material> mat = mesh->surface_get_material(i);
|
||||
materials.write[i] = mat;
|
||||
}
|
||||
|
||||
item.mesh_surfaces = surfaces;
|
||||
item.materials = materials;
|
||||
item_list[item_name] = item;
|
||||
}
|
||||
void MeshItemList::remove_item(const StringName &item_name)
|
||||
{
|
||||
item_list.erase(item_name);
|
||||
}
|
||||
|
||||
const Array &MeshItemList::get_item_arrays(const StringName &item_name) const
|
||||
{
|
||||
const Array &ret = item_list[item_name].mesh_surfaces;
|
||||
return ret;
|
||||
}
|
||||
|
||||
Ref<Mesh> MeshItemList::get_item_mesh(const StringName &item_name) const
|
||||
{
|
||||
return item_list[item_name].mesh;
|
||||
}
|
||||
|
||||
void MeshItemList::_bind_methods()
|
||||
{
|
||||
ClassDB::bind_method(D_METHOD("add_item", "item_name", "mesh"),
|
||||
&MeshItemList::add_item);
|
||||
ClassDB::bind_method(D_METHOD("remove_item", "item_name"),
|
||||
&MeshItemList::remove_item);
|
||||
ClassDB::bind_method(D_METHOD("get_item_arrays", "item_name"),
|
||||
&MeshItemList::get_item_arrays);
|
||||
ClassDB::bind_method(D_METHOD("get_item_mesh", "item_name"),
|
||||
&MeshItemList::get_item_mesh);
|
||||
}
|
||||
|
||||
void GenCitySet::set_guildhall_building_set(const Ref<GenBuildingSet> set)
|
||||
{
|
||||
guildhall_building_set = set;
|
||||
}
|
||||
|
||||
Ref<GenBuildingSet> GenCitySet::get_guildhall_building_set() const
|
||||
{
|
||||
return guildhall_building_set;
|
||||
}
|
||||
void GenCitySet::set_court_building_set(const Ref<GenBuildingSet> set)
|
||||
{
|
||||
court_building_set = set;
|
||||
}
|
||||
Ref<GenBuildingSet> GenCitySet::get_court_building_set() const
|
||||
{
|
||||
return court_building_set;
|
||||
}
|
||||
void GenCitySet::set_road_set(const Ref<GenRoadSet> set)
|
||||
{
|
||||
road_set = set;
|
||||
}
|
||||
Ref<GenRoadSet> GenCitySet::get_road_set() const
|
||||
{
|
||||
return road_set;
|
||||
}
|
||||
void GenCitySet::set_building_sets(const Array &sets)
|
||||
{
|
||||
building_sets = sets;
|
||||
}
|
||||
const Array &GenCitySet::get_building_sets() const
|
||||
{
|
||||
return building_sets;
|
||||
}
|
||||
void GenCitySet::set_center_radius(float radius)
|
||||
{
|
||||
center_radius = radius;
|
||||
}
|
||||
float GenCitySet::get_center_radius() const
|
||||
{
|
||||
return center_radius;
|
||||
}
|
||||
void GenCitySet::set_radius(float radius)
|
||||
{
|
||||
this->radius = radius;
|
||||
}
|
||||
float GenCitySet::get_radius() const
|
||||
{
|
||||
return radius;
|
||||
}
|
||||
void GenCitySet::set_min_buildings(int minb)
|
||||
{
|
||||
min_buildings = minb;
|
||||
}
|
||||
int GenCitySet::get_min_buildings() const
|
||||
{
|
||||
return min_buildings;
|
||||
}
|
||||
void GenCitySet::set_max_buildings(int maxb)
|
||||
{
|
||||
max_buildings = maxb;
|
||||
}
|
||||
int GenCitySet::get_max_buildings() const
|
||||
{
|
||||
return max_buildings;
|
||||
}
|
||||
Dictionary GenCitySet::get_items() const
|
||||
{
|
||||
Dictionary ret;
|
||||
int i;
|
||||
Vector<Ref<Resource> > sets;
|
||||
sets.push_back(guildhall_building_set);
|
||||
sets.push_back(court_building_set);
|
||||
for (i = 0; i < building_sets.size(); i++) {
|
||||
Ref<Resource> d = building_sets[i];
|
||||
sets.push_back(d);
|
||||
}
|
||||
for (i = 0; i < sets.size(); i++) {
|
||||
if (!sets[i].ptr())
|
||||
continue;
|
||||
ret[sets[i]->get("house_type")] = sets[i]->get("items");
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
/*
|
||||
void GenCitySet::_set_data(const Dictionary &data)
|
||||
{
|
||||
ERR_FAIL_COND(!data.has("gh_building_set"]);
|
||||
ERR_FAIL_COND(!data.has("ct_building_set"]);
|
||||
ERR_FAIL_COND(!data.has("building_sets"]);
|
||||
ERR_FAIL_COND(!data.has("center_radius"]);
|
||||
ERR_FAIL_COND(!data.has["radius"]);
|
||||
ERR_FAIL_COND(!data.has["min_buildings"]);
|
||||
ERR_FAIL_COND(!data.has["max_buildings"]);
|
||||
|
||||
guildhall_building_set = data["gh_building_set"];
|
||||
court_building_set = data["ct_building_set"];
|
||||
building_sets = data["building_sets"];
|
||||
center_radius = data["center_radius"];
|
||||
radius = data["radius"];
|
||||
min_buildings = data["min_buildings"];
|
||||
max_buildings = data["max_buildings"];
|
||||
}
|
||||
Dictionary GenCitySet::_get_data() const
|
||||
{
|
||||
Dictionary x;
|
||||
x["gh_building_set"] = guildhall_building_set;
|
||||
x["ct_building_set"] = court_building_set;
|
||||
x["building_sets"] = building_sets;
|
||||
x["center_radius"] = center_radius;
|
||||
x["radius"] = radius;
|
||||
x["min_buildings"] = min_buildings;
|
||||
x["max_buildings"] = max_buildings;
|
||||
return x;
|
||||
}
|
||||
*/
|
||||
|
||||
void GenCitySet::_bind_methods()
|
||||
{
|
||||
ClassDB::bind_method(D_METHOD("set_guildhall_building_set", "set"), &GenCitySet::set_guildhall_building_set);
|
||||
ClassDB::bind_method(D_METHOD("get_guildhall_building_set"), &GenCitySet::get_guildhall_building_set);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("set_court_building_set", "set"), &GenCitySet::set_court_building_set);
|
||||
ClassDB::bind_method(D_METHOD("get_court_building_set"), &GenCitySet::get_court_building_set);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("set_road_set", "set"), &GenCitySet::set_road_set);
|
||||
ClassDB::bind_method(D_METHOD("get_road_set"), &GenCitySet::get_road_set);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("set_building_sets", "set"), &GenCitySet::set_building_sets);
|
||||
ClassDB::bind_method(D_METHOD("get_building_sets"), &GenCitySet::get_building_sets);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("set_center_radius", "radius"), &GenCitySet::set_center_radius);
|
||||
ClassDB::bind_method(D_METHOD("get_center_radius"), &GenCitySet::get_center_radius);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("set_radius", "radius"), &GenCitySet::set_radius);
|
||||
ClassDB::bind_method(D_METHOD("get_radius"), &GenCitySet::get_radius);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("set_min_buildings", "minb"), &GenCitySet::set_min_buildings);
|
||||
ClassDB::bind_method(D_METHOD("get_min_buildings"), &GenCitySet::get_min_buildings);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("set_max_buildings", "maxb"), &GenCitySet::set_max_buildings);
|
||||
ClassDB::bind_method(D_METHOD("get_max_buildings"), &GenCitySet::get_max_buildings);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("get_items"), &GenCitySet::get_items);
|
||||
// ClassDB::bind_method(D_METHOD("_set_data", "data"), &GenCitySet::_set_data);
|
||||
// ClassDB::bind_method(D_METHOD("_get_data"), &GenCitySet::_get_data);
|
||||
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "guildhall_building_set", PROPERTY_HINT_RESOURCE_TYPE, "GenBuildingSet"), "set_guildhall_building_set", "get_guildhall_building_set");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "court_building_set", PROPERTY_HINT_RESOURCE_TYPE, "GenBuildingSet"), "set_court_building_set", "get_court_building_set");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "road_set", PROPERTY_HINT_RESOURCE_TYPE, "GenRoadSet"), "set_road_set", "get_road_set");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "building_sets", PROPERTY_HINT_RESOURCE_TYPE, "17/17:GenBuildingSet"), "set_building_sets", "get_building_sets");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::REAL, "center_radius"), "set_center_radius", "get_center_radius");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::REAL, "radius"), "set_radius", "get_radius");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::INT, "min_buildings"), "set_min_buildings", "get_min_buildings");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::INT, "max_buildings"), "set_max_buildings", "get_max_buildings");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "items"), "", "get_items");
|
||||
// ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "data", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE|PROPERTY_USAGE_NOEDITOR|PROPERTY_USAGE_INTERNAL), "_set_data", "_get_data");
|
||||
}
|
||||
|
||||
GenExteriorSet::GenExteriorSet()
|
||||
{
|
||||
_data["external_wall"] = Ref<ArrayMesh>(NULL);
|
||||
_data["external_wall_half"] = Ref<ArrayMesh>(NULL);
|
||||
_data["external_doorway"] = Ref<ArrayMesh>(NULL);
|
||||
_data["external_window"] = Ref<ArrayMesh>(NULL);
|
||||
_data["external_angle"] = Ref<ArrayMesh>(NULL);
|
||||
_data["roof_main"] = Ref<ArrayMesh>(NULL);
|
||||
_data["roof_side_left"] = Ref<ArrayMesh>(NULL);
|
||||
_data["roof_side_right"] = Ref<ArrayMesh>(NULL);
|
||||
_data["roof_side_left_block"] = Ref<ArrayMesh>(NULL);
|
||||
_data["roof_side_right_block"] = Ref<ArrayMesh>(NULL);
|
||||
xmap["xwall"] = "external_wall";
|
||||
xmap["xwallh"] = "external_wall_half";
|
||||
xmap["xdoor"] = "external_doorway";
|
||||
xmap["xwindow"] = "external_window";
|
||||
xmap["xangle"] = "external_angle";
|
||||
xmap["external_wall"] = "xwall";
|
||||
xmap["external_wall_half"] = "xwallh";
|
||||
xmap["external_doorway"] = "xdoor";
|
||||
xmap["external_window"] = "xwindow";
|
||||
xmap["external_angle"] = "xangle";
|
||||
}
|
||||
bool GenExteriorSet::_set(const StringName &name, const Variant &property)
|
||||
{
|
||||
if (_data.has(name)) {
|
||||
_data[name] = property;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
bool GenExteriorSet::_get(const StringName &name, Variant &property) const
|
||||
{
|
||||
if(_data.has(name)) {
|
||||
property = _data[name];
|
||||
return true;
|
||||
} else if (name == "items") {
|
||||
Dictionary ret;
|
||||
List<String> keys;
|
||||
_data.get_key_list(&keys);
|
||||
List<String>::Element *e;
|
||||
for (e = keys.front(); e; e = e->next()) {
|
||||
String k = e->get();
|
||||
Dictionary d;
|
||||
d["mesh"] = _data[k];
|
||||
if (xmap.has(k))
|
||||
ret[xmap[k]] = d;
|
||||
else
|
||||
ret[k] = d;
|
||||
}
|
||||
property = ret;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
void GenExteriorSet::_get_property_list(List<PropertyInfo> *plist) const
|
||||
{
|
||||
List<String> keys;
|
||||
_data.get_key_list(&keys);
|
||||
List<String>::Element *e;
|
||||
|
||||
for (e = keys.front(); e; e = e->next()) {
|
||||
plist->push_back(PropertyInfo(Variant::OBJECT, e->get(), PROPERTY_HINT_RESOURCE_TYPE, "ArrayMesh", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SCRIPT_VARIABLE));
|
||||
}
|
||||
plist->push_back(PropertyInfo(Variant::DICTIONARY, "items", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SCRIPT_VARIABLE));
|
||||
}
|
||||
|
||||
GenInteriorSet::GenInteriorSet()
|
||||
{
|
||||
_data["wall"] = Ref<ArrayMesh>(NULL);
|
||||
_data["wall_half"] = Ref<ArrayMesh>(NULL);
|
||||
_data["doorway"] = Ref<ArrayMesh>(NULL);
|
||||
_data["window"] = Ref<ArrayMesh>(NULL);
|
||||
_data["internal_angle"] = Ref<ArrayMesh>(NULL);
|
||||
_data["interior_floor"] = Ref<ArrayMesh>(NULL);
|
||||
_data["interior_ceiling"] = Ref<ArrayMesh>(NULL);
|
||||
xmap["iwall"] = "wall";
|
||||
xmap["iwallh"] = "wall_half";
|
||||
xmap["idoor"] = "doorway";
|
||||
xmap["iwindow"] = "window";
|
||||
xmap["iangle"] = "internal_angle";
|
||||
xmap["floor"] = "interior_floor";
|
||||
xmap["ceiling"] = "interior_ceiling";
|
||||
xmap["wall"] = "iwall";
|
||||
xmap["wall_half"] = "iwallh";
|
||||
xmap["doorway"] = "idoor";
|
||||
xmap["window"] = "iwindow";
|
||||
xmap["internal_angle"] = "iangle";
|
||||
xmap["interior_floor"] = "floor";
|
||||
xmap["interior_ceiling"] = "ceiling";
|
||||
}
|
||||
bool GenInteriorSet::_set(const StringName &name, const Variant &property)
|
||||
{
|
||||
if (_data.has(name)) {
|
||||
_data[name] = property;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
bool GenInteriorSet::_get(const StringName &name, Variant &property) const
|
||||
{
|
||||
if(_data.has(name)) {
|
||||
property = _data[name];
|
||||
return true;
|
||||
} else if (name == "items") {
|
||||
Dictionary ret;
|
||||
List<String> keys;
|
||||
_data.get_key_list(&keys);
|
||||
List<String>::Element *e;
|
||||
for (e = keys.front(); e; e = e->next()) {
|
||||
String k = e->get();
|
||||
Dictionary d;
|
||||
d["mesh"] = _data[k];
|
||||
if (xmap.has(k))
|
||||
ret[xmap[k]] = d;
|
||||
else
|
||||
ret[k] = d;
|
||||
}
|
||||
property = ret;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
void GenInteriorSet::_get_property_list(List<PropertyInfo> *plist) const
|
||||
{
|
||||
List<String> keys;
|
||||
_data.get_key_list(&keys);
|
||||
List<String>::Element *e;
|
||||
|
||||
for (e = keys.front(); e; e = e->next()) {
|
||||
plist->push_back(PropertyInfo(Variant::OBJECT, e->get(), PROPERTY_HINT_RESOURCE_TYPE, "ArrayMesh", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SCRIPT_VARIABLE));
|
||||
}
|
||||
plist->push_back(PropertyInfo(Variant::DICTIONARY, "items", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SCRIPT_VARIABLE));
|
||||
}
|
||||
|
||||
GenBuildingSet::GenBuildingSet()
|
||||
{
|
||||
_datas["house_type"] = String();
|
||||
_datai["min_wings"] = 1;
|
||||
_datai["max_wings"] = 1;
|
||||
_datai["min_wing_size_x"] = 4;
|
||||
_datai["min_wing_size_z"] = 4;
|
||||
_datai["max_wing_size_x"] = 8;
|
||||
_datai["max_wing_size_z"] = 8;
|
||||
_dataf["pwindow"] = 0.6f;
|
||||
_dataf["pmidwall"] = 0.2f;
|
||||
_dataf["wing_offset"] = 0.0f;
|
||||
_datar["exterior_set"] = Ref<GenExteriorSet>(NULL);
|
||||
_datar["interior_set"] = Ref<GenInteriorSet>(NULL);
|
||||
_datar["furniture_set"] = Ref<GenFurnitureSet>(NULL);
|
||||
}
|
||||
bool GenBuildingSet::_set(const StringName &name, const Variant &property)
|
||||
{
|
||||
if (_datas.has(name)) {
|
||||
_datas[name] = property;
|
||||
return true;
|
||||
} else if (_datai.has(name)) {
|
||||
_datai[name] = property;
|
||||
return true;
|
||||
} else if (_dataf.has(name)) {
|
||||
_dataf[name] = property;
|
||||
return true;
|
||||
} else if (_datar.has(name)) {
|
||||
_datar[name] = property;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
bool GenBuildingSet::_get(const StringName &name, Variant &property) const
|
||||
{
|
||||
if (_datas.has(name)) {
|
||||
property = _datas[name];
|
||||
return true;
|
||||
} else if (_datai.has(name)) {
|
||||
property = _datai[name];
|
||||
return true;
|
||||
} else if (_dataf.has(name)) {
|
||||
property = _dataf[name];
|
||||
return true;
|
||||
} else if (_datar.has(name)) {
|
||||
property = _datar[name];
|
||||
return true;
|
||||
} else if (name == "items") {
|
||||
Dictionary ret;
|
||||
List<String> res;
|
||||
res.push_back("exterior_set");
|
||||
res.push_back("interior_set");
|
||||
res.push_back("furniture_set");
|
||||
List<String>::Element *rd;
|
||||
for (rd = res.front(); rd; rd = rd->next()) {
|
||||
List<Variant> keys;
|
||||
Ref<Resource> mr = _datar[rd->get()];
|
||||
if (!mr.ptr())
|
||||
continue;
|
||||
Dictionary md = mr->get("items");
|
||||
if (md.empty())
|
||||
continue;
|
||||
md.get_key_list(&keys);
|
||||
List<Variant>::Element *e;
|
||||
for (e = keys.front(); e; e = e->next()) {
|
||||
String k = e->get();
|
||||
ret[k] = md[k];
|
||||
}
|
||||
}
|
||||
property = ret;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
void GenBuildingSet::_get_property_list(List<PropertyInfo> *plist) const
|
||||
{
|
||||
List<String> keys;
|
||||
_datas.get_key_list(&keys);
|
||||
_datai.get_key_list(&keys);
|
||||
_dataf.get_key_list(&keys);
|
||||
_datar.get_key_list(&keys);
|
||||
List<String>::Element *e;
|
||||
HashMap<String, String> hints;
|
||||
HashMap<String, Variant::Type> types;
|
||||
hints["exterior_set"] = "GenExteriorSet";
|
||||
hints["interior_set"] = "GenInteriorSet";
|
||||
hints["furniture_set"] = "GenFurnitureSet";
|
||||
types["house_type"] = Variant::STRING;
|
||||
types["min_wings"] = Variant::INT;
|
||||
types["max_wings"] = Variant::INT;
|
||||
types["min_wing_size_x"] = Variant::INT;
|
||||
types["min_wing_size_z"] = Variant::INT;
|
||||
types["max_wing_size_x"] = Variant::INT;
|
||||
types["max_wing_size_z"] = Variant::INT;
|
||||
types["pwindow"] = Variant::REAL;
|
||||
types["pmidwall"] = Variant::REAL;
|
||||
types["wing_offset"] = Variant::REAL;
|
||||
|
||||
for (e = keys.front(); e; e = e->next()) {
|
||||
String pname = e->get();
|
||||
if (hints.has(pname))
|
||||
plist->push_back(PropertyInfo(Variant::OBJECT, pname,
|
||||
PROPERTY_HINT_RESOURCE_TYPE,
|
||||
hints[pname],
|
||||
PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SCRIPT_VARIABLE));
|
||||
else if (types.has(pname))
|
||||
plist->push_back(PropertyInfo(types[pname],
|
||||
pname, PROPERTY_HINT_NONE,
|
||||
"",
|
||||
PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SCRIPT_VARIABLE));
|
||||
}
|
||||
plist->push_back(PropertyInfo(Variant::DICTIONARY, "items", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SCRIPT_VARIABLE));
|
||||
}
|
||||
|
||||
GenRoadSet::GenRoadSet()
|
||||
{
|
||||
_data["road_segment_short"] = Ref<ArrayMesh>(NULL);
|
||||
_data["road_segment_long"] = Ref<ArrayMesh>(NULL);
|
||||
_data["road_turn_left"] = Ref<ArrayMesh>(NULL);
|
||||
_data["road_turn_right"] = Ref<ArrayMesh>(NULL);
|
||||
_data["road_turn_left2"] = Ref<ArrayMesh>(NULL);
|
||||
_data["road_turn_right2"] = Ref<ArrayMesh>(NULL);
|
||||
_data["road_y"] = Ref<ArrayMesh>(NULL);
|
||||
_data["road_t"] = Ref<ArrayMesh>(NULL);
|
||||
_data["road_x"] = Ref<ArrayMesh>(NULL);
|
||||
segment_length = segment_width =
|
||||
short_segment_length =
|
||||
turn_angle = turn_angle2 = 0.0f;
|
||||
}
|
||||
|
||||
void GenRoadSet::_get_property_list(List<PropertyInfo> *plist) const
|
||||
{
|
||||
List<String> keys;
|
||||
_data.get_key_list(&keys);
|
||||
List<String>::Element *e;
|
||||
|
||||
for (e = keys.front(); e; e = e->next()) {
|
||||
plist->push_back(PropertyInfo(Variant::OBJECT, e->get(), PROPERTY_HINT_RESOURCE_TYPE, "ArrayMesh", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SCRIPT_VARIABLE));
|
||||
}
|
||||
plist->push_back(PropertyInfo(Variant::REAL, "segment_length", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SCRIPT_VARIABLE));
|
||||
plist->push_back(PropertyInfo(Variant::REAL, "short_segment_length", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SCRIPT_VARIABLE));
|
||||
plist->push_back(PropertyInfo(Variant::REAL, "turn_angle", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SCRIPT_VARIABLE));
|
||||
plist->push_back(PropertyInfo(Variant::REAL, "turn_angle2", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SCRIPT_VARIABLE));
|
||||
plist->push_back(PropertyInfo(Variant::DICTIONARY, "items", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SCRIPT_VARIABLE));
|
||||
}
|
||||
|
||||
bool GenRoadSet::_set(const StringName &name, const Variant &property)
|
||||
{
|
||||
if (_data.has(name)) {
|
||||
_data[name] = property;
|
||||
return true;
|
||||
} else if (name == "segment_length") {
|
||||
segment_length = property;
|
||||
return true;
|
||||
} else if (name == "short_segment_length") {
|
||||
short_segment_length = property;
|
||||
return true;
|
||||
} else if (name == "turn_angle") {
|
||||
turn_angle = property;
|
||||
return true;
|
||||
} else if (name == "turn_angle2") {
|
||||
turn_angle2 = property;
|
||||
return true;
|
||||
} else if (name == "segment_width") {
|
||||
segment_width = property;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
bool GenRoadSet::_get(const StringName &name, Variant &property) const
|
||||
{
|
||||
if(_data.has(name)) {
|
||||
property = _data[name];
|
||||
return true;
|
||||
} else if (name == "items") {
|
||||
Dictionary ret;
|
||||
List<String> keys;
|
||||
_data.get_key_list(&keys);
|
||||
List<String>::Element *e;
|
||||
for (e = keys.front(); e; e = e->next()) {
|
||||
String k = e->get();
|
||||
Dictionary d;
|
||||
d["mesh"] = _data[k];
|
||||
ret[k] = d;
|
||||
}
|
||||
property = ret;
|
||||
return true;
|
||||
} else if (name == "segment_length") {
|
||||
property = segment_length;
|
||||
return true;
|
||||
} else if (name == "short_segment_length") {
|
||||
property = short_segment_length;
|
||||
return true;
|
||||
} else if (name == "turn_angle") {
|
||||
property = turn_angle;
|
||||
return true;
|
||||
} else if (name == "turn_angle2") {
|
||||
property = turn_angle2;
|
||||
return true;
|
||||
} else if (name == "segment_width") {
|
||||
property = segment_width;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
119
modules/meshops/town.h
Normal file
119
modules/meshops/town.h
Normal file
@@ -0,0 +1,119 @@
|
||||
#ifndef TOWN_H
|
||||
#define TOWN_H
|
||||
#include <core/reference.h>
|
||||
#include <scene/resources/mesh.h>
|
||||
#include <scene/resources/material.h>
|
||||
|
||||
// #include "city_grid.h"
|
||||
|
||||
class MeshItemList: public Reference {
|
||||
GDCLASS(MeshItemList, Reference)
|
||||
protected:
|
||||
static void _bind_methods();
|
||||
private:
|
||||
struct mesh_data {
|
||||
Ref<Mesh> mesh;
|
||||
Array mesh_surfaces;
|
||||
Vector<Ref<Material> > materials;
|
||||
StringName item_name;
|
||||
};
|
||||
HashMap<String, struct mesh_data> item_list;
|
||||
public:
|
||||
void add_item(const StringName &item_name, Ref<Mesh> mesh);
|
||||
void remove_item(const StringName &item_name);
|
||||
const Array &get_item_arrays(const StringName &item_name) const;
|
||||
Ref<Mesh> get_item_mesh(const StringName &item_name) const;
|
||||
};
|
||||
|
||||
class GenBuildingSet;
|
||||
class GenRoadSet;
|
||||
|
||||
class GenCitySet: public Resource {
|
||||
GDCLASS(GenCitySet, Resource)
|
||||
protected:
|
||||
static void _bind_methods();
|
||||
Ref<GenBuildingSet> guildhall_building_set;
|
||||
Ref<GenBuildingSet> court_building_set;
|
||||
Ref<GenRoadSet> road_set;
|
||||
Array building_sets;
|
||||
float center_radius;
|
||||
float radius;
|
||||
int min_buildings;
|
||||
int max_buildings;
|
||||
public:
|
||||
void set_guildhall_building_set(const Ref<GenBuildingSet> set);
|
||||
Ref<GenBuildingSet> get_guildhall_building_set() const;
|
||||
void set_court_building_set(const Ref<GenBuildingSet> set);
|
||||
Ref<GenBuildingSet> get_court_building_set() const;
|
||||
void set_road_set(const Ref<GenRoadSet> set);
|
||||
Ref<GenRoadSet> get_road_set() const;
|
||||
void set_building_sets(const Array &sets);
|
||||
const Array &get_building_sets() const;
|
||||
void set_center_radius(float radius);
|
||||
float get_center_radius() const;
|
||||
void set_radius(float radius);
|
||||
float get_radius() const;
|
||||
void set_min_buildings(int minb);
|
||||
int get_min_buildings() const;
|
||||
void set_max_buildings(int maxb);
|
||||
int get_max_buildings() const;
|
||||
void _set_data(const Dictionary &data);
|
||||
Dictionary _get_data() const;
|
||||
Dictionary get_items() const;
|
||||
};
|
||||
class GenExteriorSet: public Resource {
|
||||
GDCLASS(GenExteriorSet, Resource)
|
||||
protected:
|
||||
HashMap<String, Ref<ArrayMesh> > _data;
|
||||
HashMap<String, String > xmap;
|
||||
bool _set(const StringName &name, const Variant &property);
|
||||
bool _get(const StringName &name, Variant &property) const;
|
||||
void _get_property_list(List<PropertyInfo> *p_list) const;
|
||||
public:
|
||||
GenExteriorSet();
|
||||
};
|
||||
class GenInteriorSet: public Resource {
|
||||
GDCLASS(GenInteriorSet, Resource)
|
||||
protected:
|
||||
HashMap<String, Ref<ArrayMesh> > _data;
|
||||
HashMap<String, String > xmap;
|
||||
bool _set(const StringName &name, const Variant &property);
|
||||
bool _get(const StringName &name, Variant &property) const;
|
||||
void _get_property_list(List<PropertyInfo> *p_list) const;
|
||||
public:
|
||||
GenInteriorSet();
|
||||
};
|
||||
class GenFurnitureSet: public Resource {
|
||||
GDCLASS(GenFurnitureSet, Resource)
|
||||
};
|
||||
|
||||
class GenBuildingSet: public Resource {
|
||||
GDCLASS(GenBuildingSet, Resource)
|
||||
protected:
|
||||
HashMap<String, int> _datai;
|
||||
HashMap<String, String> _datas;
|
||||
HashMap<String, float> _dataf;
|
||||
HashMap<String, Ref<Resource> > _datar;
|
||||
bool _set(const StringName &name, const Variant &property);
|
||||
bool _get(const StringName &name, Variant &property) const;
|
||||
void _get_property_list(List<PropertyInfo> *p_list) const;
|
||||
public:
|
||||
GenBuildingSet();
|
||||
};
|
||||
class GenRoadSet: public Resource {
|
||||
GDCLASS(GenRoadSet, Resource)
|
||||
protected:
|
||||
HashMap<String, Ref<ArrayMesh> > _data;
|
||||
float segment_length,
|
||||
segment_width,
|
||||
short_segment_length,
|
||||
turn_angle,
|
||||
turn_angle2;
|
||||
bool _set(const StringName &name, const Variant &property);
|
||||
bool _get(const StringName &name, Variant &property) const;
|
||||
void _get_property_list(List<PropertyInfo> *p_list) const;
|
||||
public:
|
||||
GenRoadSet();
|
||||
};
|
||||
#endif
|
||||
|
||||
BIN
modules/meshops/town.x11.opt.tools.64.o
Normal file
BIN
modules/meshops/town.x11.opt.tools.64.o
Normal file
Binary file not shown.
464
modules/meshops/town_queue.cpp
Normal file
464
modules/meshops/town_queue.cpp
Normal file
@@ -0,0 +1,464 @@
|
||||
#include <cassert>
|
||||
#include <cmath>
|
||||
#include <core/variant.h>
|
||||
#include <core/math/geometry.h>
|
||||
#include "town_queue.h"
|
||||
#include "town.h"
|
||||
|
||||
static inline AABB cut_left(AABB &aabb, float amount)
|
||||
{
|
||||
if (amount > aabb.size.x)
|
||||
return AABB();
|
||||
AABB ret(aabb.position, Vector3(amount, aabb.size.y, aabb.size.z));
|
||||
aabb.position.x += amount;
|
||||
aabb.size.x -= amount;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline AABB cut_ztop(AABB &aabb, float amount)
|
||||
{
|
||||
if (amount > aabb.size.z)
|
||||
return AABB();
|
||||
AABB ret(aabb.position, Vector3(aabb.size.x, aabb.size.y, amount));
|
||||
aabb.position.z += amount;
|
||||
aabb.size.z -= amount;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline Variant get_item_data(const Dictionary &item, const char *key)
|
||||
{
|
||||
const Dictionary &item_data = item["data"];
|
||||
return item_data[key];
|
||||
}
|
||||
|
||||
static inline void set_item_data(Dictionary &item, const char *key, const Variant &value)
|
||||
{
|
||||
if (!item.has("data"))
|
||||
item["data"] = Dictionary();
|
||||
Dictionary data = item["data"];
|
||||
data[key] = value;
|
||||
}
|
||||
|
||||
static inline void set_item_data(Dictionary &item, const StringName &key, const Variant &value)
|
||||
{
|
||||
if (!item.has("data"))
|
||||
item["data"] = Dictionary();
|
||||
Dictionary data = item["data"];
|
||||
data[key] = value;
|
||||
}
|
||||
|
||||
static inline String get_item_name(const Dictionary &item)
|
||||
{
|
||||
return item["name"];
|
||||
}
|
||||
|
||||
static inline void set_item_name(Dictionary &item, const StringName &value)
|
||||
{
|
||||
item["name"] = value;
|
||||
}
|
||||
|
||||
static inline bool item_has_data(const Dictionary &item, const char *key)
|
||||
{
|
||||
const Dictionary &item_data = item["data"];
|
||||
return item_data.has(key);
|
||||
}
|
||||
|
||||
#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
|
||||
|
||||
Dictionary TownQueue::produce_item(const StringName &item_name,
|
||||
const Dictionary &parent,
|
||||
const Dictionary &extra)
|
||||
{
|
||||
Dictionary item;
|
||||
const char *copy_fields[] = {
|
||||
"set",
|
||||
"town",
|
||||
"patch",
|
||||
"lot",
|
||||
"wing"
|
||||
};
|
||||
set_item_name(item, item_name);
|
||||
item["data"] = Dictionary();
|
||||
|
||||
if (!parent.empty()) {
|
||||
int j;
|
||||
const String &parent_name = parent["name"];
|
||||
set_item_data(item, parent_name, parent);
|
||||
for (j = 0; j < (int)ARRAY_SIZE(copy_fields); j++)
|
||||
if (item_has_data(parent, copy_fields[j]))
|
||||
set_item_data(item,
|
||||
copy_fields[j],
|
||||
get_item_data(parent,
|
||||
copy_fields[j]));
|
||||
}
|
||||
const Variant *e;
|
||||
for (e = extra.next(NULL); e; e = extra.next(e))
|
||||
set_item_data(item, *e, extra[*e]);
|
||||
return item;
|
||||
}
|
||||
|
||||
void TownQueue::startup(const Dictionary &town_extra)
|
||||
{
|
||||
rnd.instance();
|
||||
seed = -1;
|
||||
radius = 0.0f;
|
||||
center_radius = 0.0f;
|
||||
if (town_extra.has("seed"))
|
||||
seed = town_extra["seed"];
|
||||
if (town_extra.has("radius"))
|
||||
radius = town_extra["radius"];
|
||||
if (town_extra.has("center_radius"))
|
||||
center_radius = town_extra["center_radius"];
|
||||
if (seed < 0)
|
||||
rnd->randomize();
|
||||
seed = rnd->get_seed();
|
||||
global_meta["seed"] = seed;
|
||||
global_meta["radius"] = radius;
|
||||
global_meta["center_radius"] = center_radius;
|
||||
global_meta["lots"] = Array();
|
||||
global_meta["road_segments"] = Array();
|
||||
global_meta["road_intersections"] = Array();
|
||||
Dictionary town_item = produce_item_positional("town", Dictionary(), Vector3(), 0.0f, town_extra);
|
||||
queue.push_back(town_item);
|
||||
queue.register_callback_native("town", this, (void (Object::*)(const Dictionary&)) &TownQueue::handle_town);
|
||||
queue.register_callback_native("patch", this, (void (Object::*)(const Dictionary&)) &TownQueue::handle_patch);
|
||||
queue.register_callback_native("lot", this, (void (Object::*)(const Dictionary&)) &TownQueue::handle_lot);
|
||||
queue.register_callback_native("residence", this, (void (Object::*)(const Dictionary&)) &TownQueue::handle_residence);
|
||||
queue.register_callback_native("farm", this, (void (Object::*)(const Dictionary&)) &TownQueue::handle_farm);
|
||||
}
|
||||
|
||||
void TownQueue::init_grid(Dictionary &item)
|
||||
{
|
||||
int i,j;
|
||||
int grid_x = get_item_data(item, "grid_x");
|
||||
int grid_z = get_item_data(item, "grid_z");
|
||||
Vector3 grid_origin = get_item_data(item, "grid_origin");
|
||||
PoolVector<uint8_t> grid = get_item_data(item, "grid");
|
||||
PoolVector<Vector3> polygon = get_item_data(item, "polygon_rot");
|
||||
Vector<Vector2> poly2d;
|
||||
poly2d.resize(polygon.size());
|
||||
const Vector3 *pd = polygon.read().ptr();
|
||||
for (i = 0; i < polygon.size(); i++)
|
||||
poly2d.write[i] = Vector2(pd[i].x, pd[i].z);
|
||||
uint8_t *gptr = grid.write().ptr();
|
||||
for (i = 0; i < grid_z; i++)
|
||||
for (j = 0; j < grid_x; j++) {
|
||||
Vector3 grid_pos = grid_origin + Vector3((float)j * 16.0, 0.0f, (float)i * 16.0);
|
||||
if (Geometry::is_point_in_polygon(Vector2(grid_pos.x, grid_pos.z), poly2d))
|
||||
gptr[i * grid_x + j] = 0;
|
||||
else
|
||||
gptr[i * grid_x + j] = 0xff;
|
||||
}
|
||||
set_item_data(item, "grid", grid);
|
||||
}
|
||||
|
||||
void TownQueue::handle_town(const Dictionary &item)
|
||||
{
|
||||
Voronoi *voronoi = Voronoi::get_singleton();
|
||||
int patches_count = 5 + rnd->randi() % 10, i;
|
||||
PoolVector<Vector2> points2d;
|
||||
points2d.resize(patches_count * 8);
|
||||
float sa = rnd->randf() * 2.0 * Math_PI;
|
||||
for (i = 0; i < patches_count * 8; i++) {
|
||||
float a = sa + sqrtf((float)i) * 5.0f;
|
||||
float r = (i == 0) ? 0.0f : MIN(center_radius + (float)i * 4.0f * rnd->randf(), radius);
|
||||
float x = cos(a) * r;
|
||||
float y = sin(a) * r;
|
||||
Vector2 d(x, y);
|
||||
points2d.write()[i] = d;
|
||||
}
|
||||
Dictionary diagram = voronoi->generate_diagram(points2d, relaxations);
|
||||
global_meta["voronoi"] = diagram;
|
||||
Array sites = diagram["sites"];
|
||||
patches.resize(sites.size());
|
||||
int plaza_id = -1;
|
||||
float plength = Math_INF;
|
||||
for (i = 0; i < sites.size(); i++) {
|
||||
Dictionary site = sites[i];
|
||||
Vector<Vector2> polygon = site["polygon"];
|
||||
Vector2 pos = site["pos"];
|
||||
printf("site pos %ls\n", String(pos).c_str());
|
||||
float l = pos.length_squared();
|
||||
if (plength > l) {
|
||||
plaza_id = i;
|
||||
plength = l;
|
||||
}
|
||||
struct patch p(polygon, pos, patches.size());
|
||||
patches.write[i] = p;
|
||||
}
|
||||
for (i = 0; i < sites.size(); i++) {
|
||||
Dictionary p_extra = patches[i].get();
|
||||
if (i == plaza_id)
|
||||
p_extra["plaza"] = true;
|
||||
else
|
||||
p_extra["plaza"] = false;
|
||||
Dictionary patch_item = produce_item_positional("patch", item, p_extra["position"], 0.0f, p_extra);
|
||||
queue.push_back(patch_item);
|
||||
}
|
||||
}
|
||||
static inline float polygon_area(const PoolVector<Vector3> &polygon)
|
||||
{
|
||||
float area = 0.0f;
|
||||
int n = polygon.size();
|
||||
const Vector3 *p = polygon.read().ptr();
|
||||
|
||||
for (int i = 0; i < n; i++)
|
||||
{
|
||||
int j = (i + 1) % n;
|
||||
area += 0.5f * (p[i].x*p[j].z - p[j].x*p[i].z);
|
||||
}
|
||||
return (area);
|
||||
}
|
||||
|
||||
static inline bool get_grid_free(const Dictionary &item, int x, int z, int dx, int dz)
|
||||
{
|
||||
int grid_x = get_item_data(item, "grid_x");
|
||||
int grid_z = get_item_data(item, "grid_z");
|
||||
PoolVector<uint8_t> grid = get_item_data(item, "grid");
|
||||
const uint8_t *data = grid.read().ptr();
|
||||
int minx = MAX(0, x);
|
||||
int maxx = MIN(x + dx, grid_x);
|
||||
int minz = MAX(0, z);
|
||||
int maxz = MIN(z + dz, grid_z);
|
||||
int i, j;
|
||||
if (x >= grid_x || z >= grid_z)
|
||||
return false;
|
||||
for (i = minz; i < maxz; i++)
|
||||
for (j = minx; j < maxx; j++)
|
||||
if (data[i * grid_x + j] != 0)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
static inline bool get_grid_free(const Dictionary &item, const AABB &aabb)
|
||||
{
|
||||
Vector3 grid_origin = get_item_data(item, "grid_origin");
|
||||
Vector3 offt = aabb.position - grid_origin;
|
||||
int x = (int)((offt.x + 8.0f) / 16.0f);
|
||||
int z = (int)((offt.x + 8.0f) / 16.0f);
|
||||
int dx = (int)((aabb.size.x + 8.0f) / 16.0f);
|
||||
int dz = (int)((aabb.size.z + 8.0f) / 16.0f);
|
||||
return get_grid_free(item, x, z, dx, dz);
|
||||
}
|
||||
static inline bool shrink_aabb(const Dictionary &item, AABB &aabb)
|
||||
{
|
||||
while (aabb.size.x > 16.0f &&
|
||||
aabb.size.z > 16.0f &&
|
||||
!get_grid_free(item, aabb)) {
|
||||
aabb.position.x += 1.0f;
|
||||
aabb.position.z += 1.0f;
|
||||
aabb.size.x -= 2.0f;
|
||||
aabb.size.z -= 2.0f;
|
||||
}
|
||||
if (aabb.size.x > 16.0f && aabb.size.z > 16.0f)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
void TownQueue::handle_patch(const Dictionary &item)
|
||||
{
|
||||
int i;
|
||||
Dictionary item_data = item["data"];
|
||||
Dictionary p_extra;
|
||||
p_extra["plaza"] = item_data["plaza"];
|
||||
float rotation = rnd->randf() * 2.0f * Math_PI;
|
||||
Transform xform = Transform().rotated(Vector3(0, 1, 0), rotation);
|
||||
PoolVector<Vector3> polygon = item_data["polygon"];
|
||||
PoolVector<Vector3> polygon_rot;
|
||||
polygon_rot.resize(polygon.size());
|
||||
Vector3 position = item_data["position"];
|
||||
AABB aabb_rot(position, Vector3()), aabb(position, Vector3());
|
||||
for (i = 0; i < polygon.size(); i++) {
|
||||
aabb.expand_to(polygon.read()[i]);
|
||||
Vector3 xv = xform.xform_inv(polygon.read()[i]);
|
||||
polygon_rot.write()[i] = xv;
|
||||
aabb_rot.expand_to(xv);
|
||||
}
|
||||
aabb.size.y = 3.0f;
|
||||
aabb_rot.size.y = 3.0f;
|
||||
AABB aabb_shrunk = aabb_rot;
|
||||
Vector3 grid_origin = aabb_rot.position;
|
||||
int grid_x = (int)(aabb_rot.size.x + 8.0f / 16.0f);
|
||||
int grid_z = (int)(aabb_rot.size.z + 8.0f / 16.0f);
|
||||
PoolVector<uint8_t> grid;
|
||||
grid.resize(grid_x * grid_z);
|
||||
p_extra["polygon"] = polygon;
|
||||
p_extra["polygon_rot"] = polygon_rot;
|
||||
p_extra["aabb"] = aabb;
|
||||
p_extra["aabb_rot"] = aabb_rot;
|
||||
p_extra["grid_origin"] = grid_origin;
|
||||
p_extra["grid_x"] = grid_x;
|
||||
p_extra["grid_z"] = grid_z;
|
||||
p_extra["grid"] = grid;
|
||||
p_extra["area"] = polygon_area(polygon);
|
||||
Dictionary lot = produce_item_positional("lot", item, item_data["position"], rotation, p_extra);
|
||||
init_grid(lot);
|
||||
if (shrink_aabb(lot, aabb_shrunk))
|
||||
set_item_data(lot, "aabb_rot_shrunk", aabb_shrunk);
|
||||
else
|
||||
set_item_data(lot, "aabb_rot_shrunk", AABB());
|
||||
queue.push_back(lot);
|
||||
printf("grid_x %d grid_z %d\n", grid_x, grid_z);
|
||||
}
|
||||
void TownQueue::handle_lot(const Dictionary &item)
|
||||
{
|
||||
int grid_x = get_item_data(item, "grid_x");
|
||||
int grid_z = get_item_data(item, "grid_z");
|
||||
AABB aabb = get_item_data(item, "aabb_rot_shrunk");
|
||||
Vector3 position = get_item_data(item, "position");
|
||||
float rotation = get_item_data(item, "rotation");
|
||||
HashMap<int, String> item_selection;
|
||||
List<int> key_list;
|
||||
item_selection[80] = "industry";
|
||||
item_selection[60] = "farm";
|
||||
item_selection[40] = "residence";
|
||||
item_selection[20] = "recreation";
|
||||
item_selection.get_key_list(&key_list);
|
||||
key_list.sort();
|
||||
key_list.invert();
|
||||
String item_name = "farm";
|
||||
if (grid_x > 128 && grid_z > 128)
|
||||
item_name = "farm";
|
||||
else if (grid_x > 64 && grid_z > 64) {
|
||||
List<int>::Element *k = key_list.front();
|
||||
int choice = rnd->randi() % 100;
|
||||
while(k) {
|
||||
int key = k->get();
|
||||
if (choice > key) {
|
||||
item_name = item_selection[key];
|
||||
break;
|
||||
}
|
||||
k = k->next();
|
||||
}
|
||||
}
|
||||
else if (grid_x <= 64 && grid_z <= 64)
|
||||
item_name = "residence";
|
||||
Dictionary next_item = produce_item_positional(item_name, item, position, rotation, item["data"]);
|
||||
set_item_data(next_item, "aabb", aabb);
|
||||
queue.push_back(next_item);
|
||||
}
|
||||
void TownQueue::handle_residence(const Dictionary &item)
|
||||
{
|
||||
Dictionary lot = get_item_data(item, "lot");
|
||||
GenCitySet *city = Object::cast_to<GenCitySet>(get_item_data(item, "set"));
|
||||
const Array &buildings = city->get_building_sets();
|
||||
ERR_FAIL_COND(buildings.size() == 0);
|
||||
int bset_id = rnd->randi() % buildings.size();
|
||||
GenBuildingSet *bset = Object::cast_to<GenBuildingSet>(buildings[bset_id]);
|
||||
AABB aabb = get_item_data(item, "aabb");
|
||||
if (aabb.size.x < 16.0f || aabb.size.z < 16.0f)
|
||||
/* we better produce hut in this case */
|
||||
return;
|
||||
Dictionary p_extra;
|
||||
p_extra["bset"] = bset;
|
||||
p_extra["house_type"] = bset->get("house_type");
|
||||
p_extra["placement"] = "arc";
|
||||
p_extra["aabb"] = aabb;
|
||||
Dictionary house = produce_item_positional("house",
|
||||
item, get_item_data(item, "position"),
|
||||
/* need to remove this as lot is already rotated...,
|
||||
* but need this for house node */
|
||||
get_item_data(item, "rotation"),
|
||||
p_extra);
|
||||
queue.push_back(house);
|
||||
}
|
||||
void TownQueue::handle_farm(const Dictionary &item)
|
||||
{
|
||||
AABB aabb = get_item_data(item, "aabb");
|
||||
AABB field_aabb, farmtech_aabb, residence_aabb;
|
||||
if (aabb.size.x > aabb.size.z)
|
||||
field_aabb = cut_left(aabb, aabb.size.x * 0.5f);
|
||||
else
|
||||
field_aabb = cut_ztop(aabb, aabb.size.z * 0.5f);
|
||||
if (aabb.size.x > aabb.size.z)
|
||||
farmtech_aabb = cut_left(aabb, aabb.size.x * 0.5f);
|
||||
else
|
||||
farmtech_aabb = cut_ztop(aabb, aabb.size.z * 0.5f);
|
||||
residence_aabb = aabb;
|
||||
Vector3 field_position = field_aabb.position +
|
||||
Vector3(field_aabb.size.x, 0.0f, field_aabb.size.z) * 0.5f;
|
||||
Vector3 farmtech_position = farmtech_aabb.position +
|
||||
Vector3(farmtech_aabb.size.x, 0.0f, farmtech_aabb.size.z) * 0.5f;
|
||||
Vector3 residence_position = residence_aabb.position +
|
||||
Vector3(residence_aabb.size.x, 0.0f, residence_aabb.size.z) * 0.5f;
|
||||
Dictionary field_extra, farmtech_extra, residence_extra;
|
||||
field_extra["aabb"] = field_aabb;
|
||||
farmtech_extra["aabb"] = farmtech_aabb;
|
||||
residence_extra["aabb"] = residence_aabb;
|
||||
Dictionary field = produce_item_positional("field", item, field_position, 0.0f, field_extra);
|
||||
Dictionary farmtech = produce_item_positional("farmtech", item, farmtech_position, 0.0f, farmtech_extra);
|
||||
Dictionary residence = produce_item_positional("residence", item, residence_position, 0.0f, residence_extra);
|
||||
queue.push_back(field);
|
||||
queue.push_back(farmtech);
|
||||
queue.push_back(residence);
|
||||
}
|
||||
|
||||
void TownQueue::_bind_methods()
|
||||
{
|
||||
ClassDB::bind_method(D_METHOD("produce_item", "item_name", "parent", "extra"),
|
||||
&TownQueue::produce_item, DEFVAL(Dictionary()), DEFVAL(Dictionary()));
|
||||
ClassDB::bind_method(D_METHOD("produce_item_positional", "item_name", "parent", "position", "rotation", "extra"),
|
||||
&TownQueue::produce_item_positional, DEFVAL(0.0f), DEFVAL(Dictionary()));
|
||||
ClassDB::bind_method(D_METHOD("startup", "town_extra"),
|
||||
&TownQueue::startup);
|
||||
ClassDB::bind_method(D_METHOD("push_back", "item"),
|
||||
&TownQueue::push_back);
|
||||
ClassDB::bind_method(D_METHOD("push_front", "item"),
|
||||
&TownQueue::push_front);
|
||||
ClassDB::bind_method(D_METHOD("pop_front"),
|
||||
&TownQueue::pop_front);
|
||||
ClassDB::bind_method(D_METHOD("push_back_delayed", "item"),
|
||||
&TownQueue::push_back_delayed);
|
||||
ClassDB::bind_method(D_METHOD("register_callback", "item_name", "obj", "func"),
|
||||
&TownQueue::register_callback);
|
||||
ClassDB::bind_method(D_METHOD("register_default_callback", "obj", "func"),
|
||||
&TownQueue::register_default_callback);
|
||||
ClassDB::bind_method(D_METHOD("unregister_callback", "item_name"),
|
||||
&TownQueue::unregister_callback);
|
||||
ClassDB::bind_method(D_METHOD("process"),
|
||||
&TownQueue::process);
|
||||
ClassDB::bind_method(D_METHOD("allocate_space", "aabb", "rotation", "patch"),
|
||||
&TownQueue::allocate_space);
|
||||
}
|
||||
bool TownQueue::allocate_space(const AABB& aabb, float rotation, const Dictionary &patch)
|
||||
{
|
||||
int i;
|
||||
Transform xform = Transform().rotated(Vector3(0, 1.0f, 0), rotation);
|
||||
const PoolVector<Vector3> &polygon = patch["polygon"];
|
||||
Vector3 size = aabb.get_size();
|
||||
Vector3 center = aabb.get_position() + Vector3(size.x, 0.1f, size.z) * 0.5f;
|
||||
PoolVector<Vector2> polygon2d = patch["polygon2d"];
|
||||
Vector<Vector2> p2d;
|
||||
p2d.resize(polygon2d.size());
|
||||
for (i = 0; i < polygon2d.size(); i++)
|
||||
p2d.write[i] = polygon2d.read()[i];
|
||||
if (!Geometry::is_point_in_polygon(Vector2(center.x, center.z), p2d))
|
||||
return false;
|
||||
for (i = 0; i < polygon.size(); i++) {
|
||||
Vector3 p1 = xform.xform_inv(polygon.read()[i]);
|
||||
Vector3 p2 = xform.xform_inv(polygon.read()[(i + 1) % polygon.size()]);
|
||||
p1.y = 0.1f;
|
||||
p2.y = 0.2f;
|
||||
if (aabb.intersects_segment(p1, p2))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
Dictionary TownQueue::produce_item_positional(const StringName &item_name,
|
||||
const Dictionary &parent,
|
||||
const Vector3 &position,
|
||||
float rotation,
|
||||
const Dictionary &extra)
|
||||
{
|
||||
Dictionary item = produce_item(item_name, parent, extra);
|
||||
set_item_data(item, "position", position);
|
||||
set_item_data(item, "rotation", rotation);
|
||||
return item;
|
||||
}
|
||||
|
||||
TownQueue::TownQueue()
|
||||
{
|
||||
relaxations = 3;
|
||||
}
|
||||
|
||||
148
modules/meshops/town_queue.h
Normal file
148
modules/meshops/town_queue.h
Normal file
@@ -0,0 +1,148 @@
|
||||
#include "queue.h"
|
||||
#include <modules/voronoi/voronoi.h>
|
||||
#include <core/math/random_number_generator.h>
|
||||
|
||||
class TownQueue: public Reference {
|
||||
GDCLASS(TownQueue, Reference)
|
||||
protected:
|
||||
DelayedQueue queue;
|
||||
Ref<RandomNumberGenerator> rnd;
|
||||
static void _bind_methods();
|
||||
Dictionary global_meta;
|
||||
int relaxations, seed;
|
||||
float center_radius, radius;
|
||||
struct patch {
|
||||
PoolVector<Vector3> polygon;
|
||||
PoolVector<Vector2> polygon2d;
|
||||
Vector<Vector2> polycmp;
|
||||
int id;
|
||||
Vector3 position;
|
||||
PoolVector<uint8_t> alloc_grid;
|
||||
AABB surroundings;
|
||||
bool internal;
|
||||
void calculate()
|
||||
{
|
||||
int i, j;
|
||||
surroundings.set_position(position);
|
||||
for (i = 0; i < polygon.size(); i++)
|
||||
surroundings.expand_to(polygon.read()[i]);
|
||||
int x = (int)((surroundings.size.x + 8.0f) / 16.0f);
|
||||
int y = (int)((surroundings.size.x + 8.0f) / 16.0f);
|
||||
alloc_grid.resize(x * y / 8);
|
||||
for (i = 0; i < y; i++)
|
||||
for (j = 0; j < x; j++) {
|
||||
int data_pos = i * x + j;
|
||||
int bytepos = (data_pos >> 3);
|
||||
int bit = (1 << (j & 3));
|
||||
Vector3 pos = surroundings.position + Vector3((float)j * 16.0f + 8.0f, 0.1f, (float)i * 16.0f + 8.0f);
|
||||
}
|
||||
}
|
||||
Dictionary get() const
|
||||
{
|
||||
Dictionary r;
|
||||
r["polygon"] = polygon;
|
||||
r["polygon2d"] = polygon2d;
|
||||
r["position"] = position;
|
||||
r["internal"] = internal;
|
||||
r["id"] = id;
|
||||
return r;
|
||||
}
|
||||
patch(const Array &points2d, const Vector2 &pos, int pid, bool qinternal = true)
|
||||
{
|
||||
int i;
|
||||
position = Vector3(pos.x, 0, pos.y);
|
||||
polygon2d.resize(points2d.size());
|
||||
polygon.resize(points2d.size());
|
||||
for (i = 0; i < polygon.size(); i++) {
|
||||
Vector2 v = points2d[i];
|
||||
polygon.write()[i] = Vector3(v.x, 0.0f, v.y);
|
||||
polygon2d.write()[i] = v;
|
||||
}
|
||||
internal = qinternal;
|
||||
id = pid;
|
||||
}
|
||||
patch(const Vector<Vector2> &points2d, const Vector2 &pos, int pid, bool qinternal = true)
|
||||
{
|
||||
int i;
|
||||
position = Vector3(pos.x, 0, pos.y);
|
||||
polygon2d.resize(points2d.size());
|
||||
polygon.resize(points2d.size());
|
||||
for (i = 0; i < polygon.size(); i++) {
|
||||
Vector2 v = points2d[i];
|
||||
polygon.write()[i] = Vector3(v.x, 0.0f, v.y);
|
||||
polygon2d.write()[i] = v;
|
||||
}
|
||||
internal = qinternal;
|
||||
id = pid;
|
||||
}
|
||||
patch(const PoolVector<Vector2> &points2d, const Vector2 &pos, int pid, bool qinternal = true)
|
||||
{
|
||||
int i;
|
||||
position = Vector3(pos.x, 0, pos.y);
|
||||
polygon2d = points2d;
|
||||
polygon.resize(points2d.size());
|
||||
for (i = 0; i < polygon.size(); i++) {
|
||||
Vector2 v = points2d[i];
|
||||
polygon.write()[i] = Vector3(v.x, 0.0f, v.y);
|
||||
}
|
||||
internal = qinternal;
|
||||
id = pid;
|
||||
}
|
||||
patch()
|
||||
{
|
||||
internal = true;
|
||||
}
|
||||
};
|
||||
Vector<struct patch> patches;
|
||||
bool allocate_space(const AABB& aabb, float rotation, const Dictionary &patch);
|
||||
public:
|
||||
Dictionary produce_item(const StringName &item_name,
|
||||
const Dictionary &parent,
|
||||
const Dictionary &extra);
|
||||
Dictionary produce_item_positional(const StringName &item_name,
|
||||
const Dictionary &parent,
|
||||
const Vector3 &position,
|
||||
float rotation,
|
||||
const Dictionary &extra);
|
||||
inline void push_back(const Dictionary &data)
|
||||
{
|
||||
queue.push_back(data);
|
||||
}
|
||||
inline void push_front(const Dictionary &data)
|
||||
{
|
||||
queue.push_front(data);
|
||||
}
|
||||
inline Dictionary pop_front()
|
||||
{
|
||||
return queue.pop_front();
|
||||
}
|
||||
inline void push_back_delayed(const Dictionary &data)
|
||||
{
|
||||
queue.push_back_delayed(data);
|
||||
}
|
||||
inline void register_callback(const StringName &item_name, Object *obj, const StringName &func)
|
||||
{
|
||||
queue.register_callback(item_name, obj, func);
|
||||
}
|
||||
inline void register_default_callback(Object *obj, const StringName &func)
|
||||
{
|
||||
queue.register_default_callback(obj, func);
|
||||
}
|
||||
inline void unregister_callback(const StringName &item_name)
|
||||
{
|
||||
queue.unregister_callback(item_name);
|
||||
}
|
||||
inline void process()
|
||||
{
|
||||
queue.process();
|
||||
}
|
||||
void startup(const Dictionary &town_extra);
|
||||
void init_grid(Dictionary &item);
|
||||
void handle_town(const Dictionary &item);
|
||||
void handle_patch(const Dictionary &item);
|
||||
void handle_lot(const Dictionary &item);
|
||||
void handle_residence(const Dictionary &item);
|
||||
void handle_farm(const Dictionary &item);
|
||||
TownQueue();
|
||||
};
|
||||
|
||||
BIN
modules/meshops/town_queue.x11.opt.tools.64.o
Normal file
BIN
modules/meshops/town_queue.x11.opt.tools.64.o
Normal file
Binary file not shown.
Reference in New Issue
Block a user