source: trunk/src/gfx/particle_engine.cc @ 312

Last change on this file since 312 was 312, checked in by epyon, 11 years ago
  • particle engine now can be extended with affectors and emmiters
  • in the future we'll use a VM, but for now this completes functionality
File size: 28.5 KB
RevLine 
[306]1#include "nv/gfx/particle_engine.hh"
2
3#include <nv/interface/device.hh>
4#include <nv/random.hh>
5#include <nv/lua/lua_glm.hh>
6#include <nv/logging.hh>
[309]7#include <cmath>
[306]8
9static const char *nv_particle_engine_vertex_shader_world =
10        "#version 120\n"
11        "attribute vec3 nv_position;\n"
12        "attribute vec2 nv_texcoord;\n"
13        "attribute vec4 nv_color;\n"
14        "varying vec4 v_color;\n"
15        "varying vec2 v_texcoord;\n"
16        "uniform mat4 nv_m_view;\n"
17        "uniform mat4 nv_m_projection;\n"
18        "void main(void)\n"
19        "{\n"
20        "       gl_Position = nv_m_projection * nv_m_view * vec4 (nv_position, 1.0);\n"
21        "       v_texcoord  = nv_texcoord;\n"
22        "       v_color     = nv_color;\n"
23        "}\n";
24static const char *nv_particle_engine_vertex_shader_local =
25        "#version 120\n"
26        "attribute vec3 nv_position;\n"
27        "attribute vec2 nv_texcoord;\n"
28        "attribute vec4 nv_color;\n"
29        "varying vec4 v_color;\n"
30        "varying vec2 v_texcoord;\n"
31        "uniform mat4 nv_m_mvp;\n"
32        "void main(void)\n"
33        "{\n"
34        "       gl_Position = nv_m_mvp * vec4 (nv_position, 1.0);\n"
35        "       v_texcoord  = nv_texcoord;\n"
36        "       v_color     = nv_color;\n"
37        "}\n";
38static const char *nv_particle_engine_fragment_shader =
39        "#version 120\n"
40        "uniform sampler2D nv_t_diffuse;\n"
41        "varying vec4 v_color;\n"
42        "varying vec2 v_texcoord;\n"
43        "void main(void)\n"
44        "{\n"
45        "       vec4 tex_color = texture2D( nv_t_diffuse, v_texcoord );\n"
46        "       gl_FragColor   = v_color * tex_color;\n"
47        "}\n";
48
[312]49using namespace nv;
50
51static void nv_particle_emmiter_point( const particle_emmiter_data*, particle* p, uint32 count )
52{
53        for ( uint32 i = 0; i < count; ++i )
54        {
55                p[i].position = vec3();
56        }
57
58}
59
60static void nv_particle_emmiter_box( const particle_emmiter_data* pe, particle* p, uint32 count )
61{
62        random& r = random::get();
63        for ( uint32 i = 0; i < count; ++i )
64        {
65                p[i].position =
66                        r.frange( -pe->hextents[0], pe->hextents[0] ) * pe->cdir +
67                        r.frange( 0.0f, pe->extents[1] ) * pe->dir +
68                        r.frange( -pe->hextents[2], pe->hextents[2] ) * pe->odir;
69        }
70}
71
72static void nv_particle_emmiter_cylinder( const particle_emmiter_data* pe, particle* p, uint32 count )
73{
74        random& r = random::get();
75        for ( uint32 i = 0; i < count; ++i )
76        {
77                vec2 rellipse( r.disk_point( pe->precise ) * pe->extents[0] );
78                p[i].position =
79                        rellipse.x * pe->cdir +
80                        r.frange( 0.0f, pe->extents[1] ) * pe->dir +
81                        rellipse.y * pe->odir;
82        }
83}
84
85static void nv_particle_emmiter_sphere( const particle_emmiter_data* pe, particle* p, uint32 count )
86{
87        random& r = random::get();
88        for ( uint32 i = 0; i < count; ++i )
89        {
90                vec3 rsphere = r.sphere_point( pe->precise ) * pe->extents[0];
91                p[i].position =
92                        rsphere.x * pe->cdir +
93                        rsphere.y * pe->dir +
94                        rsphere.z * pe->odir;
95        }
96}
97
98static void nv_particle_emmiter_cylindroid( const particle_emmiter_data* pe, particle* p, uint32 count )
99{
100        random& r = random::get();
101        for ( uint32 i = 0; i < count; ++i )
102        {
103                vec2 rellipse = r.ellipse_point( vec2( pe->hextents[0], pe->hextents[2] ), pe->precise );
104                p[i].position =
105                        rellipse.x * pe->cdir +
106                        r.frange( 0.0f, pe->extents[1] ) * pe->dir +
107                        rellipse.y * pe->odir;
108        }
109}
110
111static void nv_particle_emmiter_ellipsoid( const particle_emmiter_data* pe, particle* p, uint32 count )
112{
113        random& r = random::get();
114        for ( uint32 i = 0; i < count; ++i )
115        {
116                vec3 rsphere = r.ellipsoid_point( pe->hextents, pe->precise );
117                p[i].position =
118                        rsphere.x * pe->cdir +
119                        rsphere.y * pe->dir +
120                        rsphere.z * pe->odir;
121        }
122}
123
124static void nv_particle_emmiter_hollow_cylinder( const particle_emmiter_data* pe, particle* p, uint32 count )
125{
126        random& r = random::get();
127        for ( uint32 i = 0; i < count; ++i )
128        {
129                vec2 rellipse = r.hollow_disk_point(
130                        pe->ihextents[0],
131                        pe->hextents[0],
132                        pe->precise );
133                p[i].position =
134                        rellipse.x * pe->cdir +
135                        r.frange( 0.0f, pe->extents[1] ) * pe->dir +
136                        rellipse.y * pe->odir;
137        }
138}
139
140static void nv_particle_emmiter_hollow_sphere( const particle_emmiter_data* pe, particle* p, uint32 count )
141{
142        random& r = random::get();
143        for ( uint32 i = 0; i < count; ++i )
144        {
145                vec3 rellipse = r.hollow_sphere_point( pe->ihextents[0], pe->hextents[0], pe->precise );
146                p[i].position =
147                        rellipse.x * pe->cdir +
148                        rellipse.y * pe->dir +
149                        rellipse.z * pe->odir;
150        }
151}
152
153static void nv_particle_emmiter_hollow_cylindroid( const particle_emmiter_data* pe, particle* p, uint32 count )
154{
155        random& r = random::get();
156        for ( uint32 i = 0; i < count; ++i )
157        {
158                vec2 rellipse = r.hollow_ellipse_point(
159                        vec2( pe->ihextents[0], pe->ihextents[2] ),
160                        vec2( pe->hextents[0], pe->hextents[2] ),
161                        pe->precise );
162                p[i].position =
163                        rellipse.x * pe->cdir +
164                        r.frange( 0.0f, pe->extents[1] ) * pe->dir +
165                        rellipse.y * pe->odir;
166        }
167}
168
169static void nv_particle_emmiter_hollow_ellipsoid( const particle_emmiter_data* pe, particle* p, uint32 count )
170{
171        random& r = random::get();
172        for ( uint32 i = 0; i < count; ++i )
173        {
174                vec3 rellipse = r.hollow_ellipsoid_point( pe->ihextents, pe->hextents, pe->precise );
175                p[i].position =
176                        rellipse.x * pe->cdir +
177                        rellipse.y * pe->dir +
178                        rellipse.z * pe->odir;
179        }
180}
181
182struct nvpe_linear_force_data
183{
184        nv::vec3 force_vector;
185        bool     average;
186};
187
188static bool nv_particle_affector_linear_force_init( lua::table_guard* table, particle_affector_data* data )
189{
190        nvpe_linear_force_data* datap = ((nvpe_linear_force_data*)data->paramters);
191        datap->force_vector = table->get<vec3>("force_vector", vec3() );
192        datap->average      = table->get<bool>("average", false );
193        return true;
194}
195
196static void nv_particle_affector_linear_force( const particle_affector_data* data, particle* p, float factor, uint32 count )
197{
198        nvpe_linear_force_data* datap = ((nvpe_linear_force_data*)data->paramters);
199        if ( datap->average )
200        {
201                float norm_factor = glm::min( factor, 1.0f );
202                for ( uint32 i = 0; i < count; ++i )
203                        p[i].velocity = datap->force_vector * norm_factor + p[i].velocity * ( 1.0f - norm_factor );
204        }
205        else
206        {
207                vec3 scvector = datap->force_vector * factor;
208                for ( uint32 i = 0; i < count; ++i ) p[i].velocity += scvector;
209        }
210}
211
212struct nvpe_deflector_plane_data
213{
214        nv::vec3 plane_point;
215        nv::vec3 plane_normal;
216        float    bounce;
217        float    distance;
218};
219
220static bool nv_particle_affector_deflector_plane_init( lua::table_guard* table, particle_affector_data* data )
221{
222        nvpe_deflector_plane_data* datap = ((nvpe_deflector_plane_data*)data->paramters);
223        datap->plane_point  = table->get<vec3>("plane_point",  vec3() );
224        datap->plane_normal = table->get<vec3>("plane_normal", vec3(0.0f,1.0f,0.0f) );
225        datap->plane_normal = normalize_safe( datap->plane_normal, vec3(0.0f,1.0f,0.0f) );
226        datap->bounce       = table->get<float>("bounce", 0.0f );
227        datap->distance     = -glm::dot( datap->plane_normal, datap->plane_point ) / glm::sqrt(glm::dot( datap->plane_normal, datap->plane_normal ) );
228        return true;
229}
230
231static void nv_particle_affector_deflector_plane( const particle_affector_data* data, particle* p, float factor, uint32 count )
232{
233        nvpe_deflector_plane_data* datap = ((nvpe_deflector_plane_data*)data->paramters);
234        for ( uint32 i = 0; i < count; ++i )
235        {
236                particle& pt = p[i];
237                vec3 direction  = pt.velocity * factor;
238                if ( glm::dot( datap->plane_normal, pt.position + direction ) + datap->distance <= 0.0f )
239                {
240                        float val = glm::dot( datap->plane_normal, pt.position ) + datap->distance;
241                        if ( val > 0.0f )
242                        {
243                                vec3 part_dir = direction * ( -val / glm::dot( datap->plane_normal, direction ) );
244                                pt.position = pt.position + part_dir + ( part_dir - direction ) * datap->bounce;
245                                pt.velocity = glm::reflect( pt.velocity, datap->plane_normal ) * datap->bounce;
246                        }
247                }
248        }
249}
250
251struct nvpe_color_fader_data
252{
253        nv::vec4 adjustment;
254};
255
256static bool nv_particle_affector_color_fader_init( lua::table_guard* table, particle_affector_data* data )
257{
258        nvpe_color_fader_data* datap = ((nvpe_color_fader_data*)data->paramters);
259        datap->adjustment = table->get<vec4>("adjustment",  vec4() );
260        return true;
261}
262
263static void nv_particle_affector_color_fader( const particle_affector_data* data, particle* p, float factor, uint32 count )
264{
265        nvpe_color_fader_data* datap = ((nvpe_color_fader_data*)data->paramters);
266        vec4 adjustment = datap->adjustment * factor;
267        for ( uint32 i = 0; i < count; ++i )
268        {
269                p[i].color = glm::clamp( p[i].color + adjustment, 0.0f, 1.0f );
270        }
271}
272
273struct nvpe_scaler_data
274{
275        nv::vec2 adjustment;
276};
277
278static bool nv_particle_affector_scaler_init( lua::table_guard* table, particle_affector_data* data )
279{
280        nvpe_scaler_data* datap = ((nvpe_scaler_data*)data->paramters);
281        float rate        = table->get<float>("rate", 0.0f );
282        datap->adjustment = table->get<vec2>("adjustment",  vec2(rate,rate) );
283        return true;
284}
285
286static void nv_particle_affector_scaler( const particle_affector_data* data, particle* p, float factor, uint32 count )
287{
288        nvpe_scaler_data* datap = ((nvpe_scaler_data*)data->paramters);
289        vec2 adjustment = datap->adjustment * factor;
290        for ( uint32 i = 0; i < count; ++i )
291        {
292                p[i].size = glm::max( p[i].size + adjustment, vec2() );
293        }
294}
295
[306]296void nv::particle_engine::load( lua::table_guard& table )
297{
298        std::string id = table.get_string( "id" );
299        if ( id == "" )
300        {
301                NV_LOG( LOG_ERROR, "Bad table passed to particle_engine!" )
302        }
303        // TODO : overwrite check
304        m_names[ id ] = m_data.size();
305
306        m_data.emplace_back();
307        auto& data = m_data.back();
308
309        data.quota   = table.get<uint32>("quota", 1024 );
[309]310        data.local   = table.get<bool>("local_space", false );
[306]311        data.accurate_facing = table.get<bool>("accurate_facing", false );
312        data.emmiter_count   = 0;
[312]313        data.affector_count  = 0;
[306]314
315        std::string orientation = table.get_string( "orientation", "point" );
316        if ( orientation == "point" )                     { data.orientation = particle_orientation::POINT; }
317        else if ( orientation == "oriented" )             { data.orientation = particle_orientation::ORIENTED; }
318        else if ( orientation == "oriented_common" )      { data.orientation = particle_orientation::ORIENTED_COMMON; }
319        else if ( orientation == "perpendicular" )        { data.orientation = particle_orientation::PERPENDICULAR; }
320        else if ( orientation == "perpendicular_common" ) { data.orientation = particle_orientation::PERPENDICULAR_COMMON; }
321        else
322        {
[309]323                NV_LOG( LOG_ERROR, "Unknown orientation type! (" << orientation << ")!" );
[306]324                data.orientation = particle_orientation::POINT;
325        }
[309]326
327        std::string origin = table.get_string( "origin", "center" );
328        if      ( origin == "center" )        { data.origin = particle_origin::CENTER; }
329        else if ( origin == "top_left" )      { data.origin = particle_origin::TOP_LEFT; }
330        else if ( origin == "top_center" )    { data.origin = particle_origin::TOP_CENTER; }
331        else if ( origin == "top_right" )     { data.origin = particle_origin::TOP_RIGHT; }
332        else if ( origin == "center_left" )   { data.origin = particle_origin::CENTER_LEFT; }
333        else if ( origin == "center_right" )  { data.origin = particle_origin::CENTER_RIGHT; }
334        else if ( origin == "bottom_left" )   { data.origin = particle_origin::BOTTOM_LEFT; }
335        else if ( origin == "bottom_center" ) { data.origin = particle_origin::BOTTOM_CENTER; }
336        else if ( origin == "bottom_right" )  { data.origin = particle_origin::BOTTOM_RIGHT; }
337        else
338        {
339                NV_LOG( LOG_ERROR, "Unknown particle origin! (" << origin << ")!" );
340                data.origin = particle_origin::CENTER;
341        }
342
[306]343        data.common_up  = glm::normalize( table.get<vec3>("common_up",  vec3(1,0,0) ) );
344        data.common_dir = glm::normalize( table.get<vec3>("common_dir", vec3(0,1,0) ) );
345
[309]346        vec2 def_size        = table.get<vec2>("size", vec2(0.1,0.1) );
[306]347        uint32 elements = table.get_size();
348        for ( uint32 i = 0; i < elements; ++i )
349        {
350                lua::table_guard element( table, i+1 );
[309]351                std::string type     = element.get_string("type");
352                std::string sub_type = element.get_string("sub_type");
[306]353                if ( type == "emmiter" )
354                {
355                        if ( data.emmiter_count < MAX_PARTICLE_EMMITERS )
356                        {
357                                particle_emmiter_data& edata = data.emmiters[ data.emmiter_count ];
[312]358                                auto emmiter_iter = m_emmiters.find( sub_type );
359                                if ( emmiter_iter != m_emmiters.end() )
360                                {
361                                        edata.emmiter_func = emmiter_iter->second;
362                                }
[309]363                                else
364                                {
[312]365                                        edata.emmiter_func = nv_particle_emmiter_point;
[309]366                                        NV_LOG( LOG_WARNING, "Unknown emmiter type in particle system! (" << sub_type << ")" );
367                                }
368
369                                edata.position     = element.get<vec3>("position", vec3() );
370                                edata.extents      = element.get<vec3>("extents", vec3(1,1,1) );
371                                edata.extents[0]   = element.get<float>("width",  edata.extents[0] );
372                                edata.extents[1]   = element.get<float>("depth",  edata.extents[1] );
373                                edata.extents[2]   = element.get<float>("height", edata.extents[2] );
374                                edata.extents[0]   = element.get<float>("radius",  edata.extents[0] );
375                                edata.iextents     = element.get<vec3>("inner_extents", vec3() );
376                                edata.iextents[0]  = element.get<float>("inner_width",  edata.iextents[0] );
377                                edata.iextents[1]  = element.get<float>("inner_depth",  edata.iextents[1] );
378                                edata.iextents[2]  = element.get<float>("inner_height", edata.iextents[2] );
379                                edata.iextents[0]  = element.get<float>("inner_radius",  edata.iextents[0] );
380                                edata.hextents     = 0.5f * edata.extents;
381                                edata.ihextents    = 0.5f * edata.iextents;
382                                edata.precise      = element.get<bool>("precise", false );
383                                edata.square       = element.get<bool>("square", true );
[306]384                                vec4 color         = element.get<vec4>("color", vec4(1,1,1,1) );
385                                edata.color_min    = element.get<vec4>("color_min", color );
386                                edata.color_max    = element.get<vec4>("color_max", color );
[309]387                                vec2 size          = element.get<vec2>("size", def_size );
[306]388                                edata.size_min     = element.get<vec2>("size_min", size );
389                                edata.size_max     = element.get<vec2>("size_max", size );
390                                edata.angle        = element.get<float>("angle", 0.0f );
391                                float velocity     = element.get<float>("velocity", 0.0f );
392                                edata.velocity_min = element.get<float>("velocity_min", velocity );
393                                edata.velocity_max = element.get<float>("velocity_max", velocity );
394                                float lifetime     = element.get<float>("lifetime", 1.0f );
395                                edata.lifetime_min = uint32( element.get<float>("lifetime_min", lifetime ) * 1000.f );
396                                edata.lifetime_max = uint32( element.get<float>("lifetime_max", lifetime ) * 1000.f );
[307]397                                float duration     = element.get<float>("duration", 0.0f );
398                                edata.duration_min = uint32( element.get<float>("duration_min", duration ) * 1000.f );
399                                edata.duration_max = uint32( element.get<float>("duration_max", duration ) * 1000.f );
400                                float repeat       = element.get<float>("repeat_delay", 0.0f );
401                                edata.repeat_min   = uint32( element.get<float>("repeat_delay_min", repeat ) * 1000.f );
402                                edata.repeat_max   = uint32( element.get<float>("repeat_delay_max", repeat ) * 1000.f );
403
[306]404                                edata.rate         = element.get<float>("rate", 1.0f );
405                                edata.dir          = glm::normalize( element.get<vec3>("direction", vec3(0,1,0) ) );
406                               
407                                edata.odir = glm::vec3( 0, 0, 1 );
408                                if ( edata.dir != vec3( 0, 1, 0 ) && edata.dir != vec3( 0, -1, 0 ) )
409                                        edata.odir = glm::normalize( glm::cross( edata.dir, vec3( 0, 1, 0 ) ) );                edata.cdir = glm::cross( edata.dir, edata.odir );
410
411                                data.emmiter_count++;
412                        }
413                        else
414                        {
415                                NV_LOG( LOG_ERROR, "Too many emmiters (" << MAX_PARTICLE_EMMITERS << " is MAX)!" );
416                        }
417                }
418                else if ( type == "affector" )
419                {
[312]420                        if ( data.affector_count < MAX_PARTICLE_AFFECTORS )
421                        {
422                                particle_affector_data& adata = data.affectors[ data.affector_count ];
423                                data.affector_count++;
424                                auto affector_iter = m_affectors.find( sub_type );
425                                if ( affector_iter != m_affectors.end() )
426                                {
427                                        adata.process = affector_iter->second.process;
428                                        if ( !affector_iter->second.init( &element, &adata ) )
429                                        {
430                                                data.affector_count--;
431                                                NV_LOG( LOG_WARNING, "Bad data passed to " << sub_type << " affector in particle system!" );
432                                        }
433                                }
434                                else
435                                {
436                                        data.affector_count--;
437                                        NV_LOG( LOG_WARNING, "Unknown affector type in particle system! (" << sub_type << ")" );
438                                }
439                        }
440                        else
441                        {
442                                NV_LOG( LOG_ERROR, "Too many affectors (" << MAX_PARTICLE_AFFECTORS << " is MAX)!" );
443                        }
[306]444                }
445                else
446                {
447                        NV_LOG( LOG_WARNING, "Unknown element in particle system! (" << type << ")" );
448                }
449        }
450
451}
452
453nv::particle_engine::particle_engine( context* a_context )
454{
455        m_context       = a_context;
456        m_device        = a_context->get_device();
457        m_program_local = m_device->create_program( nv_particle_engine_vertex_shader_local, nv_particle_engine_fragment_shader );
458        m_program_world = m_device->create_program( nv_particle_engine_vertex_shader_world, nv_particle_engine_fragment_shader );
[312]459
460        register_standard_emmiters();
461        register_standard_affectors();
[306]462}
463
464nv::particle_system nv::particle_engine::create_system( const std::string& id )
465{
466        auto it = m_names.find( id );
467        if ( it == m_names.end() )
468        {
469                return particle_system();
470        }
471        const particle_system_data* data = &(m_data[it->second]);
472        particle_system result = m_systems.create();
473        particle_system_info* info = m_systems.get( result );
474
475        info->data     = data;
476        uint32 ecount = data->emmiter_count;
477        for ( uint32 i = 0; i < ecount; ++i )
478        {
[307]479                info->emmiters[i].active      = true;
[306]480                info->emmiters[i].last_create = 0;
[307]481                info->emmiters[i].next_toggle = random::get().urange( data->emmiters[i].duration_min, data->emmiters[i].duration_max );
[306]482        }
483
484        info->count = 0;
485        info->particles = new particle[ data->quota ];
486        info->quads     = new particle_quad[ data->quota ];
487        info->vtx_array = m_device->create_vertex_array<particle_vtx>(
488                (particle_vtx*)info->quads, data->quota*6, STREAM_DRAW );
489        info->vtx_buffer = m_device->find_buffer( info->vtx_array, slot::POSITION );
490        info->last_update = 0;
491        info->test = false;
492//      result->m_own_va      = true;
493//      result->m_offset      = 0;
494
495        return result;
496}
497
498void nv::particle_engine::draw( particle_system system, const render_state& rs, const scene_state& ss )
499{
500        particle_system_info* info = m_systems.get( system );
501        if ( info )
502        {
503                m_context->draw( nv::TRIANGLES, rs, ss, info->data->local ?  m_program_local : m_program_world, info->vtx_array, info->count * 6 );
504        }
505}
506
507nv::particle_engine::~particle_engine()
508{
509        m_device->release( m_program_world );
510        m_device->release( m_program_local );
511}
512
513void nv::particle_engine::release( particle_system system )
514{
515        particle_system_info* info = m_systems.get( system );
516        if ( info )
517        {
518                delete[] info->particles;
519                delete[] info->quads;
520                //if ( system->own_va )
521                m_device->release( info->vtx_array );
522                m_systems.destroy( system );
523        }
524}
525
526void nv::particle_engine::update( particle_system system, const scene_state& s, uint32 ms )
527{
528        particle_system_info* info = m_systems.get( system );
529        if ( info )
530        {
531                m_view_matrix  = s.get_view();
532                m_model_matrix = s.get_model();
533                m_camera_pos   = s.get_camera().get_position();
534                m_inv_view_dir = glm::normalize(-s.get_camera().get_direction());
535
[307]536                update_emmiters( info, ms );
[306]537                destroy_particles( info, ms );
538                create_particles( info, ms );
539                update_particles( info, ms );
540
541                generate_data( info );
542                m_context->update( info->vtx_buffer, info->quads, /*system->m_offset*sizeof(particle_quad)*/ 0, info->count*sizeof(particle_quad) );
543        }
544}
545
546void nv::particle_engine::set_texcoords( particle_system system, vec2 a, vec2 b )
547{
548        particle_system_info* info = m_systems.get( system );
549        if ( info )
550        {
551                vec2 texcoords[4] = { a, vec2( b.x, a.y ), vec2( a.x, b.y ), b };
552
553                for ( uint32 i = 0; i < info->data->quota; ++i )
554                {
555                        particle_quad& rdata   = info->quads[i];
556                        rdata.data[0].texcoord = texcoords[0];
557                        rdata.data[1].texcoord = texcoords[1];
558                        rdata.data[2].texcoord = texcoords[2];
559                        rdata.data[3].texcoord = texcoords[3];
560                        rdata.data[4].texcoord = texcoords[2];
561                        rdata.data[5].texcoord = texcoords[1];
562                }
563        }
564}
565
566void nv::particle_engine::generate_data( particle_system_info* info )
567{
[309]568        vec2 lb     = vec2( -0.5f, -0.5f );
569        vec2 rt     = vec2( 0.5f, 0.5f );
[306]570
[309]571        switch ( info->data->origin )
572        {
573        case particle_origin::CENTER        : break;
574        case particle_origin::TOP_LEFT      : lb = vec2(0.f,-1.f); rt = vec2(1.f,0.f);  break;
575        case particle_origin::TOP_CENTER    : lb.y = -1.f; rt.y = 0.f; break;  break;
576        case particle_origin::TOP_RIGHT     : lb = vec2(-1.f,-1.f); rt = vec2(); break;
577        case particle_origin::CENTER_LEFT   : lb.x = 0.f; rt.x = 1.f; break;
578        case particle_origin::CENTER_RIGHT  : lb.x = -1.f; rt.x = 0.f; break;
579        case particle_origin::BOTTOM_LEFT   : lb = vec2(); rt = vec2(1.f,1.f); break;
580        case particle_origin::BOTTOM_CENTER : lb.y = 0.f; rt.y = 1.f; break;
581        case particle_origin::BOTTOM_RIGHT  : lb = vec2(-1.f,0.f); rt = vec2(.0f,1.f); break;
582        }
583
584        const vec3 sm[4] =
585        {
586                vec3( lb.x, lb.y, 0.0f ),
587                vec3( rt.x, lb.y, 0.0f ),
588                vec3( lb.x, rt.y, 0.0f ),
589                vec3( rt.x, rt.y, 0.0f ),
[306]590        };
[309]591        vec3 z( 0.0f, 0.0f ,1.0f );
[306]592
593        particle_orientation orientation = info->data->orientation;
594        vec3 common_up ( info->data->common_up );
595        vec3 common_dir( info->data->common_dir );
596        bool accurate_facing = info->data->accurate_facing;
[312]597        mat3 rot_mat;
598        vec3 right;
599        vec3 pdir( 0.0f, 1.0f, 0.0f );
[306]600
601        for ( uint32 i = 0; i < info->count; ++i )
602        {
603                const particle& pdata = info->particles[i];
604                particle_quad& rdata  = info->quads[i];
605
606                vec3 view_dir( m_inv_view_dir );
607                if ( accurate_facing ) view_dir = glm::normalize( m_camera_pos - pdata.position );
608
609                switch ( orientation )
610                {
611                case particle_orientation::POINT :
612                        right   = glm::normalize( glm::cross( view_dir, vec3( 0, 1, 0 ) ) );
613                        rot_mat = mat3( right, glm::cross( right, -view_dir ), -view_dir );
614                        break;
615                case particle_orientation::ORIENTED :
[312]616                        pdir    = normalize_safe( pdata.velocity, pdir );
617                        right   = glm::normalize( glm::cross( pdir, view_dir ) );
618                        rot_mat = mat3( right, pdir, glm::cross( pdir, right ) );
[306]619                        break;
620                case particle_orientation::ORIENTED_COMMON :
621                        right   = glm::normalize( glm::cross( common_dir, view_dir ) );
622                        rot_mat = mat3( right, common_dir, glm::cross( common_dir, right ) );
623                        break;
624                case particle_orientation::PERPENDICULAR :
[312]625                        pdir    = normalize_safe( pdata.velocity, pdir );
626                        right   = glm::normalize( glm::cross( common_up, pdir ) );
[306]627                        rot_mat = mat3( right, common_up, glm::cross( common_up, right ) );
628                        break;
629                case particle_orientation::PERPENDICULAR_COMMON :
630                        right   = glm::normalize( glm::cross( common_up, common_dir ) );
631                        rot_mat = mat3( right, common_up, glm::cross( common_up, right ) );
632                        break;
633                }
634
635                vec3 size( pdata.size.x, pdata.size.y, 0.0f );
636                vec3 s0 = rot_mat * ( ( size * sm[0] ) );
637                vec3 s1 = rot_mat * ( ( size * sm[1] ) );
638                vec3 s2 = rot_mat * ( ( size * sm[2] ) );
639                vec3 s3 = rot_mat * ( ( size * sm[3] ) );
640
641                rdata.data[0].position = pdata.position + s0;
642                rdata.data[0].color    = pdata.color;
643
644                rdata.data[1].position = pdata.position + s1;
645                rdata.data[1].color    = pdata.color;
646
647                rdata.data[2].position = pdata.position + s2;
648                rdata.data[2].color    = pdata.color;
649
650                rdata.data[3].position = pdata.position + s3;
651                rdata.data[3].color    = pdata.color;
652
653                rdata.data[4] = rdata.data[2];
654                rdata.data[5] = rdata.data[1];
655        }
656}
657
658void nv::particle_engine::destroy_particles( particle_system_info* info, uint32 ms )
659{
660        if ( info->count > 0 )
661                for ( sint32 i = info->count-1; i >= 0; --i )
662                {
663                        particle& pinfo = info->particles[i];
664                        if ( //pdata.position.y < 0.0f ||
665                                ms >= pinfo.death )
666                        {
667                                info->count--;
668                                std::swap( info->particles[i], info->particles[info->count] );
669                        }
670                }
671}
672
673void nv::particle_engine::create_particles( particle_system_info* info, uint32 ms )
674{
675        uint32 ecount = info->data->emmiter_count;
676        if ( ecount == 0 ) return;
677
678        random& r = random::get();
679        vec3 source;
680        mat3 orient;
[312]681        bool local = info->data->local;
682        if ( !local )
[306]683        {
684                source = vec3( m_model_matrix[3] );
685                orient = mat3( m_model_matrix );
686        }
[312]687
[309]688        float fms = float(ms);
[306]689
690        for ( uint32 i = 0; i < ecount; ++i )
691        {
692                const auto& edata = info->data->emmiters[i];
693                auto& einfo = info->emmiters[i];
[307]694                if ( einfo.active )
[306]695                {
[309]696                        float period = 1000.f / edata.rate;
697                        while ( fms - einfo.last_create > period )
[306]698                        {
[307]699                                if ( info->count < info->data->quota-1 )
700                                {
701                                        particle& pinfo = info->particles[info->count];
[312]702                                        edata.emmiter_func( &(info->data->emmiters[i]), &pinfo, 1 );
703
704                                        if ( !local ) pinfo.position  = orient * pinfo.position + source;
[309]705                                        pinfo.position += edata.position;
706                                        pinfo.color     = edata.color_min == edata.color_max ?
[307]707                                                edata.color_min : r.range( edata.color_min, edata.color_max );
[309]708                                        pinfo.size      = edata.size_min == edata.size_max ?
[307]709                                                edata.size_min : r.range( edata.size_min, edata.size_max );
710                                        if ( edata.square ) pinfo.size.y = pinfo.size.x;
[312]711                                        float velocity  = edata.velocity_min == edata.velocity_max ?
[307]712                                                edata.velocity_min : r.frange( edata.velocity_min, edata.velocity_max );
713                                        pinfo.death     = ms + ( edata.lifetime_min == edata.lifetime_max ?
714                                                edata.lifetime_min : r.urange( edata.lifetime_min, edata.lifetime_max ) );
715                                        //pinfo.rotation = r.frand( 360.0f );
[306]716
[312]717                                        pinfo.velocity = edata.dir;
[307]718                                        if ( edata.angle > 0.0f )
719                                        {
720                                                float emission_angle = glm::radians( edata.angle );
721                                                float cos_theta = r.frange( cos( emission_angle ), 1.0f );
722                                                float sin_theta = glm::sqrt(1.0f - cos_theta * cos_theta );
723                                                float phi       = r.frange( 0.0f, 2*glm::pi<float>() );
[312]724                                                pinfo.velocity  = orient *
[307]725                                                        ( edata.odir * ( glm::cos(phi) * sin_theta ) +
726                                                        edata.cdir * ( glm::sin(phi)*sin_theta ) +
727                                                        edata.dir  * cos_theta );
728                                        }
729
[312]730                                        pinfo.velocity *= velocity;
731
[307]732                                        info->count++;
[306]733                                }
[307]734                                einfo.last_create += period;
[306]735                        }
736                }
737        }
738}
739
[312]740void nv::particle_engine::update_particles( particle_system_info* info, uint32 ms )
[306]741{
[312]742        uint32 ticks = ms - info->last_update;
743        if ( ticks == 0 ) return;
744        float factor  = 0.001f * ticks;
745
746        uint32 acount = info->data->affector_count;
747        for ( uint32 i = 0; i < acount; ++i )
748        {
749                const particle_affector_data* padata = &(info->data->affectors[i]);
750                padata->process( padata, info->particles, factor, info->count );
751        }
752
753
754        for ( uint32 i = 0; i < info->count; ++i )
755        {
756                particle& pdata = info->particles[i];
757                pdata.position += pdata.velocity * factor;
758        }
759        info->last_update = ms;
[307]760}
761
762void nv::particle_engine::update_emmiters( particle_system_info* info, uint32 ms )
763{
764        uint32 ecount = info->data->emmiter_count;
765        if ( ecount == 0 ) return;
766        random& r = random::get();
767
768        for ( uint32 i = 0; i < ecount; ++i )
769        {
770                const auto& edata = info->data->emmiters[i];
771                auto& einfo = info->emmiters[i];
772
773                if ( einfo.next_toggle != 0 && ms >= einfo.next_toggle )
774                {
775                        if ( einfo.active )
776                        {
777                                einfo.active = false;
778                                if ( edata.repeat_min > 0 )
779                                        einfo.next_toggle += r.urange( edata.repeat_min, edata.repeat_max );
780                                else
781                                        einfo.next_toggle = 0;
782                        }
783                        else
784                        {
785                                einfo.active = true;
[309]786                                einfo.last_create = float( einfo.next_toggle );
[307]787                                einfo.next_toggle += r.urange( edata.duration_min, edata.duration_max );
788                        }
789                }
790        }
791
792}
[312]793
794void nv::particle_engine::register_emmiter_type( const std::string& name, particle_emmiter_func func )
795{
796        m_emmiters[ name ] = func;
797}
798
799void nv::particle_engine::register_standard_emmiters()
800{
801        register_emmiter_type( "point",             nv_particle_emmiter_point );
802        register_emmiter_type( "box",               nv_particle_emmiter_box );
803        register_emmiter_type( "cylinder",          nv_particle_emmiter_cylinder );
804        register_emmiter_type( "sphere",            nv_particle_emmiter_sphere );
805        register_emmiter_type( "cylindroid",        nv_particle_emmiter_cylindroid );
806        register_emmiter_type( "ellipsoid",         nv_particle_emmiter_ellipsoid );
807        register_emmiter_type( "hollow_cylinder",   nv_particle_emmiter_hollow_cylinder );
808        register_emmiter_type( "hollow_sphere",     nv_particle_emmiter_hollow_sphere );
809        register_emmiter_type( "hollow_cylindroid", nv_particle_emmiter_hollow_cylindroid );
810        register_emmiter_type( "hollow_ellipsoid",  nv_particle_emmiter_hollow_ellipsoid );
811}
812
813void nv::particle_engine::register_affector_type( const std::string& name, particle_affector_init_func init, particle_affector_func process )
814{
815        m_affectors[ name ].init    = init;
816        m_affectors[ name ].process = process;
817}
818
819void nv::particle_engine::register_standard_affectors()
820{
821        register_affector_type( "linear_force",    nv_particle_affector_linear_force_init, nv_particle_affector_linear_force );
822        register_affector_type( "deflector_plane", nv_particle_affector_deflector_plane_init, nv_particle_affector_deflector_plane );
823        register_affector_type( "color_fader",     nv_particle_affector_color_fader_init, nv_particle_affector_color_fader );
824        register_affector_type( "scaler",          nv_particle_affector_scaler_init, nv_particle_affector_scaler );
825}
826
Note: See TracBrowser for help on using the repository browser.