Index: /trunk/nv/engine/particle_engine.hh
===================================================================
--- /trunk/nv/engine/particle_engine.hh	(revision 521)
+++ /trunk/nv/engine/particle_engine.hh	(revision 522)
@@ -13,4 +13,5 @@
 #include <nv/stl/unordered_map.hh>
 #include <nv/stl/handle.hh>
+#include <nv/stl/functional/function.hh>
 #include <nv/lua/lua_state.hh>
 #include <nv/gfx/texture_atlas.hh>
@@ -19,4 +20,5 @@
 #include <nv/interface/scene_node.hh>
 #include <nv/interface/context.hh>
+#include <nv/interface/physics_world.hh>
 #include <nv/engine/particle_group.hh>
 
@@ -84,22 +86,26 @@
 	struct particle_system_data : particle_group_settings
 	{
-		uint32 quota;
-		uint32                 emitter_count;
-		particle_emitter_data  emitters[MAX_PARTICLE_EMITTERS];
-		uint32                 affector_count;
-		particle_affector_data affectors[MAX_PARTICLE_AFFECTORS];
+		uint32                       quota;
+		uint32                       emitter_count;
+		particle_emitter_data        emitters[MAX_PARTICLE_EMITTERS];
+		uint32                       affector_count;
+		particle_affector_data       affectors[MAX_PARTICLE_AFFECTORS];
 	};
 
 	struct particle_system_tag {};
 	typedef handle< uint32, 16, 16, particle_system_tag > particle_system;
+//	using particle_on_collide_func = function<bool( vec3, vec3 )>;
+	using particle_on_collide_func = function<void( const vec3&, const vec3& )>;
 
 	struct particle_system_info
 	{
-		particle*             particles;
-		particle_emitter_info emitters[MAX_PARTICLE_EMITTERS];
+		particle*                particles;
+		particle_emitter_info    emitters[MAX_PARTICLE_EMITTERS];
+		particle_on_collide_func on_collide;
 
 		uint32         count;
 		vec2           texcoords[2];
 		particle_group group;
+
 
 		const particle_system_data*    data;
@@ -124,6 +130,8 @@
 		void release( particle_group group );
 		void release( particle_system system );
+		bool is_finished( particle_system system );
 		void update( particle_system system, transform model, float dtime );
 		void render( particle_system system, const scene_state& s );
+		void set_on_collide( particle_system system, const particle_on_collide_func& f );
 		void set_texcoords( particle_system system, vec2 a, vec2 b );
 		static void register_emitter_type( const string_view& name, particle_emitter_func func );
Index: /trunk/nv/engine/renderer.hh
===================================================================
--- /trunk/nv/engine/renderer.hh	(revision 521)
+++ /trunk/nv/engine/renderer.hh	(revision 522)
@@ -46,4 +46,5 @@
 		transform                model;
 		flags< 32 >              flags;
+		blending                 blending;
 	};
 
Index: /trunk/nv/interface/render_state.hh
===================================================================
--- /trunk/nv/interface/render_state.hh	(revision 521)
+++ /trunk/nv/interface/render_state.hh	(revision 522)
@@ -101,4 +101,21 @@
 			color( vec4() ) {}
 	};
+
+	constexpr bool operator==( const blending& rhs, const blending& lhs )
+	{
+		return 
+			rhs.enabled          == lhs.enabled &&
+			rhs.src_rgb_factor   == lhs.src_rgb_factor &&
+			rhs.src_alpha_factor == lhs.src_alpha_factor &&
+			rhs.dst_rgb_factor   == lhs.dst_rgb_factor &&
+			rhs.dst_alpha_factor == lhs.dst_alpha_factor &&
+			rhs.rgb_equation     == lhs.rgb_equation &&
+			rhs.alpha_equation   == lhs.alpha_equation &&
+			rhs.color            == lhs.color;
+	}
+	constexpr bool operator!=( const blending& rhs, const blending& lhs )
+	{
+		return !( rhs == lhs );
+	}
 
 	struct stencil_test_face
