Index: trunk/nv/engine/particle_engine.hh
===================================================================
--- trunk/nv/engine/particle_engine.hh	(revision 499)
+++ trunk/nv/engine/particle_engine.hh	(revision 500)
@@ -76,6 +76,9 @@
 		vec3   velocity;
 		vec2   size;
-		//float  rotation;
-		uint32 death;
+		vec2   tcoord_a;
+		vec2   tcoord_b;
+		float  rotation;
+		float  lifetime;
+		float  death;
 	};
 
@@ -103,13 +106,13 @@
 		float  velocity_min;
 		float  velocity_max;
-		uint32 lifetime_min;
-		uint32 lifetime_max;
+		float  lifetime_min;
+		float  lifetime_max;
 		vec3   dir;
 		vec3   odir;
 		vec3   cdir;
-		uint32 duration_min;
-		uint32 duration_max;
-		uint32 repeat_min;
-		uint32 repeat_max;
+		float  duration_min;
+		float  duration_max;
+		float  repeat_min;
+		float  repeat_max;
 		float  rate;
 	};
@@ -118,6 +121,6 @@
 	{
 		bool   active;
-		uint32 next_toggle;
-		float  last_create;
+		float  pause;
+		float  next;
 	};
 
@@ -144,10 +147,9 @@
 	struct particle_system_info
 	{
-		uint32                last_update;
 		particle*             particles;
 		particle_emmiter_info emmiters[MAX_PARTICLE_EMMITERS];
 
 		uint32                count;
-		vec2                  texcoords[4];
+		vec2                  texcoords[2];
 		particle_system_group group;
 
@@ -163,4 +165,11 @@
 		bool                  local;
 		particle_quad*        quads;
+		uint32                ref_counter;
+	};
+
+	struct particle_render_data
+	{
+		uint32                count;
+		vertex_array          vtx_array;
 	};
 
@@ -170,4 +179,5 @@
 		particle_engine( context* a_context );
 		void reset();
+		bool loaded( const string_view& system_id );
 		void load( lua::table_guard& table );
 		void draw( particle_system_group group, const render_state& rs, const scene_state& ss );
@@ -177,9 +187,10 @@
 		void release( particle_system_group group );
 		void release( particle_system system );
-		void update( const scene_state& s, uint32 ms );
-		void update( particle_system system );
+		void update( particle_system system, float dtime );
+		void render( particle_system system, const scene_state& s );
 		void set_texcoords( particle_system system, vec2 a, vec2 b );
 		void register_emmiter_type( const string_view& name, particle_emmiter_func func );
 		void register_affector_type( const string_view& name, particle_affector_init_func init, particle_affector_func process );
+		particle_render_data get_render_data( particle_system_group group );
 		~particle_engine();
 	private:
@@ -187,9 +198,9 @@
 		void register_standard_emmiters();
 		void register_standard_affectors();
-		void generate_data( particle_system_info* info );
-		void destroy_particles( particle_system_info* info, uint32 ms );
-		void create_particles( particle_system_info* info, uint32 ms );
-		void update_particles( particle_system_info* info, uint32 ms );
-		void update_emmiters( particle_system_info* info, uint32 ms );
+		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 update_particles( particle_system_info* info, float dtime );
+		void update_emmiters( particle_system_info* info, float dtime );
 
 		device*  m_device;
@@ -198,12 +209,4 @@
 		program  m_program_local;
 		program  m_program_world;
-
-		mat4     m_view_matrix;
-		mat4     m_model_matrix;
-		vec3     m_inv_view_dir;
-		vec3     m_camera_pos;
-		uint32   m_last_update;
-		vec2     m_tc_a;
-		vec2     m_tc_b;
 
 		handle_store< particle_system_info, particle_system >             m_systems;
Index: trunk/nv/gl/gl_context.hh
===================================================================
--- trunk/nv/gl/gl_context.hh	(revision 499)
+++ trunk/nv/gl/gl_context.hh	(revision 500)
@@ -48,5 +48,5 @@
 		virtual void blit( framebuffer from, framebuffer to, clear_state::buffers_type mask, ivec2 src1, ivec2 src2, ivec2 dst1, ivec2 dst2 );
 
