36PStatCollector 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) {
125int 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";
195set_from_node(
const NodePath &node_path,
const std::string &model,
const std::string &node,
bool size_from_texels) {
247add_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);
393void SpriteParticleRenderer::
394resize_pool(
int new_size) {
395 if (new_size != _pool_size) {
396 _pool_size = new_size;
405void 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);
510void SpriteParticleRenderer::
511birth_particle(
int index) {
512 _birth_list.push_back(index);
518void SpriteParticleRenderer::
525void 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;
750output(std::ostream &out)
const {
752 out<<
"SpriteParticleRenderer";
760write(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";
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
Pure virtual particle renderer base class.
GeomNode * get_render_node() const
Query the geomnode pointer.
PN_stdfloat get_user_alpha() const
gets alpha for "user" alpha mode
virtual void write(std::ostream &out, int indent=0) const
Write a string representation of this instance to <out>.
An individual, physically-modelable particle abstract base class.
virtual PN_stdfloat get_theta() const
for spriteParticleRenderer
This defines a bounding sphere, consisting of a center and a radius.
High level class for color interpolation.
A node that holds Geom objects, renderable pieces of geometry.
void add_geom(Geom *geom, const RenderState *state=RenderState::make_empty())
Adds a new Geom to the node.
get_num_geoms
Returns the number of geoms in the node.
void remove_all_geoms()
Removes all the geoms from the node at once.
void set_geom(int n, Geom *geom)
Replaces the nth Geom of the node with a new pointer.
bool check_valid() const
Verifies that the each Geom within the GeomNode reference vertices that actually exist within its Geo...
Defines a series of disconnected points.
This is an abstract base class for a family of classes that represent the fundamental geometry primit...
get_vertex
Returns the ith vertex index in the table.
get_num_vertices
Returns the number of indices used by all the primitives in this object.
This defines the actual numeric vertex data stored in a Geom, in the structure defined by a particula...
This object provides a high-level interface for quickly reading a sequence of numeric values from a v...
void set_row_unsafe(int row)
Sets the start row to the indicated value, without internal checks.
const LVecBase2 & get_data2()
Returns the data associated with the read row, expressed as a 2-component value, and advances the rea...
bool has_column() const
Returns true if a valid data type has been successfully set, or false if the data type does not exist...
const LVecBase3 & get_data3()
Returns the data associated with the read row, expressed as a 3-component value, and advances the rea...
This object provides a high-level interface for quickly writing a sequence of numeric values from a v...
A container for geometry primitives.
void add_primitive(const GeomPrimitive *primitive)
Inserts a new GeomPrimitive structure to the Geom object.
This is a set of zero or more NodePaths.
void add_path(const NodePath &node_path)
Adds a new NodePath to the collection.
get_num_paths
Returns the number of NodePaths in the collection.
void clear()
Removes all NodePaths from the collection.
NodePath is the fundamental system for disambiguating instances, and also provides a higher-level int...
int get_num_children(Thread *current_thread=Thread::get_current_thread()) const
Returns the number of children of the referenced node.
NodePath find(const std::string &path) const
Searches for a node below the referenced node that matches the indicated string.
bool is_empty() const
Returns true if the NodePath contains no nodes.
Texture * find_texture(const std::string &name) const
Returns the first texture found applied to geometry at this node or below that matches the indicated ...
PandaNode * node() const
Returns the referenced node of the path.
NodePath get_child(int n, Thread *current_thread=Thread::get_current_thread()) const
Returns a NodePath representing the nth child of the referenced node.
TextureCollection find_all_textures() const
Returns a list of a textures applied to geometry at this node and below.
A lightweight class that represents a single element that may be timed and/or counted via stats.
A lightweight class that can be used to automatically start and stop a PStatCollector around a sectio...
A body on which physics will be applied.
get_position
Position Query.
This represents a unique collection of RenderAttrib objects that correspond to a particular renderabl...
Helper class used by SpriteParticleRenderer to keep track of its textures and their respective UVs an...
Renders a particle system with high-speed nasty trick sprites.
void set_size(PN_stdfloat width, PN_stdfloat height)
Sets the size of each particle in world units.
virtual ~SpriteParticleRenderer()
destructor
SpriteParticleRenderer(Texture *tex=nullptr)
constructor
virtual BaseParticleRenderer * make_copy()
child dynamic copy
void add_from_node(const NodePath &node_path, bool size_from_texels=false, bool resize=false)
This will allow the renderer to randomly choose from more than one texture or sequence at particle bi...
virtual void output(std::ostream &out) const
Write a string representation of this instance to <out>.
void set_texture(Texture *tex, PN_stdfloat texels_per_unit=1.0f)
Sets the renderer up to render the entire texture image.
virtual void write(std::ostream &out, int indent_level=0) const
Write a string representation of this instance to <out>.
void set_from_node(const NodePath &node_path, bool size_from_texels=false)
Sets the properties on this renderer from the geometry referenced by the indicated NodePath.
Helper class used by SpriteParticleRenderer to keep track of the various GeomVertexWriters associated...
Manages a list of Texture objects, as returned by TexturePool::find_all_textures().
get_num_textures
Returns the number of Textures in the collection.
void add_texture(Texture *texture)
Adds a new Texture to the collection.
void add_textures_from(const TextureCollection &other)
Adds all the Textures indicated in the other collection to this texture.
void clear()
Removes all Textures from the collection.
get_default
Returns the default TextureStage that will be used for all texturing that does not name a particular ...
Represents a texture object, which is typically a single 2-d image but may also represent a 1-d or 3-...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
std::ostream & indent(std::ostream &out, int indent_level)
A handy function for doing text formatting.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.