From 8c2116a87b96f2c0211b29a57ed73beb42c60111 Mon Sep 17 00:00:00 2001 From: stechyo Date: Tue, 13 Feb 2024 18:17:22 +0000 Subject: [PATCH] Add dynamic geometry (closes #30). --- project/scenes/wooden_house.tscn | 5 +- src/geometry.cpp | 165 ++----------------------------- src/geometry.hpp | 3 +- src/geometry_common.hpp | 160 ++++++++++++++++++++++++++++++ src/geometry_dynamic.cpp | 146 +++++++++++++++++++++++++++ src/geometry_dynamic.hpp | 50 ++++++++++ src/register_types.cpp | 2 + src/server.cpp | 26 ++++- src/server.hpp | 6 +- src/server_init.hpp | 1 - 10 files changed, 396 insertions(+), 168 deletions(-) create mode 100644 src/geometry_common.hpp create mode 100644 src/geometry_dynamic.cpp create mode 100644 src/geometry_dynamic.hpp diff --git a/project/scenes/wooden_house.tscn b/project/scenes/wooden_house.tscn index eea5931..86d38c4 100644 --- a/project/scenes/wooden_house.tscn +++ b/project/scenes/wooden_house.tscn @@ -1,6 +1,6 @@ [gd_scene load_steps=15 format=3 uid="uid://6sgtpvtg5aic"] -[ext_resource type="SteamAudioMaterial" uid="uid://oyakg0idhulv" path="res://addons/steamaudio/materials/wood_material.tres" id="2_lm25q"] +[ext_resource type="SteamAudioMaterial" uid="uid://oyakg0idhulv" path="res://addons/godot-steam-audio/materials/wood_material.tres" id="2_lm25q"] [sub_resource type="StandardMaterial3D" id="StandardMaterial3D_xa5je"] albedo_color = Color(0.203922, 0.0901961, 0, 1) @@ -65,8 +65,7 @@ mesh = SubResource("BoxMesh_1ds6j") [node name="CollisionShape3D" type="CollisionShape3D" parent="MeshInstance3D/StaticBody3D"] shape = SubResource("ConcavePolygonShape3D_fpg8h") -[node name="SteamAudioGeometry" type="SteamAudioGeometry" parent="MeshInstance3D/StaticBody3D/CollisionShape3D"] -material = ExtResource("2_lm25q") +[node name="SteamAudioDynamicGeometry" type="SteamAudioDynamicGeometry" parent="MeshInstance3D/StaticBody3D/CollisionShape3D"] [node name="MeshInstance3D2" type="MeshInstance3D" parent="."] transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.5, -2) diff --git a/src/geometry.cpp b/src/geometry.cpp index 3ec1683..58f3940 100644 --- a/src/geometry.cpp +++ b/src/geometry.cpp @@ -1,22 +1,12 @@ #include "geometry.hpp" -#include "godot_cpp/classes/box_mesh.hpp" -#include "godot_cpp/classes/box_shape3d.hpp" -#include "godot_cpp/classes/capsule_mesh.hpp" -#include "godot_cpp/classes/capsule_shape3d.hpp" -#include "godot_cpp/classes/concave_polygon_shape3d.hpp" -#include "godot_cpp/classes/cylinder_mesh.hpp" -#include "godot_cpp/classes/cylinder_shape3d.hpp" +#include "geometry_common.hpp" +#include "godot_cpp/classes/collision_shape3d.hpp" #include "godot_cpp/classes/engine.hpp" -#include "godot_cpp/classes/importer_mesh.hpp" -#include "godot_cpp/classes/mesh.hpp" -#include "godot_cpp/classes/sphere_mesh.hpp" -#include "godot_cpp/classes/sphere_shape3d.hpp" +#include "godot_cpp/classes/mesh_instance3d.hpp" #include "godot_cpp/variant/array.hpp" -#include "godot_cpp/variant/transform3d.hpp" #include "godot_cpp/variant/utility_functions.hpp" #include "phonon.h" #include "server.hpp" -#include "steam_audio.hpp" void SteamAudioGeometry::_bind_methods() { ClassDB::bind_method(D_METHOD("get_material"), &SteamAudioGeometry::get_material); @@ -37,7 +27,6 @@ SteamAudioGeometry::~SteamAudioGeometry() { unregister_geometry(); destroy_geometry(); - iplSceneCommit(SteamAudioServer::get_singleton()->get_global_state()->scene); } void SteamAudioGeometry::_ready() { @@ -49,142 +38,6 @@ void SteamAudioGeometry::_ready() { register_geometry(); } -IPLStaticMesh godot_mesh_to_ipl_mesh(Ref mesh, IPLMaterial material, Transform3D trf, int surface_idx) { - Array dat = mesh->surface_get_arrays(surface_idx); - Array verts = dat[Mesh::ARRAY_VERTEX]; - Array tris = dat[Mesh::ARRAY_INDEX]; - - std::vector ipl_verts(verts.size()); - std::vector ipl_tris(tris.size() / 3); - std::vector ipl_mat_indices(tris.size() / 3); - - for (int j = 0; j < verts.size(); j++) { - Vector3 vert = verts[j]; - vert = trf.basis.xform(vert); - vert += trf.origin; - ipl_verts[j] = ipl_vec3_from(vert); - } - - for (int j = 0; j < tris.size(); j += 3) { - // godot tris are cw, ipl tris are ccw - ipl_tris[j / 3].indices[0] = tris[j]; - ipl_tris[j / 3].indices[1] = tris[j + 2]; - ipl_tris[j / 3].indices[2] = tris[j + 1]; - ipl_mat_indices[j / 3] = 0; - } - - IPLStaticMeshSettings static_mesh_cfg{}; - static_mesh_cfg.numVertices = int(verts.size()); - static_mesh_cfg.numTriangles = int(tris.size() / 3); - static_mesh_cfg.numMaterials = 1; - static_mesh_cfg.vertices = ipl_verts.data(); - static_mesh_cfg.triangles = ipl_tris.data(); - static_mesh_cfg.materialIndices = ipl_mat_indices.data(); - static_mesh_cfg.materials = &material; - IPLStaticMesh ipl_mesh; - iplStaticMeshCreate(SteamAudioServer::get_singleton()->get_global_state()->scene, &static_mesh_cfg, &ipl_mesh); - - return ipl_mesh; -} - -std::vector create_meshes_from_mesh_inst_3d(MeshInstance3D *mesh_inst, Ref mat) { - std::vector p_meshes; - Ref mesh = mesh_inst->get_mesh(); - Transform3D trf = mesh_inst->get_global_transform(); - - IPLMaterial material; - if (mat == nullptr) { - material = IPLMaterial{ { 0.f, 0.f, 0.f }, 0.f, { 0.f, 0.f, 0.f } }; - } else { - material = mat->get_material(); - } - - for (int i = 0; i < mesh->get_surface_count(); i++) { - auto ipl_mesh = godot_mesh_to_ipl_mesh(mesh, material, trf, i); - p_meshes.push_back(ipl_mesh); - } - - return p_meshes; -} - -std::vector create_meshes_from_coll_inst_3d(CollisionShape3D *coll_inst, Ref mat) { - std::vector p_meshes; - Transform3D trf = coll_inst->get_global_transform(); - Ref mesh; - - IPLMaterial material; - if (mat == nullptr) { - material = IPLMaterial{ { 0.f, 0.f, 0.f }, 0.f, { 0.f, 0.f, 0.f } }; - } else { - material = mat->get_material(); - } - - if (Object::cast_to(coll_inst->get_shape().ptr())) { - Ref shape = coll_inst->get_shape(); - Ref box_mesh; - box_mesh.instantiate(); - box_mesh->set_size(shape->get_size()); - mesh = box_mesh; - } else if (Object::cast_to(coll_inst->get_shape().ptr())) { - Ref shape = coll_inst->get_shape(); - Ref cyl_mesh; - cyl_mesh.instantiate(); - cyl_mesh->set_radial_segments(4); - cyl_mesh->set_rings(4); - cyl_mesh->set_bottom_radius(shape->get_radius()); - cyl_mesh->set_top_radius(shape->get_radius()); - cyl_mesh->set_height(shape->get_height()); - mesh = cyl_mesh; - } else if (Object::cast_to(coll_inst->get_shape().ptr())) { - Ref shape = coll_inst->get_shape(); - Ref cap_mesh; - cap_mesh.instantiate(); - cap_mesh->set_radial_segments(4); - cap_mesh->set_rings(4); - cap_mesh->set_radius(shape->get_radius()); - cap_mesh->set_height(shape->get_height()); - mesh = cap_mesh; - } else if (Object::cast_to(coll_inst->get_shape().ptr())) { - Ref shape = coll_inst->get_shape(); - Ref sph_mesh; - sph_mesh.instantiate(); - sph_mesh->set_radial_segments(4); - sph_mesh->set_rings(4); - sph_mesh->set_radius(shape->get_radius()); - sph_mesh->set_height(shape->get_radius() * 2); - mesh = sph_mesh; - } else if (Object::cast_to(coll_inst->get_shape().ptr())) { - Ref concave = coll_inst->get_shape(); - Ref arr_mesh; - arr_mesh.instantiate(); - auto faces = concave->get_faces(); - - PackedInt32Array tris; - tris.resize(faces.size()); - for (int i = 0; i < faces.size(); i++) { - tris[i] = i; - } - - Array surface_array; - surface_array.resize(Mesh::ArrayType::ARRAY_MAX); - surface_array[Mesh::ArrayType::ARRAY_VERTEX] = faces; - surface_array[Mesh::ArrayType::ARRAY_INDEX] = tris; - - arr_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, surface_array); - mesh = arr_mesh; - } else { - UtilityFunctions::push_error("SteamAudioGeometry supports sphere, box, cylinder, capsule and concave polygon shapes. Something else was provided, so this geometry will not do anything."); - return p_meshes; - } - - for (int i = 0; i < mesh->get_surface_count(); i++) { - auto ipl_mesh = godot_mesh_to_ipl_mesh(mesh, material, trf, i); - p_meshes.push_back(ipl_mesh); - } - mesh.unref(); - return p_meshes; -} - void SteamAudioGeometry::set_disabled(bool p_disabled) { if (disabled == p_disabled) { return; @@ -218,10 +71,10 @@ void SteamAudioGeometry::create_geometry() { } void SteamAudioGeometry::destroy_geometry() { - for (auto mesh : meshes) { - iplStaticMeshRelease(&mesh); - } - meshes.clear(); + for (auto mesh : meshes) { + iplStaticMeshRelease(&mesh); + } + meshes.clear(); } void SteamAudioGeometry::register_geometry() { @@ -231,9 +84,9 @@ void SteamAudioGeometry::register_geometry() { } void SteamAudioGeometry::unregister_geometry() { - for (auto ipl_mesh : meshes) { + for (auto ipl_mesh : meshes) { SteamAudioServer::get_singleton()->remove_static_mesh(ipl_mesh); - } + } } PackedStringArray SteamAudioGeometry::_get_configuration_warnings() const { diff --git a/src/geometry.hpp b/src/geometry.hpp index fc52d14..39430c2 100644 --- a/src/geometry.hpp +++ b/src/geometry.hpp @@ -1,8 +1,6 @@ #ifndef STEAM_AUDIO_GEOMETRY_H #define STEAM_AUDIO_GEOMETRY_H -#include "godot_cpp/classes/collision_shape3d.hpp" -#include "godot_cpp/classes/mesh_instance3d.hpp" #include "godot_cpp/classes/node3d.hpp" #include "godot_cpp/classes/wrapped.hpp" #include "material.hpp" @@ -21,6 +19,7 @@ class SteamAudioGeometry : public Node3D { void destroy_geometry(); void register_geometry(); void unregister_geometry(); + protected: static void _bind_methods(); diff --git a/src/geometry_common.hpp b/src/geometry_common.hpp new file mode 100644 index 0000000..438373a --- /dev/null +++ b/src/geometry_common.hpp @@ -0,0 +1,160 @@ +#ifndef STEAM_AUDIO_GEOMETRY_COMMON_H +#define STEAM_AUDIO_GEOMETRY_COMMON_H + +#include "godot_cpp/classes/array_mesh.hpp" +#include "godot_cpp/classes/box_mesh.hpp" +#include "godot_cpp/classes/box_shape3d.hpp" +#include "godot_cpp/classes/capsule_mesh.hpp" +#include "godot_cpp/classes/capsule_shape3d.hpp" +#include "godot_cpp/classes/collision_shape3d.hpp" +#include "godot_cpp/classes/concave_polygon_shape3d.hpp" +#include "godot_cpp/classes/cylinder_mesh.hpp" +#include "godot_cpp/classes/cylinder_shape3d.hpp" +#include "godot_cpp/classes/mesh.hpp" +#include "godot_cpp/classes/mesh_instance3d.hpp" +#include "godot_cpp/classes/sphere_mesh.hpp" +#include "godot_cpp/classes/sphere_shape3d.hpp" +#include "material.hpp" +#include "phonon.h" +#include "server.hpp" +#include "steam_audio.hpp" +#include +using namespace godot; + +inline IPLStaticMesh godot_mesh_to_ipl_mesh(Ref mesh, IPLMaterial material, Transform3D trf, int surface_idx) { + Array dat = mesh->surface_get_arrays(surface_idx); + Array verts = dat[Mesh::ARRAY_VERTEX]; + Array tris = dat[Mesh::ARRAY_INDEX]; + + std::vector ipl_verts(verts.size()); + std::vector ipl_tris(tris.size() / 3); + std::vector ipl_mat_indices(tris.size() / 3); + + for (int j = 0; j < verts.size(); j++) { + Vector3 vert = verts[j]; + vert = trf.basis.xform(vert); + vert += trf.origin; + ipl_verts[j] = ipl_vec3_from(vert); + } + + for (int j = 0; j < tris.size(); j += 3) { + // godot tris are cw, ipl tris are ccw + ipl_tris[j / 3].indices[0] = tris[j]; + ipl_tris[j / 3].indices[1] = tris[j + 2]; + ipl_tris[j / 3].indices[2] = tris[j + 1]; + ipl_mat_indices[j / 3] = 0; + } + + IPLStaticMeshSettings static_mesh_cfg{}; + static_mesh_cfg.numVertices = int(verts.size()); + static_mesh_cfg.numTriangles = int(tris.size() / 3); + static_mesh_cfg.numMaterials = 1; + static_mesh_cfg.vertices = ipl_verts.data(); + static_mesh_cfg.triangles = ipl_tris.data(); + static_mesh_cfg.materialIndices = ipl_mat_indices.data(); + static_mesh_cfg.materials = &material; + IPLStaticMesh ipl_mesh; + iplStaticMeshCreate(SteamAudioServer::get_singleton()->get_global_state()->scene, &static_mesh_cfg, &ipl_mesh); + + return ipl_mesh; +} + +inline std::vector create_meshes_from_mesh_inst_3d(MeshInstance3D *mesh_inst, Ref mat) { + std::vector p_meshes; + Ref mesh = mesh_inst->get_mesh(); + Transform3D trf = mesh_inst->get_global_transform(); + + IPLMaterial material; + if (mat == nullptr) { + material = IPLMaterial{ { 0.f, 0.f, 0.f }, 0.f, { 0.f, 0.f, 0.f } }; + } else { + material = mat->get_material(); + } + + for (int i = 0; i < mesh->get_surface_count(); i++) { + auto ipl_mesh = godot_mesh_to_ipl_mesh(mesh, material, trf, i); + p_meshes.push_back(ipl_mesh); + } + + return p_meshes; +} + +inline std::vector create_meshes_from_coll_inst_3d(CollisionShape3D *coll_inst, Ref mat) { + std::vector p_meshes; + Transform3D trf = coll_inst->get_global_transform(); + Ref mesh; + + IPLMaterial material; + if (mat == nullptr) { + material = IPLMaterial{ { 0.f, 0.f, 0.f }, 0.f, { 0.f, 0.f, 0.f } }; + } else { + material = mat->get_material(); + } + + if (Object::cast_to(coll_inst->get_shape().ptr())) { + Ref shape = coll_inst->get_shape(); + Ref box_mesh; + box_mesh.instantiate(); + box_mesh->set_size(shape->get_size()); + mesh = box_mesh; + } else if (Object::cast_to(coll_inst->get_shape().ptr())) { + Ref shape = coll_inst->get_shape(); + Ref cyl_mesh; + cyl_mesh.instantiate(); + cyl_mesh->set_radial_segments(4); + cyl_mesh->set_rings(4); + cyl_mesh->set_bottom_radius(shape->get_radius()); + cyl_mesh->set_top_radius(shape->get_radius()); + cyl_mesh->set_height(shape->get_height()); + mesh = cyl_mesh; + } else if (Object::cast_to(coll_inst->get_shape().ptr())) { + Ref shape = coll_inst->get_shape(); + Ref cap_mesh; + cap_mesh.instantiate(); + cap_mesh->set_radial_segments(4); + cap_mesh->set_rings(4); + cap_mesh->set_radius(shape->get_radius()); + cap_mesh->set_height(shape->get_height()); + mesh = cap_mesh; + } else if (Object::cast_to(coll_inst->get_shape().ptr())) { + Ref shape = coll_inst->get_shape(); + Ref sph_mesh; + sph_mesh.instantiate(); + sph_mesh->set_radial_segments(4); + sph_mesh->set_rings(4); + sph_mesh->set_radius(shape->get_radius()); + sph_mesh->set_height(shape->get_radius() * 2); + mesh = sph_mesh; + } else if (Object::cast_to(coll_inst->get_shape().ptr())) { + Ref concave = coll_inst->get_shape(); + Ref arr_mesh; + arr_mesh.instantiate(); + auto faces = concave->get_faces(); + + PackedInt32Array tris; + tris.resize(faces.size()); + for (int i = 0; i < faces.size(); i++) { + tris[i] = i; + } + + Array surface_array; + surface_array.resize(Mesh::ArrayType::ARRAY_MAX); + surface_array[Mesh::ArrayType::ARRAY_VERTEX] = faces; + surface_array[Mesh::ArrayType::ARRAY_INDEX] = tris; + + arr_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, surface_array); + mesh = arr_mesh; + } else { + SteamAudio::log(SteamAudio::log_error, "SteamAudioGeometry supports sphere, box, cylinder, capsule and concave polygon shapes. Something else was provided, so this geometry will not do anything."); + return p_meshes; + } + + for (int i = 0; i < mesh->get_surface_count(); i++) { + auto ipl_mesh = godot_mesh_to_ipl_mesh(mesh, material, trf, i); + p_meshes.push_back(ipl_mesh); + } + mesh.unref(); + return p_meshes; +} + +#endif // STEAM_AUDIO_GEOMETRY_COMMON_H diff --git a/src/geometry_dynamic.cpp b/src/geometry_dynamic.cpp new file mode 100644 index 0000000..dcac63d --- /dev/null +++ b/src/geometry_dynamic.cpp @@ -0,0 +1,146 @@ +#include "geometry_dynamic.hpp" +#include "geometry_common.hpp" +#include "godot_cpp/classes/collision_shape3d.hpp" +#include "godot_cpp/classes/engine.hpp" +#include "godot_cpp/classes/mesh_instance3d.hpp" +#include "phonon.h" +#include "server.hpp" +#include "steam_audio.hpp" + +SteamAudioDynamicGeometry::SteamAudioDynamicGeometry() {} + +SteamAudioDynamicGeometry::~SteamAudioDynamicGeometry() { + if (Engine::get_singleton()->is_editor_hint()) { + return; + } + + unregister_geometry(); + destroy_geometry(); +} + +void SteamAudioDynamicGeometry::_bind_methods() { + ClassDB::bind_method(D_METHOD("get_material"), &SteamAudioDynamicGeometry::get_material); + ClassDB::bind_method(D_METHOD("set_material", "p_material"), &SteamAudioDynamicGeometry::set_material); + ClassDB::bind_method(D_METHOD("recalculate"), &SteamAudioDynamicGeometry::recalculate); + + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "material", PROPERTY_HINT_RESOURCE_TYPE, "SteamAudioMaterial"), "set_material", "get_material"); +} + +void SteamAudioDynamicGeometry::recalculate() { + unregister_geometry(); + destroy_geometry(); + create_geometry(); + register_geometry(); +} + +void SteamAudioDynamicGeometry::_notification(int p_what) { + switch (p_what) { + case NOTIFICATION_ENTER_TREE: + ready_internal(); + break; + case NOTIFICATION_PROCESS: + process_internal(get_process_delta_time()); + break; + } +} + +void SteamAudioDynamicGeometry::ready_internal() { + if (Engine::get_singleton()->is_editor_hint()) { + return; + } + + create_geometry(); + register_geometry(); +} + +void SteamAudioDynamicGeometry::process_internal(double delta) { + if (!is_init.load()) { + register_geometry(); + if (!is_init.load()) { + return; // SteamAudio is not properly initialized yet + } + } + + auto new_orig = get_global_transform().origin - trf_at_register.origin; + auto new_right = get_global_transform().get_basis().get_column(0) - trf_at_register.get_basis().get_column(0); + auto new_up = get_global_transform().get_basis().get_column(1) - trf_at_register.get_basis().get_column(1); + auto new_fwd = get_global_transform().get_basis().get_column(2) - trf_at_register.get_basis().get_column(2); + + IPLMatrix4x4 new_trf{ + { + { new_right.x, new_up.x, new_fwd.x, new_orig.x }, + { new_right.y, new_up.y, new_fwd.y, new_orig.y }, + { new_right.z, new_up.z, new_fwd.z, new_orig.z }, + { 0., 0., 0., 1. }, + } + }; + + // TODO: check if it improves perf to skip this if the object does not move. + iplInstancedMeshUpdateTransform(mesh, SteamAudioServer::get_singleton()->get_global_state()->scene, new_trf); +} + +Ref SteamAudioDynamicGeometry::get_material() { return mat; } +void SteamAudioDynamicGeometry::set_material(Ref p_material) { mat = p_material; } + +PackedStringArray SteamAudioDynamicGeometry::_get_configuration_warnings() const { + PackedStringArray res; + if (!Object::cast_to(get_parent()) && !Object::cast_to(get_parent())) { + res.push_back("The parent of SteamAudioGeometry must be a MeshInstance3D or a CollisionShape3D."); + } + return res; +} + +void SteamAudioDynamicGeometry::create_geometry() { + if (Object::cast_to(get_parent())) { + meshes = create_meshes_from_mesh_inst_3d(Object::cast_to(get_parent()), mat); + } else if (Object::cast_to(get_parent())) { + meshes = create_meshes_from_coll_inst_3d(Object::cast_to(get_parent()), mat); + } else { + SteamAudio::log(SteamAudio::log_error, "The parent of SteamAudioGeometry must be a MeshInstance3D or a CollisionShape3D."); + return; + } +} + +void SteamAudioDynamicGeometry::destroy_geometry() { + for (auto m : meshes) { + iplStaticMeshRelease(&m); + } + meshes.clear(); +} + +void SteamAudioDynamicGeometry::register_geometry() { + auto gs = SteamAudioServer::get_singleton()->get_global_state(); + if (gs == nullptr) { + return; // not inititalized yet, ret + } + + IPLMatrix4x4 trf = IPLMatrix4x4{ { + { 1., 0., 0., 0. }, + { 0., 1., 0., 0. }, + { 0., 0., 1., 0. }, + { 0., 0., 0., 1. }, + } }; + trf_at_register = get_global_transform(); + + IPLSceneSettings sub_scene_cfg = {}; + sub_scene_cfg.type = IPL_SCENETYPE_DEFAULT; + IPLScene sub_scene; + IPLerror err = iplSceneCreate(gs->ctx, &sub_scene_cfg, &sub_scene); + handleErr(err); + + for (auto m : meshes) { + iplStaticMeshAdd(m, sub_scene); + } + iplSceneCommit(sub_scene); + + IPLInstancedMeshSettings mesh_cfg{ sub_scene, trf }; + err = iplInstancedMeshCreate(gs->scene, &mesh_cfg, &mesh); + handleErr(err); + + is_init.store(true); + SteamAudioServer::get_singleton()->add_dynamic_mesh(mesh); +} + +void SteamAudioDynamicGeometry::unregister_geometry() { + SteamAudioServer::get_singleton()->remove_dynamic_mesh(mesh); +} diff --git a/src/geometry_dynamic.hpp b/src/geometry_dynamic.hpp new file mode 100644 index 0000000..c12470c --- /dev/null +++ b/src/geometry_dynamic.hpp @@ -0,0 +1,50 @@ +#ifndef STEAM_AUDIO_DYNAMIC_GEOMETRY_H +#define STEAM_AUDIO_DYNAMIC_GEOMETRY_H + +#include "godot_cpp/classes/node3d.hpp" +#include "godot_cpp/variant/transform3d.hpp" +#include "material.hpp" +#include "phonon.h" +#include + +using namespace godot; + +class SteamAudioDynamicGeometry : public Node3D { + GDCLASS(SteamAudioDynamicGeometry, Node3D); + +private: + std::atomic_bool is_init; + IPLInstancedMesh mesh = nullptr; + std::vector meshes; + Ref mat; + // TODO: when we register, the transform will be zeros-only. This is done so + // because the internal meshes themselves are already transformed, so when + // motion happens we only apply a delta between the transform at register and + // the transform at _process(). + Transform3D trf_at_register; + + void create_geometry(); + void destroy_geometry(); + void register_geometry(); + void unregister_geometry(); + +protected: + static void _bind_methods(); + +public: + SteamAudioDynamicGeometry(); + ~SteamAudioDynamicGeometry(); + void ready_internal(); + void process_internal(double delta); + void _notification(int p_what); + + void recalculate(); + void init_mesh(); + + Ref get_material(); + void set_material(Ref p_material); + + PackedStringArray _get_configuration_warnings() const override; +}; + +#endif // STEAM_AUDIO_DYNAMIC_GEOMETRY_H diff --git a/src/register_types.cpp b/src/register_types.cpp index f3bf443..8eb9325 100644 --- a/src/register_types.cpp +++ b/src/register_types.cpp @@ -2,6 +2,7 @@ #include "config.hpp" #include "geometry.hpp" +#include "geometry_dynamic.hpp" #include "listener.hpp" #include "material.hpp" #include "player.hpp" @@ -25,6 +26,7 @@ void init_ext(ModuleInitializationLevel p_level) { ClassDB::register_class(); ClassDB::register_class(); ClassDB::register_class(); + ClassDB::register_class(); ClassDB::register_class(); ClassDB::register_class(); ClassDB::register_class(); diff --git a/src/server.cpp b/src/server.cpp index bb15cd1..6e62f9c 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -185,7 +185,7 @@ GlobalSteamAudioState *SteamAudioServer::get_global_state(bool should_init) { IPLerror err = iplSceneCreate(global_state.ctx, &scene_cfg, &global_state.scene); handleErr(err); global_state.scene = iplSceneRetain(global_state.scene); - for (auto m : meshes_to_add) { + for (auto m : static_meshes_to_add) { iplStaticMeshAdd(m, global_state.scene); } @@ -254,7 +254,7 @@ void SteamAudioServer::add_static_mesh(IPLStaticMesh mesh) { if (is_global_state_init.load()) { iplStaticMeshAdd(mesh, global_state.scene); } else { - meshes_to_add.push_back(mesh); + static_meshes_to_add.push_back(mesh); } } @@ -263,13 +263,29 @@ void SteamAudioServer::remove_static_mesh(IPLStaticMesh mesh) { iplStaticMeshRemove(mesh, global_state.scene); } else { // Probably won't happen? - auto it = std::find(meshes_to_add.begin(), meshes_to_add.end(), mesh); - if (it != meshes_to_add.end()) { - meshes_to_add.erase(it); + auto it = std::find(static_meshes_to_add.begin(), static_meshes_to_add.end(), mesh); + if (it != static_meshes_to_add.end()) { + static_meshes_to_add.erase(it); } } } +void SteamAudioServer::add_dynamic_mesh(IPLInstancedMesh mesh) { + if (is_global_state_init.load()) { + iplInstancedMeshAdd(mesh, global_state.scene); + } else { + SteamAudio::log(SteamAudio::log_error, "Adding a dynamic mesh, but SteamAudio is not initialized. Probably crashing soon."); + } +} + +void SteamAudioServer::remove_dynamic_mesh(IPLInstancedMesh mesh) { + if (!is_global_state_init.load()) { + return; // We've probably already deleted the scene. + } + + iplInstancedMeshRemove(mesh, global_state.scene); +} + SteamAudioServer::SteamAudioServer() { self = this; is_global_state_init.store(false); diff --git a/src/server.hpp b/src/server.hpp index 0140727..6421636 100644 --- a/src/server.hpp +++ b/src/server.hpp @@ -27,7 +27,9 @@ class SteamAudioServer : public Object { std::mutex refl_mux; std::condition_variable cv; - std::vector meshes_to_add; + // meshes to add to the global state scene after it's initialized. + std::vector static_meshes_to_add; + std::vector dynamic_meshes_to_add; // TODO: allow for multiple SteamAudioListener *listener; @@ -52,6 +54,8 @@ class SteamAudioServer : public Object { void remove_local_state(LocalSteamAudioState *ls); void add_static_mesh(IPLStaticMesh mesh); void remove_static_mesh(IPLStaticMesh mesh); + void add_dynamic_mesh(IPLInstancedMesh mesh); + void remove_dynamic_mesh(IPLInstancedMesh mesh); void tick(); }; diff --git a/src/server_init.hpp b/src/server_init.hpp index 78745f5..fac1ced 100644 --- a/src/server_init.hpp +++ b/src/server_init.hpp @@ -4,7 +4,6 @@ using namespace godot; IPLAudioSettings create_audio_cfg(); -void create_scene(IPLContext ctx, IPLSceneSettings *scene_cfg, IPLScene *scene); IPLHRTF create_hrtf(IPLContext ctx, IPLAudioSettings audio_cfg); IPLAmbisonicsDecodeEffect create_ambisonics_decode_effect(IPLContext ctx, IPLAudioSettings audio_cfg, IPLHRTF hrtf); IPLAmbisonicsEncodeEffect create_ambisonics_encode_effect(IPLContext ctx, IPLAudioSettings audio_cfg);