-		virtual void attach( framebuffer f, output_slot slot, texture t );
+		virtual void attach( framebuffer f, output_slot slot, texture t, int layer = -1 );
 		virtual void attach( framebuffer f, texture depth, int layer = -1 );
 		virtual void attach( framebuffer f, ivec2 size );
Index: trunk/nv/interface/context.hh
===================================================================
--- trunk/nv/interface/context.hh	(revision 499)
+++ trunk/nv/interface/context.hh	(revision 500)
@@ -165,5 +165,5 @@
 		virtual void blit( framebuffer from, framebuffer to, clear_state::buffers_type mask, ivec2 src1, ivec2 src2, ivec2 dst1, ivec2 dst2 ) = 0;
 
-		virtual void attach( framebuffer f, output_slot slot, texture t ) = 0;
+		virtual void attach( framebuffer f, output_slot slot, texture t, int layer = -1 ) = 0;
 		virtual void attach( framebuffer f, texture depth, int layer = -1 ) = 0;
 		virtual void attach( framebuffer f, ivec2 size ) = 0;
Index: trunk/nv/interface/image_data.hh
===================================================================
--- trunk/nv/interface/image_data.hh	(revision 499)
+++ trunk/nv/interface/image_data.hh	(revision 500)
@@ -42,4 +42,10 @@
 		R32I,
 		R32UI,
+		RGBA8I,
+		RGBA8UI,
+		RGBA16I,
+		RGBA16UI,
+		RGBA32I,
+		RGBA32UI,
 	};
 	
Index: trunk/nv/interface/uniform.hh
===================================================================
--- trunk/nv/interface/uniform.hh	(revision 499)
+++ trunk/nv/interface/uniform.hh	(revision 500)
@@ -75,5 +75,5 @@
 			}
 		}
-
+		
 		void set_value( const T* value, uint32 count ) 
 		{ 
@@ -83,5 +83,8 @@
 		}
 
