Index: trunk/src/gfx/particle_engine.cc
===================================================================
--- trunk/src/gfx/particle_engine.cc	(revision 319)
+++ 	(revision )
@@ -1,830 +1,0 @@
-// Copyright (C) 2014 ChaosForge Ltd
-// This file is part of NV Libraries.
-// For conditions of distribution and use, see copyright notice in nv.hh
-
-#include "nv/gfx/particle_engine.hh"
-
-#include <nv/interface/device.hh>
-#include <nv/core/random.hh>
-#include <nv/lua/lua_glm.hh>
-#include <nv/core/logging.hh>
-#include <cmath>
-
-static const char *nv_particle_engine_vertex_shader_world =
-	"#version 120\n"
-	"attribute vec3 nv_position;\n"
-	"attribute vec2 nv_texcoord;\n"
-	"attribute vec4 nv_color;\n"
-	"varying vec4 v_color;\n"
-	"varying vec2 v_texcoord;\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"
-	"}\n";
-static const char *nv_particle_engine_vertex_shader_local =
-	"#version 120\n"
-	"attribute vec3 nv_position;\n"
-	"attribute vec2 nv_texcoord;\n"
-	"attribute vec4 nv_color;\n"
-	"varying vec4 v_color;\n"
-	"varying vec2 v_texcoord;\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"
-	"}\n";
-static const char *nv_particle_engine_fragment_shader =
-	"#version 120\n"
-	"uniform sampler2D nv_t_diffuse;\n"
-	"varying vec4 v_color;\n"
-	"varying vec2 v_texcoord;\n"
-	"void main(void)\n"
-	"{\n"
-	"	vec4 tex_color = texture2D( nv_t_diffuse, v_texcoord );\n"
-	"	gl_FragColor   = v_color * tex_color;\n"
-	"}\n";
-
-using namespace nv;
-
-static void nv_particle_emmiter_point( const particle_emmiter_data*, particle* p, uint32 count )
-{
-	for ( uint32 i = 0; i < count; ++i )
-	{
-		p[i].position = vec3();
-	}
-
-}
-
-static void nv_particle_emmiter_box( const particle_emmiter_data* pe, particle* p, uint32 count )
-{
-	random& r = random::get();
-	for ( uint32 i = 0; i < count; ++i )
-	{
-		p[i].position = 
-			r.frange( -pe->hextents[0], pe->hextents[0] ) * pe->cdir +
-			r.frange( 0.0f, pe->extents[1] ) * pe->dir +
-			r.frange( -pe->hextents[2], pe->hextents[2] ) * pe->odir;
-	}
-}
-
-static void nv_particle_emmiter_cylinder( const particle_emmiter_data* pe, particle* p, uint32 count )
-{
-	random& r = random::get();
-	for ( uint32 i = 0; i < count; ++i )
-	{
-		vec2 rellipse( r.disk_point( pe->precise ) * pe->extents[0] );
-		p[i].position = 
-			rellipse.x * pe->cdir +
-			r.frange( 0.0f, pe->extents[1] ) * pe->dir +
-			rellipse.y * pe->odir;
-	}
-}
-
-static void nv_particle_emmiter_sphere( const particle_emmiter_data* pe, particle* p, uint32 count )
-{
-	random& r = random::get();
-	for ( uint32 i = 0; i < count; ++i )
-	{
-		vec3 rsphere = r.sphere_point( pe->precise ) * pe->extents[0];
-		p[i].position = 
-			rsphere.x * pe->cdir +
-			rsphere.y * pe->dir +
-			rsphere.z * pe->odir;
-	}
-}
-
-static void nv_particle_emmiter_cylindroid( const particle_emmiter_data* pe, particle* p, uint32 count )
-{
-	random& r = random::get();
-	for ( uint32 i = 0; i < count; ++i )
-	{
-		vec2 rellipse = r.ellipse_point( vec2( pe->hextents[0], pe->hextents[2] ), pe->precise );
-		p[i].position = 
-			rellipse.x * pe->cdir +
-			r.frange( 0.0f, pe->extents[1] ) * pe->dir +
-			rellipse.y * pe->odir;
-	}
-}
-
-static void nv_particle_emmiter_ellipsoid( const particle_emmiter_data* pe, particle* p, uint32 count )
-{
-	random& r = random::get();
-	for ( uint32 i = 0; i < count; ++i )
-	{
-		vec3 rsphere = r.ellipsoid_point( pe->hextents, pe->precise );
-		p[i].position = 
-			rsphere.x * pe->cdir +
-			rsphere.y * pe->dir +
-			rsphere.z * pe->odir;
-	}
-}
-
-static void nv_particle_emmiter_hollow_cylinder( const particle_emmiter_data* pe, particle* p, uint32 count )
-{
-	random& r = random::get();
-	for ( uint32 i = 0; i < count; ++i )
-	{
-		vec2 rellipse = r.hollow_disk_point( 
-			pe->ihextents[0],
-			pe->hextents[0],
-			pe->precise );
-		p[i].position = 
-			rellipse.x * pe->cdir +
-			r.frange( 0.0f, pe->extents[1] ) * pe->dir +
-			rellipse.y * pe->odir;
-	}
-}
-
-static void nv_particle_emmiter_hollow_sphere( const particle_emmiter_data* pe, particle* p, uint32 count )
-{
-	random& r = random::get();
-	for ( uint32 i = 0; i < count; ++i )
-	{
-		vec3 rellipse = r.hollow_sphere_point( pe->ihextents[0], pe->hextents[0], pe->precise );
-		p[i].position = 
-			rellipse.x * pe->cdir +
-			rellipse.y * pe->dir +
-			rellipse.z * pe->odir;
-	}
-}
-
-static void nv_particle_emmiter_hollow_cylindroid( const particle_emmiter_data* pe, particle* p, uint32 count )
-{
-	random& r = random::get();
-	for ( uint32 i = 0; i < count; ++i )
-	{
-		vec2 rellipse = r.hollow_ellipse_point( 
-			vec2( pe->ihextents[0], pe->ihextents[2] ), 
-			vec2( pe->hextents[0], pe->hextents[2] ), 
-			pe->precise );
-		p[i].position = 
-			rellipse.x * pe->cdir +
-			r.frange( 0.0f, pe->extents[1] ) * pe->dir +
-			rellipse.y * pe->odir;
-	}
-}
-
-static void nv_particle_emmiter_hollow_ellipsoid( const particle_emmiter_data* pe, particle* p, uint32 count )
-{
-	random& r = random::get();
-	for ( uint32 i = 0; i < count; ++i )
-	{
-		vec3 rellipse = r.hollow_ellipsoid_point( pe->ihextents, pe->hextents, pe->precise );
-		p[i].position = 
-			rellipse.x * pe->cdir +
-			rellipse.y * pe->dir +
-			rellipse.z * pe->odir;
-	}
-}
-
-struct nvpe_linear_force_data
-{
-	nv::vec3 force_vector;
-	bool     average;
-};
-
-static bool nv_particle_affector_linear_force_init( lua::table_guard* table, particle_affector_data* data )
-{
-	nvpe_linear_force_data* datap = ((nvpe_linear_force_data*)data->paramters);
-	datap->force_vector = table->get<vec3>("force_vector", vec3() );
-	datap->average      = table->get<bool>("average", false );
-	return true;
-}
-
-static void nv_particle_affector_linear_force( const particle_affector_data* data, particle* p, float factor, uint32 count )
-{
-	nvpe_linear_force_data* datap = ((nvpe_linear_force_data*)data->paramters);
-	if ( datap->average )
-	{
-		float norm_factor = glm::min( factor, 1.0f );
-		for ( uint32 i = 0; i < count; ++i ) 
-			p[i].velocity = datap->force_vector * norm_factor + p[i].velocity * ( 1.0f - norm_factor );
-	}
-	else
-	{
-		vec3 scvector = datap->force_vector * factor;
-		for ( uint32 i = 0; i < count; ++i ) p[i].velocity += scvector;
-	}
-}
-
-struct nvpe_deflector_plane_data
-{
-	nv::vec3 plane_point;
-	nv::vec3 plane_normal;
-	float    bounce;
-	float    distance;
-};
-
-static bool nv_particle_affector_deflector_plane_init( lua::table_guard* table, particle_affector_data* data )
-{
-	nvpe_deflector_plane_data* datap = ((nvpe_deflector_plane_data*)data->paramters);
-	datap->plane_point  = table->get<vec3>("plane_point",  vec3() );
-	datap->plane_normal = table->get<vec3>("plane_normal", vec3(0.0f,1.0f,0.0f) );
-	datap->plane_normal = normalize_safe( datap->plane_normal, vec3(0.0f,1.0f,0.0f) );
-	datap->bounce       = table->get<float>("bounce", 0.0f );
-	datap->distance     = -glm::dot( datap->plane_normal, datap->plane_point ) / glm::sqrt(glm::dot( datap->plane_normal, datap->plane_normal ) );
-	return true;
-}
-
-static void nv_particle_affector_deflector_plane( const particle_affector_data* data, particle* p, float factor, uint32 count )
-{
-	nvpe_deflector_plane_data* datap = ((nvpe_deflector_plane_data*)data->paramters);
-	for ( uint32 i = 0; i < count; ++i )
-	{
-		particle& pt = p[i];
-		vec3 direction  = pt.velocity * factor;
-		if ( glm::dot( datap->plane_normal, pt.position + direction ) + datap->distance <= 0.0f )
-		{
-			float val = glm::dot( datap->plane_normal, pt.position ) + datap->distance;
-			if ( val > 0.0f )
-			{
-				vec3 part_dir = direction * ( -val / glm::dot( datap->plane_normal, direction ) );
-				pt.position = pt.position + part_dir + ( part_dir - direction ) * datap->bounce;
-				pt.velocity = glm::reflect( pt.velocity, datap->plane_normal ) * datap->bounce;
-			}
-		}
-	}
-}
-
-struct nvpe_color_fader_data
-{
-	nv::vec4 adjustment;
-};
-
-static bool nv_particle_affector_color_fader_init( lua::table_guard* table, particle_affector_data* data )
-{
-	nvpe_color_fader_data* datap = ((nvpe_color_fader_data*)data->paramters);
-	datap->adjustment = table->get<vec4>("adjustment",  vec4() );
-	return true;
-}
-
-static void nv_particle_affector_color_fader( const particle_affector_data* data, particle* p, float factor, uint32 count )
-{
-	nvpe_color_fader_data* datap = ((nvpe_color_fader_data*)data->paramters);
-	vec4 adjustment = datap->adjustment * factor;
-	for ( uint32 i = 0; i < count; ++i )
-	{
-		p[i].color = glm::clamp( p[i].color + adjustment, 0.0f, 1.0f );
-	}
-}
-
-struct nvpe_scaler_data
-{
-	nv::vec2 adjustment;
-};
-
-static bool nv_particle_affector_scaler_init( lua::table_guard* table, particle_affector_data* data )
-{
-	nvpe_scaler_data* datap = ((nvpe_scaler_data*)data->paramters);
-	float rate        = table->get<float>("rate", 0.0f );
-	datap->adjustment = table->get<vec2>("adjustment",  vec2(rate,rate) );
-	return true;
-}
-
-static void nv_particle_affector_scaler( const particle_affector_data* data, particle* p, float factor, uint32 count )
-{
-	nvpe_scaler_data* datap = ((nvpe_scaler_data*)data->paramters);
-	vec2 adjustment = datap->adjustment * factor;
-	for ( uint32 i = 0; i < count; ++i )
-	{
-		p[i].size = glm::max( p[i].size + adjustment, vec2() );
-	}
-}
-
-void nv::particle_engine::load( lua::table_guard& table )
-{
-	std::string id = table.get_string( "id" );
-	if ( id == "" )
-	{
-		NV_LOG( LOG_ERROR, "Bad table passed to particle_engine!" )
-	}
-	// TODO : overwrite check
-	m_names[ id ] = m_data.size();
-
-	m_data.emplace_back();
-	auto& data = m_data.back();
-
-	data.quota   = table.get<uint32>("quota", 1024 );
-	data.local   = table.get<bool>("local_space", false );
-	data.accurate_facing = table.get<bool>("accurate_facing", false );
-	data.emmiter_count   = 0;
-	data.affector_count  = 0;
-
-	std::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( LOG_ERROR, "Unknown orientation type! (" << orientation << ")!" );
-		data.orientation = particle_orientation::POINT;
-	}
-
-	std::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( LOG_ERROR, "Unknown particle origin! (" << origin << ")!" );
-		data.origin = particle_origin::CENTER;
-	}
-
-	data.common_up  = glm::normalize( table.get<vec3>("common_up",  vec3(1,0,0) ) );
-	data.common_dir = glm::normalize( table.get<vec3>("common_dir", vec3(0,1,0) ) );
-
-	vec2 def_size        = table.get<vec2>("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 );
-		std::string type     = element.get_string("type");
-		std::string sub_type = element.get_string("sub_type");
-		if ( type == "emmiter" )
-		{
-			if ( data.emmiter_count < MAX_PARTICLE_EMMITERS )
-			{
-				particle_emmiter_data& edata = data.emmiters[ data.emmiter_count ];
-				auto emmiter_iter = m_emmiters.find( sub_type );
-				if ( emmiter_iter != m_emmiters.end() )
-				{
-					edata.emmiter_func = emmiter_iter->second;
-				}
-				else
-				{
-					edata.emmiter_func = nv_particle_emmiter_point;
-					NV_LOG( LOG_WARNING, "Unknown emmiter type in particle system! (" << sub_type << ")" );
-				}
-
-				edata.position     = element.get<vec3>("position", vec3() );
-				edata.extents      = element.get<vec3>("extents", vec3(1,1,1) );
-				edata.extents[0]   = element.get<float>("width",  edata.extents[0] );
-				edata.extents[1]   = element.get<float>("depth",  edata.extents[1] );
-				edata.extents[2]   = element.get<float>("height", edata.extents[2] );
-				edata.extents[0]   = element.get<float>("radius",  edata.extents[0] );
-				edata.iextents     = element.get<vec3>("inner_extents", vec3() );
-				edata.iextents[0]  = element.get<float>("inner_width",  edata.iextents[0] );
-				edata.iextents[1]  = element.get<float>("inner_depth",  edata.iextents[1] );
-				edata.iextents[2]  = element.get<float>("inner_height", edata.iextents[2] );
-				edata.iextents[0]  = element.get<float>("inner_radius",  edata.iextents[0] );
-				edata.hextents     = 0.5f * edata.extents;
-				edata.ihextents    = 0.5f * edata.iextents;
-				edata.precise      = element.get<bool>("precise", false );
-				edata.square       = element.get<bool>("square", true );
-				vec4 color         = element.get<vec4>("color", vec4(1,1,1,1) );
-				edata.color_min    = element.get<vec4>("color_min", color );
-				edata.color_max    = element.get<vec4>("color_max", color );
-				vec2 size          = element.get<vec2>("size", def_size );
-				edata.size_min     = element.get<vec2>("size_min", size );
-				edata.size_max     = element.get<vec2>("size_max", size );
-				edata.angle        = element.get<float>("angle", 0.0f );
-				float velocity     = element.get<float>("velocity", 0.0f );
-				edata.velocity_min = element.get<float>("velocity_min", velocity );
-				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 );
-				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 );
-				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.rate         = element.get<float>("rate", 1.0f );
-				edata.dir          = glm::normalize( element.get<vec3>("direction", vec3(0,1,0) ) );
-				
-				edata.odir = glm::vec3( 0, 0, 1 );
-				if ( edata.dir != vec3( 0, 1, 0 ) && edata.dir != vec3( 0, -1, 0 ) )
-					edata.odir = glm::normalize( glm::cross( edata.dir, vec3( 0, 1, 0 ) ) );		edata.cdir = glm::cross( edata.dir, edata.odir );
-
-				data.emmiter_count++;
-			}
-			else
-			{
-				NV_LOG( LOG_ERROR, "Too many emmiters (" << MAX_PARTICLE_EMMITERS << " is MAX)!" );
-			}
-		}
-		else if ( type == "affector" )
-		{
-			if ( data.affector_count < MAX_PARTICLE_AFFECTORS )
-			{
-				particle_affector_data& adata = data.affectors[ data.affector_count ];
-				data.affector_count++;
-				auto affector_iter = m_affectors.find( sub_type );
-				if ( affector_iter != m_affectors.end() )
-				{
-					adata.process = affector_iter->second.process;
-					if ( !affector_iter->second.init( &element, &adata ) )
-					{
-						data.affector_count--;
-						NV_LOG( LOG_WARNING, "Bad data passed to " << sub_type << " affector in particle system!" );
-					}
-				}
-				else
-				{
-					data.affector_count--;
-					NV_LOG( LOG_WARNING, "Unknown affector type in particle system! (" << sub_type << ")" );
-				}
-			}
-			else
-			{
-				NV_LOG( LOG_ERROR, "Too many affectors (" << MAX_PARTICLE_AFFECTORS << " is MAX)!" );
-			}
-		}
-		else 
-		{
-			NV_LOG( LOG_WARNING, "Unknown element in particle system! (" << type << ")" );
-		}
-	}
-
-}
-
-nv::particle_engine::particle_engine( context* a_context )
-{
-	m_context       = a_context;
-	m_device        = a_context->get_device();
-	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 );
-
-	register_standard_emmiters();
-	register_standard_affectors();
-}
-
-nv::particle_system nv::particle_engine::create_system( const std::string& id )
-{
-	auto it = m_names.find( id );
-	if ( it == m_names.end() )
-	{
-		return particle_system();
-	}
-	const particle_system_data* data = &(m_data[it->second]);
-	particle_system result = m_systems.create();
-	particle_system_info* info = m_systems.get( result );
-
-	info->data     = data;
-	uint32 ecount = data->emmiter_count;
-	for ( uint32 i = 0; i < ecount; ++i )
-	{
-		info->emmiters[i].active      = true;
-		info->emmiters[i].last_create = 0;
-		info->emmiters[i].next_toggle = random::get().urange( data->emmiters[i].duration_min, data->emmiters[i].duration_max );
-	}
-
-	info->count = 0;
-	info->particles = new particle[ data->quota ];
-	info->quads     = new particle_quad[ data->quota ];
-	info->vtx_array = m_context->create_vertex_array<particle_vtx>( 
-		(particle_vtx*)info->quads, data->quota*6, STREAM_DRAW );
-	info->vtx_buffer = m_context->find_buffer( info->vtx_array, slot::POSITION );
-	info->last_update = 0;
-	info->test = false;
-//	result->m_own_va      = true;
-//	result->m_offset      = 0;
-
-	return result;
-}
-
-void nv::particle_engine::draw( particle_system system, const render_state& rs, const scene_state& ss )
-{
-	particle_system_info* info = m_systems.get( system );
-	if ( info )
-	{
-		m_context->draw( nv::TRIANGLES, rs, ss, info->data->local ?  m_program_local : m_program_world, info->vtx_array, info->count * 6 );
-	}
-}
-
-nv::particle_engine::~particle_engine()
-{
-	m_device->release( m_program_world );
-	m_device->release( m_program_local );
-}
-
-void nv::particle_engine::release( particle_system system )
-{
-	particle_system_info* info = m_systems.get( system );
-	if ( info )
-	{
-		delete[] info->particles;
-		delete[] info->quads;
-		//if ( system->own_va ) 
-		m_context->release( info->vtx_array );
-		m_systems.destroy( system );
-	}
-}
-
-void nv::particle_engine::update( particle_system system, const scene_state& s, uint32 ms )
-{
-	particle_system_info* info = m_systems.get( system );
-	if ( info )
-	{
-		m_view_matrix  = s.get_view();
-		m_model_matrix = s.get_model();
-		m_camera_pos   = s.get_camera().get_position();
-		m_inv_view_dir = glm::normalize(-s.get_camera().get_direction());
-
-		update_emmiters( info, ms );
-		destroy_particles( info, ms );
-		create_particles( info, ms );
-		update_particles( info, ms );
-
-		generate_data( info );
-		m_context->update( info->vtx_buffer, info->quads, /*system->m_offset*sizeof(particle_quad)*/ 0, info->count*sizeof(particle_quad) );
-	}
-}
-
-void nv::particle_engine::set_texcoords( particle_system system, vec2 a, vec2 b )
-{
-	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 < info->data->quota; ++i )
-		{
-			particle_quad& rdata   = info->quads[i];
-			rdata.data[0].texcoord = texcoords[0];
-			rdata.data[1].texcoord = texcoords[1];
-			rdata.data[2].texcoord = texcoords[2];
-			rdata.data[3].texcoord = texcoords[3];
-			rdata.data[4].texcoord = texcoords[2];
-			rdata.data[5].texcoord = texcoords[1];
-		}
-	}
-}
-
-void nv::particle_engine::generate_data( particle_system_info* info )
-{
-	vec2 lb     = vec2( -0.5f, -0.5f );
-	vec2 rt     = vec2( 0.5f, 0.5f );
-
-	switch ( info->data->origin )
-	{
-	case particle_origin::CENTER        : break;
-	case particle_origin::TOP_LEFT      : lb = vec2(0.f,-1.f); rt = vec2(1.f,0.f);  break;
-	case particle_origin::TOP_CENTER    : lb.y = -1.f; rt.y = 0.f; break;  break;
-	case particle_origin::TOP_RIGHT     : lb = vec2(-1.f,-1.f); rt = vec2(); break;
-	case particle_origin::CENTER_LEFT   : lb.x = 0.f; rt.x = 1.f; break;
-	case particle_origin::CENTER_RIGHT  : lb.x = -1.f; rt.x = 0.f; break;
-	case particle_origin::BOTTOM_LEFT   : lb = vec2(); rt = vec2(1.f,1.f); break;
-	case particle_origin::BOTTOM_CENTER : lb.y = 0.f; rt.y = 1.f; break; 
-	case particle_origin::BOTTOM_RIGHT  : lb = vec2(-1.f,0.f); rt = vec2(.0f,1.f); break;
-	}
-
-	const vec3 sm[4] = 
-	{ 
-		vec3( lb.x, lb.y, 0.0f ),
-		vec3( rt.x, lb.y, 0.0f ),
-		vec3( lb.x, rt.y, 0.0f ),
-		vec3( rt.x, rt.y, 0.0f ),
-	};
-	vec3 z( 0.0f, 0.0f ,1.0f );
-
-	particle_orientation orientation = info->data->orientation;
-	vec3 common_up ( info->data->common_up );
-	vec3 common_dir( info->data->common_dir );
-	bool accurate_facing = info->data->accurate_facing;
-	mat3 rot_mat;
-	vec3 right;
-	vec3 pdir( 0.0f, 1.0f, 0.0f );
-
-	for ( uint32 i = 0; i < info->count; ++i )
-	{
-		const particle& pdata = info->particles[i];
-		particle_quad& rdata  = info->quads[i];
-
-		vec3 view_dir( m_inv_view_dir );
-		if ( accurate_facing ) view_dir = glm::normalize( m_camera_pos - pdata.position );
-
-		switch ( orientation )
-		{
-		case particle_orientation::POINT :
-			right   = glm::normalize( glm::cross( view_dir, vec3( 0, 1, 0 ) ) );
-			rot_mat = mat3( right, glm::cross( right, -view_dir ), -view_dir );
-			break;
-		case particle_orientation::ORIENTED :
-			pdir    = normalize_safe( pdata.velocity, pdir );
-			right   = glm::normalize( glm::cross( pdir, view_dir ) );
-			rot_mat = mat3( right, pdir, glm::cross( pdir, right ) );
-			break;
-		case particle_orientation::ORIENTED_COMMON :
-			right   = glm::normalize( glm::cross( common_dir, view_dir ) );
-			rot_mat = mat3( right, common_dir, glm::cross( common_dir, right ) );
-			break;
-		case particle_orientation::PERPENDICULAR :
-			pdir    = normalize_safe( pdata.velocity, pdir );
-			right   = glm::normalize( glm::cross( common_up, pdir ) );
-			rot_mat = mat3( right, common_up, glm::cross( common_up, right ) );
-			break;
-		case particle_orientation::PERPENDICULAR_COMMON :
-			right   = glm::normalize( glm::cross( common_up, common_dir ) );
-			rot_mat = mat3( right, common_up, glm::cross( common_up, right ) );
-			break;
-		}
-
-		vec3 size( pdata.size.x, pdata.size.y, 0.0f );
-		vec3 s0 = rot_mat * ( ( size * sm[0] ) );
-		vec3 s1 = rot_mat * ( ( size * sm[1] ) );
-		vec3 s2 = rot_mat * ( ( size * sm[2] ) );
-		vec3 s3 = rot_mat * ( ( size * sm[3] ) );
-
-		rdata.data[0].position = pdata.position + s0;
-		rdata.data[0].color    = pdata.color;
-
-		rdata.data[1].position = pdata.position + s1;
-		rdata.data[1].color    = pdata.color;
-
-		rdata.data[2].position = pdata.position + s2;
-		rdata.data[2].color    = pdata.color;
-
-		rdata.data[3].position = pdata.position + s3;
-		rdata.data[3].color    = pdata.color;
-
-		rdata.data[4] = rdata.data[2];
-		rdata.data[5] = rdata.data[1];
-	}
-}
-
-void nv::particle_engine::destroy_particles( particle_system_info* info, uint32 ms )
-{
-	if ( info->count > 0 )
-		for ( sint32 i = info->count-1; i >= 0; --i )
-		{
-			particle& pinfo = info->particles[i];
-			if ( //pdata.position.y < 0.0f ||
-				ms >= pinfo.death )
-			{
-				info->count--;
-				std::swap( info->particles[i], info->particles[info->count] );
-			}
-		}
-}
-
-void nv::particle_engine::create_particles( particle_system_info* info, uint32 ms )
-{
-	uint32 ecount = info->data->emmiter_count;
-	if ( ecount == 0 ) return;
-
-	random& r = random::get();
-	vec3 source;
-	mat3 orient;
-	bool local = info->data->local;
-	if ( !local ) 
-	{
-		source = vec3( m_model_matrix[3] );
-		orient = mat3( m_model_matrix );
-	}
-
-	float fms = float(ms);
-
-	for ( uint32 i = 0; i < ecount; ++i )
-	{
-		const auto& edata = info->data->emmiters[i];
-		auto& einfo = info->emmiters[i];
-		if ( einfo.active )
-		{
-			float period = 1000.f / edata.rate;
-			while ( fms - einfo.last_create > period )
-			{
-				if ( info->count < info->data->quota-1 )
-				{
-					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 ? 
-						edata.color_min : r.range( edata.color_min, edata.color_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 ?
-						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.velocity = edata.dir;
-					if ( edata.angle > 0.0f )
-					{
-						float emission_angle = glm::radians( edata.angle );
-						float cos_theta = r.frange( cos( emission_angle ), 1.0f );
-						float sin_theta = glm::sqrt(1.0f - cos_theta * cos_theta );
-						float phi       = r.frange( 0.0f, 2*glm::pi<float>() );
-						pinfo.velocity  = orient * 
-							( edata.odir * ( glm::cos(phi) * sin_theta ) +
-							edata.cdir * ( glm::sin(phi)*sin_theta ) + 
-							edata.dir  * cos_theta );
-					}
-
-					pinfo.velocity *= velocity;
-
-					info->count++;
-				}
-				einfo.last_create += period;
-			}
-		}
-	}
-}
-
-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;
-
-	uint32 acount = info->data->affector_count;
-	for ( uint32 i = 0; i < acount; ++i )
-	{
-		const particle_affector_data* padata = &(info->data->affectors[i]);
-		padata->process( padata, info->particles, factor, info->count );
-	}
-
-
-	for ( uint32 i = 0; i < info->count; ++i )
-	{
-		particle& pdata = info->particles[i];
-		pdata.position += pdata.velocity * factor;
-	}
-	info->last_update = ms;
-}
-
-void nv::particle_engine::update_emmiters( particle_system_info* info, uint32 ms )
-{
-	uint32 ecount = info->data->emmiter_count;
-	if ( ecount == 0 ) return;
-	random& r = random::get();
-
-	for ( uint32 i = 0; i < ecount; ++i )
-	{
-		const auto& edata = info->data->emmiters[i];
-		auto& einfo = info->emmiters[i];
-
-		if ( einfo.next_toggle != 0 && ms >= einfo.next_toggle )
-		{
-			if ( einfo.active )
-			{
-				einfo.active = false;
-				if ( edata.repeat_min > 0 )
-					einfo.next_toggle += r.urange( edata.repeat_min, edata.repeat_max );
-				else
-					einfo.next_toggle = 0;
-			}
-			else
-			{
-				einfo.active = true;
-				einfo.last_create = float( einfo.next_toggle );
-				einfo.next_toggle += r.urange( edata.duration_min, edata.duration_max );
-			}
-		}
-	}
-
-}
-
-void nv::particle_engine::register_emmiter_type( const std::string& name, particle_emmiter_func func )
-{
-	m_emmiters[ name ] = func;
-}
-
-void nv::particle_engine::register_standard_emmiters()
-{
-	register_emmiter_type( "point",             nv_particle_emmiter_point );
-	register_emmiter_type( "box",               nv_particle_emmiter_box );
-	register_emmiter_type( "cylinder",          nv_particle_emmiter_cylinder );
-	register_emmiter_type( "sphere",            nv_particle_emmiter_sphere );
-	register_emmiter_type( "cylindroid",        nv_particle_emmiter_cylindroid );
-	register_emmiter_type( "ellipsoid",         nv_particle_emmiter_ellipsoid );
-	register_emmiter_type( "hollow_cylinder",   nv_particle_emmiter_hollow_cylinder );
-	register_emmiter_type( "hollow_sphere",     nv_particle_emmiter_hollow_sphere );
-	register_emmiter_type( "hollow_cylindroid", nv_particle_emmiter_hollow_cylindroid );
-	register_emmiter_type( "hollow_ellipsoid",  nv_particle_emmiter_hollow_ellipsoid );
-}
-
-void nv::particle_engine::register_affector_type( const std::string& name, particle_affector_init_func init, particle_affector_func process )
-{
-	m_affectors[ name ].init    = init;
-	m_affectors[ name ].process = process;
-}
-
-void nv::particle_engine::register_standard_affectors()
-{
-	register_affector_type( "linear_force",    nv_particle_affector_linear_force_init, nv_particle_affector_linear_force );
-	register_affector_type( "deflector_plane", nv_particle_affector_deflector_plane_init, nv_particle_affector_deflector_plane );
-	register_affector_type( "color_fader",     nv_particle_affector_color_fader_init, nv_particle_affector_color_fader );
-	register_affector_type( "scaler",          nv_particle_affector_scaler_init, nv_particle_affector_scaler );
-}
-
