#include "nv/engine/particle_manager.hh" #include "nv/lua/lua_raw.hh" #include "nv/lua/lua_math.hh" static int nv_psystem_emitter_closure( lua_State * L ) { luaL_checktype( L, 1, LUA_TTABLE ); lua_settop( L, 1 ); lua_pushvalue( L, lua_upvalueindex( 1 ) ); // type lua_setfield( L, 1, "sub_type" ); lua_pushliteral( L, "emitter" ); lua_setfield( L, 1, "type" ); return 1; } static int nv_psystem_affector_closure( lua_State * L ) { luaL_checktype( L, 1, LUA_TTABLE ); lua_settop( L, 1 ); lua_pushvalue( L, lua_upvalueindex( 1 ) ); // type lua_setfield( L, 1, "sub_type" ); lua_pushliteral( L, "affector" ); lua_setfield( L, 1, "type" ); return 1; } static int nv_psystem_emitter( lua_State * L ) { luaL_checkstring( L, 1 ); lua_settop( L, 1 ); lua_pushcclosure( L, nv_psystem_emitter_closure, 1 ); return 1; } static int nv_psystem_affector( lua_State * L ) { luaL_checkstring( L, 1 ); lua_settop( L, 1 ); lua_pushcclosure( L, nv_psystem_affector_closure, 1 ); return 1; } void nv::particle_manager::initialize( lua::state* state ) { lua_resource_manager_base::initialize( state ); lua_State* L = state->get_raw(); lua_pushcfunction( L, nv_psystem_emitter ); lua_setglobal( L, "emitter" ); lua_pushcfunction( L, nv_psystem_affector ); lua_setglobal( L, "affector" ); } bool nv::particle_manager::load_resource( lua::table_guard& table, shash64 id ) { particle_system_data* data = new particle_system_data; data->quota = table.get("quota", 1024 ); // data->local = table.get("local_space", false ); data->accurate_facing = table.get("accurate_facing", false ); data->emitter_count = 0; data->affector_count = 0; data->orientation = particle_orientation( table["orientation"].get_uint32() ); data->origin = particle_origin( table["origin"].get_uint32() ); data->common_up = math::normalize( table["common_up"].as( vec3(1,0,0) ) ); data->common_dir = math::normalize( table["common_dir"].as( vec3(0,1,0) ) ); vec2 def_size = table.get("size", vec2(0.1,0.1) ); uint32 elements = table.size(); for ( uint32 i = 0; i < elements; ++i ) { lua::table_guard element( table, i+1 ); const_string type = element["type"].get_string(); const_string sub_type = element["sub_type"].get_string(); if ( type == "emitter" ) { if ( data->emitter_count < MAX_PARTICLE_EMITTERS ) { particle_emitter_data& edata = data->emitters[ data->emitter_count ]; edata.emitter_func = particle_engine::get_emitter( sub_type ); if ( edata.emitter_func == nullptr ) { NV_LOG_WARNING( "Unknown emitter type in particle system! (", sub_type, ")" ); break; } edata.position = element["position"].as( vec3() ); edata.extents = element["extents"].as( vec3(1,1,1) ); edata.extents[0] = element["width"].as( edata.extents[0] ); edata.extents[1] = element["depth"].as( edata.extents[1] ); edata.extents[2] = element["height"].as( edata.extents[2] ); edata.extents[0] = element["radius"].as( edata.extents[0] ); edata.iextents = element["inner_extents"].as( vec3() ); edata.iextents[0] = element["inner_width"].as( edata.iextents[0] ); edata.iextents[1] = element["inner_depth"].as( edata.iextents[1] ); edata.iextents[2] = element["inner_height"].as( edata.iextents[2] ); edata.iextents[0] = element["inner_radius"].as( edata.iextents[0] ); edata.hextents = 0.5f * edata.extents; edata.ihextents = 0.5f * edata.iextents; edata.precise = element["precise"].as( false ); edata.square = element["square"].as( true ); vec4 color = element["color"].as( vec4(1,1,1,1) ); edata.color_min = element["color_min"].as( color ); edata.color_max = element["color_max"].as( color ); vec2 size = element["size"].as( def_size ); edata.size_min = element["size_min"].as( size ); edata.size_max = element["size_max"].as( size ); edata.angle = element["angle"].as( 0.0f ); float velocity = element["velocity"].as( 0.0f ); edata.velocity_min = element["velocity_min"].as( velocity ); edata.velocity_max = element["velocity_max"].as( velocity ); float lifetime = element["lifetime"].as( 1.0f ); edata.lifetime_min = element["lifetime_min"].as( lifetime ); edata.lifetime_max = element["lifetime_max"].as( lifetime ); float duration = element["duration"].as( 0.0f ); edata.duration_min = element["duration_min"].as( duration ); edata.duration_max = element["duration_max"].as( duration ); float repeat = element["repeat_delay"].as( 0.0f ); edata.repeat_min = element["repeat_delay_min"].as( repeat ); edata.repeat_max = element["repeat_delay_max"].as( repeat ); edata.rate = element["rate"].as( 1.0f ); edata.dir = math::normalize( element["direction"].as( vec3(0,1,0) ) ); edata.odir = vec3( 0, 0, 1 ); if ( edata.dir != vec3( 0, 1, 0 ) && edata.dir != vec3( 0, -1, 0 ) ) edata.odir = math::normalize( math::cross( edata.dir, vec3( 0, 1, 0 ) ) ); edata.cdir = math::cross( edata.dir, edata.odir ); data->emitter_count++; } else { NV_LOG_ERROR( "Too many emitters (", MAX_PARTICLE_EMITTERS, " is MAX)!" ); } } else if ( type == "affector" ) { if ( data->affector_count < MAX_PARTICLE_AFFECTORS ) { particle_affector_data& adata = data->affectors[ data->affector_count ]; auto afuncs = particle_engine::get_affector( sub_type ); if ( !afuncs.init || !afuncs.process ) { NV_LOG_WARNING( "Unknown affector type in particle system! (", sub_type, ")" ); continue; } adata.process = afuncs.process; if ( !afuncs.init( &element, &adata ) ) { NV_LOG_WARNING( "Bad data passed to ", sub_type, " affector in particle system!" ); } data->affector_count++; } else { NV_LOG_ERROR( "Too many affectors (", MAX_PARTICLE_AFFECTORS, " is MAX)!" ); } } else { NV_LOG_WARNING( "Unknown element in particle system! (", type, ")" ); } } add( id, data ); return true; }