-		const T* get_value() const { return m_value; }
+		const T* get_value() const
+		{
+			return m_value;
+		}
 		virtual ~uniform() 
 		{
Index: trunk/src/engine/particle_engine.cc
===================================================================
--- trunk/src/engine/particle_engine.cc	(revision 499)
+++ trunk/src/engine/particle_engine.cc	(revision 500)
@@ -20,11 +20,13 @@
 	"varying vec4 v_color;\n"
 	"varying vec2 v_texcoord;\n"
+	"varying vec3 v_position;\n"
 	"uniform mat4 nv_m_view;\n"
 	"uniform mat4 nv_m_projection;\n"
 	"void main(void)\n"
 	"{\n"
-	"	gl_Position = nv_m_projection * nv_m_view * vec4 (nv_position, 1.0);\n"
-	"	v_texcoord  = nv_texcoord;\n"
-	"	v_color     = nv_color;\n"
+	"	v_position    = nv_position;\n"
+	"	v_texcoord    = nv_texcoord;\n"
+	"	v_color       = nv_color;\n"
+	"	gl_Position   = nv_m_projection * nv_m_view * vec4 (nv_position, 1.0);\n"
 	"}\n";
 static const char *nv_particle_engine_vertex_shader_local =
@@ -35,10 +37,12 @@
 	"varying vec4 v_color;\n"
 	"varying vec2 v_texcoord;\n"
+	"varying vec3 v_position;\n"
 	"uniform mat4 nv_m_mvp;\n"
 	"void main(void)\n"
 	"{\n"
-	"	gl_Position = nv_m_mvp * vec4 (nv_position, 1.0);\n"
-	"	v_texcoord  = nv_texcoord;\n"
-	"	v_color     = nv_color;\n"
+	"	v_position    = nv_position;\n"
+	"	v_texcoord    = nv_texcoord;\n"
+	"	v_color       = nv_color;\n"
+	"	gl_Position   = nv_m_mvp * vec4 (nv_position, 1.0);\n"
 	"}\n";
 static const char *nv_particle_engine_fragment_shader =
@@ -47,8 +51,10 @@
 	"varying vec4 v_color;\n"
 	"varying vec2 v_texcoord;\n"
+	"varying vec3 v_position;\n"
 	"void main(void)\n"
 	"{\n"
 	"	vec4 tex_color = texture2D( nv_t_diffuse, v_texcoord );\n"
-	"	gl_FragColor   = v_color * tex_color;\n"
+	"	float edge = smoothstep( 0.0, 0.1, v_position.y );\n"
+	"	gl_FragColor   = v_color * tex_color * edge;\n"
 	"}\n";
 
@@ -205,5 +211,5 @@
 	if ( datap->average )
 	{
-		float norm_factor = nv::min( factor, 1.0f );
+		float norm_factor = nv::min( factor, 1.0f, p->lifetime );
 		for ( uint32 i = 0; i < count; ++i ) 
 			p[i].velocity = datap->force_vector * norm_factor + p[i].velocity * ( 1.0f - norm_factor );
@@ -211,5 +217,5 @@
 	else
 	{
-		vec3 scvector = datap->force_vector * factor;
+		vec3 scvector = datap->force_vector * nv::min( factor, p->lifetime );
 		for ( uint32 i = 0; i < count; ++i ) p[i].velocity += scvector;
 	}
@@ -241,5 +247,5 @@
 	{
 		particle& pt = p[i];
-		vec3 direction  = pt.velocity * factor;
+		vec3 direction  = pt.velocity * nv::min( factor, p->lifetime );
 		if ( math::dot( datap->plane_normal, pt.position + direction ) + datap->distance <= 0.0f )
 		{
@@ -270,5 +276,5 @@
 {
 	const nvpe_color_fader_data* datap = reinterpret_cast<const nvpe_color_fader_data*>( data->paramters );
-	vec4 adjustment = datap->adjustment * factor;
+	vec4 adjustment = datap->adjustment * nv::min( factor, p->lifetime );
 	for ( uint32 i = 0; i < count; ++i )
 	{
@@ -293,5 +299,5 @@
 {
 	const nvpe_scaler_data* datap = reinterpret_cast<const nvpe_scaler_data*>( data->paramters );
-	vec2 adjustment = datap->adjustment * factor;
+	vec2 adjustment = datap->adjustment * nv::min( factor, p->lifetime );
 	for ( uint32 i = 0; i < count; ++i )
 	{
@@ -399,12 +405,12 @@
 				edata.velocity_max = element.get<float>("velocity_max", velocity );
 				float lifetime     = element.get<float>("lifetime", 1.0f );
-				edata.lifetime_min = uint32( element.get<float>("lifetime_min", lifetime ) * 1000.f );
-				edata.lifetime_max = uint32( element.get<float>("lifetime_max", lifetime ) * 1000.f );
+				edata.lifetime_min = element.get<float>("lifetime_min", lifetime );
+				edata.lifetime_max = element.get<float>("lifetime_max", lifetime );
 				float duration     = element.get<float>("duration", 0.0f );
-				edata.duration_min = uint32( element.get<float>("duration_min", duration ) * 1000.f );
-				edata.duration_max = uint32( element.get<float>("duration_max", duration ) * 1000.f );
+				edata.duration_min = element.get<float>("duration_min", duration );
+				edata.duration_max = element.get<float>("duration_max", duration );
 				float repeat       = element.get<float>("repeat_delay", 0.0f );
-				edata.repeat_min   = uint32( element.get<float>("repeat_delay_min", repeat ) * 1000.f );
-				edata.repeat_max   = uint32( element.get<float>("repeat_delay_max", repeat ) * 1000.f );
+				edata.repeat_min   = element.get<float>("repeat_delay_min", repeat );
+				edata.repeat_max   = element.get<float>("repeat_delay_max", repeat );
 
 				edata.rate         = element.get<float>("rate", 1.0f );
@@ -464,5 +470,4 @@
 	m_program_local = m_device->create_program( nv_particle_engine_vertex_shader_local, nv_particle_engine_fragment_shader );
 	m_program_world = m_device->create_program( nv_particle_engine_vertex_shader_world, nv_particle_engine_fragment_shader );
-	m_last_update = 0;
 
 	register_standard_emmiters();
@@ -472,4 +477,7 @@
 nv::particle_system nv::particle_engine::create_system( const string_view& id, particle_system_group group )
 {
+	particle_system_group_info* ginfo = m_groups.get( group );
+	if ( !ginfo ) return nv::particle_system();
+
 	auto it = m_names.find( id );
 	if ( it == m_names.end() )
@@ -486,9 +494,8 @@
 	{
 		info->emmiters[i].active      = true;
-		info->emmiters[i].last_create = float( m_last_update );
-		if ( data->emmiters[i].duration_max == 0 )
-			info->emmiters[i].next_toggle = 0;
+		if ( data->emmiters[i].duration_max == 0.0f )
+			info->emmiters[i].pause = 0;
 		else
-			info->emmiters[i].next_toggle = m_last_update + random::get().urange( data->emmiters[i].duration_min, data->emmiters[i].duration_max );
+			info->emmiters[i].pause = random::get().frange( data->emmiters[i].duration_min, data->emmiters[i].duration_max );
 
 	}
@@ -496,5 +503,5 @@
 	info->count = 0;
 	info->particles = new particle[ data->quota ];
-	info->last_update = m_last_update;
+	ginfo->ref_counter++;
 
 	return result;
@@ -531,4 +538,5 @@
 	info->vtx_array = m_context->create_vertex_array( desc );
 	info->quads     = new particle_quad[info->quota];
+	info->ref_counter = 0;
 	return result;
 }
@@ -546,4 +554,9 @@
 	register_standard_emmiters();
 	register_standard_affectors();
+}
+
+bool nv::particle_engine::loaded( const string_view& system_id )
+{
+	return m_names.find( system_id ) != m_names.end();
 }
 
@@ -558,5 +571,4 @@
 	m_names.clear();
 	m_data.clear();
-	m_last_update = 0;
 }
 
@@ -567,5 +579,7 @@
 	if ( info )
 	{
-		delete[] info->particles;
+		particle_system_group_info* ginfo = m_groups.get( info->group );
+		if ( ginfo ) ginfo->ref_counter--;
+				delete[] info->particles;
 		m_systems.destroy( system );
 	}
@@ -583,39 +597,48 @@
 }
 
-void nv::particle_engine::update( const scene_state& s, uint32 ms )
-{
-	m_last_update += ms;
-	m_view_matrix  = s.get_view();
-	m_model_matrix = s.get_model();
-	m_camera_pos   = s.get_camera().get_position();
-	m_inv_view_dir = math::normalize(-s.get_camera().get_direction());
-}
-
-void nv::particle_engine::update( particle_system system )
+void nv::particle_engine::render( particle_system system, const scene_state& s )
 {
 	particle_system_info* info = m_systems.get( system );
 	if ( info )
 	{
-		update_emmiters( info, m_last_update );
-		destroy_particles( info, m_last_update );
-		create_particles( info, m_last_update );
-		update_particles( info, m_last_update );
-
-		generate_data( info );
-	}
-}
-
-void nv::particle_engine::set_texcoords( particle_system system, vec2 a, vec2 b )
+		generate_data( info, s );
+	}
+}
+
+void nv::particle_engine::update( particle_system system, float dtime )
 {
 	particle_system_info* info = m_systems.get( system );
 	if ( info )
 	{
-		vec2 texcoords[4] = { a, vec2( b.x, a.y ), vec2( a.x, b.y ), b };
-		for ( uint32 i = 0; i < 4; ++i )
-			info->texcoords[i] = texcoords[i];
-	}
-}
-
-void nv::particle_engine::generate_data( particle_system_info* info )
+// 		while ( dtime > 0.2 )
+// 		{
+// 			update_emmiters( info, 0.2 );
+// 			destroy_particles( info, 0.2 );
+// 			create_particles( info, 0.2 );
+// 			update_particles( info, 0.2 );
+// 			dtime -= 0.2;
+//		}
+
+		update_emmiters( info, dtime );
+		destroy_particles( info, dtime );
+		create_particles( info, dtime );
+		update_particles( info, dtime );
+
+//		generate_data( info );
+	}
+}
+
+void nv::particle_engine::set_texcoords( particle_system system, vec2 a, vec2 b )
+{
+
+	particle_system_info* info = m_systems.get( system );
+	if ( info )
+	{
+		info->texcoords[0] = a;
+		info->texcoords[1] = b;
+	}
+}
+
+void nv::particle_engine::generate_data( particle_system_info* info, const scene_state& s )
 {
 //  	void* rawptr = m_context->map_buffer( info->vtx_buffer, nv::WRITE_UNSYNCHRONIZED, offset, info->count*sizeof( particle_quad ) );
@@ -661,11 +684,6 @@
 	vec3 pdir( 0.0f, 1.0f, 0.0f );
 
-	vec2 texcoords[4] =
-	{
-		info->texcoords[0],
-		info->texcoords[1],
-		info->texcoords[2],
-		info->texcoords[3],
-	};
+	vec3 camera_pos   = s.get_camera().get_position();
+	vec3 inv_view_dir = math::normalize( -s.get_camera().get_direction() );
 
 	for ( uint32 i = 0; i < info->count; ++i )
@@ -675,6 +693,6 @@
 		particle_quad& rdata  = group->quads[i + group->count];
 
-		vec3 view_dir( m_inv_view_dir );
-		if ( accurate_facing ) view_dir = math::normalize( m_camera_pos - pdata.position );
+		vec3 view_dir( inv_view_dir );
+		if ( accurate_facing ) view_dir = math::normalize( camera_pos - pdata.position );
 
 		switch ( orientation )
@@ -682,4 +700,5 @@
 		case particle_orientation::POINT :
 			right   = math::normalize( math::cross( view_dir, vec3( 0, 1, 0 ) ) );
+			right   = math::rotate( right, pdata.rotation, view_dir );
 			rot_mat = mat3( right, math::cross( right, -view_dir ), -view_dir );
 			break;
@@ -704,4 +723,12 @@
 		}
 
+		vec2 texcoords[4] =
+		{
+			pdata.tcoord_a,
+			vec2( pdata.tcoord_b.x, pdata.tcoord_a.y ),
+			vec2( pdata.tcoord_a.x, pdata.tcoord_b.y ),
+			pdata.tcoord_b
+		};
+
 		vec3 size( pdata.size.x, pdata.size.y, 0.0f );
 		vec3 s0 = rot_mat * ( ( size * sm[0] ) );
@@ -735,5 +762,5 @@
 }
 
