// Copyright (C) 2016-2016 ChaosForge Ltd // http://chaosforge.org/ // // This file is part of Nova libraries. // For conditions of distribution and use, see copying.txt file in root folder. #include "nv/engine/ragdoll_manager.hh" #include "nv/lua/lua_math.hh" using namespace nv; nv::ragdoll_manager::ragdoll_manager( model_manager* model ) : m_world( nullptr ), m_model( model ) { } void nv::ragdoll_manager::initialize( lua::state* state ) { lua_resource_manager< ragdoll_data >::initialize( state ); } bool nv::ragdoll_manager::load_resource( lua::table_guard& table, shash64 id ) { NV_ASSERT_ALWAYS( m_world, "Physics world not setup in ragdoll_manager!" ); bool result = false; nv::string64 model_id = table.get_string64( "model" ); nv::resource< model > mr = m_model->get( model_id ); if ( !mr ) return false; nv::resource< animator_bind_data > bindr; if ( auto m = mr.lock() ) bindr = mr.lock()->bind_data; if ( !bindr ) return false; ragdoll_data* d = new ragdoll_data; { nv::lua::table_guard root( table, 1 ); result = load_ragdoll( root, bindr, d, -1 ); } if ( result ) { if ( auto bind = bindr.lock() ) { const nv::data_node_list& bl = bind->get_bone_list(); d->bone_mask.resize( bl.size(), true ); for ( nv::uint32 i = 1; i < d->parts.size(); ++i ) { d->bone_mask[d->parts[i].bone_id] = false; } } add( id, d ); } return result; } void nv::ragdoll_manager::release( ragdoll_data* p ) { for ( auto& part : p->parts ) m_world->release( part.shape ); } bool nv::ragdoll_manager::load_ragdoll( lua::table_guard& table, resource< animator_bind_data > rbind, ragdoll_data* data, int pindex ) { if ( auto bind_data = rbind.lock() ) { data->id = table.get_string32( "id" ); int index = data->parts.size(); data->parts.emplace_back(); auto& part = data->parts.back(); part.name = table.get_string_hash_64( "name" ); part.bone_id = nv::uint32( bind_data->get_bone_list().resolve( table.get_string_hash_64( "bone" ) ) ); NV_ASSERT( part.bone_id < 256, "Bone ID not found!" ); float radius = table.get_float( "radius" ); float length = 0.0f; if ( table.has_field( "target" ) ) { const auto& of = bind_data->get_bone_transforms().m_offsets; int target = bind_data->get_bone_list().resolve( table.get_string_hash_64( "target" ) ); if ( target < 0 ) return false; length = math::distance( of[part.bone_id].get_position(), of[target].get_position() ); } else { length = table.get_float( "length" ); } NV_ASSERT( radius > 0.0f && length > 0.0f, "Bad parameters!" ); part.shape = m_world->create_capsule( radius, length ); part.parent_idx = pindex; part.mass = table.get_float( "mass", 1.0f ); part.cone_twist = false; // Joints if ( pindex != -1 ) { part.cone_twist = table.get_string_hash_64("joint") == shash64( "cone_twist"_ls ); part.limits = table.get< vec3 >( "limits" ); } uint32 child_count = table.get_size(); bool result = true; if ( child_count > 0 ) { for( uint32 i = 1; i <= child_count; ++i ) { lua::table_guard child_table( table, i ); result = load_ragdoll( child_table, rbind, data, index ); if ( !result ) return false; } } return result; } return false; }