Skip to content

Commit

Permalink
Merge pull request #40 from Demindiro/extra-functions-call
Browse files Browse the repository at this point in the history
  • Loading branch information
Demindiro authored Jul 13, 2021
2 parents 1d020c4 + 0e01780 commit feb34ad
Show file tree
Hide file tree
Showing 18 changed files with 615 additions and 9 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,4 @@ module/api.gen.h
module/server.gen.cpp
__pycache__/
*.o
*.pyc
22 changes: 22 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

23 changes: 22 additions & 1 deletion module/generate.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@
'body_set_force_integration_callback',
'body_get_direct_state',
'body_get_collision_exceptions',
'call',
'free',
'soft_body_get_collision_exceptions',
'soft_body_update_visual_server',
Expand All @@ -74,6 +75,11 @@

# Extra functions to add to the API
API_CUSTOM_FUNCTIONS = {
'call': ('struct physics_call_result', [
('const wchar_t *', 'method'),
('const godot_variant **', 'args'),
('size_t', 'arg_count'),
]),
'area_get_body_event': ('bool', [
('index_t', 'area'),
('struct physics_area_monitor_event *', 'event')
Expand Down Expand Up @@ -124,10 +130,24 @@
'soft_body_get_collision_exception_count': ('int', [
('index_t', 'body')
]),
'server_get_index': ('index_t', [
('const struct physics_server *', 'server'),
('godot_rid', 'rid'),
]),
'server_get_rid': ('godot_rid', [
('const struct physics_server *', 'server'),
('index_t', 'index'),
]),
}

# Structs to include in the API
API_STRUCTS = {
'physics_call_result': [
('godot_variant', 'value'),
('uint8_t', 'status'),
('uint8_t', 'argument'),
('uint8_t', 'expected_type'),
],
'physics_body_state': [
('godot_transform', 'transform'),
('godot_vector3', 'linear_velocity'),
Expand Down Expand Up @@ -190,7 +210,8 @@
('index_t', 'id'),
('int', 'object_id'),
('bool', 'added'),
]
],
'physics_server': [],
}

# Functions for which to validate all RIDs
Expand Down
34 changes: 32 additions & 2 deletions module/server.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ PluggablePhysicsServer::~PluggablePhysicsServer() {

void PluggablePhysicsServer::_bind_methods() {
ClassDB::bind_method(D_METHOD("step", "delta"), &PluggablePhysicsServer::step);
ClassDB::bind_method(D_METHOD("get_rid", "index"), &PluggablePhysicsServer::get_rid);
ClassDB::bind_method(D_METHOD("get_index", "rid"), &PluggablePhysicsServer::get_index);
}

void PluggablePhysicsServer::area_set_monitor_callback(RID area, Object *receiver, const StringName &method) {
Expand Down Expand Up @@ -63,11 +65,39 @@ void PluggablePhysicsServer::init() {
ERR_FAIL_COND_MSG(err, "Failed to get init handle");

// SAFETY: the callee must have the exact same signature
void (*init_func)(struct fn_table *) = reinterpret_cast<void (*)(struct fn_table *)>(handle);
init_func(&this->fn_table);
void (*init_func)(const struct physics_server *ps, struct fn_table *) = reinterpret_cast<void (*)(const struct physics_server *ps, struct fn_table *)>(handle);
// SAFETY: it's just a pointer
const struct physics_server *ps = reinterpret_cast<struct physics_server *>(this);
// SAFETY: the two functions are ABI compatible.
this->fn_table.server_get_index = _get_index;
// SAFETY: Ditto
this->fn_table.server_get_rid = _get_rid;
init_func(ps, &this->fn_table);
}
}

Variant PluggablePhysicsServer::call(const StringName &method, const Variant **args, int argcount, Variant::CallError &error) {
if (this->fn_table.call != nullptr) {
// TODO should we call the Godot or the Rapier method first?
// I've decided to go with Rapier method first since it uses a match statement internally,
// which is very likely to be much faster than a hashmap lookup (which is what Godot will do).

// TODO find a way that avoids potential redundant malloc calls.
// Because malloc may return NULL the compiler isn't always able to optimize it out if it
// would have side effects (e.g. error message).
String m(method);
struct physics_call_result result = (*this->fn_table.call)(m.ptr(), args, (size_t)argcount);
error.error = (Variant::CallError::Error)result.status;
if (error.error != Variant::CallError::Error::CALL_ERROR_INVALID_METHOD) {
error.argument = result.argument;
error.expected = (Variant::Type)result.expected_type;
return result.value;
}
}

return PhysicsServer::call(method, args, argcount, error);
}

void PluggablePhysicsServer::step(float delta) {
EXEC_FFI_FN(this, step, delta);

Expand Down
23 changes: 23 additions & 0 deletions module/server.h
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,12 @@ class PluggablePhysicsServer : public PhysicsServer {
return rid;
}

/**
* Returns the index associated with a RID. An index is a 64 bit integer used internally by the
* physics engine and is necessary to use any of the additional methods.
*
* Returns `0` if the RID is invalid.
*/
_FORCE_INLINE_ index_t get_index(RID rid) const {
if (rid.is_valid()) {
PluggablePhysicsRID_Data *data = this->rids.get(rid);
Expand All @@ -104,13 +110,30 @@ class PluggablePhysicsServer : public PhysicsServer {
return 0;
}

/**
* Returns the RID associated with an index. An index is a 64 bit integer used internally by the
* physics engine and is necessary to use any of the additional methods.
*/
_FORCE_INLINE_ RID get_rid(index_t index) const {
return index != 0 ? this->reverse_rids.get(index) : RID();
}

// Every line of C++ I write makes me hate the language even more.
//
// See https://isocpp.org/wiki/faq/pointers-to-members
static index_t _get_index(const struct physics_server *server, godot_rid rid) {
return reinterpret_cast<const PluggablePhysicsServer *>(server)->get_index(rid);
}

static godot_rid _get_rid(const struct physics_server *server, index_t index) {
return reinterpret_cast<const PluggablePhysicsServer *>(server)->get_rid(index);
}

protected:
static void _bind_methods();

Variant call(const StringName &p_method, const Variant **p_args, int p_argcount, Variant::CallError &r_error);

public:
PluggablePhysicsServer();
~PluggablePhysicsServer();
Expand Down
1 change: 1 addition & 0 deletions module/typedef.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,6 @@ typedef Vector3 godot_vector3;
typedef Variant godot_variant;
typedef StringName godot_string_name;
typedef Object godot_object;
typedef RID godot_rid;

#endif
1 change: 1 addition & 0 deletions rapier3d/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ name = "godot_rapier3d"
rapier3d = { git = "https://github.com/Demindiro/rapier", branch = "godot-0.9", version = "*", features = ["simd-nightly"] }
gdnative = "*"
lazy_static = "*"
wchar = "*"

[build-dependencies]
json = "*"
Expand Down
13 changes: 13 additions & 0 deletions rapier3d/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -152,14 +152,18 @@ fn generate_structs(api: &json::JsonValue) -> TokenStream {
fn map_type(t: &str) -> TokenStream {
match t {
"index_t" | "maybe_index_t" => quote!(u64),
"uint8_t" => quote!(u8),
"uint32_t" => quote!(u32),
"int" => quote!(i32),
"bool" => quote!(bool),
"float" | "real_t" => quote!(f32),
"size_t" => quote!(usize),
"void" => quote!(()),
"void *" => quote!(*const ()),
"const wchar_t *" => quote!(*const wchar::wchar_t),
"const index_t *" => quote!(*mut u64),
"struct physics_call_result" => quote!(physics_call_result),
"const godot_variant **" => quote!(*const *const sys::godot_variant),
_ if t.starts_with("struct ") && t.ends_with(" *") => {
format!("*mut {}", &t["struct ".len()..t.len() - " *".len()])
.parse()
Expand Down Expand Up @@ -201,15 +205,19 @@ fn convert_type_from_sys(name: &TokenStream, t: &str) -> (TokenStream, bool) {
"size_t" | "uint32_t" | "int" | "bool" | "float" | "real_t" | "void *" => {
(quote!(#name), false)
}
"const wchar_t *" => (quote!(#name), false),
"struct physics_ray_info" => (quote!(&*#name), false),
"godot_rid" => (quote!(RID), false),
"godot_vector3 *" => (
quote!(&mut *(#name as *mut sys::godot_vector3 as *mut Vector3)),
false,
),
//"godot_variant" => (quote!(#name), false),
"const godot_variant *" => (
quote!(&*(#name as *const sys::godot_variant as *const Variant)),
false,
),
"const godot_variant **" => (quote!(#name as *const &Variant), false),
"const godot_transform *" => (
quote!(&*(#name as *const sys::godot_transform as *const Transform)),
false,
Expand All @@ -232,14 +240,19 @@ fn get_type_from_sys(t: &str) -> TokenStream {
"index_t" => quote!(Index),
"maybe_index_t" => quote!(Option<Index>),
"void *" => quote!(*const ()),
"uint8_t" => quote!(u8),
"uint32_t" => quote!(u32),
"int" => quote!(i32),
"bool" => quote!(bool),
"float" | "real_t" => quote!(f32),
"size_t" => quote!(usize),
"const wchar_t *" => quote!(*const wchar::wchar_t),
"godot_rid" => quote!(RID),
"godot_vector3 *" => quote!(&mut Vector3),
"godot_pool_vector3_array" => quote!(TypedArray<Vector3>),
//"godot_variant" => quote!(Variant),
"const godot_variant *" => quote!(&Variant),
"const godot_variant **" => quote!(*const *const sys::godot_variant),
"const godot_transform *" => quote!(&Transform),
"const godot_vector3 *" => quote!(&Vector3),
_ if t.starts_with("struct ") && t.ends_with(" *") => {
Expand Down
10 changes: 10 additions & 0 deletions rapier3d/src/body.rs
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,7 @@ impl Body {
mp.local_com = Point3::new(0.0, 0.0, 0.0);
};
mp.inv_mass = body.mass_properties().inv_mass;
mp.local_com = body.mass_properties().local_com;
body.set_mass_properties(mp, true);
self.inertia_stale = false;
}
Expand Down Expand Up @@ -859,6 +860,15 @@ impl Body {
};
self.map_rigidbody(|body| body.is_rotation_locked()[axis])
}

/// Set the local center of mass of this body.
pub fn set_local_com(&mut self, position: Vector3, wake_up: bool) {
self.map_rigidbody_mut(|body| {
let mut mp = *body.mass_properties();
mp.local_com = Point::new(position.x, position.y, position.z);
body.set_mass_properties(mp, wake_up);
})
}
}

impl ContactEvent {
Expand Down
1 change: 1 addition & 0 deletions rapier3d/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#![feature(destructuring_assignment)]
#![feature(option_result_unwrap_unchecked)]

mod area;
mod body;
Expand Down
25 changes: 25 additions & 0 deletions rapier3d/src/server/body.rs
Original file line number Diff line number Diff line change
Expand Up @@ -430,6 +430,31 @@ fn is_axis_locked(body: Index, axis: i32) -> bool {
}
}

/// Extra methods exposed through the "call" function.
mod call {
use super::super::call;
use super::*;
use ffi::{PhysicsCallError, VariantType};

/// Set the local center of mass.
pub fn set_local_com(arguments: &[&Variant]) -> call::Result {
call_check_arg_count!(arguments in 2..3)?;
let body = call_get_arg!(arguments[0] => Rid)?;
let com = call_get_arg!(arguments[1] => Vector3)?;
let wake = call_get_arg!(arguments[2] => bool || true)?;
if let Ok(body) = super::get_index(body) {
map_or_err!(body, map_body_mut, |body, _| {
body.set_local_com(com, wake);
});
} else {
godot_error!("Invalid index");
}
Ok(Variant::new())
}
}

pub(super) use call::*;

/// Godot's "It's local position but global rotation" is such a mindfuck that this function exists
/// to help out
fn transform_force_arguments(
Expand Down
Loading

0 comments on commit feb34ad

Please sign in to comment.