-void nv::particle_engine::destroy_particles( particle_system_info* info, uint32 ms )
+void nv::particle_engine::destroy_particles( particle_system_info* info, float dtime )
 {
 	if ( info->count > 0 )
@@ -741,6 +768,6 @@
 		{
 			particle& pinfo = info->particles[i];
-			if ( //pdata.position.y < 0.0f ||
-				ms >= pinfo.death )
+			pinfo.lifetime += dtime;
+			if ( pinfo.lifetime >= pinfo.death )
 			{
 				info->count--;
@@ -750,5 +777,5 @@
 }
 
-void nv::particle_engine::create_particles( particle_system_info* info, uint32 ms )
+void nv::particle_engine::create_particles( particle_system_info* info, float dtime )
 {
 	uint32 ecount = info->data->emmiter_count;
@@ -759,11 +786,9 @@
 	mat3 orient;
 	bool local = info->data->local;
-	if ( !local ) 
-	{
-		source = vec3( m_model_matrix[3] );
-		orient = mat3( m_model_matrix );
-	}
-
-	float fms = float(ms);
+// 	if ( !local ) 
+// 	{
+// 		source = vec3( m_model_matrix[3] );
+// 		orient = mat3( m_model_matrix );
+// 	}
 
 	for ( uint32 i = 0; i < ecount; ++i )
@@ -773,6 +798,7 @@
 		if ( einfo.active )
 		{
-			float period = 1000.f / edata.rate;
-			while ( fms - einfo.last_create > period )
+			einfo.next -= dtime;
+			float fperiod = 1.0f / edata.rate;
+			while ( einfo.next < 0.0f )
 			{
 				if ( info->count < info->data->quota-1 )
@@ -780,17 +806,20 @@
 					particle& pinfo = info->particles[info->count];
 					edata.emmiter_func( &(info->data->emmiters[i]), &pinfo, 1 );
-
-					if ( !local ) pinfo.position  = orient * pinfo.position + source;
-					pinfo.position += edata.position;
-					pinfo.color     = edata.color_min == edata.color_max ? 
+					pinfo.position = vec3();
+//					if ( !local ) pinfo.position  = orient * pinfo.position + source;
+					pinfo.position+= edata.position;
+					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 ?
+					pinfo.size     = edata.size_min == edata.size_max ?
 						edata.size_min : r.range( edata.size_min, edata.size_max );
 					if ( edata.square ) pinfo.size.y = pinfo.size.x;
-					float velocity  = edata.velocity_min == edata.velocity_max ?
+					float velocity = edata.velocity_min == edata.velocity_max ?
 						edata.velocity_min : r.frange( edata.velocity_min, edata.velocity_max );
-					pinfo.death     = ms + ( edata.lifetime_min == edata.lifetime_max ?
-						edata.lifetime_min : r.urange( edata.lifetime_min, edata.lifetime_max ) );
-					//pinfo.rotation = r.frand( 360.0f );
+					pinfo.lifetime = dtime + einfo.next;
+					pinfo.death = ( edata.lifetime_min == edata.lifetime_max ?
+						edata.lifetime_min : r.frange( edata.lifetime_min, edata.lifetime_max ) );
+					pinfo.rotation = r.frand( 2* math::pi<float>() );
+					pinfo.tcoord_a = info->texcoords[0];
+					pinfo.tcoord_b = info->texcoords[1];
 
 					pinfo.velocity = edata.dir;
@@ -811,15 +840,14 @@
 					info->count++;
 				}
-				einfo.last_create += period;
+				einfo.next += fperiod;
 			}
+
 		}
 	}
 }
 
