Skip to content

Commit

Permalink
Add dynamic geometry (closes #30).
Browse files Browse the repository at this point in the history
  • Loading branch information
stechyo committed Feb 13, 2024
1 parent a4a5712 commit 3189fd7
Show file tree
Hide file tree
Showing 5 changed files with 304 additions and 158 deletions.
165 changes: 9 additions & 156 deletions src/geometry.cpp
Original file line number Diff line number Diff line change
@@ -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);
Expand All @@ -37,7 +27,6 @@ SteamAudioGeometry::~SteamAudioGeometry() {

unregister_geometry();
destroy_geometry();
iplSceneCommit(SteamAudioServer::get_singleton()->get_global_state()->scene);
}

void SteamAudioGeometry::_ready() {
Expand All @@ -49,142 +38,6 @@ void SteamAudioGeometry::_ready() {
register_geometry();
}

IPLStaticMesh godot_mesh_to_ipl_mesh(Ref<Mesh> 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<IPLVector3> ipl_verts(verts.size());
std::vector<IPLTriangle> ipl_tris(tris.size() / 3);
std::vector<IPLint32> 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<IPLStaticMesh> create_meshes_from_mesh_inst_3d(MeshInstance3D *mesh_inst, Ref<SteamAudioMaterial> mat) {
std::vector<IPLStaticMesh> p_meshes;
Ref<Mesh> 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<IPLStaticMesh> create_meshes_from_coll_inst_3d(CollisionShape3D *coll_inst, Ref<SteamAudioMaterial> mat) {
std::vector<IPLStaticMesh> p_meshes;
Transform3D trf = coll_inst->get_global_transform();
Ref<Mesh> 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<BoxShape3D>(coll_inst->get_shape().ptr())) {
Ref<BoxShape3D> shape = coll_inst->get_shape();
Ref<BoxMesh> box_mesh;
box_mesh.instantiate();
box_mesh->set_size(shape->get_size());
mesh = box_mesh;
} else if (Object::cast_to<CylinderShape3D>(coll_inst->get_shape().ptr())) {
Ref<CylinderShape3D> shape = coll_inst->get_shape();
Ref<CylinderMesh> 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<CapsuleShape3D>(coll_inst->get_shape().ptr())) {
Ref<CapsuleShape3D> shape = coll_inst->get_shape();
Ref<CapsuleMesh> 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<SphereShape3D>(coll_inst->get_shape().ptr())) {
Ref<SphereShape3D> shape = coll_inst->get_shape();
Ref<SphereMesh> 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<ConcavePolygonShape3D>(coll_inst->get_shape().ptr())) {
Ref<ConcavePolygonShape3D> concave = coll_inst->get_shape();
Ref<ArrayMesh> 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;
Expand Down Expand Up @@ -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() {
Expand All @@ -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 {
Expand Down
3 changes: 1 addition & 2 deletions src/geometry.hpp
Original file line number Diff line number Diff line change
@@ -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"
Expand All @@ -21,6 +19,7 @@ class SteamAudioGeometry : public Node3D {
void destroy_geometry();
void register_geometry();
void unregister_geometry();

protected:
static void _bind_methods();

Expand Down
160 changes: 160 additions & 0 deletions src/geometry_common.hpp
Original file line number Diff line number Diff line change
@@ -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 <vector>
using namespace godot;

inline IPLStaticMesh godot_mesh_to_ipl_mesh(Ref<Mesh> 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<IPLVector3> ipl_verts(verts.size());
std::vector<IPLTriangle> ipl_tris(tris.size() / 3);
std::vector<IPLint32> 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<IPLStaticMesh> create_meshes_from_mesh_inst_3d(MeshInstance3D *mesh_inst, Ref<SteamAudioMaterial> mat) {
std::vector<IPLStaticMesh> p_meshes;
Ref<Mesh> 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<IPLStaticMesh> create_meshes_from_coll_inst_3d(CollisionShape3D *coll_inst, Ref<SteamAudioMaterial> mat) {
std::vector<IPLStaticMesh> p_meshes;
Transform3D trf = coll_inst->get_global_transform();
Ref<Mesh> 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<BoxShape3D>(coll_inst->get_shape().ptr())) {
Ref<BoxShape3D> shape = coll_inst->get_shape();
Ref<BoxMesh> box_mesh;
box_mesh.instantiate();
box_mesh->set_size(shape->get_size());
mesh = box_mesh;
} else if (Object::cast_to<CylinderShape3D>(coll_inst->get_shape().ptr())) {
Ref<CylinderShape3D> shape = coll_inst->get_shape();
Ref<CylinderMesh> 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<CapsuleShape3D>(coll_inst->get_shape().ptr())) {
Ref<CapsuleShape3D> shape = coll_inst->get_shape();
Ref<CapsuleMesh> 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<SphereShape3D>(coll_inst->get_shape().ptr())) {
Ref<SphereShape3D> shape = coll_inst->get_shape();
Ref<SphereMesh> 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<ConcavePolygonShape3D>(coll_inst->get_shape().ptr())) {
Ref<ConcavePolygonShape3D> concave = coll_inst->get_shape();
Ref<ArrayMesh> 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
Loading

0 comments on commit 3189fd7

Please sign in to comment.