// 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["model"].get_string64(); 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["id"].get_string32(); int index = data->parts.size(); data->parts.emplace_back(); auto& part = data->parts.back(); part.name = table["name"].get_shash64(); part.bone_id = nv::uint32( bind_data->get_bone_list().resolve( table["bone"].get_shash64() ) ); NV_ASSERT( part.bone_id < 256, "Bone ID not found!" ); float radius = table["radius"].get_f32(); float length = 0.0f; if ( table[ "target" ] ) { const auto& of = bind_data->get_bone_transforms().m_offsets; int target = bind_data->get_bone_list().resolve( table["target"].get_shash64() ); if ( target < 0 ) return false; length = math::distance( of[part.bone_id].get_position(), of[target].get_position() ); } else { length = table["length"].get_f32(); } 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["mass"].get_f32( 1.0f ); part.cone_twist = false; // Joints if ( pindex != -1 ) { part.cone_twist = table["joint"].get_shash64() == shash64( "cone_twist"_ls ); part.limits = table["limits"].as< vec3 >(); } uint32 child_count = table.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; }