36 PStatCollector SpriteParticleRenderer::_render_collector(
"App:Particles:Sprite:Render");
44 _color(LColor(1.0f, 1.0f, 1.0f, 1.0f)),
47 _initial_x_scale(1.0f),
49 _initial_y_scale(1.0f),
54 _animate_frames_rate(0.0f),
55 _animate_frames_index(0),
56 _animate_x_ratio(false),
57 _animate_y_ratio(false),
58 _animate_theta(false),
59 _alpha_disable(false),
60 _animate_frames(false),
61 _animation_removed(true),
62 _blend_method(PP_BLEND_LINEAR),
77 _height(copy._height),
79 _initial_x_scale(copy._initial_x_scale),
80 _final_x_scale(copy._final_x_scale),
81 _initial_y_scale(copy._initial_y_scale),
82 _final_y_scale(copy._final_y_scale),
84 _base_y_scale(copy._base_y_scale),
85 _aspect_ratio(copy._aspect_ratio),
86 _animate_frames_rate(copy._animate_frames_rate),
87 _animate_frames_index(copy._animate_frames_index),
88 _animate_x_ratio(copy._animate_x_ratio),
89 _animate_y_ratio(copy._animate_y_ratio),
90 _animate_theta(copy._animate_theta),
91 _alpha_disable(copy._alpha_disable),
92 _animate_frames(copy._animate_frames),
93 _animation_removed(true),
94 _blend_method(copy._blend_method),
95 _color_interpolation_manager(copy._color_interpolation_manager),
97 _birth_list(copy._birth_list) {
125 int SpriteParticleRenderer::
132 if (!tex_node_path.
is_empty() && tex_node_path.
node()->get_type() != SequenceNode::get_class_type()) {
133 tex_node_path = node_path.
find(
"**/+SequenceNode");
141 for (
int i = 0; i < frame_count; ++i) {
142 geom_node_path = tex_node_path.
get_child(i);
162 if (!node_path.
is_empty() && node_path.
node()->get_type() != GeomNode::get_class_type()) {
163 geom_node_path = node_path.
find(
"**/+GeomNode");
165 particlesystem_cat.error();
169 geom_node_path = node_path;
175 particlesystem_cat.error()
176 << geom_node_path <<
" does not contain a texture.\n";
195 set_from_node(
const NodePath &node_path,
const std::string &model,
const std::string &node,
bool size_from_texels) {
247 add_from_node(
const NodePath &node_path,
const std::string &model,
const std::string &node,
bool size_from_texels,
bool resize) {
248 int anim_count = _anims.size();
252 if (anim_count < (
int)_anims.size()) {
253 get_last_anim()->set_source_info(model,node);
276 if (extract_textures_from_node(node_path,np_col,tex_col)) {
284 gnode = DCAST(
GeomNode, np_col[i].node());
288 geom = gnode->get_geom(0);
290 bool got_texcoord =
false;
291 LTexCoord min_uv(0.0f, 0.0f);
292 LTexCoord max_uv(0.0f, 0.0f);
295 InternalName::get_texcoord());
297 for (
size_t pi = 0; pi < geom->get_num_primitives(); ++pi) {
298 primitive = geom->get_primitive(pi);
308 const LVecBase2 &uv = texcoord.
get_data2();
310 min_uv[0] = min(min_uv[0], uv[0]);
311 max_uv[0] = max(max_uv[0], uv[0]);
312 min_uv[1] = min(min_uv[1], uv[1]);
313 max_uv[1] = max(max_uv[1], uv[1]);
323 ll.push_back(min_uv);
324 ur.push_back(max_uv);
328 _anims.push_back(
new SpriteAnim(tex_col,ll,ur));
331 gnode = DCAST(
GeomNode, np_col[0].node());
332 geom = gnode->get_geom(0);
334 bool got_vertex =
false;
335 LVertex min_xyz(0.0f, 0.0f, 0.0f);
336 LVertex max_xyz(0.0f, 0.0f, 0.0f);
339 InternalName::get_vertex());
341 for (
size_t pi = 0; pi < geom->get_num_primitives(); ++pi) {
342 primitive = geom->get_primitive(pi);
352 const LVecBase3 &xyz = vertex.
get_data3();
354 min_xyz[0] = min(min_xyz[0], xyz[0]);
355 max_xyz[0] = max(max_xyz[0], xyz[0]);
356 min_xyz[1] = min(min_xyz[1], xyz[1]);
357 max_xyz[1] = max(max_xyz[1], xyz[1]);
358 min_xyz[2] = min(min_xyz[2], xyz[2]);
359 max_xyz[2] = max(max_xyz[2], xyz[2]);
366 PN_stdfloat width = max_xyz[0] - min_xyz[0];
367 PN_stdfloat height = max(max_xyz[1] - min_xyz[1],
368 max_xyz[2] - min_xyz[2]);
370 if (size_from_texels) {
373 PN_stdfloat y_texels = _anims[0]->get_frame(0)->get_y_size() * fabs(_anims[0]->get_ur(0)[1] - _anims[0]->get_ll(0)[1]);
374 set_size(y_texels * width / height, y_texels);
393 void SpriteParticleRenderer::
394 resize_pool(
int new_size) {
395 if (new_size != _pool_size) {
396 _pool_size = new_size;
405 void SpriteParticleRenderer::
409 int anim_count = _anims.size();
414 (InternalName::get_vertex(), 3, Geom::NT_stdfloat, Geom::C_point,
415 InternalName::get_color(), 1, Geom::NT_packed_dabc, Geom::C_color);
417 if (_animate_theta || _theta != 0.0f) {
418 array_format->add_column
419 (InternalName::get_rotate(), 1, Geom::NT_stdfloat, Geom::C_other);
422 _base_y_scale = _initial_y_scale;
423 _aspect_ratio = _width / _height;
425 PN_stdfloat final_x_scale = _animate_x_ratio ? _final_x_scale : _initial_x_scale;
426 PN_stdfloat final_y_scale = _animate_y_ratio ? _final_y_scale : _initial_y_scale;
428 if (_animate_y_ratio) {
429 _base_y_scale = max(_initial_y_scale, _final_y_scale);
430 array_format->add_column
431 (InternalName::get_size(), 1, Geom::NT_stdfloat, Geom::C_other);
434 if (_aspect_ratio * _initial_x_scale != _initial_y_scale ||
435 _aspect_ratio * final_x_scale != final_y_scale) {
436 array_format->add_column
437 (InternalName::get_aspect_ratio(), 1, Geom::NT_stdfloat,
445 for (i = 0; i < (int)_ttl_count.size(); ++i) {
446 PANDA_FREE_ARRAY(_ttl_count[i]);
448 _anim_size.resize(anim_count);
450 _ttl_count.resize(anim_count);
453 _sprite_primitive.clear();
456 _sprite_writer.clear();
462 for (i = 0; i < anim_count; ++i) {
464 _anim_size[i] = anim->get_num_frames();
472 for (j = 0; j < _anim_size[i]; ++j) {
473 _ttl_count[i] = (
int *)PANDA_MALLOC_ARRAY(_anim_size[i] *
sizeof(
int));
474 _vdata[i].push_back(
new GeomVertexData(
"sprite_particles", format, Geom::UH_stream));
475 PT(
Geom) geom =
new Geom(_vdata[i][j]);
476 _sprite_primitive[i].push_back((
Geom*)geom);
477 _sprites[i].push_back(
new GeomPoints(Geom::UH_stream));
484 state = state->add_attrib(RenderModeAttrib::make(RenderModeAttrib::M_unchanged, _base_y_scale * _height,
true));
485 if (anim->get_frame(j) !=
nullptr) {
486 state = state->add_attrib(TextureAttrib::make(anim->get_frame(j)));
491 LPoint2 ul(anim->get_ll(j)[0], anim->get_ur(j)[1]);
492 LPoint2 lr(anim->get_ur(j)[0], anim->get_ll(j)[1]);
493 LVector2 sc = lr - ul;
495 CPT(
TransformState) ts = TransformState::make_pos_rotate_scale2d(ul, 0.0f, sc);
499 render_node->
add_geom(_sprite_primitive[i][j], state);
510 void SpriteParticleRenderer::
511 birth_particle(
int index) {
512 _birth_list.push_back(index);
518 void SpriteParticleRenderer::
525 void SpriteParticleRenderer::
529 if (_anims.empty()) {
534 int remaining_particles = ttl_particles;
536 int anim_count = _anims.size();
540 if (_animate_frames || anim_count) {
541 if (!_birth_list.empty()) {
542 for (vector_int::iterator vIter = _birth_list.begin(); vIter != _birth_list.end(); ++vIter) {
544 i = int(NORMALIZED_RAND()*anim_count);
548 cur_particle->set_index(i < anim_count?i:i-1);
558 if (_animate_frames) {
559 cur_particle->set_age(cur_particle->get_age()+i/10.0*cur_particle->get_lifespan());
569 for (i = 0; i < anim_count; ++i) {
570 for (j = 0; j < _anim_size[i]; ++j) {
572 memset(_ttl_count[i], 0, _anim_size[i]*
sizeof(
int));
573 _sprite_writer[i][j].vertex =
GeomVertexWriter(_vdata[i][j], InternalName::get_vertex());
574 _sprite_writer[i][j].color =
GeomVertexWriter(_vdata[i][j], InternalName::get_color());
575 _sprite_writer[i][j].rotate =
GeomVertexWriter(_vdata[i][j], InternalName::get_rotate());
576 _sprite_writer[i][j].size =
GeomVertexWriter(_vdata[i][j], InternalName::get_size());
577 _sprite_writer[i][j].aspect_ratio =
GeomVertexWriter(_vdata[i][j], InternalName::get_aspect_ratio());
582 _aabb_min.set(99999.0f, 99999.0f, 99999.0f);
583 _aabb_max.set(-99999.0f, -99999.0f, -99999.0f);
586 for (i = 0; i < (int)po_vector.size(); i++) {
589 if (!cur_particle->get_alive()) {
596 if (position[0] > _aabb_max[0])
597 _aabb_max[0] = position[0];
598 else if (position[0] < _aabb_min[0])
599 _aabb_min[0] = position[0];
602 if (position[1] > _aabb_max[1])
603 _aabb_max[1] = position[1];
604 else if (position[1] < _aabb_min[1])
605 _aabb_min[1] = position[1];
608 if (position[2] > _aabb_max[2])
609 _aabb_max[2] = position[2];
610 else if (position[2] < _aabb_min[2])
611 _aabb_min[2] = position[2];
614 PN_stdfloat t = cur_particle->get_parameterized_age();
615 int anim_index = cur_particle->get_index();
619 if(_animation_removed && (anim_index >= anim_count)) {
620 anim_index = int(NORMALIZED_RAND()*anim_count);
621 anim_index = anim_index<anim_count?anim_index:anim_index-1;
622 cur_particle->set_index(anim_index);
626 if (_animate_frames) {
627 if (_animate_frames_rate == 0.0f) {
628 frame = (int)(t*_anim_size[anim_index]);
630 frame = (int)fmod(cur_particle->get_age()*_animate_frames_rate+1,_anim_size[anim_index]);
633 frame = _animate_frames_index;
637 frame = (frame < _anim_size[anim_index]) ? frame : (_anim_size[anim_index]-1);
638 ++_ttl_count[anim_index][frame];
642 LColor c = _color_interpolation_manager->generateColor(t);
644 int alphamode=get_alpha_mode();
645 if (alphamode != PR_ALPHA_NONE) {
646 if (alphamode == PR_ALPHA_OUT)
648 else if (alphamode == PR_ALPHA_IN)
650 else if (alphamode == PR_ALPHA_IN_OUT) {
654 assert(alphamode == PR_ALPHA_USER);
660 _sprite_writer[anim_index][frame].vertex.add_data3(position);
661 _sprite_writer[anim_index][frame].color.add_data4(c);
663 PN_stdfloat current_x_scale = _initial_x_scale;
664 PN_stdfloat current_y_scale = _initial_y_scale;
666 if (_animate_x_ratio || _animate_y_ratio) {
667 if (_blend_method == PP_BLEND_CUBIC) {
671 if (_animate_x_ratio) {
672 current_x_scale = (_initial_x_scale +
673 (t * (_final_x_scale - _initial_x_scale)));
675 if (_animate_y_ratio) {
676 current_y_scale = (_initial_y_scale +
677 (t * (_final_y_scale - _initial_y_scale)));
681 if (_sprite_writer[anim_index][frame].size.has_column()) {
682 _sprite_writer[anim_index][frame].size.add_data1f(current_y_scale * _height);
684 if (_sprite_writer[anim_index][frame].aspect_ratio.has_column()) {
685 _sprite_writer[anim_index][frame].aspect_ratio.add_data1f(_aspect_ratio * current_x_scale / current_y_scale);
687 if (_animate_theta) {
688 _sprite_writer[anim_index][frame].rotate.add_data1f(cur_particle->
get_theta());
689 }
else if (_sprite_writer[anim_index][frame].rotate.has_column()) {
690 _sprite_writer[anim_index][frame].rotate.add_data1f(_theta);
694 remaining_particles--;
695 if (remaining_particles == 0) {
702 for (i = 0; i < anim_count; ++i) {
703 for (j = 0; j < _anim_size[i]; ++j) {
704 _sprites[i][j]->clear_vertices();
705 _sprite_writer[i][j].clear();
709 _sprite_primitive[i][j]->set_primitive(0, _sprites[i][j]);
710 _sprite_primitive[i][j]->set_vertex_data(_vdata[i][j]);
712 render_node->
set_geom(n, _sprite_primitive[i][j]);
717 if (_animate_frames) {
718 for (i = 0; i < anim_count; ++i) {
719 for (j = 0; j < _anim_size[i]; ++j) {
720 _sprites[i][j]->add_next_vertices(_ttl_count[i][j]);
724 for (i = 0; i < anim_count; ++i) {
725 _sprites[i][_animate_frames_index]->add_next_vertices(_ttl_count[i][_animate_frames_index]);
730 LPoint3 aabb_center = _aabb_min + ((_aabb_max - _aabb_min) * 0.5f);
731 PN_stdfloat radius = (aabb_center - _aabb_min).length();
733 for (i = 0; i < anim_count; ++i) {
734 for (j = 0; j < _anim_size[i]; ++j) {
735 nassertv(_sprite_primitive[i][j]->check_valid());
737 _sprite_primitive[i][j]->set_bounds(&sphere);
743 _animation_removed =
false;
750 output(std::ostream &out)
const {
752 out<<
"SpriteParticleRenderer";
760 write(std::ostream &out,
int indent_level)
const {
761 indent(out, indent_level) <<
"SpriteParticleRenderer:\n";
764 indent(out, indent_level + 2) <<
"_color "<<_color<<
"\n";
765 indent(out, indent_level + 2) <<
"_initial_x_scale "<<_initial_x_scale<<
"\n";
766 indent(out, indent_level + 2) <<
"_final_x_scale "<<_final_x_scale<<
"\n";
767 indent(out, indent_level + 2) <<
"_initial_y_scale "<<_initial_y_scale<<
"\n";
768 indent(out, indent_level + 2) <<
"_final_y_scale "<<_final_y_scale<<
"\n";
769 indent(out, indent_level + 2) <<
"_theta "<<_theta<<
"\n";
770 indent(out, indent_level + 2) <<
"_animate_x_ratio "<<_animate_x_ratio<<
"\n";
771 indent(out, indent_level + 2) <<
"_animate_y_ratio "<<_animate_y_ratio<<
"\n";
772 indent(out, indent_level + 2) <<
"_animate_theta "<<_animate_theta<<
"\n";
773 indent(out, indent_level + 2) <<
"_blend_method "<<_blend_method<<
"\n";
774 indent(out, indent_level + 2) <<
"_aabb_min "<<_aabb_min<<
"\n";
775 indent(out, indent_level + 2) <<
"_aabb_max "<<_aabb_max<<
"\n";
776 indent(out, indent_level + 2) <<
"_pool_size "<<_pool_size<<
"\n";