godot_voxel/terrain/instancing/voxel_instance_library_item.cpp
2021-04-05 00:24:46 -04:00

296 lines
10 KiB
C++

#include "voxel_instance_library_item.h"
#include "voxel_instancer.h"
#include <core/core_string_names.h>
#include <scene/3d/collision_shape.h>
#include <scene/3d/mesh_instance.h>
#include <scene/3d/physics_body.h>
void VoxelInstanceLibraryItem::set_item_name(String name) {
_name = name;
}
String VoxelInstanceLibraryItem::get_item_name() const {
return _name;
}
void VoxelInstanceLibraryItem::set_lod_index(int lod) {
ERR_FAIL_COND(lod < 0 || lod >= VoxelInstancer::MAX_LOD);
if (_lod_index == lod) {
return;
}
_lod_index = lod;
notify_listeners(CHANGE_LOD_INDEX);
}
int VoxelInstanceLibraryItem::get_lod_index() const {
return _lod_index;
}
void VoxelInstanceLibraryItem::set_generator(Ref<VoxelInstanceGenerator> generator) {
if (_generator == generator) {
return;
}
if (_generator.is_valid()) {
_generator->disconnect(CoreStringNames::get_singleton()->changed, this, "_on_generator_changed");
}
_generator = generator;
if (_generator.is_valid()) {
_generator->connect(CoreStringNames::get_singleton()->changed, this, "_on_generator_changed");
}
notify_listeners(CHANGE_GENERATOR);
}
Ref<VoxelInstanceGenerator> VoxelInstanceLibraryItem::get_generator() const {
return _generator;
}
void VoxelInstanceLibraryItem::set_persistent(bool persistent) {
_persistent = persistent;
}
bool VoxelInstanceLibraryItem::is_persistent() const {
return _persistent;
}
void VoxelInstanceLibraryItem::set_mesh(Ref<Mesh> mesh, int mesh_lod_index) {
ERR_FAIL_INDEX(mesh_lod_index, VoxelInstancer::MAX_LOD);
if (_mesh_lods[mesh_lod_index] == mesh) {
return;
}
_mesh_lods[mesh_lod_index] = mesh;
// Update count
unsigned int count = _mesh_lods.size();
for (unsigned int i = _mesh_lods.size() - 1; i > 0; --i) {
if (_mesh_lods[i].is_valid()) {
break;
}
--count;
}
_mesh_lod_count = count;
notify_listeners(CHANGE_VISUAL);
}
int VoxelInstanceLibraryItem::get_mesh_lod_count() const {
return _mesh_lod_count;
}
Ref<Mesh> VoxelInstanceLibraryItem::get_mesh(int mesh_lod_index) const {
ERR_FAIL_INDEX_V(mesh_lod_index, VoxelInstancer::MAX_LOD, Ref<Mesh>());
return _mesh_lods[mesh_lod_index];
}
void VoxelInstanceLibraryItem::set_material_override(Ref<Material> material) {
if (material == _material_override) {
return;
}
_material_override = material;
notify_listeners(CHANGE_VISUAL);
}
Ref<Material> VoxelInstanceLibraryItem::get_material_override() const {
return _material_override;
}
void VoxelInstanceLibraryItem::set_cast_shadows_setting(VisualServer::ShadowCastingSetting mode) {
if (mode == _shadow_casting_setting) {
return;
}
_shadow_casting_setting = mode;
notify_listeners(CHANGE_VISUAL);
}
VisualServer::ShadowCastingSetting VoxelInstanceLibraryItem::get_cast_shadows_setting() const {
return _shadow_casting_setting;
}
void VoxelInstanceLibraryItem::set_collision_layer(int collision_layer) {
_collision_layer = collision_layer;
}
int VoxelInstanceLibraryItem::get_collision_layer() const {
return _collision_layer;
}
void VoxelInstanceLibraryItem::set_collision_mask(int collision_mask) {
_collision_mask = collision_mask;
}
int VoxelInstanceLibraryItem::get_collision_mask() const {
return _collision_mask;
}
void VoxelInstanceLibraryItem::setup_from_template(Node *root) {
_collision_shapes.clear();
PhysicsBody *physics_body = Object::cast_to<PhysicsBody>(root);
if (physics_body != nullptr) {
_collision_layer = physics_body->get_collision_layer();
_collision_mask = physics_body->get_collision_mask();
}
for (int i = 0; i < root->get_child_count(); ++i) {
MeshInstance *mi = Object::cast_to<MeshInstance>(root->get_child(i));
if (mi != nullptr) {
_mesh_lods[0] = mi->get_mesh();
_mesh_lod_count = 1;
_material_override = mi->get_material_override();
}
if (physics_body != nullptr) {
CollisionShape *cs = Object::cast_to<CollisionShape>(physics_body->get_child(i));
if (cs != nullptr) {
CollisionShapeInfo info;
info.shape = cs->get_shape();
info.transform = cs->get_transform();
_collision_shapes.push_back(info);
}
}
}
notify_listeners(CHANGE_VISUAL);
}
void VoxelInstanceLibraryItem::add_listener(IListener *listener, int id) {
ListenerSlot slot;
slot.listener = listener;
slot.id = id;
ERR_FAIL_COND(_listeners.find(slot) != -1);
_listeners.push_back(slot);
}
void VoxelInstanceLibraryItem::remove_listener(IListener *listener, int id) {
ListenerSlot slot;
slot.listener = listener;
slot.id = id;
int i = _listeners.find(slot);
ERR_FAIL_COND(i == -1);
_listeners.remove(i);
}
void VoxelInstanceLibraryItem::notify_listeners(ChangeType change) {
for (int i = 0; i < _listeners.size(); ++i) {
ListenerSlot &slot = _listeners.write[i];
slot.listener->on_library_item_changed(slot.id, change);
}
}
void VoxelInstanceLibraryItem::_on_generator_changed() {
notify_listeners(CHANGE_GENERATOR);
}
void VoxelInstanceLibraryItem::_b_set_collision_shapes(Array shape_infos) {
ERR_FAIL_COND(shape_infos.size() % 2 != 0);
_collision_shapes.clear();
for (int i = 0; i < shape_infos.size(); i += 2) {
CollisionShapeInfo info;
info.transform = shape_infos[i];
info.shape = shape_infos[i + 1];
ERR_FAIL_COND(info.shape.is_null());
_collision_shapes.push_back(info);
}
}
Array VoxelInstanceLibraryItem::_b_get_collision_shapes() const {
Array infos;
for (int i = 0; i < _collision_shapes.size(); ++i) {
const CollisionShapeInfo &info = _collision_shapes[i];
infos.push_back(info.shape);
infos.push_back(info.transform);
}
return infos;
}
void VoxelInstanceLibraryItem::_bind_methods() {
// Can't be just "set_name" because Resource already defines that, despite being for a `resource_name` property
ClassDB::bind_method(D_METHOD("set_item_name", "name"), &VoxelInstanceLibraryItem::set_item_name);
ClassDB::bind_method(D_METHOD("get_item_name"), &VoxelInstanceLibraryItem::get_item_name);
ClassDB::bind_method(D_METHOD("set_lod_index", "lod"), &VoxelInstanceLibraryItem::set_lod_index);
ClassDB::bind_method(D_METHOD("get_lod_index"), &VoxelInstanceLibraryItem::get_lod_index);
ClassDB::bind_method(D_METHOD("set_generator", "generator"), &VoxelInstanceLibraryItem::set_generator);
ClassDB::bind_method(D_METHOD("get_generator"), &VoxelInstanceLibraryItem::get_generator);
ClassDB::bind_method(D_METHOD("set_persistent", "persistent"), &VoxelInstanceLibraryItem::set_persistent);
ClassDB::bind_method(D_METHOD("is_persistent"), &VoxelInstanceLibraryItem::is_persistent);
ClassDB::bind_method(D_METHOD("set_mesh", "mesh", "mesh_lod_index"), &VoxelInstanceLibraryItem::set_mesh);
ClassDB::bind_method(D_METHOD("get_mesh", "mesh_lod_index"), &VoxelInstanceLibraryItem::get_mesh);
ClassDB::bind_method(D_METHOD("_set_mesh_lod0", "mesh"), &VoxelInstanceLibraryItem::_b_set_mesh_lod0);
ClassDB::bind_method(D_METHOD("_set_mesh_lod1", "mesh"), &VoxelInstanceLibraryItem::_b_set_mesh_lod1);
ClassDB::bind_method(D_METHOD("_set_mesh_lod2", "mesh"), &VoxelInstanceLibraryItem::_b_set_mesh_lod2);
ClassDB::bind_method(D_METHOD("_set_mesh_lod3", "mesh"), &VoxelInstanceLibraryItem::_b_set_mesh_lod3);
ClassDB::bind_method(D_METHOD("_get_mesh_lod0"), &VoxelInstanceLibraryItem::_b_get_mesh_lod0);
ClassDB::bind_method(D_METHOD("_get_mesh_lod1"), &VoxelInstanceLibraryItem::_b_get_mesh_lod1);
ClassDB::bind_method(D_METHOD("_get_mesh_lod2"), &VoxelInstanceLibraryItem::_b_get_mesh_lod2);
ClassDB::bind_method(D_METHOD("_get_mesh_lod3"), &VoxelInstanceLibraryItem::_b_get_mesh_lod3);
ClassDB::bind_method(D_METHOD("set_material_override", "material"),
&VoxelInstanceLibraryItem::set_material_override);
ClassDB::bind_method(D_METHOD("get_material_override"), &VoxelInstanceLibraryItem::get_material_override);
ClassDB::bind_method(D_METHOD("set_cast_shadows_setting", "mode"),
&VoxelInstanceLibraryItem::set_cast_shadows_setting);
ClassDB::bind_method(D_METHOD("get_cast_shadows_setting"), &VoxelInstanceLibraryItem::get_cast_shadows_setting);
ClassDB::bind_method(D_METHOD("set_collision_layer", "collision_layer"),
&VoxelInstanceLibraryItem::set_collision_layer);
ClassDB::bind_method(D_METHOD("get_collision_layer"), &VoxelInstanceLibraryItem::get_collision_layer);
ClassDB::bind_method(D_METHOD("set_collision_mask", "collision_mask"),
&VoxelInstanceLibraryItem::set_collision_mask);
ClassDB::bind_method(D_METHOD("get_collision_mask"), &VoxelInstanceLibraryItem::get_collision_mask);
ClassDB::bind_method(D_METHOD("set_collision_shapes", "shape_infos"),
&VoxelInstanceLibraryItem::_b_set_collision_shapes);
ClassDB::bind_method(D_METHOD("get_collision_shapes"), &VoxelInstanceLibraryItem::_b_get_collision_shapes);
ClassDB::bind_method(D_METHOD("setup_from_template", "node"), &VoxelInstanceLibraryItem::setup_from_template);
ClassDB::bind_method(D_METHOD("_on_generator_changed"), &VoxelInstanceLibraryItem::_on_generator_changed);
ADD_PROPERTY(PropertyInfo(Variant::STRING, "name"), "set_item_name", "get_item_name");
ADD_PROPERTY(PropertyInfo(Variant::INT, "lod_index", PROPERTY_HINT_RANGE, "0,8,1"),
"set_lod_index", "get_lod_index");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "generator", PROPERTY_HINT_RESOURCE_TYPE, "VoxelInstanceGenerator"),
"set_generator", "get_generator");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "persistent"), "set_persistent", "is_persistent");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "mesh", PROPERTY_HINT_RESOURCE_TYPE, "Mesh"),
"_set_mesh_lod0", "_get_mesh_lod0");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "mesh_lod1", PROPERTY_HINT_RESOURCE_TYPE, "Mesh"),
"_set_mesh_lod1", "_get_mesh_lod1");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "mesh_lod2", PROPERTY_HINT_RESOURCE_TYPE, "Mesh"),
"_set_mesh_lod2", "_get_mesh_lod2");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "mesh_lod3", PROPERTY_HINT_RESOURCE_TYPE, "Mesh"),
"_set_mesh_lod3", "_get_mesh_lod3");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "material_override", PROPERTY_HINT_RESOURCE_TYPE, "Material"),
"set_material_override", "get_material_override");
ADD_PROPERTY(PropertyInfo(Variant::INT, "cast_shadow", PROPERTY_HINT_ENUM, "Off,On,Double-Sided,Shadows Only"), "set_cast_shadows_setting", "get_cast_shadows_setting");
ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_layer", PROPERTY_HINT_LAYERS_3D_PHYSICS),
"set_collision_layer", "get_collision_layer");
ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_mask", PROPERTY_HINT_LAYERS_3D_PHYSICS),
"set_collision_mask", "get_collision_mask");
BIND_CONSTANT(MAX_MESH_LODS);
BIND_ENUM_CONSTANT(VisualServer::SHADOW_CASTING_SETTING_OFF);
BIND_ENUM_CONSTANT(VisualServer::SHADOW_CASTING_SETTING_ON);
BIND_ENUM_CONSTANT(VisualServer::SHADOW_CASTING_SETTING_DOUBLE_SIDED);
BIND_ENUM_CONSTANT(VisualServer::SHADOW_CASTING_SETTING_SHADOWS_ONLY);
}