-void nv::particle_engine::update_particles( particle_system_info* info, uint32 ms )
-{
-	uint32 ticks = ms - info->last_update;
-	if ( ticks == 0 ) return;
-	float factor  = 0.001f * ticks;
+void nv::particle_engine::update_particles( particle_system_info* info, float dtime )
+{
+	if ( dtime <= 0.0f ) return;
 
 	uint32 acount = info->data->affector_count;
@@ -827,5 +855,5 @@
 	{
 		const particle_affector_data* padata = &(info->data->affectors[i]);
-		padata->process( padata, info->particles, factor, info->count );
+		padata->process( padata, info->particles, dtime, info->count );
 	}
 
@@ -834,10 +862,10 @@
 	{
 		particle& pdata = info->particles[i];
+		float factor = min( dtime, pdata.lifetime );
 		pdata.position += pdata.velocity * factor;
 	}
-	info->last_update = ms;
-}
-
-void nv::particle_engine::update_emmiters( particle_system_info* info, uint32 ms )
+}
+
+void nv::particle_engine::update_emmiters( particle_system_info* info, float dtime )
 {
 	uint32 ecount = info->data->emmiter_count;
@@ -850,19 +878,24 @@
 		auto& einfo = info->emmiters[i];
 
-		if ( einfo.next_toggle != 0 && ms >= einfo.next_toggle )
+		if ( einfo.pause > 0.0f )
+		{
+			einfo.pause -= dtime;
+			if ( einfo.pause == 0.0f ) einfo.pause = -0.001f;
+		}
+
+		if ( einfo.pause < 0.0f )
 		{
 			if ( einfo.active )
 			{
 				einfo.active = false;
-				if ( edata.repeat_min > 0 )
-					einfo.next_toggle += r.urange( edata.repeat_min, edata.repeat_max );
+				if ( edata.repeat_min > 0.0f )
+					einfo.pause += r.frange( edata.repeat_min, edata.repeat_max );
 				else
-					einfo.next_toggle = 0;
+					einfo.pause = 0.0f;
 			}
 			else
 			{
 				einfo.active = true;
-				einfo.last_create = float( einfo.next_toggle );
-				einfo.next_toggle += r.urange( edata.duration_min, edata.duration_max );
+				einfo.pause += r.frange( edata.duration_min, edata.duration_max );
 			}
 		}
@@ -896,4 +929,14 @@
 }
 
