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

Last change on this file since 309 was 309, checked in by epyon, 11 years ago
  • origin parameter for particle system (TOP_LEFT, etc)
  • precise parameter for switching to more precise distribution
  • support for multiple emmiter types: POINT, BOX, CYLINDER, CYLINDROID, SPHERE, ELLIPSOID, HOLLOW_CYLINDER, HOLLOW_CYLINDROID, HOLLOW_SPHERE, HOLLOW_ELLIPSOID
  • minor fixes
File size: 22.8 KB
Line 
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>
7#include <cmath>
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
49void nv::particle_engine::load( lua::table_guard& table )
50{
51        std::string id = table.get_string( "id" );
52        if ( id == "" )
53        {
54                NV_LOG( LOG_ERROR, "Bad table passed to particle_engine!" )
55        }
56        // TODO : overwrite check
57        m_names[ id ] = m_data.size();
58
59        m_data.emplace_back();
60        auto& data = m_data.back();
61
62        data.gravity = table.get<vec3>("gravity", vec3() );
63        data.quota   = table.get<uint32>("quota", 1024 );
64        data.local   = table.get<bool>("local_space", false );
65        data.accurate_facing = table.get<bool>("accurate_facing", false );
66        data.emmiter_count   = 0;
67
68        std::string orientation = table.get_string( "orientation", "point" );
69        if ( orientation == "point" )                     { data.orientation = particle_orientation::POINT; }
70        else if ( orientation == "oriented" )             { data.orientation = particle_orientation::ORIENTED; }
71        else if ( orientation == "oriented_common" )      { data.orientation = particle_orientation::ORIENTED_COMMON; }
72        else if ( orientation == "perpendicular" )        { data.orientation = particle_orientation::PERPENDICULAR; }
73        else if ( orientation == "perpendicular_common" ) { data.orientation = particle_orientation::PERPENDICULAR_COMMON; }
74        else
75        {
76                NV_LOG( LOG_ERROR, "Unknown orientation type! (" << orientation << ")!" );
77                data.orientation = particle_orientation::POINT;
78        }
79
80        std::string origin = table.get_string( "origin", "center" );
81        if      ( origin == "center" )        { data.origin = particle_origin::CENTER; }
82        else if ( origin == "top_left" )      { data.origin = particle_origin::TOP_LEFT; }
83        else if ( origin == "top_center" )    { data.origin = particle_origin::TOP_CENTER; }
84        else if ( origin == "top_right" )     { data.origin = particle_origin::TOP_RIGHT; }
85        else if ( origin == "center_left" )   { data.origin = particle_origin::CENTER_LEFT; }
86        else if ( origin == "center_right" )  { data.origin = particle_origin::CENTER_RIGHT; }
87        else if ( origin == "bottom_left" )   { data.origin = particle_origin::BOTTOM_LEFT; }
88        else if ( origin == "bottom_center" ) { data.origin = particle_origin::BOTTOM_CENTER; }
89        else if ( origin == "bottom_right" )  { data.origin = particle_origin::BOTTOM_RIGHT; }
90        else
91        {
92                NV_LOG( LOG_ERROR, "Unknown particle origin! (" << origin << ")!" );
93                data.origin = particle_origin::CENTER;
94        }
95
96        data.common_up  = glm::normalize( table.get<vec3>("common_up",  vec3(1,0,0) ) );
97        data.common_dir = glm::normalize( table.get<vec3>("common_dir", vec3(0,1,0) ) );
98
99        vec2 def_size        = table.get<vec2>("size", vec2(0.1,0.1) );
100        uint32 elements = table.get_size();
101        for ( uint32 i = 0; i < elements; ++i )
102        {
103                lua::table_guard element( table, i+1 );
104                std::string type     = element.get_string("type");
105                std::string sub_type = element.get_string("sub_type");
106                if ( type == "emmiter" )
107                {
108                        if ( data.emmiter_count < MAX_PARTICLE_EMMITERS )
109                        {
110                                particle_emmiter_data& edata = data.emmiters[ data.emmiter_count ];
111
112                                     if ( sub_type == "point" )             edata.type = particle_emmiter_type::POINT;
113                                else if ( sub_type == "box" )               edata.type = particle_emmiter_type::BOX;
114                                else if ( sub_type == "cylinder" )          edata.type = particle_emmiter_type::CYLINDER;
115                                else if ( sub_type == "sphere" )            edata.type = particle_emmiter_type::SPHERE;
116                                else if ( sub_type == "cylindroid" )        edata.type = particle_emmiter_type::CYLINDROID;
117                                else if ( sub_type == "ellipsoid" )         edata.type = particle_emmiter_type::ELLIPSOID;
118                                else if ( sub_type == "hollow_cylinder" )   edata.type = particle_emmiter_type::HOLLOW_CYLINDER;
119                                else if ( sub_type == "hollow_sphere" )     edata.type = particle_emmiter_type::HOLLOW_SPHERE;
120                                else if ( sub_type == "hollow_cylindroid" ) edata.type = particle_emmiter_type::HOLLOW_CYLINDROID;
121                                else if ( sub_type == "hollow_ellipsoid" )  edata.type = particle_emmiter_type::HOLLOW_ELLIPSOID;
122                                else
123                                {
124                                        edata.type = particle_emmiter_type::POINT;
125                                        NV_LOG( LOG_WARNING, "Unknown emmiter type in particle system! (" << sub_type << ")" );
126                                }
127
128                                edata.position     = element.get<vec3>("position", vec3() );
129                                edata.extents      = element.get<vec3>("extents", vec3(1,1,1) );
130                                edata.extents[0]   = element.get<float>("width",  edata.extents[0] );
131                                edata.extents[1]   = element.get<float>("depth",  edata.extents[1] );
132                                edata.extents[2]   = element.get<float>("height", edata.extents[2] );
133                                edata.extents[0]   = element.get<float>("radius",  edata.extents[0] );
134                                edata.iextents     = element.get<vec3>("inner_extents", vec3() );
135                                edata.iextents[0]  = element.get<float>("inner_width",  edata.iextents[0] );
136                                edata.iextents[1]  = element.get<float>("inner_depth",  edata.iextents[1] );
137                                edata.iextents[2]  = element.get<float>("inner_height", edata.iextents[2] );
138                                edata.iextents[0]  = element.get<float>("inner_radius",  edata.iextents[0] );
139                                edata.hextents     = 0.5f * edata.extents;
140                                edata.ihextents    = 0.5f * edata.iextents;
141                                edata.precise      = element.get<bool>("precise", false );
142                                edata.square       = element.get<bool>("square", true );
143                                vec4 color         = element.get<vec4>("color", vec4(1,1,1,1) );
144                                edata.color_min    = element.get<vec4>("color_min", color );
145                                edata.color_max    = element.get<vec4>("color_max", color );
146                                vec2 size          = element.get<vec2>("size", def_size );
147                                edata.size_min     = element.get<vec2>("size_min", size );
148                                edata.size_max     = element.get<vec2>("size_max", size );
149                                edata.angle        = element.get<float>("angle", 0.0f );
150                                float velocity     = element.get<float>("velocity", 0.0f );
151                                edata.velocity_min = element.get<float>("velocity_min", velocity );
152                                edata.velocity_max = element.get<float>("velocity_max", velocity );
153                                float lifetime     = element.get<float>("lifetime", 1.0f );
154                                edata.lifetime_min = uint32( element.get<float>("lifetime_min", lifetime ) * 1000.f );
155                                edata.lifetime_max = uint32( element.get<float>("lifetime_max", lifetime ) * 1000.f );
156                                float duration     = element.get<float>("duration", 0.0f );
157                                edata.duration_min = uint32( element.get<float>("duration_min", duration ) * 1000.f );
158                                edata.duration_max = uint32( element.get<float>("duration_max", duration ) * 1000.f );
159                                float repeat       = element.get<float>("repeat_delay", 0.0f );
160                                edata.repeat_min   = uint32( element.get<float>("repeat_delay_min", repeat ) * 1000.f );
161                                edata.repeat_max   = uint32( element.get<float>("repeat_delay_max", repeat ) * 1000.f );
162
163                                edata.rate         = element.get<float>("rate", 1.0f );
164                                edata.dir          = glm::normalize( element.get<vec3>("direction", vec3(0,1,0) ) );
165                               
166                                edata.odir = glm::vec3( 0, 0, 1 );
167                                if ( edata.dir != vec3( 0, 1, 0 ) && edata.dir != vec3( 0, -1, 0 ) )
168                                        edata.odir = glm::normalize( glm::cross( edata.dir, vec3( 0, 1, 0 ) ) );                edata.cdir = glm::cross( edata.dir, edata.odir );
169
170                                data.emmiter_count++;
171                        }
172                        else
173                        {
174                                NV_LOG( LOG_ERROR, "Too many emmiters (" << MAX_PARTICLE_EMMITERS << " is MAX)!" );
175                        }
176                }
177                else if ( type == "affector" )
178                {
179
180                }
181                else
182                {
183                        NV_LOG( LOG_WARNING, "Unknown element in particle system! (" << type << ")" );
184                }
185        }
186
187}
188
189nv::particle_engine::particle_engine( context* a_context )
190{
191        m_context       = a_context;
192        m_device        = a_context->get_device();
193        m_program_local = m_device->create_program( nv_particle_engine_vertex_shader_local, nv_particle_engine_fragment_shader );
194        m_program_world = m_device->create_program( nv_particle_engine_vertex_shader_world, nv_particle_engine_fragment_shader );
195}
196
197nv::particle_system nv::particle_engine::create_system( const std::string& id )
198{
199        auto it = m_names.find( id );
200        if ( it == m_names.end() )
201        {
202                return particle_system();
203        }
204        const particle_system_data* data = &(m_data[it->second]);
205        particle_system result = m_systems.create();
206        particle_system_info* info = m_systems.get( result );
207
208        info->data     = data;
209        uint32 ecount = data->emmiter_count;
210        for ( uint32 i = 0; i < ecount; ++i )
211        {
212                info->emmiters[i].active      = true;
213                info->emmiters[i].last_create = 0;
214                info->emmiters[i].next_toggle = random::get().urange( data->emmiters[i].duration_min, data->emmiters[i].duration_max );
215        }
216
217        info->count = 0;
218        info->particles = new particle[ data->quota ];
219        info->quads     = new particle_quad[ data->quota ];
220        info->vtx_array = m_device->create_vertex_array<particle_vtx>(
221                (particle_vtx*)info->quads, data->quota*6, STREAM_DRAW );
222        info->vtx_buffer = m_device->find_buffer( info->vtx_array, slot::POSITION );
223        info->last_update = 0;
224        info->test = false;
225//      result->m_own_va      = true;
226//      result->m_offset      = 0;
227
228        return result;
229}
230
231void nv::particle_engine::draw( particle_system system, const render_state& rs, const scene_state& ss )
232{
233        particle_system_info* info = m_systems.get( system );
234        if ( info )
235        {
236                m_context->draw( nv::TRIANGLES, rs, ss, info->data->local ?  m_program_local : m_program_world, info->vtx_array, info->count * 6 );
237        }
238}
239
240nv::particle_engine::~particle_engine()
241{
242        m_device->release( m_program_world );
243        m_device->release( m_program_local );
244}
245
246void nv::particle_engine::release( particle_system system )
247{
248        particle_system_info* info = m_systems.get( system );
249        if ( info )
250        {
251                delete[] info->particles;
252                delete[] info->quads;
253                //if ( system->own_va )
254                m_device->release( info->vtx_array );
255                m_systems.destroy( system );
256        }
257}
258
259void nv::particle_engine::update( particle_system system, const scene_state& s, uint32 ms )
260{
261        particle_system_info* info = m_systems.get( system );
262        if ( info )
263        {
264                m_view_matrix  = s.get_view();
265                m_model_matrix = s.get_model();
266                m_camera_pos   = s.get_camera().get_position();
267                m_inv_view_dir = glm::normalize(-s.get_camera().get_direction());
268
269                update_emmiters( info, ms );
270                destroy_particles( info, ms );
271                create_particles( info, ms );
272                update_particles( info, ms );
273
274                generate_data( info );
275                m_context->update( info->vtx_buffer, info->quads, /*system->m_offset*sizeof(particle_quad)*/ 0, info->count*sizeof(particle_quad) );
276        }
277}
278
279void nv::particle_engine::set_texcoords( particle_system system, vec2 a, vec2 b )
280{
281        particle_system_info* info = m_systems.get( system );
282        if ( info )
283        {
284                vec2 texcoords[4] = { a, vec2( b.x, a.y ), vec2( a.x, b.y ), b };
285
286                for ( uint32 i = 0; i < info->data->quota; ++i )
287                {
288                        particle_quad& rdata   = info->quads[i];
289                        rdata.data[0].texcoord = texcoords[0];
290                        rdata.data[1].texcoord = texcoords[1];
291                        rdata.data[2].texcoord = texcoords[2];
292                        rdata.data[3].texcoord = texcoords[3];
293                        rdata.data[4].texcoord = texcoords[2];
294                        rdata.data[5].texcoord = texcoords[1];
295                }
296        }
297}
298
299void nv::particle_engine::generate_data( particle_system_info* info )
300{
301        vec2 lb     = vec2( -0.5f, -0.5f );
302        vec2 rt     = vec2( 0.5f, 0.5f );
303
304        switch ( info->data->origin )
305        {
306        case particle_origin::CENTER        : break;
307        case particle_origin::TOP_LEFT      : lb = vec2(0.f,-1.f); rt = vec2(1.f,0.f);  break;
308        case particle_origin::TOP_CENTER    : lb.y = -1.f; rt.y = 0.f; break;  break;
309        case particle_origin::TOP_RIGHT     : lb = vec2(-1.f,-1.f); rt = vec2(); break;
310        case particle_origin::CENTER_LEFT   : lb.x = 0.f; rt.x = 1.f; break;
311        case particle_origin::CENTER_RIGHT  : lb.x = -1.f; rt.x = 0.f; break;
312        case particle_origin::BOTTOM_LEFT   : lb = vec2(); rt = vec2(1.f,1.f); break;
313        case particle_origin::BOTTOM_CENTER : lb.y = 0.f; rt.y = 1.f; break;
314        case particle_origin::BOTTOM_RIGHT  : lb = vec2(-1.f,0.f); rt = vec2(.0f,1.f); break;
315        }
316
317        const vec3 sm[4] =
318        {
319                vec3( lb.x, lb.y, 0.0f ),
320                vec3( rt.x, lb.y, 0.0f ),
321                vec3( lb.x, rt.y, 0.0f ),
322                vec3( rt.x, rt.y, 0.0f ),
323        };
324        vec3 z( 0.0f, 0.0f ,1.0f );
325
326        mat3 rot_mat;
327        vec3 right;
328        mat3 irot_mat = glm::transpose( mat3( m_view_matrix ) );
329        particle_orientation orientation = info->data->orientation;
330        vec3 common_up ( info->data->common_up );
331        vec3 common_dir( info->data->common_dir );
332        bool accurate_facing = info->data->accurate_facing;
333
334
335        for ( uint32 i = 0; i < info->count; ++i )
336        {
337                const particle& pdata = info->particles[i];
338                particle_quad& rdata  = info->quads[i];
339
340                vec3 view_dir( m_inv_view_dir );
341                if ( accurate_facing ) view_dir = glm::normalize( m_camera_pos - pdata.position );
342
343                switch ( orientation )
344                {
345                case particle_orientation::POINT :
346                        right   = glm::normalize( glm::cross( view_dir, vec3( 0, 1, 0 ) ) );
347                        rot_mat = mat3( right, glm::cross( right, -view_dir ), -view_dir );
348//                      rot_mat = irot_mat * glm::mat3_cast( glm::angleAxis( pdata.rotation, z ) );
349                        break;
350                case particle_orientation::ORIENTED :
351                        right   = glm::normalize( glm::cross( pdata.dir, view_dir ) );
352                        rot_mat = mat3( right, pdata.dir, glm::cross( pdata.dir, right ) );
353                        break;
354                case particle_orientation::ORIENTED_COMMON :
355                        right   = glm::normalize( glm::cross( common_dir, view_dir ) );
356                        rot_mat = mat3( right, common_dir, glm::cross( common_dir, right ) );
357                        break;
358                case particle_orientation::PERPENDICULAR :
359                        right   = glm::normalize( glm::cross( common_up, pdata.dir ) );
360                        rot_mat = mat3( right, common_up, glm::cross( common_up, right ) );
361                        break;
362                case particle_orientation::PERPENDICULAR_COMMON :
363                        right   = glm::normalize( glm::cross( common_up, common_dir ) );
364                        rot_mat = mat3( right, common_up, glm::cross( common_up, right ) );
365                        break;
366                }
367
368                vec3 size( pdata.size.x, pdata.size.y, 0.0f );
369                vec3 s0 = rot_mat * ( ( size * sm[0] ) );
370                vec3 s1 = rot_mat * ( ( size * sm[1] ) );
371                vec3 s2 = rot_mat * ( ( size * sm[2] ) );
372                vec3 s3 = rot_mat * ( ( size * sm[3] ) );
373
374                rdata.data[0].position = pdata.position + s0;
375                rdata.data[0].color    = pdata.color;
376
377                rdata.data[1].position = pdata.position + s1;
378                rdata.data[1].color    = pdata.color;
379
380                rdata.data[2].position = pdata.position + s2;
381                rdata.data[2].color    = pdata.color;
382
383                rdata.data[3].position = pdata.position + s3;
384                rdata.data[3].color    = pdata.color;
385
386                rdata.data[4] = rdata.data[2];
387                rdata.data[5] = rdata.data[1];
388        }
389}
390
391void nv::particle_engine::destroy_particles( particle_system_info* info, uint32 ms )
392{
393        if ( info->count > 0 )
394                for ( sint32 i = info->count-1; i >= 0; --i )
395                {
396                        particle& pinfo = info->particles[i];
397                        if ( //pdata.position.y < 0.0f ||
398                                ms >= pinfo.death )
399                        {
400                                info->count--;
401                                std::swap( info->particles[i], info->particles[info->count] );
402                        }
403                }
404}
405
406void nv::particle_engine::create_particles( particle_system_info* info, uint32 ms )
407{
408        uint32 ecount = info->data->emmiter_count;
409        if ( ecount == 0 ) return;
410
411        random& r = random::get();
412        vec3 source;
413        mat3 orient;
414        if ( !info->data->local )
415        {
416                source = vec3( m_model_matrix[3] );
417                orient = mat3( m_model_matrix );
418        }
419        float fms = float(ms);
420
421        for ( uint32 i = 0; i < ecount; ++i )
422        {
423                const auto& edata = info->data->emmiters[i];
424                auto& einfo = info->emmiters[i];
425                if ( einfo.active )
426                {
427                        float period = 1000.f / edata.rate;
428                        while ( fms - einfo.last_create > period )
429                        {
430                                if ( info->count < info->data->quota-1 )
431                                {
432                                        particle& pinfo = info->particles[info->count];
433                                        switch ( edata.type )
434                                        {
435                                        case particle_emmiter_type::POINT:
436                                                pinfo.position = source;
437                                                break;
438                                        case particle_emmiter_type::BOX:
439                                                pinfo.position = source + orient * (
440                                                        r.frange( -edata.hextents[0], edata.hextents[0] ) * edata.cdir +
441                                                        r.frange( 0.0f, edata.extents[1] ) * edata.dir +
442                                                        r.frange( -edata.hextents[2], edata.hextents[2] ) * edata.odir
443                                                );
444                                                break;
445                                        case particle_emmiter_type::CYLINDER:
446                                                {
447                                                        vec2 rellipse = r.disk_point( edata.precise );
448                                                        pinfo.position = source + orient * (
449                                                                rellipse.x * edata.extents[0] * edata.cdir +
450                                                                r.frange( 0.0f, edata.extents[1] ) * edata.dir +
451                                                                rellipse.y * edata.extents[0] * edata.odir
452                                                                );
453                                                }
454                                                break;
455                                        case particle_emmiter_type::SPHERE:
456                                                {
457                                                        vec3 rellipse = r.sphere_point( edata.precise );
458                                                        pinfo.position = source + orient * (
459                                                                rellipse.x * edata.extents[0] * edata.cdir +
460                                                                rellipse.y * edata.extents[0] * edata.dir +
461                                                                rellipse.z * edata.extents[0] * edata.odir
462                                                                );
463                                                }
464                                                break;
465                                        // TODO : this method is NOT uniform if width != height!
466                                        case particle_emmiter_type::CYLINDROID:
467                                                {
468                                                        vec2 rellipse = r.ellipse_point( vec2( edata.hextents[0], edata.hextents[2] ), edata.precise );
469                                                        pinfo.position = source + orient * (
470                                                                rellipse.x * edata.cdir +
471                                                                r.frange( 0.0f, edata.extents[1] ) * edata.dir +
472                                                                rellipse.y * edata.odir
473                                                        );
474                                                }
475                                                break;
476                                        // TODO : this method is NOT uniform if all dimension are not equal!
477                                        case particle_emmiter_type::ELLIPSOID:
478                                                {
479                                                        vec3 rsphere = r.ellipsoid_point( edata.hextents, edata.precise );
480                                                        pinfo.position = source + orient * (
481                                                                rsphere.x * edata.cdir +
482                                                                rsphere.y * edata.dir +
483                                                                rsphere.z * edata.odir
484                                                                );
485                                                }
486                                                break;
487                                        case particle_emmiter_type::HOLLOW_CYLINDER:
488                                                {
489                                                        vec2 rellipse = r.hollow_disk_point(
490                                                                edata.ihextents[0],
491                                                                edata.hextents[0],
492                                                                edata.precise );
493                                                        pinfo.position = source + orient * (
494                                                                rellipse.x * edata.cdir +
495                                                                r.frange( 0.0f, edata.extents[1] ) * edata.dir +
496                                                                rellipse.y * edata.odir
497                                                                );
498                                                }
499                                                break;
500                                        case particle_emmiter_type::HOLLOW_SPHERE:
501                                                {
502                                                        vec3 rellipse = r.hollow_sphere_point(
503                                                                edata.ihextents[0],
504                                                                edata.hextents[0],
505                                                                edata.precise );
506                                                        pinfo.position = source + orient * (
507                                                                rellipse.x * edata.cdir +
508                                                                rellipse.y * edata.dir +
509                                                                rellipse.z * edata.odir
510                                                                );
511                                                }
512                                                break;
513                                        case particle_emmiter_type::HOLLOW_CYLINDROID:
514                                                {
515                                                        vec2 rellipse = r.hollow_ellipse_point(
516                                                                vec2( edata.ihextents[0], edata.ihextents[2] ),
517                                                                vec2( edata.hextents[0], edata.hextents[2] ),
518                                                                edata.precise );
519                                                        pinfo.position = source + orient * (
520                                                                rellipse.x * edata.cdir +
521                                                                r.frange( 0.0f, edata.extents[1] ) * edata.dir +
522                                                                rellipse.y * edata.odir
523                                                                );
524                                                }
525                                                break;
526                                        // TODO : this method is NOT uniform if all dimension are not equal!
527                                        case particle_emmiter_type::HOLLOW_ELLIPSOID:
528                                                {
529                                                        vec3 rellipse = r.hollow_ellipsoid_point( edata.ihextents, edata.hextents, edata.precise );
530                                                        pinfo.position = source + orient * (
531                                                                rellipse.x * edata.cdir +
532                                                                rellipse.y * edata.dir +
533                                                                rellipse.z * edata.odir
534                                                                );
535                                                }
536                                                break;
537                                        }
538                                        pinfo.position += edata.position;
539                                        pinfo.color     = edata.color_min == edata.color_max ?
540                                                edata.color_min : r.range( edata.color_min, edata.color_max );
541                                        pinfo.size      = edata.size_min == edata.size_max ?
542                                                edata.size_min : r.range( edata.size_min, edata.size_max );
543                                        if ( edata.square ) pinfo.size.y = pinfo.size.x;
544                                        pinfo.velocity  = edata.velocity_min == edata.velocity_max ?
545                                                edata.velocity_min : r.frange( edata.velocity_min, edata.velocity_max );
546                                        pinfo.death     = ms + ( edata.lifetime_min == edata.lifetime_max ?
547                                                edata.lifetime_min : r.urange( edata.lifetime_min, edata.lifetime_max ) );
548                                        //pinfo.rotation = r.frand( 360.0f );
549
550                                        pinfo.dir = edata.dir;
551                                        if ( edata.angle > 0.0f )
552                                        {
553                                                float emission_angle = glm::radians( edata.angle );
554                                                float cos_theta = r.frange( cos( emission_angle ), 1.0f );
555                                                float sin_theta = glm::sqrt(1.0f - cos_theta * cos_theta );
556                                                float phi       = r.frange( 0.0f, 2*glm::pi<float>() );
557                                                pinfo.dir = orient *
558                                                        ( edata.odir * ( glm::cos(phi) * sin_theta ) +
559                                                        edata.cdir * ( glm::sin(phi)*sin_theta ) +
560                                                        edata.dir  * cos_theta );
561                                        }
562
563                                        info->count++;
564                                }
565                                einfo.last_create += period;
566                        }
567                }
568        }
569}
570
571void nv::particle_engine::update_particles( particle_system_info* system, uint32 ms )
572{
573        uint32 ticks = ms - system->last_update;
574        if ( ticks > 0 )
575                for ( uint32 i = 0; i < system->count; ++i )
576                {
577                        particle& pdata = system->particles[i];
578                        vec3 velocity_vec = pdata.dir * pdata.velocity;
579                        pdata.position += velocity_vec * ( 0.001f * ticks );
580                        velocity_vec   += system->data->gravity * ( 0.001f * ticks );
581                        pdata.velocity  = glm::length( velocity_vec );
582                        if ( pdata.velocity > 0.0f ) pdata.dir       = glm::normalize( velocity_vec );
583                        if ( pdata.position.y < 0.0f )
584                        {
585                                if ( pdata.velocity > 1.0f )
586                                {
587                                        pdata.position.y = -pdata.position.y;
588                                        pdata.velocity   = 0.5f*pdata.velocity;
589                                        pdata.dir.y      = -pdata.dir.y;
590                                }
591                                else
592                                {
593                                        pdata.position.y = 0.0f;
594                                        pdata.velocity   = 0.0f;
595                                }
596                        }
597                }
598                system->last_update = ms;
599}
600
601void nv::particle_engine::update_emmiters( particle_system_info* info, uint32 ms )
602{
603        uint32 ecount = info->data->emmiter_count;
604        if ( ecount == 0 ) return;
605        random& r = random::get();
606
607        for ( uint32 i = 0; i < ecount; ++i )
608        {
609                const auto& edata = info->data->emmiters[i];
610                auto& einfo = info->emmiters[i];
611
612                if ( einfo.next_toggle != 0 && ms >= einfo.next_toggle )
613                {
614                        if ( einfo.active )
615                        {
616                                einfo.active = false;
617                                if ( edata.repeat_min > 0 )
618                                        einfo.next_toggle += r.urange( edata.repeat_min, edata.repeat_max );
619                                else
620                                        einfo.next_toggle = 0;
621                        }
622                        else
623                        {
624                                einfo.active = true;
625                                einfo.last_create = float( einfo.next_toggle );
626                                einfo.next_toggle += r.urange( edata.duration_min, edata.duration_max );
627                        }
628                }
629        }
630
631}
Note: See TracBrowser for help on using the repository browser.