Index: trunk/nv/engine/model_manager.hh
===================================================================
--- trunk/nv/engine/model_manager.hh	(revision 514)
+++ trunk/nv/engine/model_manager.hh	(revision 515)
@@ -40,4 +40,5 @@
 		resource< data_channel_set > mesh;
 		resource< material >         material;
+		string32                     tag;
 		transform                    local;
 		random_range< vec3 >         position;
@@ -54,4 +55,5 @@
 			target->mesh      = mesh;
 			target->material  = material;
+			target->tag       = tag;
 			target->local     = local;
 			target->rotation  = rotation;
@@ -84,4 +86,5 @@
 		resource< data_channel_set > mesh;
 		resource< material >         material;
+		shash64                      tag;
 		sint16                       attach_id;
 		sint16                       parent_id;
@@ -176,5 +179,5 @@
 			if ( m == selected ) parent_flags |= FMF_FOCUS;
 
-			if ( m->mesh || m->force )
+			if ( m->mesh || m->force || !m->tag.empty() )
 			{
 				uint32 id = result.count++;
@@ -183,4 +186,5 @@
 				re.material = m->material;
 				re.local = tr;
+				re.tag = m->tag;
 				re.parent_id = parent_id;
 				re.attach_id = m->attach_id;
Index: trunk/nv/engine/particle_engine.hh
===================================================================
--- trunk/nv/engine/particle_engine.hh	(revision 514)
+++ trunk/nv/engine/particle_engine.hh	(revision 515)
@@ -187,5 +187,5 @@
 		void release( particle_system_group group );
 		void release( particle_system system );
-		void update( particle_system system, float dtime );
+		void update( particle_system system, transform model, float dtime );
 		void render( particle_system system, const scene_state& s );
 		void set_texcoords( particle_system system, vec2 a, vec2 b );
@@ -200,5 +200,5 @@
 		void generate_data( particle_system_info* info, const scene_state& s );
 		void destroy_particles( particle_system_info* info, float dtime );
-		void create_particles( particle_system_info* info, float dtime );
+		void create_particles( particle_system_info* info, transform tr, float dtime );
 		void update_particles( particle_system_info* info, float dtime );
 		void update_emmiters( particle_system_info* info, float dtime );
Index: trunk/nv/interface/device.hh
===================================================================
--- trunk/nv/interface/device.hh	(revision 514)
+++ trunk/nv/interface/device.hh	(revision 515)
@@ -130,10 +130,12 @@
 		wrap wrap_s;
 		wrap wrap_t;
-
-		sampler() : filter_min( LINEAR ), filter_max( LINEAR ), wrap_s( REPEAT ), wrap_t( REPEAT ) {}
-		sampler( filter min, filter max, wrap s, wrap t )
-			: filter_min( min ), filter_max( max ), wrap_s( s ), wrap_t( t ) {}
+		wrap wrap_r;
+
+		sampler() : filter_min( LINEAR ), filter_max( LINEAR ), wrap_s( REPEAT ), wrap_t( REPEAT ), wrap_r( REPEAT ) {}
+		sampler( filter min, filter max, wrap s, wrap t, wrap r )
+			: filter_min( min ), filter_max( max ), wrap_s( s ), wrap_t( t ), wrap_r( r ) {}
 		sampler( filter f, wrap w )
-			: filter_min( f ), filter_max( f ), wrap_s( w ), wrap_t( w ) {}
+			: filter_min( f ), filter_max( f ), wrap_s( w ), wrap_t( w ), wrap_r( w )
+		{}
 
 	};
Index: trunk/nv/lua/lua_state.hh
===================================================================
--- trunk/nv/lua/lua_state.hh	(revision 514)
+++ trunk/nv/lua/lua_state.hh	(revision 515)
@@ -378,4 +378,5 @@
 			string128 get_string128( string_view element, string_view defval = string_view() );
 			string64 get_string64( string_view element, string_view defval = string_view() );
+			string32 get_string32( string_view element, string_view defval = string_view() );
 
 			char get_char( string_view element, char defval = ' ' );
Index: trunk/src/engine/model_manager.cc
===================================================================
--- trunk/src/engine/model_manager.cc	(revision 514)
+++ trunk/src/engine/model_manager.cc	(revision 515)
@@ -58,4 +58,7 @@
 	if ( table.is_string( "material" ) )
 		cmaterial = m_rm->get< material >( table.get_string128( "material" ) );