Index: /trunk/src/engine/mesh_manager.cc
===================================================================
--- /trunk/src/engine/mesh_manager.cc	(revision 521)
+++ /trunk/src/engine/mesh_manager.cc	(revision 522)
@@ -85,10 +85,10 @@
 
 		NV_LOG_ERROR( "Resource path fail! - ", path );
-		NV_ASSERT( false, "Resource path fail!" );
+		//NV_ASSERT( false, "Resource path fail!" );
 	}
 	else
 	{
 		NV_LOG_ERROR( "Resource lock fail! - ", path );
-		NV_ASSERT( false, "Resource lock fail!" );
+		//NV_ASSERT( false, "Resource lock fail!" );
 	}
 	return nv::resource< nv::data_channel_set >();
Index: /trunk/src/engine/particle_engine.cc
===================================================================
--- /trunk/src/engine/particle_engine.cc	(revision 521)
+++ /trunk/src/engine/particle_engine.cc	(revision 522)
@@ -306,5 +306,4 @@
 		else
 			info->emitters[i].pause = m_rng->frange( data->emitters[i].duration_min, data->emitters[i].duration_max );
-
 	}
 
@@ -313,4 +312,11 @@
 
 	return result;
+}
+
+void nv::particle_engine::set_on_collide( particle_system system, const particle_on_collide_func& f )
+{
+	particle_system_info* info = m_systems.get( system );
+	if ( info )
+		info->on_collide = f;
 }
 
@@ -364,4 +370,22 @@
 		m_systems.destroy( system );
 	}
+}
+
+bool nv::particle_engine::is_finished( particle_system system )
+{
+	particle_system_info* info = m_systems.get( system );
+	if ( info )
+	{
+		if ( info->count > 0 ) return false;
+		for ( uint32 i = 0; i < info->data->emitter_count; ++i )
+		{
+			const auto& edata = info->emitters[i];
+			if ( edata.active || edata.pause > 0.0f )
+			{
+				return false;
+			}
+		}
+	}
+	return true;
 }
 
@@ -403,5 +427,4 @@
 void nv::particle_engine::set_texcoords( particle_system system, vec2 a, vec2 b )
 {
-
 	particle_system_info* info = m_systems.get( system );
 	if ( info )
@@ -513,4 +536,18 @@
 		pdata.position += pdata.velocity * factor;
 	}
+
+	if ( info->on_collide )
+	{
+		for ( uint32 i = 0; i < info->count; ++i )
+		{
+			particle& pdata = info->particles[i];
+			if ( pdata.position.y <= 0.0f )
+			{
+				info->on_collide( pdata.position, pdata.velocity );
+				pdata.death = pdata.lifetime;
+			}
+		}
+	}
+
 }
 
Index: /trunk/src/engine/renderer.cc
===================================================================
--- /trunk/src/engine/renderer.cc	(revision 521)
+++ /trunk/src/engine/renderer.cc	(revision 522)
@@ -117,4 +117,5 @@
 
 	scene_state ss( s );
+	render_state rs( pass.rstate );
 	m_context->bind( pass.fbuffer, FRAMEBUFFER );
 	m_context->set_draw_buffers( pass.output_count, pass.output );
@@ -157,9 +158,11 @@
 					m_context->get_device()->set_opt_uniform( *program, "nv_index", unsigned( index ) );
 					m_context->apply_engine_uniforms( *program, ss );
+					if ( rs.blending != element.blending )
+						rs.blending = element.blending;
 
 					if ( element.instances > 0 )
-						m_context->draw_instanced( TRIANGLES, pass.rstate, *program, element.instances, element.va, element.count, element.first );
+						m_context->draw_instanced( TRIANGLES, rs, *program, element.instances, element.va, element.count, element.first );
 					else
-						m_context->draw( TRIANGLES, pass.rstate, *program, element.va, element.count, element.first );
+						m_context->draw( TRIANGLES, rs, *program, element.va, element.count, element.first );
 
 					m_statistics[TRIANGLE_COUNT] += ( element.count / 3 ) * max< uint32 >( element.instances, 1 );
