00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015 #include "spriteParticleRenderer.h"
00016 #include "boundingSphere.h"
00017 #include "geomNode.h"
00018 #include "sequenceNode.h"
00019 #include "nodePath.h"
00020 #include "dcast.h"
00021 #include "geom.h"
00022 #include "geomVertexReader.h"
00023 #include "geomVertexWriter.h"
00024 #include "renderModeAttrib.h"
00025 #include "texMatrixAttrib.h"
00026 #include "texGenAttrib.h"
00027 #include "textureAttrib.h"
00028 #include "textureCollection.h"
00029 #include "nodePathCollection.h"
00030 #include "indent.h"
00031 #include "config_particlesystem.h"
00032 #include "pStatTimer.h"
00033
00034 PStatCollector SpriteParticleRenderer::_render_collector("App:Particles:Sprite:Render");
00035
00036
00037
00038
00039
00040
00041 SpriteParticleRenderer::
00042 SpriteParticleRenderer(Texture *tex) :
00043 BaseParticleRenderer(PR_ALPHA_NONE),
00044 _color(LColor(1.0f, 1.0f, 1.0f, 1.0f)),
00045 _height(1.0f),
00046 _width(1.0f),
00047 _initial_x_scale(1.0f),
00048 _final_x_scale(1.0f),
00049 _initial_y_scale(1.0f),
00050 _final_y_scale(1.0f),
00051 _theta(0.0f),
00052 _base_y_scale(1.0f),
00053 _aspect_ratio(1.0f),
00054 _animate_frames_rate(0.0f),
00055 _animate_frames_index(0),
00056 _animate_x_ratio(false),
00057 _animate_y_ratio(false),
00058 _animate_theta(false),
00059 _alpha_disable(false),
00060 _animate_frames(false),
00061 _animation_removed(true),
00062 _blend_method(PP_BLEND_LINEAR),
00063 _color_interpolation_manager(new ColorInterpolationManager(_color)),
00064 _pool_size(0) {
00065 set_texture(tex);
00066 init_geoms();
00067 }
00068
00069
00070
00071
00072
00073
00074 SpriteParticleRenderer::
00075 SpriteParticleRenderer(const SpriteParticleRenderer& copy) :
00076 BaseParticleRenderer(copy),
00077 _anims(copy._anims),
00078 _color(copy._color),
00079 _height(copy._height),
00080 _width(copy._width),
00081 _initial_x_scale(copy._initial_x_scale),
00082 _final_x_scale(copy._final_x_scale),
00083 _initial_y_scale(copy._initial_y_scale),
00084 _final_y_scale(copy._final_y_scale),
00085 _theta(copy._theta),
00086 _base_y_scale(copy._base_y_scale),
00087 _aspect_ratio(copy._aspect_ratio),
00088 _animate_frames_rate(copy._animate_frames_rate),
00089 _animate_frames_index(copy._animate_frames_index),
00090 _animate_x_ratio(copy._animate_x_ratio),
00091 _animate_y_ratio(copy._animate_y_ratio),
00092 _animate_theta(copy._animate_theta),
00093 _alpha_disable(copy._alpha_disable),
00094 _animate_frames(copy._animate_frames),
00095 _animation_removed(true),
00096 _blend_method(copy._blend_method),
00097 _color_interpolation_manager(copy._color_interpolation_manager),
00098 _pool_size(0),
00099 _birth_list(copy._birth_list) {
00100 init_geoms();
00101 }
00102
00103
00104
00105
00106
00107
00108 SpriteParticleRenderer::
00109 ~SpriteParticleRenderer() {
00110 get_render_node()->remove_all_geoms();
00111 }
00112
00113
00114
00115
00116
00117
00118 BaseParticleRenderer *SpriteParticleRenderer::
00119 make_copy() {
00120 return new SpriteParticleRenderer(*this);
00121 }
00122
00123
00124
00125
00126
00127
00128
00129
00130
00131
00132
00133 int SpriteParticleRenderer::
00134 extract_textures_from_node(const NodePath &node_path, NodePathCollection &np_col, TextureCollection &tex_col) {
00135 NodePath tex_node_path = node_path;
00136 NodePath geom_node_path;
00137
00138
00139 if (!tex_node_path.is_empty() && tex_node_path.node()->get_type() != SequenceNode::get_class_type()) {
00140 tex_node_path = node_path.find("**/+SequenceNode");
00141 }
00142
00143
00144 if (!tex_node_path.is_empty()) {
00145 int frame_count = tex_node_path.get_num_children();
00146
00147
00148 for (int i = 0; i < frame_count; ++i) {
00149 geom_node_path = tex_node_path.get_child(i);
00150 if (!geom_node_path.is_empty()) {
00151
00152 tex_col.add_textures_from(geom_node_path.find_all_textures());
00153 np_col.add_path(geom_node_path);
00154 }
00155 }
00156
00157 if (tex_col.get_num_textures() == 0) {
00158 geom_node_path = NodePath();
00159 tex_col.clear();
00160 np_col.clear();
00161 }
00162 }
00163
00164
00165 if (geom_node_path.is_empty()) {
00166
00167 if (!node_path.is_empty() && node_path.node()->get_type() != GeomNode::get_class_type()) {
00168 geom_node_path = node_path.find("**/+GeomNode");
00169 if (geom_node_path.is_empty()) {
00170 particlesystem_cat.error();
00171 return 0;
00172 }
00173 } else {
00174 geom_node_path = node_path;
00175 }
00176
00177
00178 tex_col.add_texture(geom_node_path.find_texture("*"));
00179 if (tex_col.get_num_textures() < 1) {
00180 particlesystem_cat.error()
00181 << geom_node_path << " does not contain a texture.\n";
00182 return 0;
00183 } else {
00184 np_col.add_path(geom_node_path);
00185 }
00186 }
00187 return 1;
00188 }
00189
00190
00191
00192
00193
00194
00195
00196
00197
00198
00199
00200
00201 void SpriteParticleRenderer::
00202 set_from_node(const NodePath &node_path, const string &model, const string &node, bool size_from_texels) {
00203
00204 _anims.clear();
00205 add_from_node(node_path,model,node,size_from_texels,true);
00206 }
00207
00208
00209
00210
00211
00212
00213
00214
00215
00216
00217
00218
00219
00220
00221
00222
00223
00224
00225
00226
00227
00228
00229
00230
00231
00232
00233
00234
00235
00236
00237
00238
00239
00240 void SpriteParticleRenderer::
00241 set_from_node(const NodePath &node_path, bool size_from_texels) {
00242 nassertv(!node_path.is_empty());
00243
00244 _anims.clear();
00245 add_from_node(node_path,size_from_texels,true);
00246 }
00247
00248
00249
00250
00251
00252
00253
00254
00255
00256
00257
00258
00259
00260
00261
00262
00263
00264
00265 void SpriteParticleRenderer::
00266 add_from_node(const NodePath &node_path, const string &model, const string &node, bool size_from_texels, bool resize) {
00267 int anim_count = _anims.size();
00268 if (anim_count == 0)
00269 resize = true;
00270 add_from_node(node_path,size_from_texels,resize);
00271 if (anim_count < (int)_anims.size()) {
00272 get_last_anim()->set_source_info(model,node);
00273 }
00274 }
00275
00276
00277
00278
00279
00280
00281
00282
00283
00284
00285
00286
00287
00288 void SpriteParticleRenderer::
00289 add_from_node(const NodePath &node_path, bool size_from_texels, bool resize) {
00290 nassertv(!node_path.is_empty());
00291
00292 NodePathCollection np_col;
00293 TextureCollection tex_col;
00294
00295 if (_anims.empty())
00296 resize = true;
00297
00298
00299 if (extract_textures_from_node(node_path,np_col,tex_col)) {
00300 pvector< LTexCoord > ll,ur;
00301 GeomNode *gnode = NULL;
00302 const Geom *geom;
00303 const GeomPrimitive *primitive;
00304
00305 for (int i = 0; i < np_col.get_num_paths(); ++i) {
00306
00307 gnode = DCAST(GeomNode, np_col[i].node());
00308
00309
00310 nassertv(gnode->get_num_geoms() > 0);
00311 geom = gnode->get_geom(0);
00312
00313 bool got_texcoord = false;
00314 LTexCoord min_uv(0.0f, 0.0f);
00315 LTexCoord max_uv(0.0f, 0.0f);
00316
00317 GeomVertexReader texcoord(geom->get_vertex_data(),
00318 InternalName::get_texcoord());
00319 if (texcoord.has_column()) {
00320 for (int pi = 0; pi < geom->get_num_primitives(); ++pi) {
00321 primitive = geom->get_primitive(pi);
00322 for (int vi = 0; vi < primitive->get_num_vertices(); ++vi) {
00323 int vert = primitive->get_vertex(vi);
00324 texcoord.set_row_unsafe(vert);
00325
00326 if (!got_texcoord) {
00327 min_uv = max_uv = texcoord.get_data2();
00328 got_texcoord = true;
00329
00330 } else {
00331 const LVecBase2 &uv = texcoord.get_data2();
00332
00333 min_uv[0] = min(min_uv[0], uv[0]);
00334 max_uv[0] = max(max_uv[0], uv[0]);
00335 min_uv[1] = min(min_uv[1], uv[1]);
00336 max_uv[1] = max(max_uv[1], uv[1]);
00337 }
00338 }
00339 }
00340 }
00341
00342 if (got_texcoord) {
00343
00344
00345
00346 ll.push_back(min_uv);
00347 ur.push_back(max_uv);
00348 }
00349 }
00350
00351 _anims.push_back(new SpriteAnim(tex_col,ll,ur));
00352
00353 if (resize) {
00354 gnode = DCAST(GeomNode, np_col[0].node());
00355 geom = gnode->get_geom(0);
00356
00357 bool got_vertex = false;
00358 LVertex min_xyz(0.0f, 0.0f, 0.0f);
00359 LVertex max_xyz(0.0f, 0.0f, 0.0f);
00360
00361 GeomVertexReader vertex(geom->get_vertex_data(),
00362 InternalName::get_vertex());
00363 if (vertex.has_column()) {
00364 for (int pi = 0; pi < geom->get_num_primitives(); ++pi) {
00365 primitive = geom->get_primitive(pi);
00366 for (int vi = 0; vi < primitive->get_num_vertices(); ++vi) {
00367 int vert = primitive->get_vertex(vi);
00368 vertex.set_row_unsafe(vert);
00369
00370 if (!got_vertex) {
00371 min_xyz = max_xyz = vertex.get_data3();
00372 got_vertex = true;
00373
00374 } else {
00375 const LVecBase3 &xyz = vertex.get_data3();
00376
00377 min_xyz[0] = min(min_xyz[0], xyz[0]);
00378 max_xyz[0] = max(max_xyz[0], xyz[0]);
00379 min_xyz[1] = min(min_xyz[1], xyz[1]);
00380 max_xyz[1] = max(max_xyz[1], xyz[1]);
00381 min_xyz[2] = min(min_xyz[2], xyz[2]);
00382 max_xyz[2] = max(max_xyz[2], xyz[2]);
00383 }
00384 }
00385 }
00386 }
00387
00388 if (got_vertex) {
00389 PN_stdfloat width = max_xyz[0] - min_xyz[0];
00390 PN_stdfloat height = max(max_xyz[1] - min_xyz[1],
00391 max_xyz[2] - min_xyz[2]);
00392
00393 if (size_from_texels) {
00394
00395
00396 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]);
00397 set_size(y_texels * width / height, y_texels);
00398 } else {
00399
00400
00401 set_size(width, height);
00402 }
00403
00404 } else {
00405
00406 set_size(1.0f, 1.0f);
00407 }
00408 }
00409 init_geoms();
00410 }
00411 }
00412
00413
00414
00415
00416
00417
00418 void SpriteParticleRenderer::
00419 resize_pool(int new_size) {
00420 if (new_size != _pool_size) {
00421 _pool_size = new_size;
00422 init_geoms();
00423 }
00424 }
00425
00426
00427
00428
00429
00430
00431
00432
00433 void SpriteParticleRenderer::
00434 init_geoms() {
00435 CPT(RenderState) state = _render_state;
00436 SpriteAnim *anim;
00437 int anim_count = _anims.size();
00438 int i,j;
00439
00440
00441 PT(GeomVertexArrayFormat) array_format = new GeomVertexArrayFormat
00442 (InternalName::get_vertex(), 3, Geom::NT_stdfloat, Geom::C_point,
00443 InternalName::get_color(), 1, Geom::NT_packed_dabc, Geom::C_color);
00444
00445 if (_animate_theta || _theta != 0.0f) {
00446 array_format->add_column
00447 (InternalName::get_rotate(), 1, Geom::NT_stdfloat, Geom::C_other);
00448 }
00449
00450 _base_y_scale = _initial_y_scale;
00451 _aspect_ratio = _width / _height;
00452
00453 PN_stdfloat final_x_scale = _animate_x_ratio ? _final_x_scale : _initial_x_scale;
00454 PN_stdfloat final_y_scale = _animate_y_ratio ? _final_y_scale : _initial_y_scale;
00455
00456 if (_animate_y_ratio) {
00457 _base_y_scale = max(_initial_y_scale, _final_y_scale);
00458 array_format->add_column
00459 (InternalName::get_size(), 1, Geom::NT_stdfloat, Geom::C_other);
00460 }
00461
00462 if (_aspect_ratio * _initial_x_scale != _initial_y_scale ||
00463 _aspect_ratio * final_x_scale != final_y_scale) {
00464 array_format->add_column
00465 (InternalName::get_aspect_ratio(), 1, Geom::NT_stdfloat,
00466 Geom::C_other);
00467 }
00468
00469 CPT(GeomVertexFormat) format = GeomVertexFormat::register_format
00470 (new GeomVertexFormat(array_format));
00471
00472
00473 for (i = 0; i < (int)_ttl_count.size(); ++i) {
00474 PANDA_FREE_ARRAY(_ttl_count[i]);
00475 }
00476 _anim_size.resize(anim_count);
00477 _ttl_count.clear();
00478 _ttl_count.resize(anim_count);
00479
00480
00481 _sprite_primitive.clear();
00482 _sprites.clear();
00483 _vdata.clear();
00484 _sprite_writer.clear();
00485
00486 GeomNode *render_node = get_render_node();
00487 render_node->remove_all_geoms();
00488
00489
00490 for (i = 0; i < anim_count; ++i) {
00491 anim = _anims[i];
00492 _anim_size[i] = anim->get_num_frames();
00493
00494 _sprite_primitive.push_back(pvector<PT(Geom)>());
00495 _sprites.push_back(pvector<PT(GeomPoints)>());
00496 _vdata.push_back(pvector<PT(GeomVertexData)>());
00497 _sprite_writer.push_back(pvector<SpriteWriter>());
00498
00499
00500 for (j = 0; j < _anim_size[i]; ++j) {
00501 _ttl_count[i] = (int *)PANDA_MALLOC_ARRAY(_anim_size[i] * sizeof(int));
00502 _vdata[i].push_back(new GeomVertexData("sprite_particles", format, Geom::UH_stream));
00503 PT(Geom) geom = new Geom(_vdata[i][j]);
00504 _sprite_primitive[i].push_back((Geom*)geom);
00505 _sprites[i].push_back(new GeomPoints(Geom::UH_stream));
00506 geom->add_primitive(_sprites[i][j]);
00507
00508
00509 _sprite_writer[i].push_back(SpriteWriter());
00510
00511 state = state->add_attrib(RenderModeAttrib::make(RenderModeAttrib::M_unchanged, _base_y_scale * _height, true));
00512 if (anim->get_frame(j) != (Texture *)NULL) {
00513 state = state->add_attrib(TextureAttrib::make(anim->get_frame(j)));
00514 state = state->add_attrib(TexGenAttrib::make(TextureStage::get_default(), TexGenAttrib::M_point_sprite));
00515
00516
00517
00518 LPoint2 ul(anim->get_ll(j)[0], anim->get_ur(j)[1]);
00519 LPoint2 lr(anim->get_ur(j)[0], anim->get_ll(j)[1]);
00520 LVector2 sc = lr - ul;
00521
00522 CPT(TransformState) ts = TransformState::make_pos_rotate_scale2d(ul, 0.0f, sc);
00523 state = state->add_attrib(TexMatrixAttrib::make(TextureStage::get_default(), ts));
00524 }
00525
00526 render_node->add_geom(_sprite_primitive[i][j], state);
00527 }
00528 }
00529
00530 nassertv(render_node->check_valid());
00531 }
00532
00533
00534
00535
00536
00537
00538
00539
00540 void SpriteParticleRenderer::
00541 birth_particle(int index) {
00542 _birth_list.push_back(index);
00543 }
00544
00545
00546
00547
00548
00549
00550 void SpriteParticleRenderer::
00551 kill_particle(int) {
00552 }
00553
00554
00555
00556
00557
00558
00559 void SpriteParticleRenderer::
00560 render(pvector< PT(PhysicsObject) >& po_vector, int ttl_particles) {
00561 PStatTimer t1(_render_collector);
00562
00563 if (_anims.empty()) {
00564 return;
00565 }
00566
00567 BaseParticle *cur_particle;
00568 int remaining_particles = ttl_particles;
00569 int i,j;
00570 int anim_count = _anims.size();
00571 int frame;
00572
00573 if (_animate_frames || anim_count) {
00574 if (!_birth_list.empty()) {
00575 for (vector_int::iterator vIter = _birth_list.begin(); vIter != _birth_list.end(); ++vIter) {
00576 cur_particle = (BaseParticle*)po_vector[*vIter].p();
00577 i = int(NORMALIZED_RAND()*anim_count);
00578
00579
00580 cur_particle->set_index(i < anim_count?i:i-1);
00581
00582
00583
00584
00585
00586
00587 if (_animate_frames) {
00588 cur_particle->set_age(cur_particle->get_age()+i/10.0*cur_particle->get_lifespan());
00589 }
00590 }
00591 }
00592 }
00593 _birth_list.clear();
00594
00595
00596
00597
00598 for (i = 0; i < anim_count; ++i) {
00599 for (j = 0; j < _anim_size[i]; ++j) {
00600
00601 memset(_ttl_count[i], 0, _anim_size[i]*sizeof(int));
00602 _sprite_writer[i][j].vertex = GeomVertexWriter(_vdata[i][j], InternalName::get_vertex());
00603 _sprite_writer[i][j].color = GeomVertexWriter(_vdata[i][j], InternalName::get_color());
00604 _sprite_writer[i][j].rotate = GeomVertexWriter(_vdata[i][j], InternalName::get_rotate());
00605 _sprite_writer[i][j].size = GeomVertexWriter(_vdata[i][j], InternalName::get_size());
00606 _sprite_writer[i][j].aspect_ratio = GeomVertexWriter(_vdata[i][j], InternalName::get_aspect_ratio());
00607 }
00608 }
00609
00610
00611 _aabb_min.set(99999.0f, 99999.0f, 99999.0f);
00612 _aabb_max.set(-99999.0f, -99999.0f, -99999.0f);
00613
00614
00615 for (i = 0; i < (int)po_vector.size(); i++) {
00616 cur_particle = (BaseParticle *) po_vector[i].p();
00617
00618 if (!cur_particle->get_alive()) {
00619 continue;
00620 }
00621
00622 LPoint3 position = cur_particle->get_position();
00623
00624
00625 if (position[0] > _aabb_max[0])
00626 _aabb_max[0] = position[0];
00627 else if (position[0] < _aabb_min[0])
00628 _aabb_min[0] = position[0];
00629
00630
00631 if (position[1] > _aabb_max[1])
00632 _aabb_max[1] = position[1];
00633 else if (position[1] < _aabb_min[1])
00634 _aabb_min[1] = position[1];
00635
00636
00637 if (position[2] > _aabb_max[2])
00638 _aabb_max[2] = position[2];
00639 else if (position[2] < _aabb_min[2])
00640 _aabb_min[2] = position[2];
00641
00642
00643 PN_stdfloat t = cur_particle->get_parameterized_age();
00644 int anim_index = cur_particle->get_index();
00645
00646
00647
00648 if(_animation_removed && (anim_index >= anim_count)) {
00649 anim_index = int(NORMALIZED_RAND()*anim_count);
00650 anim_index = anim_index<anim_count?anim_index:anim_index-1;
00651 cur_particle->set_index(anim_index);
00652 }
00653
00654
00655 if (_animate_frames) {
00656 if (_animate_frames_rate == 0.0f) {
00657 frame = (int)(t*_anim_size[anim_index]);
00658 } else {
00659 frame = (int)fmod(cur_particle->get_age()*_animate_frames_rate+1,_anim_size[anim_index]);
00660 }
00661 } else {
00662 frame = _animate_frames_index;
00663 }
00664
00665
00666 frame = (frame < _anim_size[anim_index]) ? frame : (_anim_size[anim_index]-1);
00667 ++_ttl_count[anim_index][frame];
00668
00669
00670
00671 LColor c = _color_interpolation_manager->generateColor(t);
00672
00673 int alphamode=get_alpha_mode();
00674 if (alphamode != PR_ALPHA_NONE) {
00675 if (alphamode == PR_ALPHA_OUT)
00676 c[3] *= (1.0f - t) * get_user_alpha();
00677 else if (alphamode == PR_ALPHA_IN)
00678 c[3] *= t * get_user_alpha();
00679 else if (alphamode == PR_ALPHA_IN_OUT) {
00680 c[3] *= 2.0f * min(t, 1.0f - t) * get_user_alpha();
00681 }
00682 else {
00683 assert(alphamode == PR_ALPHA_USER);
00684 c[3] *= get_user_alpha();
00685 }
00686 }
00687
00688
00689 _sprite_writer[anim_index][frame].vertex.add_data3(position);
00690 _sprite_writer[anim_index][frame].color.add_data4(c);
00691
00692 PN_stdfloat current_x_scale = _initial_x_scale;
00693 PN_stdfloat current_y_scale = _initial_y_scale;
00694
00695 if (_animate_x_ratio || _animate_y_ratio) {
00696 if (_blend_method == PP_BLEND_CUBIC) {
00697 t = CUBIC_T(t);
00698 }
00699
00700 if (_animate_x_ratio) {
00701 current_x_scale = (_initial_x_scale +
00702 (t * (_final_x_scale - _initial_x_scale)));
00703 }
00704 if (_animate_y_ratio) {
00705 current_y_scale = (_initial_y_scale +
00706 (t * (_final_y_scale - _initial_y_scale)));
00707 }
00708 }
00709
00710 if (_sprite_writer[anim_index][frame].size.has_column()) {
00711 _sprite_writer[anim_index][frame].size.add_data1f(current_y_scale * _height);
00712 }
00713 if (_sprite_writer[anim_index][frame].aspect_ratio.has_column()) {
00714 _sprite_writer[anim_index][frame].aspect_ratio.add_data1f(_aspect_ratio * current_x_scale / current_y_scale);
00715 }
00716 if (_animate_theta) {
00717 _sprite_writer[anim_index][frame].rotate.add_data1f(cur_particle->get_theta());
00718 } else if (_sprite_writer[anim_index][frame].rotate.has_column()) {
00719 _sprite_writer[anim_index][frame].rotate.add_data1f(_theta);
00720 }
00721
00722
00723 remaining_particles--;
00724 if (remaining_particles == 0) {
00725 break;
00726 }
00727 }
00728 int n = 0;
00729 GeomNode *render_node = get_render_node();
00730
00731 for (i = 0; i < anim_count; ++i) {
00732 for (j = 0; j < _anim_size[i]; ++j) {
00733 _sprites[i][j]->clear_vertices();
00734 _sprite_writer[i][j].clear();
00735
00736
00737
00738
00739 _sprite_primitive[i][j]->set_primitive(0, _sprites[i][j]);
00740 _sprite_primitive[i][j]->set_vertex_data(_vdata[i][j]);
00741
00742 render_node->set_geom(n, _sprite_primitive[i][j]);
00743 ++n;
00744 }
00745 }
00746
00747 if (_animate_frames) {
00748 for (i = 0; i < anim_count; ++i) {
00749 for (j = 0; j < _anim_size[i]; ++j) {
00750 _sprites[i][j]->add_next_vertices(_ttl_count[i][j]);
00751 }
00752 }
00753 } else {
00754 for (i = 0; i < anim_count; ++i) {
00755 _sprites[i][_animate_frames_index]->add_next_vertices(_ttl_count[i][_animate_frames_index]);
00756 }
00757 }
00758
00759
00760 LPoint3 aabb_center = _aabb_min + ((_aabb_max - _aabb_min) * 0.5f);
00761 PN_stdfloat radius = (aabb_center - _aabb_min).length();
00762
00763 for (i = 0; i < anim_count; ++i) {
00764 for (j = 0; j < _anim_size[i]; ++j) {
00765 nassertv(_sprite_primitive[i][j]->check_valid());
00766 BoundingSphere sphere(aabb_center, radius);
00767 _sprite_primitive[i][j]->set_bounds(&sphere);
00768 }
00769 }
00770
00771 get_render_node()->mark_internal_bounds_stale();
00772 nassertv(render_node->check_valid());
00773 _animation_removed = false;
00774 }
00775
00776
00777
00778
00779
00780
00781
00782 void SpriteParticleRenderer::
00783 output(ostream &out) const {
00784 #ifndef NDEBUG //[
00785 out<<"SpriteParticleRenderer";
00786 #endif //] NDEBUG
00787 }
00788
00789
00790
00791
00792
00793
00794
00795 void SpriteParticleRenderer::
00796 write(ostream &out, int indent_level) const {
00797 indent(out, indent_level) << "SpriteParticleRenderer:\n";
00798
00799 indent(out, indent_level + 2) << "_color "<<_color<<"\n";
00800 indent(out, indent_level + 2) << "_initial_x_scale "<<_initial_x_scale<<"\n";
00801 indent(out, indent_level + 2) << "_final_x_scale "<<_final_x_scale<<"\n";
00802 indent(out, indent_level + 2) << "_initial_y_scale "<<_initial_y_scale<<"\n";
00803 indent(out, indent_level + 2) << "_final_y_scale "<<_final_y_scale<<"\n";
00804 indent(out, indent_level + 2) << "_theta "<<_theta<<"\n";
00805 indent(out, indent_level + 2) << "_animate_x_ratio "<<_animate_x_ratio<<"\n";
00806 indent(out, indent_level + 2) << "_animate_y_ratio "<<_animate_y_ratio<<"\n";
00807 indent(out, indent_level + 2) << "_animate_theta "<<_animate_theta<<"\n";
00808 indent(out, indent_level + 2) << "_blend_method "<<_blend_method<<"\n";
00809 indent(out, indent_level + 2) << "_aabb_min "<<_aabb_min<<"\n";
00810 indent(out, indent_level + 2) << "_aabb_max "<<_aabb_max<<"\n";
00811 indent(out, indent_level + 2) << "_pool_size "<<_pool_size<<"\n";
00812 BaseParticleRenderer::write(out, indent_level + 2);
00813 }