+
+	if ( table.is_string( "tag" ) )
+		node->tag = table.get_string32( "tag" );
 
 	if ( table.has_field( "path" ) )
Index: trunk/src/engine/particle_engine.cc
===================================================================
--- trunk/src/engine/particle_engine.cc	(revision 514)
+++ trunk/src/engine/particle_engine.cc	(revision 515)
@@ -605,5 +605,5 @@
 }
 
-void nv::particle_engine::update( particle_system system, float dtime )
+void nv::particle_engine::update( particle_system system, transform model, float dtime  )
 {
 	particle_system_info* info = m_systems.get( system );
@@ -621,5 +621,5 @@
 		update_emmiters( info, dtime );
 		destroy_particles( info, dtime );
-		create_particles( info, dtime );
+		create_particles( info, model, dtime );
 		update_particles( info, dtime );
 
@@ -776,5 +776,5 @@
 }
 
-void nv::particle_engine::create_particles( particle_system_info* info, float dtime )
+void nv::particle_engine::create_particles( particle_system_info* info, transform model, float dtime )
 {
 	uint32 ecount = info->data->emmiter_count;
@@ -782,7 +782,5 @@
 
 	random& r = random::get();
-	vec3 source;
-	mat3 orient;
-//	bool local = info->data->local;
+	bool local = model.is_identity();
 // 	if ( !local ) 
 // 	{
@@ -806,7 +804,8 @@
 					edata.emmiter_func( &(info->data->emmiters[i]), &pinfo, 1 );
 					pinfo.position = vec3();
-//					if ( !local ) pinfo.position  = orient * pinfo.position + source;
 					pinfo.position+= edata.position;
-					pinfo.color    = edata.color_min == edata.color_max ? 
+					if ( !local )
+						pinfo.position = pinfo.position * model;
+					pinfo.color    = edata.color_min == edata.color_max ?
 						edata.color_min : r.range( edata.color_min, edata.color_max );
 					pinfo.size     = edata.size_min == edata.size_max ?
@@ -829,5 +828,5 @@
 						float sin_theta = sqrt(1.0f - cos_theta * cos_theta );
 						float phi       = r.frange( 0.0f, 2* math::pi<float>() );
-						pinfo.velocity  = orient * 
+						pinfo.velocity  = model.get_orientation() * 
 							( edata.odir * ( cos(phi) * sin_theta ) +
 							edata.cdir * ( sin(phi)*sin_theta ) +
Index: trunk/src/gl/gl_context.cc
===================================================================
--- trunk/src/gl/gl_context.cc	(revision 514)
+++ trunk/src/gl/gl_context.cc	(revision 515)
@@ -964,4 +964,5 @@
 	glTexParameteri( gl_type, GL_TEXTURE_WRAP_S, GLint( nv::sampler_wrap_to_enum( asampler.wrap_s ) ) );
 	glTexParameteri( gl_type, GL_TEXTURE_WRAP_T, GLint( nv::sampler_wrap_to_enum( asampler.wrap_t ) ) );
+	glTexParameteri( gl_type, GL_TEXTURE_WRAP_R, GLint( nv::sampler_wrap_to_enum( asampler.wrap_r ) ) );
 
 	if ( is_depth )
Index: trunk/src/lua/lua_state.cc
===================================================================
--- trunk/src/lua/lua_state.cc	(revision 514)
+++ trunk/src/lua/lua_state.cc	(revision 515)
@@ -344,4 +344,23 @@
 }
 
+
+nv::string32 nv::lua::table_guard::get_string32( string_view element, string_view defval /*= string_view() */ )
+{
+	lua_getfield( m_state, -1, element.data() );
+	size_t l = 0;
+	const char* str = nullptr;
+	if ( lua_type( m_state, -1 ) == LUA_TSTRING )
+	{
+		str = lua_tolstring( m_state, -1, &l );
+	}
+	else
+	{
+		l = defval.size();
+		str = defval.data();
+	}
+	string32 result( str, l );
+	lua_pop( m_state, 1 );
+	return result;
+}
 
 char lua::table_guard::get_char( string_view element, char defval /*= "" */ )