+nv::particle_render_data nv::particle_engine::get_render_data( particle_system_group group )
+{
+	const particle_system_group_info* info = m_groups.get( group );
+	if ( info )
+	{
+		return{ info->count, info->vtx_array };
+	}
+	return { 0, nv::vertex_array() };
+}
+
 void nv::particle_engine::register_standard_affectors()
 {
Index: trunk/src/gl/gl_context.cc
===================================================================
--- trunk/src/gl/gl_context.cc	(revision 499)
+++ trunk/src/gl/gl_context.cc	(revision 500)
@@ -132,5 +132,5 @@
 }
 
-void nv::gl_context::attach( framebuffer f, output_slot slot, texture t )
+void nv::gl_context::attach( framebuffer f, output_slot slot, texture t, int layer /* = -1*/ )
 {
 	// TODO: framebuffer variable, so no re-binding?
@@ -143,14 +143,13 @@
 		glBindFramebuffer( GL_FRAMEBUFFER, info->glid );
 		unsigned gl_type = texture_type_to_enum( tinfo->type );
-
-		if ( tinfo )
-		{
-			//		if ( tinfo->size.y == 0 )
-				//			glFramebufferTexture1D( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0+(unsigned)slot, GL_TEXTURE_1D, tinfo->glid, 0 );
-			glFramebufferTexture2D( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0+unsigned( slot ), gl_type, tinfo->glid, 0 );
+		unsigned tglid = tinfo ? tinfo->glid : 0;
+
+		if ( layer >= 0 )
+		{
+			glFramebufferTextureLayer( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + unsigned( slot ), tglid, 0, layer );
 		}
 		else
 		{
-			glFramebufferTexture2D( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0+unsigned( slot ), gl_type, 0, 0 );
+			glFramebufferTexture2D( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + unsigned( slot ), gl_type, tglid, 0 );
 		}
 
@@ -171,5 +170,5 @@
 		if ( layer >= 0 )
 		{
-			glFramebufferTextureLayer( GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, tinfo->glid, 0, layer );
+			glFramebufferTextureLayer( GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, glid, 0, layer );
 		}
 		else
Index: trunk/src/gl/gl_enum.cc
===================================================================
--- trunk/src/gl/gl_enum.cc	(revision 499)
+++ trunk/src/gl/gl_enum.cc	(revision 500)
@@ -202,4 +202,10 @@
 	case R32I    : return GL_RED_INTEGER;
 	case R32UI   : return GL_RED_INTEGER;
+	case RGBA8I  : return GL_RGBA;
+	case RGBA8UI : return GL_RGBA;
+	case RGBA16I : return GL_RGBA;
+	case RGBA16UI: return GL_RGBA;
+	case RGBA32I : return GL_RGBA;
+	case RGBA32UI: return GL_RGBA;
 	NV_RETURN_COVERED_DEFAULT( 0 );
 	}
@@ -230,4 +236,11 @@
 	case R32I    : return GL_R32I;
 	case R32UI   : return GL_R32UI;
+	case RGBA8I  : return GL_RGBA8I;
+	case RGBA8UI : return GL_RGBA8UI;
+	case RGBA16I : return GL_RGBA16I;
+	case RGBA16UI: return GL_RGBA16UI;
+	case RGBA32I : return GL_RGBA32I;
+	case RGBA32UI: return GL_RGBA32UI;
+
 	NV_RETURN_COVERED_DEFAULT( 0 );
 	}
