source: trunk/src/engine/particle_engine.cc @ 468

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