1 | // Copyright (C) 2016-2016 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_group.hh"
|
---|
8 |
|
---|
9 | using namespace nv;
|
---|
10 |
|
---|
11 | particle_group_manager::particle_group_manager( context* a_context )
|
---|
12 | : m_context( a_context )
|
---|
13 | {
|
---|
14 |
|
---|
15 | }
|
---|
16 |
|
---|
17 | particle_group particle_group_manager::create_group( uint32 max_particles )
|
---|
18 | {
|
---|
19 | particle_group result = m_groups.create();
|
---|
20 | particle_group_info* info = m_groups.get( result );
|
---|
21 | info->local = false;
|
---|
22 | info->count = 0;
|
---|
23 | info->quota = max_particles;
|
---|
24 | info->vtx_buffer = m_context->create_buffer( VERTEX_BUFFER, STREAM_DRAW, info->quota * sizeof( particle_quad )/*, info->quads_[0].data*/ );
|
---|
25 | vertex_array_desc desc;
|
---|
26 | desc.add_vertex_buffers< particle_vtx >( info->vtx_buffer, true );
|
---|
27 | info->vtx_array = m_context->create_vertex_array( desc );
|
---|
28 | info->quads = new particle_quad[info->quota];
|
---|
29 | info->ref_counter = 0;
|
---|
30 | return result;
|
---|
31 | }
|
---|
32 |
|
---|
33 | void particle_group_manager::release( particle_group group )
|
---|
34 | {
|
---|
35 | particle_group_info* info = m_groups.get( group );
|
---|
36 | if ( info )
|
---|
37 | {
|
---|
38 | delete[] info->quads;
|
---|
39 | m_context->release( info->vtx_array );
|
---|
40 | m_groups.destroy( group );
|
---|
41 | }
|
---|
42 | }
|
---|
43 |
|
---|
44 | void particle_group_manager::prepare( particle_group group )
|
---|
45 | {
|
---|
46 | particle_group_info* info = m_groups.get( group );
|
---|
47 | if ( info )
|
---|
48 | {
|
---|
49 | info->count = 0;
|
---|
50 | }
|
---|
51 | }
|
---|
52 |
|
---|
53 | void particle_group_manager::reset()
|
---|
54 | {
|
---|
55 | clear();
|
---|
56 | }
|
---|
57 |
|
---|
58 | void particle_group_manager::generate_data(
|
---|
59 | array_view< particle > particles,
|
---|
60 | const particle_group_settings* data,
|
---|
61 | particle_group pgroup,
|
---|
62 | const scene_state& s
|
---|
63 | )
|
---|
64 | {
|
---|
65 | // void* rawptr = m_context->map_buffer( info->vtx_buffer, nv::WRITE_UNSYNCHRONIZED, offset, info->count*sizeof( particle_quad ) );
|
---|
66 | // particle_quad* quads = reinterpret_cast<particle_quad*>( rawptr );
|
---|
67 |
|
---|
68 | particle_group_info* group = m_groups.get( pgroup );
|
---|
69 |
|
---|
70 | if ( particles.size() == 0 || !data || !group )
|
---|
71 | {
|
---|
72 | return;
|
---|
73 | }
|
---|
74 |
|
---|
75 | vec2 lb = vec2( -0.5f, -0.5f );
|
---|
76 | vec2 rt = vec2( 0.5f, 0.5f );
|
---|
77 |
|
---|
78 | switch ( data->origin )
|
---|
79 | {
|
---|
80 | case particle_origin::CENTER: break;
|
---|
81 | case particle_origin::TOP_LEFT: lb = vec2( 0.f, -1.f ); rt = vec2( 1.f, 0.f ); break;
|
---|
82 | case particle_origin::TOP_CENTER: lb.y = -1.f; rt.y = 0.f; break;
|
---|
83 | case particle_origin::TOP_RIGHT: lb = vec2( -1.f, -1.f ); rt = vec2(); break;
|
---|
84 | case particle_origin::CENTER_LEFT: lb.x = 0.f; rt.x = 1.f; break;
|
---|
85 | case particle_origin::CENTER_RIGHT: lb.x = -1.f; rt.x = 0.f; break;
|
---|
86 | case particle_origin::BOTTOM_LEFT: lb = vec2(); rt = vec2( 1.f, 1.f ); break;
|
---|
87 | case particle_origin::BOTTOM_CENTER: lb.y = 0.f; rt.y = 1.f; break;
|
---|
88 | case particle_origin::BOTTOM_RIGHT: lb = vec2( -1.f, 0.f ); rt = vec2( .0f, 1.f ); break;
|
---|
89 | }
|
---|
90 |
|
---|
91 | const vec3 sm[4] =
|
---|
92 | {
|
---|
93 | vec3( lb.x, lb.y, 0.0f ),
|
---|
94 | vec3( rt.x, lb.y, 0.0f ),
|
---|
95 | vec3( lb.x, rt.y, 0.0f ),
|
---|
96 | vec3( rt.x, rt.y, 0.0f ),
|
---|
97 | };
|
---|
98 | vec3 z( 0.0f, 0.0f, 1.0f );
|
---|
99 |
|
---|
100 | particle_orientation orientation = data->orientation;
|
---|
101 | vec3 common_up( data->common_up );
|
---|
102 | vec3 common_dir( data->common_dir );
|
---|
103 | bool accurate_facing = data->accurate_facing;
|
---|
104 | mat3 rot_mat;
|
---|
105 | vec3 right;
|
---|
106 | vec3 pdir( 0.0f, 1.0f, 0.0f );
|
---|
107 |
|
---|
108 | vec3 camera_pos = s.get_camera().get_position();
|
---|
109 | vec3 inv_view_dir = math::normalize( -s.get_camera().get_direction() );
|
---|
110 |
|
---|
111 | for ( uint32 i = 0; i < particles.size(); ++i )
|
---|
112 | {
|
---|
113 | const particle& pdata = particles[i];
|
---|
114 | // particle_quad& rdata = quads[i];
|
---|
115 | particle_quad& rdata = group->quads[i + group->count];
|
---|
116 |
|
---|
117 | vec3 view_dir( inv_view_dir );
|
---|
118 | if ( accurate_facing ) view_dir = math::normalize( camera_pos - pdata.position );
|
---|
119 |
|
---|
120 | switch ( orientation )
|
---|
121 | {
|
---|
122 | case particle_orientation::POINT:
|
---|
123 | right = math::normalize( math::cross( view_dir, vec3( 0, 1, 0 ) ) );
|
---|
124 | right = math::rotate( right, pdata.rotation, view_dir );
|
---|
125 | rot_mat = mat3( right, math::cross( right, -view_dir ), -view_dir );
|
---|
126 | break;
|
---|
127 | case particle_orientation::ORIENTED:
|
---|
128 | pdir = normalize_safe( pdata.velocity, pdir );
|
---|
129 | right = math::normalize( math::cross( pdir, view_dir ) );
|
---|
130 | rot_mat = mat3( right, pdir, math::cross( pdir, right ) );
|
---|
131 | break;
|
---|
132 | case particle_orientation::ORIENTED_COMMON:
|
---|
133 | right = math::normalize( math::cross( common_dir, view_dir ) );
|
---|
134 | rot_mat = mat3( right, common_dir, math::cross( common_dir, right ) );
|
---|
135 | break;
|
---|
136 | case particle_orientation::PERPENDICULAR:
|
---|
137 | pdir = normalize_safe( pdata.velocity, pdir );
|
---|
138 | right = math::normalize( math::cross( common_up, pdir ) );
|
---|
139 | rot_mat = mat3( right, common_up, math::cross( common_up, right ) );
|
---|
140 | break;
|
---|
141 | case particle_orientation::PERPENDICULAR_COMMON:
|
---|
142 | right = math::normalize( math::cross( common_up, common_dir ) );
|
---|
143 | rot_mat = mat3( right, common_up, math::cross( common_up, right ) );
|
---|
144 | break;
|
---|
145 | }
|
---|
146 |
|
---|
147 | vec2 texcoords[4] =
|
---|
148 | {
|
---|
149 | pdata.tcoord_a,
|
---|
150 | vec2( pdata.tcoord_b.x, pdata.tcoord_a.y ),
|
---|
151 | vec2( pdata.tcoord_a.x, pdata.tcoord_b.y ),
|
---|
152 | pdata.tcoord_b
|
---|
153 | };
|
---|
154 |
|
---|
155 | vec3 size( pdata.size.x, pdata.size.y, 0.0f );
|
---|
156 | vec3 s0 = rot_mat * ( ( size * sm[0] ) );
|
---|
157 | vec3 s1 = rot_mat * ( ( size * sm[1] ) );
|
---|
158 | vec3 s2 = rot_mat * ( ( size * sm[2] ) );
|
---|
159 | vec3 s3 = rot_mat * ( ( size * sm[3] ) );
|
---|
160 |
|
---|
161 | rdata.data[0].position = pdata.position + s0;
|
---|
162 | rdata.data[0].color = pdata.color;
|
---|
163 | rdata.data[0].texcoord = texcoords[0];
|
---|
164 |
|
---|
165 | rdata.data[1].position = pdata.position + s1;
|
---|
166 | rdata.data[1].color = pdata.color;
|
---|
167 | rdata.data[1].texcoord = texcoords[1];
|
---|
168 |
|
---|
169 | rdata.data[2].position = pdata.position + s2;
|
---|
170 | rdata.data[2].color = pdata.color;
|
---|
171 | rdata.data[2].texcoord = texcoords[2];
|
---|
172 |
|
---|
173 | rdata.data[3].position = pdata.position + s3;
|
---|
174 | rdata.data[3].color = pdata.color;
|
---|
175 | rdata.data[3].texcoord = texcoords[3];
|
---|
176 |
|
---|
177 | rdata.data[4] = rdata.data[2];
|
---|
178 | rdata.data[5] = rdata.data[1];
|
---|
179 | }
|
---|
180 | // m_context->unmap_buffer( info->vtx_buffer );
|
---|
181 |
|
---|
182 | m_context->update( group->vtx_buffer, group->quads, group->count * sizeof( particle_quad ), particles.size() * sizeof( particle_quad ) );
|
---|
183 | group->count += particles.size();
|
---|
184 | }
|
---|
185 |
|
---|
186 | particle_render_data nv::particle_group_manager::get_render_data( particle_group group )
|
---|
187 | {
|
---|
188 | const particle_group_info* info = m_groups.get( group );
|
---|
189 | if ( info )
|
---|
190 | {
|
---|
191 | return{ info->count, info->vtx_array };
|
---|
192 | }
|
---|
193 | return{ 0, nv::vertex_array() };
|
---|
194 | }
|
---|
195 |
|
---|
196 | particle_group_manager::~particle_group_manager()
|
---|
197 | {
|
---|
198 | clear();
|
---|
199 | }
|
---|
200 |
|
---|
201 | void particle_group_manager::clear()
|
---|
202 | {
|
---|
203 | while ( m_groups.size() > 0 )
|
---|
204 | release( m_groups.get_handle( 0 ) );
|
---|
205 | }
|
---|
206 |
|
---|
207 | bool particle_group_manager::ref( particle_group group )
|
---|
208 | {
|
---|
209 | particle_group_info* info = m_groups.get( group );
|
---|
210 | if ( !info ) return false;
|
---|
211 | info->ref_counter++;
|
---|
212 | return true;
|
---|
213 | }
|
---|
214 |
|
---|
215 | bool particle_group_manager::unref( particle_group group )
|
---|
216 | {
|
---|
217 | particle_group_info* info = m_groups.get( group );
|
---|
218 | if ( !info ) return false;
|
---|
219 | info->ref_counter--;
|
---|
220 | return true;
|
---|
221 | }
|
---|
222 |
|
---|
223 |
|
---|