Index: trunk/src/gfx/particle_engine.cc
===================================================================
--- trunk/src/gfx/particle_engine.cc	(revision 307)
+++ trunk/src/gfx/particle_engine.cc	(revision 309)
@@ -5,4 +5,5 @@
 #include <nv/lua/lua_glm.hh>
 #include <nv/logging.hh>
+#include <cmath>
 
 static const char *nv_particle_engine_vertex_shader_world =
@@ -61,5 +62,5 @@
 	data.gravity = table.get<vec3>("gravity", vec3() );
 	data.quota   = table.get<uint32>("quota", 1024 );
-	data.local   = table.get<bool>("local", false );
+	data.local   = table.get<bool>("local_space", false );
 	data.accurate_facing = table.get<bool>("accurate_facing", false );
 	data.emmiter_count   = 0;
@@ -73,16 +74,34 @@
 	else 
 	{
-		NV_LOG( LOG_ERROR, "Unknown orientation type! (" << orientation << " is MAX)!" );
+		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 etype = element.get_string("etype");
+		std::string type     = element.get_string("type");
+		std::string sub_type = element.get_string("sub_type");
 		if ( type == "emmiter" )
 		{
@@ -90,11 +109,42 @@
 			{
 				particle_emmiter_data& edata = data.emmiters[ data.emmiter_count ];
+
+				     if ( sub_type == "point" )             edata.type = particle_emmiter_type::POINT;
+				else if ( sub_type == "box" )               edata.type = particle_emmiter_type::BOX;
+				else if ( sub_type == "cylinder" )          edata.type = particle_emmiter_type::CYLINDER;
+				else if ( sub_type == "sphere" )            edata.type = particle_emmiter_type::SPHERE;
+				else if ( sub_type == "cylindroid" )        edata.type = particle_emmiter_type::CYLINDROID;
+				else if ( sub_type == "ellipsoid" )         edata.type = particle_emmiter_type::ELLIPSOID;
+				else if ( sub_type == "hollow_cylinder" )   edata.type = particle_emmiter_type::HOLLOW_CYLINDER;
+				else if ( sub_type == "hollow_sphere" )     edata.type = particle_emmiter_type::HOLLOW_SPHERE;
+				else if ( sub_type == "hollow_cylindroid" ) edata.type = particle_emmiter_type::HOLLOW_CYLINDROID;
+				else if ( sub_type == "hollow_ellipsoid" )  edata.type = particle_emmiter_type::HOLLOW_ELLIPSOID;
+				else
+				{
+					edata.type = particle_emmiter_type::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", vec2(0.1,0.1) );
+				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.square       = element.get<bool>("square", true );
 				edata.angle        = element.get<float>("angle", 0.0f );
 				float velocity     = element.get<float>("velocity", 0.0f );
@@ -249,14 +299,28 @@
 void nv::particle_engine::generate_data( particle_system_info* info )
 {
-	const vec3 x( 0.5f, 0.0f, 0.0f );
-	const vec3 y( 0.0f, 0.5f, 0.0f );
-	const vec3 z( 0.0f, 0.0f ,1.0f );
-
-	const vec3 sm[4] = {
-		vec3( -x-y ),
-		vec3(  x-y ),
-		vec3( -x+y ),
-		vec3(  x+y )
+	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 );
 
 	mat3 rot_mat;
@@ -353,4 +417,5 @@
 		orient = mat3( m_model_matrix );
 	}
+	float fms = float(ms);
 
 	for ( uint32 i = 0; i < ecount; ++i )
@@ -360,14 +425,119 @@
 		if ( einfo.active )
 		{
-			uint32 period = glm::max<uint32>( uint32(1000.f / edata.rate), 1 );
-			while ( ms - einfo.last_create > period )
+			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];
-					pinfo.position = source;
-					pinfo.color    = edata.color_min == edata.color_max ? 
+					switch ( edata.type )
+					{
+					case particle_emmiter_type::POINT:
+						pinfo.position = source;
+						break;
+					case particle_emmiter_type::BOX:
+						pinfo.position = source + orient * ( 
+							r.frange( -edata.hextents[0], edata.hextents[0] ) * edata.cdir +
+							r.frange( 0.0f, edata.extents[1] ) * edata.dir +
+							r.frange( -edata.hextents[2], edata.hextents[2] ) * edata.odir
+						);
+						break;
+					case particle_emmiter_type::CYLINDER:
+						{
+							vec2 rellipse = r.disk_point( edata.precise );
+							pinfo.position = source + orient * ( 
+								rellipse.x * edata.extents[0] * edata.cdir +
+								r.frange( 0.0f, edata.extents[1] ) * edata.dir +
+								rellipse.y * edata.extents[0] * edata.odir
+								);
+						}
+						break;
+					case particle_emmiter_type::SPHERE:
+						{
+							vec3 rellipse = r.sphere_point( edata.precise );
+							pinfo.position = source + orient * ( 
+								rellipse.x * edata.extents[0] * edata.cdir +
+								rellipse.y * edata.extents[0] * edata.dir +
+								rellipse.z * edata.extents[0] * edata.odir
+								);
+						}
+						break;
+					// TODO : this method is NOT uniform if width != height!
+					case particle_emmiter_type::CYLINDROID:
+						{
+							vec2 rellipse = r.ellipse_point( vec2( edata.hextents[0], edata.hextents[2] ), edata.precise );
+							pinfo.position = source + orient * ( 
+								rellipse.x * edata.cdir +
+								r.frange( 0.0f, edata.extents[1] ) * edata.dir +
+								rellipse.y * edata.odir
+							);
+						}
+						break;
+					// TODO : this method is NOT uniform if all dimension are not equal!
+					case particle_emmiter_type::ELLIPSOID:
+						{
+							vec3 rsphere = r.ellipsoid_point( edata.hextents, edata.precise );
+ 							pinfo.position = source + orient * ( 
+								rsphere.x * edata.cdir +
+								rsphere.y * edata.dir +
+								rsphere.z * edata.odir
+								);
+						}
+						break;
+					case particle_emmiter_type::HOLLOW_CYLINDER:
+						{
+							vec2 rellipse = r.hollow_disk_point( 
+								edata.ihextents[0],
+								edata.hextents[0],
+								edata.precise );
+							pinfo.position = source + orient * ( 
+								rellipse.x * edata.cdir +
+								r.frange( 0.0f, edata.extents[1] ) * edata.dir +
+								rellipse.y * edata.odir
+								);
+						}
+						break;
+					case particle_emmiter_type::HOLLOW_SPHERE:
+						{
+							vec3 rellipse = r.hollow_sphere_point( 
+								edata.ihextents[0],
+								edata.hextents[0],
+								edata.precise );
+							pinfo.position = source + orient * ( 
+								rellipse.x * edata.cdir +
+								rellipse.y * edata.dir +
+								rellipse.z * edata.odir
+								);
+						}
+						break;
+					case particle_emmiter_type::HOLLOW_CYLINDROID:
+						{
+							vec2 rellipse = r.hollow_ellipse_point( 
+								vec2( edata.ihextents[0], edata.ihextents[2] ), 
+								vec2( edata.hextents[0], edata.hextents[2] ), 
+								edata.precise );
+							pinfo.position = source + orient * ( 
+								rellipse.x * edata.cdir +
+								r.frange( 0.0f, edata.extents[1] ) * edata.dir +
+								rellipse.y * edata.odir
+								);
+						}
+						break;
+					// TODO : this method is NOT uniform if all dimension are not equal!
+					case particle_emmiter_type::HOLLOW_ELLIPSOID:
+						{
+							vec3 rellipse = r.hollow_ellipsoid_point( edata.ihextents, edata.hextents, edata.precise );
+							pinfo.position = source + orient * ( 
+								rellipse.x * edata.cdir +
+								rellipse.y * edata.dir +
+								rellipse.z * edata.odir
+								);
+						}
+						break;
+					}
+					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;
@@ -453,5 +623,5 @@
 			{
 				einfo.active = true;
-				einfo.last_create = einfo.next_toggle;
+				einfo.last_create = float( einfo.next_toggle );
 				einfo.next_toggle += r.urange( edata.duration_min, edata.duration_max );
 			}
