#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; const_string orientation = table.get_string( "orientation", "point" ); if ( orientation == "point" ) { data->orientation = particle_orientation::POINT; } else if ( orientation == "oriented" ) { data->orientation = particle_orientation::ORIENTED; } else if ( orientation == "oriented_common" ) { data->orientation = particle_orientation::ORIENTED_COMMON; } else if ( orientation == "perpendicular" ) { data->orientation = particle_orientation::PERPENDICULAR; } else if ( orientation == "perpendicular_common" ) { data->orientation = particle_orientation::PERPENDICULAR_COMMON; } else { NV_LOG_ERROR( "Unknown orientation type! (", orientation, ")!" ); data->orientation = particle_orientation::POINT; } const_string origin = table.get_string( "origin", "center" ); if ( origin == "center" ) { data->origin = particle_origin::CENTER; } else if ( origin == "top_left" ) { data->origin = particle_origin::TOP_LEFT; } else if ( origin == "top_center" ) { data->origin = particle_origin::TOP_CENTER; } else if ( origin == "top_right" ) { data->origin = particle_origin::TOP_RIGHT; } else if ( origin == "center_left" ) { data->origin = particle_origin::CENTER_LEFT; } else if ( origin == "center_right" ) { data->origin = particle_origin::CENTER_RIGHT; } else if ( origin == "bottom_left" ) { data->origin = particle_origin::BOTTOM_LEFT; } else if ( origin == "bottom_center" ) { data->origin = particle_origin::BOTTOM_CENTER; } else if ( origin == "bottom_right" ) { data->origin = particle_origin::BOTTOM_RIGHT; } else { NV_LOG_ERROR( "Unknown particle origin! (", origin, ")!" ); data->origin = particle_origin::CENTER; } data->common_up = math::normalize( table.get("common_up", vec3(1,0,0) ) ); data->common_dir = math::normalize( table.get("common_dir", vec3(0,1,0) ) ); vec2 def_size = table.get("size", vec2(0.1,0.1) ); uint32 elements = table.get_size(); for ( uint32 i = 0; i < elements; ++i ) { lua::table_guard element( table, i+1 ); const_string type = element.get_string( "type" ); const_string sub_type = element.get_string( "sub_type" ); 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.get("position", vec3() ); edata.extents = element.get("extents", vec3(1,1,1) ); edata.extents[0] = element.get("width", edata.extents[0] ); edata.extents[1] = element.get("depth", edata.extents[1] ); edata.extents[2] = element.get("height", edata.extents[2] ); edata.extents[0] = element.get("radius", edata.extents[0] ); edata.iextents = element.get("inner_extents", vec3() ); edata.iextents[0] = element.get("inner_width", edata.iextents[0] ); edata.iextents[1] = element.get("inner_depth", edata.iextents[1] ); edata.iextents[2] = element.get("inner_height", edata.iextents[2] ); edata.iextents[0] = element.get("inner_radius", edata.iextents[0] ); edata.hextents = 0.5f * edata.extents; edata.ihextents = 0.5f * edata.iextents; edata.precise = element.get("precise", false ); edata.square = element.get("square", true ); vec4 color = element.get("color", vec4(1,1,1,1) ); edata.color_min = element.get("color_min", color ); edata.color_max = element.get("color_max", color ); vec2 size = element.get("size", def_size ); edata.size_min = element.get("size_min", size ); edata.size_max = element.get("size_max", size ); edata.angle = element.get("angle", 0.0f ); float velocity = element.get("velocity", 0.0f ); edata.velocity_min = element.get("velocity_min", velocity ); edata.velocity_max = element.get("velocity_max", velocity ); float lifetime = element.get("lifetime", 1.0f ); edata.lifetime_min = element.get("lifetime_min", lifetime ); edata.lifetime_max = element.get("lifetime_max", lifetime ); float duration = element.get("duration", 0.0f ); edata.duration_min = element.get("duration_min", duration ); edata.duration_max = element.get("duration_max", duration ); float repeat = element.get("repeat_delay", 0.0f ); edata.repeat_min = element.get("repeat_delay_min", repeat ); edata.repeat_max = element.get("repeat_delay_max", repeat ); edata.rate = element.get("rate", 1.0f ); edata.dir = math::normalize( element.get("direction", 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; }