eggGroup.cxx 40 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509
  1. /**
  2. * PANDA 3D SOFTWARE
  3. * Copyright (c) Carnegie Mellon University. All rights reserved.
  4. *
  5. * All use of this software is subject to the terms of the revised BSD
  6. * license. You should have received a copy of this license along
  7. * with this source code in a file named "LICENSE."
  8. *
  9. * @file eggGroup.cxx
  10. * @author drose
  11. * @date 1999-01-16
  12. */
  13. #include "eggGroup.h"
  14. #include "eggMiscFuncs.h"
  15. #include "eggVertexPool.h"
  16. #include "eggBin.h"
  17. #include "lexerDefs.h"
  18. #include "indent.h"
  19. #include "string_utils.h"
  20. #include "lmatrix.h"
  21. #include "dcast.h"
  22. using std::ostream;
  23. using std::string;
  24. TypeHandle EggGroup::_type_handle;
  25. /**
  26. *
  27. */
  28. EggGroup::
  29. EggGroup(const string &name) : EggGroupNode(name) {
  30. _flags = 0;
  31. _flags2 = 0;
  32. _fps = 0.0;
  33. _blend_mode = BM_unspecified;
  34. _blend_operand_a = BO_unspecified;
  35. _blend_operand_b = BO_unspecified;
  36. _blend_color = LColor::zero();
  37. _u_speed = 0;
  38. _v_speed = 0;
  39. _w_speed = 0;
  40. _r_speed = 0;
  41. }
  42. /**
  43. *
  44. */
  45. EggGroup::
  46. EggGroup(const EggGroup &copy) {
  47. (*this) = copy;
  48. }
  49. /**
  50. *
  51. */
  52. EggGroup &EggGroup::
  53. operator = (const EggGroup &copy) {
  54. EggTransform::operator = (copy);
  55. _flags = copy._flags;
  56. _flags2 = copy._flags2;
  57. _collide_mask = copy._collide_mask;
  58. _from_collide_mask = copy._from_collide_mask;
  59. _into_collide_mask = copy._into_collide_mask;
  60. _billboard_center = copy._billboard_center;
  61. _object_types = copy._object_types;
  62. _collision_name = copy._collision_name;
  63. _fps = copy._fps;
  64. _lod = copy._lod;
  65. _blend_mode = copy._blend_mode;
  66. _blend_operand_a = copy._blend_operand_a;
  67. _blend_operand_b = copy._blend_operand_b;
  68. _blend_color = copy._blend_color;
  69. _tag_data = copy._tag_data;
  70. _u_speed = copy._u_speed;
  71. _v_speed = copy._v_speed;
  72. _w_speed = copy._w_speed;
  73. _r_speed = copy._r_speed;
  74. _default_pose = copy._default_pose;
  75. unref_all_vertices();
  76. _vref = copy._vref;
  77. // We must walk through the vertex ref list, and flag each vertex as now
  78. // reffed by this group.
  79. VertexRef::iterator vri;
  80. for (vri = _vref.begin(); vri != _vref.end(); ++vri) {
  81. EggVertex *vert = (*vri).first;
  82. bool inserted = vert->_gref.insert(this).second;
  83. // Did the group not exist previously in the vertex's gref list? If it
  84. // was there already, we must be out of sync between vertices and groups.
  85. nassertr(inserted, *this);
  86. }
  87. // These must be down here, because the EggNode assignment operator will
  88. // force an update_under(). Therefore, we can't call it until all the
  89. // attributes that affect adjust_under() are in place.
  90. EggGroupNode::operator = (copy);
  91. EggRenderMode::operator = (copy);
  92. return *this;
  93. }
  94. /**
  95. *
  96. */
  97. EggGroup::
  98. ~EggGroup() {
  99. unref_all_vertices();
  100. }
  101. /**
  102. *
  103. */
  104. void EggGroup::
  105. set_group_type(GroupType type) {
  106. if (type != get_group_type()) {
  107. #ifndef NDEBUG
  108. if (type != GT_instance) {
  109. // Only valid to change to a non-instance type if we have no group refs.
  110. nassertv(_group_refs.empty());
  111. }
  112. #endif
  113. // Make sure the user didn't give us any stray bits.
  114. nassertv((type & ~F_group_type)==0);
  115. _flags = (_flags & ~F_group_type) | type;
  116. // Now we might have changed the type to or from an instance node, so we
  117. // have to recompute the under_flags.
  118. update_under(0);
  119. }
  120. }
  121. /**
  122. * Returns true if the indicated object type has been added to the group, or
  123. * false otherwise.
  124. */
  125. bool EggGroup::
  126. has_object_type(const string &object_type) const {
  127. vector_string::const_iterator oi;
  128. for (oi = _object_types.begin(); oi != _object_types.end(); ++oi) {
  129. if (cmp_nocase_uh((*oi), object_type) == 0) {
  130. return true;
  131. }
  132. }
  133. return false;
  134. }
  135. /**
  136. * Removes the first instance of the indicated object type from the group if
  137. * it is present. Returns true if the object type was found and removed,
  138. * false otherwise.
  139. */
  140. bool EggGroup::
  141. remove_object_type(const string &object_type) {
  142. vector_string::iterator oi;
  143. for (oi = _object_types.begin(); oi != _object_types.end(); ++oi) {
  144. if (cmp_nocase_uh((*oi), object_type) == 0) {
  145. _object_types.erase(oi);
  146. return true;
  147. }
  148. }
  149. return false;
  150. }
  151. /**
  152. * Writes the group and all of its children to the indicated output stream in
  153. * Egg format.
  154. */
  155. void EggGroup::
  156. write(ostream &out, int indent_level) const {
  157. test_under_integrity();
  158. switch (get_group_type()) {
  159. case GT_group:
  160. write_header(out, indent_level, "<Group>");
  161. break;
  162. case GT_instance:
  163. write_header(out, indent_level, "<Instance>");
  164. break;
  165. case GT_joint:
  166. write_header(out, indent_level, "<Joint>");
  167. break;
  168. default:
  169. // invalid group type
  170. nassert_raise("invalid EggGroup type");
  171. return;
  172. }
  173. if (is_of_type(EggBin::get_class_type())) {
  174. indent(out, indent_level + 2)
  175. << "// Bin " << DCAST(EggBin, this)->get_bin_number() << "\n";
  176. }
  177. if (has_lod()) {
  178. get_lod().write(out, indent_level + 2);
  179. }
  180. write_billboard_flags(out, indent_level + 2);
  181. write_collide_flags(out, indent_level + 2);
  182. write_model_flags(out, indent_level + 2);
  183. write_switch_flags(out, indent_level + 2);
  184. if (has_transform()) {
  185. EggTransform::write(out, indent_level + 2, "<Transform>");
  186. }
  187. if (get_group_type() == GT_joint && _default_pose.has_transform()) {
  188. _default_pose.write(out, indent_level + 2, "<DefaultPose>");
  189. }
  190. if (get_scroll_u() != 0) {
  191. indent(out, indent_level + 2)
  192. << "<Scalar> scroll_u { " << get_scroll_u() << " }\n";
  193. }
  194. if (get_scroll_v() != 0) {
  195. indent(out, indent_level + 2)
  196. << "<Scalar> scroll_v { " << get_scroll_v() << " }\n";
  197. }
  198. if (get_scroll_w() != 0) {
  199. indent(out, indent_level + 2)
  200. << "<Scalar> scroll_w { " << get_scroll_w() << " }\n";
  201. }
  202. if (get_scroll_r() != 0) {
  203. indent(out, indent_level + 2)
  204. << "<Scalar> scroll_r { " << get_scroll_r() << " }\n";
  205. }
  206. write_object_types(out, indent_level + 2);
  207. write_decal_flags(out, indent_level + 2);
  208. write_tags(out, indent_level + 2);
  209. write_render_mode(out, indent_level + 2);
  210. if (get_portal_flag()) {
  211. indent(out, indent_level + 2) << "<Scalar> portal { 1 }\n";
  212. }
  213. if (get_occluder_flag()) {
  214. indent(out, indent_level + 2) << "<Scalar> occluder { 1 }\n";
  215. }
  216. if (get_polylight_flag()) {
  217. indent(out, indent_level + 2) << "<Scalar> polylight { 1 }\n";
  218. }
  219. if (has_indexed_flag()) {
  220. indent(out, indent_level + 2)
  221. << "<Scalar> indexed { " << get_indexed_flag() << " }\n";
  222. }
  223. if (get_blend_mode() != BM_unspecified) {
  224. indent(out, indent_level + 2)
  225. << "<Scalar> blend { " << get_blend_mode() << " }\n";
  226. }
  227. if (get_blend_operand_a() != BO_unspecified) {
  228. indent(out, indent_level + 2)
  229. << "<Scalar> blendop-a { " << get_blend_operand_a() << " }\n";
  230. }
  231. if (get_blend_operand_b() != BO_unspecified) {
  232. indent(out, indent_level + 2)
  233. << "<Scalar> blendop-b { " << get_blend_operand_b() << " }\n";
  234. }
  235. if (has_blend_color()) {
  236. const LColor &c = get_blend_color();
  237. indent(out, indent_level + 2)
  238. << "<Scalar> blendr { " << c[0] << " }\n";
  239. indent(out, indent_level + 2)
  240. << "<Scalar> blendg { " << c[1] << " }\n";
  241. indent(out, indent_level + 2)
  242. << "<Scalar> blendb { " << c[2] << " }\n";
  243. indent(out, indent_level + 2)
  244. << "<Scalar> blenda { " << c[3] << " }\n";
  245. }
  246. GroupRefs::const_iterator gri;
  247. for (gri = _group_refs.begin(); gri != _group_refs.end(); ++gri) {
  248. EggGroup *group_ref = (*gri);
  249. indent(out, indent_level + 2)
  250. << "<Ref> { " << group_ref->get_name() << " }\n";
  251. }
  252. // We have to write the children nodes before we write the vertex
  253. // references, since we might be referencing a vertex that's defined in one
  254. // of those children nodes!
  255. EggGroupNode::write(out, indent_level + 2);
  256. write_vertex_ref(out, indent_level + 2);
  257. indent(out, indent_level) << "}\n";
  258. }
  259. /**
  260. * Writes just the <Billboard> entry and related fields to the indicated
  261. * ostream.
  262. */
  263. void EggGroup::
  264. write_billboard_flags(ostream &out, int indent_level) const {
  265. if (get_billboard_type() != BT_none) {
  266. indent(out, indent_level)
  267. << "<Billboard> { " << get_billboard_type() << " }\n";
  268. }
  269. if (has_billboard_center()) {
  270. indent(out, indent_level)
  271. << "<BillboardCenter> { " << get_billboard_center() << " }\n";
  272. }
  273. }
  274. /**
  275. * Writes just the <Collide> entry and related fields to the indicated
  276. * ostream.
  277. */
  278. void EggGroup::
  279. write_collide_flags(ostream &out, int indent_level) const {
  280. if (get_cs_type() != CST_none) {
  281. indent(out, indent_level) << "<Collide> ";
  282. if (has_collision_name()) {
  283. enquote_string(out, get_collision_name()) << " ";
  284. }
  285. out << "{ " << get_cs_type();
  286. if (get_collide_flags() != CF_none) {
  287. out << " " << get_collide_flags();
  288. }
  289. out << " }\n";
  290. }
  291. if (has_collide_mask()) {
  292. indent(out, indent_level)
  293. << "<Scalar> collide-mask { 0x";
  294. get_collide_mask().output_hex(out, 0);
  295. out << " }\n";
  296. }
  297. if (has_from_collide_mask()) {
  298. indent(out, indent_level)
  299. << "<Scalar> from-collide-mask { 0x";
  300. get_from_collide_mask().output_hex(out, 0);
  301. out << " }\n";
  302. }
  303. if (has_into_collide_mask()) {
  304. indent(out, indent_level)
  305. << "<Scalar> into-collide-mask { 0x";
  306. get_into_collide_mask().output_hex(out, 0);
  307. out << " }\n";
  308. }
  309. }
  310. /**
  311. * Writes the <Model> flag and related flags to the indicated ostream.
  312. */
  313. void EggGroup::
  314. write_model_flags(ostream &out, int indent_level) const {
  315. if (get_dcs_type() != DC_unspecified) {
  316. indent(out, indent_level)
  317. << "<DCS> { " << get_dcs_type() << " }\n";
  318. }
  319. if (get_dart_type() != DT_none) {
  320. indent(out, indent_level)
  321. << "<Dart> { " << get_dart_type() << " }\n";
  322. }
  323. if (get_model_flag()) {
  324. indent(out, indent_level) << "<Model> { 1 }\n";
  325. }
  326. if (get_texlist_flag()) {
  327. indent(out, indent_level) << "<TexList> { 1 }\n";
  328. }
  329. if (get_direct_flag()) {
  330. indent(out, indent_level) << "<Scalar> direct { 1 }\n";
  331. }
  332. }
  333. /**
  334. * Writes the <Switch> flag and related flags to the indicated ostream.
  335. */
  336. void EggGroup::
  337. write_switch_flags(ostream &out, int indent_level) const {
  338. if (get_switch_flag()) {
  339. indent(out, indent_level) << "<Switch> { 1 }\n";
  340. if (get_switch_fps() != 0.0) {
  341. indent(out, indent_level)
  342. << "<Scalar> fps { " << get_switch_fps() << " }\n";
  343. }
  344. }
  345. }
  346. /**
  347. * Writes just the <ObjectTypes> entries, if any, to the indicated ostream.
  348. */
  349. void EggGroup::
  350. write_object_types(ostream &out, int indent_level) const {
  351. vector_string::const_iterator oi;
  352. for (oi = _object_types.begin(); oi != _object_types.end(); ++oi) {
  353. indent(out, indent_level)
  354. << "<ObjectType> { ";
  355. enquote_string(out, (*oi)) << " }\n";
  356. }
  357. }
  358. /**
  359. * Writes the flags related to decaling, if any.
  360. */
  361. void EggGroup::
  362. write_decal_flags(ostream &out, int indent_level) const {
  363. if (get_decal_flag()) {
  364. indent(out, indent_level) << "<Scalar> decal { 1 }\n";
  365. }
  366. }
  367. /**
  368. * Writes just the <Tag> entries, if any, to the indicated ostream.
  369. */
  370. void EggGroup::
  371. write_tags(ostream &out, int indent_level) const {
  372. TagData::const_iterator ti;
  373. for (ti = _tag_data.begin(); ti != _tag_data.end(); ++ti) {
  374. const string &key = (*ti).first;
  375. const string &value = (*ti).second;
  376. indent(out, indent_level) << "<Tag> ";
  377. enquote_string(out, key) << " {\n";
  378. enquote_string(out, value, indent_level + 2) << "\n";
  379. indent(out, indent_level) << "}\n";
  380. }
  381. }
  382. /**
  383. * Writes the flags inherited from EggRenderMode and similar flags that
  384. * control obscure render effects.
  385. */
  386. void EggGroup::
  387. write_render_mode(ostream &out, int indent_level) const {
  388. EggRenderMode::write(out, indent_level);
  389. if (get_nofog_flag()) {
  390. indent(out, indent_level) << "<Scalar> no-fog { 1 }\n";
  391. }
  392. }
  393. /**
  394. * Returns true if this particular node represents a <Joint> entry or not.
  395. * This is a handy thing to know since Joints are sorted to the end of their
  396. * sibling list when writing an egg file. See EggGroupNode::write().
  397. */
  398. bool EggGroup::
  399. is_joint() const {
  400. return (get_group_type() == GT_joint);
  401. }
  402. /**
  403. * Walks back up the hierarchy, looking for an EggGroup or EggPrimitive or
  404. * some such object at this level or above this group that has an alpha_mode
  405. * other than AM_unspecified. Returns a valid EggRenderMode pointer if one is
  406. * found, or NULL otherwise.
  407. */
  408. EggRenderMode *EggGroup::
  409. determine_alpha_mode() {
  410. if (get_alpha_mode() != AM_unspecified) {
  411. return this;
  412. }
  413. return EggGroupNode::determine_alpha_mode();
  414. }
  415. /**
  416. * Walks back up the hierarchy, looking for an EggGroup or EggPrimitive or
  417. * some such object at this level or above this group that has a
  418. * depth_write_mode other than DWM_unspecified. Returns a valid EggRenderMode
  419. * pointer if one is found, or NULL otherwise.
  420. */
  421. EggRenderMode *EggGroup::
  422. determine_depth_write_mode() {
  423. if (get_depth_write_mode() != DWM_unspecified) {
  424. return this;
  425. }
  426. return EggGroupNode::determine_depth_write_mode();
  427. }
  428. /**
  429. * Walks back up the hierarchy, looking for an EggGroup or EggPrimitive or
  430. * some such object at this level or above this group that has a
  431. * depth_test_mode other than DTM_unspecified. Returns a valid EggRenderMode
  432. * pointer if one is found, or NULL otherwise.
  433. */
  434. EggRenderMode *EggGroup::
  435. determine_depth_test_mode() {
  436. if (get_depth_test_mode() != DTM_unspecified) {
  437. return this;
  438. }
  439. return EggGroupNode::determine_depth_test_mode();
  440. }
  441. /**
  442. * Walks back up the hierarchy, looking for an EggGroup or EggPrimitive or
  443. * some such object at this level or above this group that has a
  444. * visibility_mode other than VM_unspecified. Returns a valid EggRenderMode
  445. * pointer if one is found, or NULL otherwise.
  446. */
  447. EggRenderMode *EggGroup::
  448. determine_visibility_mode() {
  449. if (get_visibility_mode() != VM_unspecified) {
  450. return this;
  451. }
  452. return EggGroupNode::determine_visibility_mode();
  453. }
  454. /**
  455. * Walks back up the hierarchy, looking for an EggGroup or EggPrimitive or
  456. * some such object at this level or above this group that has a depth_offset
  457. * specified. Returns a valid EggRenderMode pointer if one is found, or NULL
  458. * otherwise.
  459. */
  460. EggRenderMode *EggGroup::
  461. determine_depth_offset() {
  462. if (has_depth_offset()) {
  463. return this;
  464. }
  465. return EggGroupNode::determine_depth_offset();
  466. }
  467. /**
  468. * Walks back up the hierarchy, looking for an EggGroup or EggPrimitive or
  469. * some such object at this level or above this group that has a draw_order
  470. * specified. Returns a valid EggRenderMode pointer if one is found, or NULL
  471. * otherwise.
  472. */
  473. EggRenderMode *EggGroup::
  474. determine_draw_order() {
  475. if (has_draw_order()) {
  476. return this;
  477. }
  478. return EggGroupNode::determine_draw_order();
  479. }
  480. /**
  481. * Walks back up the hierarchy, looking for an EggGroup or EggPrimitive or
  482. * some such object at this level or above this group that has a bin
  483. * specified. Returns a valid EggRenderMode pointer if one is found, or NULL
  484. * otherwise.
  485. */
  486. EggRenderMode *EggGroup::
  487. determine_bin() {
  488. if (has_bin()) {
  489. return this;
  490. }
  491. return EggGroupNode::determine_bin();
  492. }
  493. /**
  494. * Walks back up the hierarchy, looking for an EggGroup at this level or above
  495. * that has the "indexed" scalar set. Returns the value of the indexed scalar
  496. * if it is found, or false if it is not.
  497. *
  498. * In other words, returns true if the "indexed" flag is in effect for the
  499. * indicated node, false otherwise.
  500. */
  501. bool EggGroup::
  502. determine_indexed() {
  503. if (has_indexed_flag()) {
  504. return get_indexed_flag();
  505. }
  506. return EggGroupNode::determine_indexed();
  507. }
  508. /**
  509. * Walks back up the hierarchy, looking for an EggGroup at this level or above
  510. * that has the "decal" flag set. Returns the value of the decal flag if it
  511. * is found, or false if it is not.
  512. *
  513. * In other words, returns true if the "decal" flag is in effect for the
  514. * indicated node, false otherwise.
  515. */
  516. bool EggGroup::
  517. determine_decal() {
  518. if (get_decal_flag()) {
  519. return true;
  520. }
  521. return EggGroupNode::determine_decal();
  522. }
  523. /**
  524. * Adds the vertex to the set of those referenced by the group, at the
  525. * indicated membership level. If the vertex is already being referenced,
  526. * increases the membership amount by the indicated amount.
  527. */
  528. void EggGroup::
  529. ref_vertex(EggVertex *vert, double membership) {
  530. VertexRef::iterator vri = _vref.find(vert);
  531. if (vri != _vref.end()) {
  532. // The vertex was already being reffed; increment its membership amount.
  533. (*vri).second += membership;
  534. // If that takes us down to zero, go ahead and unref the vertex.
  535. if ((*vri).second == 0.0) {
  536. unref_vertex(vert);
  537. }
  538. } else {
  539. // The vertex was not already reffed; ref it.
  540. if (membership != 0.0) {
  541. _vref[vert] = membership;
  542. bool inserted = vert->_gref.insert(this).second;
  543. // Did the group not exist previously in the vertex's gref list? If it
  544. // was there already, we must be out of sync between vertices and
  545. // groups.
  546. nassertv(inserted);
  547. }
  548. }
  549. }
  550. /**
  551. * Removes the vertex from the set of those referenced by the group. Does
  552. * nothing if the vertex is not already reffed.
  553. */
  554. void EggGroup::
  555. unref_vertex(EggVertex *vert) {
  556. VertexRef::iterator vri = _vref.find(vert);
  557. if (vri != _vref.end()) {
  558. _vref.erase(vri);
  559. int count = vert->_gref.erase(this);
  560. // Did the group exist in the vertex's gref list? If it didn't, we must
  561. // be out of sync between vertices and groups.
  562. nassertv(count == 1);
  563. }
  564. }
  565. /**
  566. * Removes all vertices from the reference list.
  567. */
  568. void EggGroup::
  569. unref_all_vertices() {
  570. // We must walk through the vertex ref list, and flag each vertex as
  571. // unreffed in its own structure.
  572. VertexRef::iterator vri;
  573. for (vri = _vref.begin(); vri != _vref.end(); ++vri) {
  574. EggVertex *vert = (*vri).first;
  575. int count = vert->_gref.erase(this);
  576. // Did the group exist in the vertex's gref list? If it didn't, we must
  577. // be out of sync between vertices and groups.
  578. nassertv(count == 1);
  579. }
  580. _vref.clear();
  581. }
  582. /**
  583. * Returns the amount of membership of the indicated vertex in this group. If
  584. * the vertex is not reffed by the group, returns 0.
  585. */
  586. double EggGroup::
  587. get_vertex_membership(const EggVertex *vert) const {
  588. VertexRef::const_iterator vri = _vref.find((EggVertex *)vert);
  589. if (vri != _vref.end()) {
  590. return (*vri).second;
  591. } else {
  592. return 0.0;
  593. }
  594. }
  595. /**
  596. * Explicitly sets the net membership of the indicated vertex in this group to
  597. * the given value.
  598. */
  599. void EggGroup::
  600. set_vertex_membership(EggVertex *vert, double membership) {
  601. if (membership == 0.0) {
  602. unref_vertex(vert);
  603. return;
  604. }
  605. VertexRef::iterator vri = _vref.find(vert);
  606. if (vri != _vref.end()) {
  607. // The vertex was already being reffed; just change its membership amount.
  608. (*vri).second = membership;
  609. } else {
  610. // The vertex was not already reffed; ref it.
  611. _vref[vert] = membership;
  612. bool inserted = vert->_gref.insert(this).second;
  613. // Did the group not exist previously in the vertex's gref list? If it
  614. // was there already, we must be out of sync between vertices and groups.
  615. nassertv(inserted);
  616. }
  617. }
  618. /**
  619. * Moves all of the vertex references from the indicated other group into this
  620. * one. If a given vertex was previously shared by both groups, the relative
  621. * memberships will be summed.
  622. */
  623. void EggGroup::
  624. steal_vrefs(EggGroup *other) {
  625. nassertv(other != this);
  626. VertexRef::const_iterator vri;
  627. for (vri = other->vref_begin(); vri != other->vref_end(); ++vri) {
  628. EggVertex *vert = (*vri).first;
  629. double membership = (*vri).second;
  630. ref_vertex(vert, membership);
  631. }
  632. other->unref_all_vertices();
  633. }
  634. #ifdef _DEBUG
  635. /**
  636. * Verifies that each vertex in the group exists and that it knows it is
  637. * referenced by the group.
  638. */
  639. void EggGroup::
  640. test_vref_integrity() const {
  641. test_ref_count_integrity();
  642. VertexRef::const_iterator vri;
  643. for (vri = vref_begin(); vri != vref_end(); ++vri) {
  644. const EggVertex *vert = (*vri).first;
  645. vert->test_ref_count_integrity();
  646. nassertv(vert->has_gref(this));
  647. }
  648. }
  649. #endif // _DEBUG
  650. /**
  651. * Adds a new <Ref> entry to the group. This declares an internal reference
  652. * to another node, and is used to implement scene-graph instancing; it is
  653. * only valid if the group_type is GT_instance.
  654. */
  655. void EggGroup::
  656. add_group_ref(EggGroup *group) {
  657. nassertv(get_group_type() == GT_instance);
  658. _group_refs.push_back(group);
  659. }
  660. /**
  661. * Returns the number of <Ref> entries within this group. See
  662. * add_group_ref().
  663. */
  664. int EggGroup::
  665. get_num_group_refs() const {
  666. return _group_refs.size();
  667. }
  668. /**
  669. * Returns the nth <Ref> entry within this group. See add_group_ref().
  670. */
  671. EggGroup *EggGroup::
  672. get_group_ref(int n) const {
  673. nassertr(n >= 0 && n < (int)_group_refs.size(), nullptr);
  674. return _group_refs[n];
  675. }
  676. /**
  677. * Removes the nth <Ref> entry within this group. See add_group_ref().
  678. */
  679. void EggGroup::
  680. remove_group_ref(int n) {
  681. nassertv(n >= 0 && n < (int)_group_refs.size());
  682. _group_refs.erase(_group_refs.begin() + n);
  683. }
  684. /**
  685. * Removes all of the <Ref> entries within this group. See add_group_ref().
  686. */
  687. void EggGroup::
  688. clear_group_refs() {
  689. _group_refs.clear();
  690. }
  691. /**
  692. * Returns the GroupType value associated with the given string
  693. * representation, or GT_invalid if the string does not match any known
  694. * GroupType value.
  695. */
  696. EggGroup::GroupType EggGroup::
  697. string_group_type(const string &strval) {
  698. if (cmp_nocase_uh(strval, "group") == 0) {
  699. return GT_group;
  700. } else if (cmp_nocase_uh(strval, "instance") == 0) {
  701. return GT_instance;
  702. } else if (cmp_nocase_uh(strval, "joint") == 0) {
  703. return GT_joint;
  704. } else {
  705. return GT_invalid;
  706. }
  707. }
  708. /**
  709. * Returns the DartType value associated with the given string representation,
  710. * or DT_none if the string does not match any known DartType value.
  711. */
  712. EggGroup::DartType EggGroup::
  713. string_dart_type(const string &strval) {
  714. if (cmp_nocase_uh(strval, "sync") == 0) {
  715. return DT_sync;
  716. } else if (cmp_nocase_uh(strval, "nosync") == 0) {
  717. return DT_nosync;
  718. } else if (cmp_nocase_uh(strval, "default") == 0) {
  719. return DT_default;
  720. } else if (cmp_nocase_uh(strval, "structured") == 0) {
  721. return DT_structured;
  722. } else {
  723. return DT_none;
  724. }
  725. }
  726. /**
  727. * Returns the DCSType value associated with the given string representation,
  728. * or DC_unspecified if the string does not match any known DCSType value.
  729. */
  730. EggGroup::DCSType EggGroup::
  731. string_dcs_type(const string &strval) {
  732. if (cmp_nocase_uh(strval, "none") == 0) {
  733. return DC_none;
  734. } else if (cmp_nocase_uh(strval, "local") == 0) {
  735. return DC_local;
  736. } else if (cmp_nocase_uh(strval, "net") == 0) {
  737. return DC_net;
  738. } else if (cmp_nocase_uh(strval, "no_touch") == 0) {
  739. return DC_no_touch;
  740. } else if (cmp_nocase_uh(strval, "default") == 0) {
  741. return DC_default;
  742. } else {
  743. return DC_unspecified;
  744. }
  745. }
  746. /**
  747. * Returns the BillboardType value associated with the given string
  748. * representation, or BT_none if the string does not match any known
  749. * BillboardType value.
  750. */
  751. EggGroup::BillboardType EggGroup::
  752. string_billboard_type(const string &strval) {
  753. if (cmp_nocase_uh(strval, "axis") == 0) {
  754. return BT_axis;
  755. } else if (cmp_nocase_uh(strval, "point_eye") == 0) {
  756. return BT_point_camera_relative;
  757. } else if (cmp_nocase_uh(strval, "point_world") == 0) {
  758. return BT_point_world_relative;
  759. } else if (cmp_nocase_uh(strval, "point") == 0) {
  760. return BT_point_world_relative;
  761. } else {
  762. return BT_none;
  763. }
  764. }
  765. /**
  766. * Returns the CollisionSolidType value associated with the given string
  767. * representation, or CST_none if the string does not match any known
  768. * CollisionSolidType value.
  769. */
  770. EggGroup::CollisionSolidType EggGroup::
  771. string_cs_type(const string &strval) {
  772. if (cmp_nocase_uh(strval, "plane") == 0) {
  773. return CST_plane;
  774. } else if (cmp_nocase_uh(strval, "polygon") == 0) {
  775. return CST_polygon;
  776. } else if (cmp_nocase_uh(strval, "polyset") == 0) {
  777. return CST_polyset;
  778. } else if (cmp_nocase_uh(strval, "sphere") == 0) {
  779. return CST_sphere;
  780. } else if (cmp_nocase_uh(strval, "box") == 0) {
  781. return CST_box;
  782. } else if (cmp_nocase_uh(strval, "inv-sphere") == 0 ||
  783. cmp_nocase_uh(strval, "invsphere") == 0) {
  784. return CST_inv_sphere;
  785. } else if (cmp_nocase_uh(strval, "tube") == 0) {
  786. return CST_tube;
  787. } else if (cmp_nocase_uh(strval, "floor-mesh") == 0 ||
  788. cmp_nocase_uh(strval, "floormesh") == 0) {
  789. return CST_floor_mesh;
  790. } else {
  791. return CST_none;
  792. }
  793. }
  794. /**
  795. * Returns the CollideFlags value associated with the given string
  796. * representation, or CF_none if the string does not match any known
  797. * CollideFlags value. This only recognizes a single keyword; it does not
  798. * attempt to parse a string of keywords.
  799. */
  800. EggGroup::CollideFlags EggGroup::
  801. string_collide_flags(const string &strval) {
  802. if (cmp_nocase_uh(strval, "intangible") == 0) {
  803. return CF_intangible;
  804. } else if (cmp_nocase_uh(strval, "event") == 0) {
  805. return CF_event;
  806. } else if (cmp_nocase_uh(strval, "descend") == 0) {
  807. return CF_descend;
  808. } else if (cmp_nocase_uh(strval, "keep") == 0) {
  809. return CF_keep;
  810. } else if (cmp_nocase_uh(strval, "solid") == 0) {
  811. return CF_solid;
  812. } else if (cmp_nocase_uh(strval, "center") == 0) {
  813. return CF_center;
  814. } else if (cmp_nocase_uh(strval, "turnstile") == 0) {
  815. return CF_turnstile;
  816. } else if (cmp_nocase_uh(strval, "level") == 0) {
  817. return CF_level;
  818. } else {
  819. return CF_none;
  820. }
  821. }
  822. /**
  823. * Returns the BlendMode value associated with the given string
  824. * representation, or BM_none if the string does not match any known
  825. * BlendMode.
  826. */
  827. EggGroup::BlendMode EggGroup::
  828. string_blend_mode(const string &strval) {
  829. if (cmp_nocase_uh(strval, "none") == 0) {
  830. return BM_none;
  831. } else if (cmp_nocase_uh(strval, "add") == 0) {
  832. return BM_add;
  833. } else if (cmp_nocase_uh(strval, "subtract") == 0) {
  834. return BM_subtract;
  835. } else if (cmp_nocase_uh(strval, "inv_subtract") == 0) {
  836. return BM_inv_subtract;
  837. } else if (cmp_nocase_uh(strval, "min") == 0) {
  838. return BM_min;
  839. } else if (cmp_nocase_uh(strval, "max") == 0) {
  840. return BM_max;
  841. } else {
  842. return BM_unspecified;
  843. }
  844. }
  845. /**
  846. * Returns the BlendOperand value associated with the given string
  847. * representation, or BO_none if the string does not match any known
  848. * BlendOperand.
  849. */
  850. EggGroup::BlendOperand EggGroup::
  851. string_blend_operand(const string &strval) {
  852. if (cmp_nocase_uh(strval, "zero") == 0) {
  853. return BO_zero;
  854. } else if (cmp_nocase_uh(strval, "one") == 0) {
  855. return BO_one;
  856. } else if (cmp_nocase_uh(strval, "incoming_color") == 0) {
  857. return BO_incoming_color;
  858. } else if (cmp_nocase_uh(strval, "one_minus_incoming_color") == 0) {
  859. return BO_one_minus_incoming_color;
  860. } else if (cmp_nocase_uh(strval, "fbuffer_color") == 0) {
  861. return BO_fbuffer_color;
  862. } else if (cmp_nocase_uh(strval, "one_minus_fbuffer_color") == 0) {
  863. return BO_one_minus_fbuffer_color;
  864. } else if (cmp_nocase_uh(strval, "incoming_alpha") == 0) {
  865. return BO_incoming_alpha;
  866. } else if (cmp_nocase_uh(strval, "one_minus_incoming_alpha") == 0) {
  867. return BO_one_minus_incoming_alpha;
  868. } else if (cmp_nocase_uh(strval, "fbuffer_alpha") == 0) {
  869. return BO_fbuffer_alpha;
  870. } else if (cmp_nocase_uh(strval, "one_minus_fbuffer_alpha") == 0) {
  871. return BO_one_minus_fbuffer_alpha;
  872. } else if (cmp_nocase_uh(strval, "constant_color") == 0) {
  873. return BO_constant_color;
  874. } else if (cmp_nocase_uh(strval, "one_minus_constant_color") == 0) {
  875. return BO_one_minus_constant_color;
  876. } else if (cmp_nocase_uh(strval, "constant_alpha") == 0) {
  877. return BO_constant_alpha;
  878. } else if (cmp_nocase_uh(strval, "one_minus_constant_alpha") == 0) {
  879. return BO_one_minus_constant_alpha;
  880. } else if (cmp_nocase_uh(strval, "incoming_color_saturate") == 0) {
  881. return BO_incoming_color_saturate;
  882. } else if (cmp_nocase_uh(strval, "color_scale") == 0) {
  883. return BO_color_scale;
  884. } else if (cmp_nocase_uh(strval, "one_minus_color_scale") == 0) {
  885. return BO_one_minus_color_scale;
  886. } else if (cmp_nocase_uh(strval, "alpha_scale") == 0) {
  887. return BO_alpha_scale;
  888. } else if (cmp_nocase_uh(strval, "one_minus_alpha_scale") == 0) {
  889. return BO_one_minus_alpha_scale;
  890. } else {
  891. return BO_unspecified;
  892. }
  893. }
  894. /**
  895. * Returns this object cross-cast to an EggTransform pointer, if it inherits
  896. * from EggTransform, or NULL if it does not.
  897. */
  898. EggTransform *EggGroup::
  899. as_transform() {
  900. return this;
  901. }
  902. /**
  903. * Writes out the vertex ref component of the group body only. This may
  904. * consist of a number of <VertexRef> entries, each with its own membership
  905. * value.
  906. */
  907. void EggGroup::
  908. write_vertex_ref(ostream &out, int indent_level) const {
  909. // We want to put the vertices together into groups first by vertex pool,
  910. // then by membership value. Each of these groups becomes a separate
  911. // VertexRef entry. Within each group, we'll sort the vertices by index
  912. // number.
  913. typedef pset<int> Indices;
  914. typedef pmap<double, Indices> Memberships;
  915. typedef pmap<EggVertexPool *, Memberships> Pools;
  916. Pools _entries;
  917. bool all_membership_one = true;
  918. VertexRef::const_iterator vri;
  919. for (vri = _vref.begin(); vri != _vref.end(); ++vri) {
  920. EggVertex *vert = (*vri).first;
  921. double membership = (*vri).second;
  922. if (membership != 1.0) {
  923. all_membership_one = false;
  924. }
  925. _entries[vert->get_pool()][membership].insert(vert->get_index());
  926. }
  927. // Now that we've reordered them, we can simply traverse the entries and
  928. // write them out.
  929. Pools::const_iterator pi;
  930. for (pi = _entries.begin(); pi != _entries.end(); ++pi) {
  931. EggVertexPool *pool = (*pi).first;
  932. const Memberships &memberships = (*pi).second;
  933. Memberships::const_iterator mi;
  934. for (mi = memberships.begin(); mi != memberships.end(); ++mi) {
  935. double membership = (*mi).first;
  936. const Indices &indices = (*mi).second;
  937. indent(out, indent_level)
  938. << "<VertexRef> {\n";
  939. write_long_list(out, indent_level+2, indices.begin(), indices.end(),
  940. "", "", 72);
  941. // If all vrefs in this group have membership of 1, don't bother to
  942. // write out the membership scalar.
  943. if (!all_membership_one) {
  944. indent(out, indent_level + 2)
  945. << "<Scalar> membership { " << membership << " }\n";
  946. }
  947. if (pool == nullptr) {
  948. indent(out, indent_level + 2)
  949. << "// Invalid NULL vertex pool.\n";
  950. } else {
  951. indent(out, indent_level + 2)
  952. << "<Ref> { " << pool->get_name() << " }\n";
  953. }
  954. indent(out, indent_level)
  955. << "}\n";
  956. }
  957. }
  958. }
  959. /**
  960. * This function is called within parse_egg(). It should call the appropriate
  961. * function on the lexer to initialize the parser into the state associated
  962. * with this object. If the object cannot be parsed into directly, it should
  963. * return false.
  964. */
  965. bool EggGroup::
  966. egg_start_parse_body() {
  967. egg_start_group_body();
  968. return true;
  969. }
  970. /**
  971. * This is called within update_under() after all the various under settings
  972. * have been inherited directly from the parent node. It is responsible for
  973. * adjusting these settings to reflect states local to the current node; for
  974. * instance, an <Instance> node will force the UF_under_instance bit on.
  975. */
  976. void EggGroup::
  977. adjust_under() {
  978. // If we have our own transform, it carries forward.
  979. // As of 41801, this now also affects the local_coord flag, below. This
  980. // means that a <Transform> entry within an <Instance> node transforms the
  981. // instance itself.
  982. if (has_transform()) {
  983. _under_flags |= UF_under_transform;
  984. // Our own transform also affects our node frame.
  985. _node_frame =
  986. new MatrixFrame(get_transform3d() * get_node_frame());
  987. // To prevent trying to invert a sigular matrix
  988. LMatrix4d mat;
  989. bool invert_ok = mat.invert_from(get_node_frame());
  990. if (invert_ok) {
  991. _node_frame_inv =
  992. new MatrixFrame(mat);
  993. } else {
  994. _node_frame_inv = nullptr;
  995. }
  996. _vertex_to_node =
  997. new MatrixFrame(get_vertex_frame() * get_node_frame_inv());
  998. _node_to_vertex =
  999. new MatrixFrame(get_node_frame() * get_vertex_frame_inv());
  1000. }
  1001. if (is_instance_type()) {
  1002. _under_flags |= UF_under_instance;
  1003. if (_under_flags & UF_under_transform) {
  1004. // If we've reached an instance node and we're under a transform, that
  1005. // means we've just defined a local coordinate system.
  1006. _under_flags |= UF_local_coord;
  1007. }
  1008. // An instance node means that from this point and below, vertices are
  1009. // defined relative to this node. Thus, the node frame becomes the vertex
  1010. // frame.
  1011. _vertex_frame = _node_frame;
  1012. _vertex_frame_inv = _node_frame_inv;
  1013. _vertex_to_node = nullptr;
  1014. _node_to_vertex = nullptr;
  1015. }
  1016. }
  1017. /**
  1018. * This is called from within the egg code by transform(). It applies a
  1019. * transformation matrix to the current node in some sensible way, then
  1020. * continues down the tree.
  1021. *
  1022. * The first matrix is the transformation to apply; the second is its inverse.
  1023. * The third parameter is the coordinate system we are changing to, or
  1024. * CS_default if we are not changing coordinate systems.
  1025. */
  1026. void EggGroup::
  1027. r_transform(const LMatrix4d &mat, const LMatrix4d &inv,
  1028. CoordinateSystem to_cs) {
  1029. if (has_transform() || get_group_type() == GT_joint) {
  1030. // Since we want to apply this transform to all matrices, including nested
  1031. // matrices, we can't simply premult it in and leave it, because that
  1032. // would leave the rotational component in the scene graph's matrix, and
  1033. // all nested matrices would inherit the same rotational component. So we
  1034. // have to premult and then postmult by the inverse to undo the rotational
  1035. // component each time.
  1036. LMatrix4d mat1 = mat;
  1037. LMatrix4d inv1 = inv;
  1038. // If we have a translation component, we should only apply it to the top
  1039. // matrix. All subsequent matrices get just the rotational component.
  1040. mat1.set_row(3, LVector3d(0.0, 0.0, 0.0));
  1041. inv1.set_row(3, LVector3d(0.0, 0.0, 0.0));
  1042. internal_set_transform(inv1 * get_transform3d() * mat);
  1043. if (_default_pose.has_transform()) {
  1044. LMatrix4d t = _default_pose.get_transform3d();
  1045. _default_pose.clear_transform();
  1046. _default_pose.add_matrix4(inv1 * t * mat);
  1047. }
  1048. EggGroupNode::r_transform(mat1, inv1, to_cs);
  1049. } else {
  1050. EggGroupNode::r_transform(mat, inv, to_cs);
  1051. }
  1052. // Convert the LOD description too.
  1053. if (has_lod()) {
  1054. _lod->transform(mat);
  1055. }
  1056. if (has_billboard_center()) {
  1057. _billboard_center = _billboard_center * mat;
  1058. }
  1059. }
  1060. /**
  1061. * The recursive implementation of flatten_transforms().
  1062. */
  1063. void EggGroup::
  1064. r_flatten_transforms() {
  1065. EggGroupNode::r_flatten_transforms();
  1066. if (is_local_coord()) {
  1067. LMatrix4d mat = get_vertex_frame();
  1068. if (has_lod()) {
  1069. _lod->transform(mat);
  1070. }
  1071. if (get_billboard_type() != BT_none && !has_billboard_center()) {
  1072. // If we had a billboard without an explicit center, it was an implicit
  1073. // instance. Now it's not any more.
  1074. set_billboard_center(LPoint3d(0.0, 0.0, 0.0) * mat);
  1075. } else if (has_billboard_center()) {
  1076. _billboard_center = _billboard_center * mat;
  1077. }
  1078. }
  1079. if (get_group_type() == GT_instance) {
  1080. set_group_type(GT_group);
  1081. }
  1082. if (get_group_type() != GT_joint) {
  1083. internal_clear_transform();
  1084. }
  1085. }
  1086. /**
  1087. * This virtual method is inherited by EggTransform3d; it is called whenever
  1088. * the transform is changed.
  1089. */
  1090. void EggGroup::
  1091. transform_changed() {
  1092. // Recompute all of the cached transforms at this node and below. We should
  1093. // probably make this smarter and do lazy evaluation of these transforms,
  1094. // rather than having to recompute the whole tree with every change to a
  1095. // parent node's transform.
  1096. update_under(0);
  1097. }
  1098. /**
  1099. *
  1100. */
  1101. ostream &operator << (ostream &out, EggGroup::GroupType t) {
  1102. switch (t) {
  1103. case EggGroup::GT_invalid:
  1104. return out << "invalid group";
  1105. case EggGroup::GT_group:
  1106. return out << "group";
  1107. case EggGroup::GT_instance:
  1108. return out << "instance";
  1109. case EggGroup::GT_joint:
  1110. return out << "joint";
  1111. }
  1112. nassertr(false, out);
  1113. return out << "(**invalid**)";
  1114. }
  1115. /**
  1116. *
  1117. */
  1118. ostream &operator << (ostream &out, EggGroup::DartType t) {
  1119. switch (t) {
  1120. case EggGroup::DT_none:
  1121. return out << "none";
  1122. case EggGroup::DT_sync:
  1123. return out << "sync";
  1124. case EggGroup::DT_nosync:
  1125. return out << "nosync";
  1126. case EggGroup::DT_structured:
  1127. return out << "structured";
  1128. case EggGroup::DT_default:
  1129. return out << "1";
  1130. }
  1131. nassertr(false, out);
  1132. return out << "(**invalid**)";
  1133. }
  1134. /**
  1135. *
  1136. */
  1137. ostream &operator << (ostream &out, EggGroup::DCSType t) {
  1138. switch (t) {
  1139. case EggGroup::DC_unspecified:
  1140. return out << "unspecified";
  1141. case EggGroup::DC_none:
  1142. return out << "none";
  1143. case EggGroup::DC_local:
  1144. return out << "local";
  1145. case EggGroup::DC_net:
  1146. return out << "net";
  1147. case EggGroup::DC_no_touch:
  1148. return out << "no_touch";
  1149. case EggGroup::DC_default:
  1150. return out << "1";
  1151. }
  1152. nassertr(false, out);
  1153. return out << "(**invalid**)";
  1154. }
  1155. /**
  1156. *
  1157. */
  1158. ostream &operator << (ostream &out, EggGroup::BillboardType t) {
  1159. switch (t) {
  1160. case EggGroup::BT_none:
  1161. return out << "none";
  1162. case EggGroup::BT_axis:
  1163. return out << "axis";
  1164. case EggGroup::BT_point_camera_relative:
  1165. return out << "point_eye";
  1166. case EggGroup::BT_point_world_relative:
  1167. return out << "point_world";
  1168. }
  1169. nassertr(false, out);
  1170. return out << "(**invalid**)";
  1171. }
  1172. /**
  1173. *
  1174. */
  1175. ostream &operator << (ostream &out, EggGroup::CollisionSolidType t) {
  1176. switch (t) {
  1177. case EggGroup::CST_none:
  1178. return out << "None";
  1179. case EggGroup::CST_plane:
  1180. return out << "Plane";
  1181. case EggGroup::CST_polygon:
  1182. return out << "Polygon";
  1183. case EggGroup::CST_polyset:
  1184. return out << "Polyset";
  1185. case EggGroup::CST_sphere:
  1186. return out << "Sphere";
  1187. case EggGroup::CST_inv_sphere:
  1188. return out << "InvSphere";
  1189. case EggGroup::CST_tube:
  1190. return out << "Tube";
  1191. case EggGroup::CST_floor_mesh:
  1192. return out << "FloorMesh";
  1193. case EggGroup::CST_box:
  1194. return out << "Box";
  1195. }
  1196. nassertr(false, out);
  1197. return out << "(**invalid**)";
  1198. }
  1199. /**
  1200. *
  1201. */
  1202. ostream &operator << (ostream &out, EggGroup::CollideFlags t) {
  1203. if (t == EggGroup::CF_none) {
  1204. return out << "none";
  1205. }
  1206. int bits = (int)t;
  1207. const char *space = "";
  1208. if (bits & EggGroup::CF_intangible) {
  1209. out << space << "intangible";
  1210. space = " ";
  1211. }
  1212. if (bits & EggGroup::CF_event) {
  1213. out << space << "event";
  1214. space = " ";
  1215. }
  1216. if (bits & EggGroup::CF_descend) {
  1217. out << space << "descend";
  1218. space = " ";
  1219. }
  1220. if (bits & EggGroup::CF_keep) {
  1221. out << space << "keep";
  1222. space = " ";
  1223. }
  1224. if (bits & EggGroup::CF_solid) {
  1225. out << space << "solid";
  1226. space = " ";
  1227. }
  1228. if (bits & EggGroup::CF_center) {
  1229. out << space << "center";
  1230. space = " ";
  1231. }
  1232. if (bits & EggGroup::CF_turnstile) {
  1233. out << space << "turnstile";
  1234. space = " ";
  1235. }
  1236. if (bits & EggGroup::CF_level) {
  1237. out << space << "level";
  1238. space = " ";
  1239. }
  1240. return out;
  1241. }
  1242. /**
  1243. *
  1244. */
  1245. ostream &
  1246. operator << (ostream &out, EggGroup::BlendMode t) {
  1247. switch (t) {
  1248. case EggGroup::BM_unspecified:
  1249. return out << "unspecified";
  1250. case EggGroup::BM_none:
  1251. return out << "none";
  1252. case EggGroup::BM_add:
  1253. return out << "add";
  1254. case EggGroup::BM_subtract:
  1255. return out << "subtract";
  1256. case EggGroup::BM_inv_subtract:
  1257. return out << "inv_subtract";
  1258. case EggGroup::BM_min:
  1259. return out << "min";
  1260. case EggGroup::BM_max:
  1261. return out << "max";
  1262. }
  1263. return out << "**invalid EggGroup::BlendMode(" << (int)t << ")**";
  1264. }
  1265. /**
  1266. *
  1267. */
  1268. ostream &
  1269. operator << (ostream &out, EggGroup::BlendOperand t) {
  1270. switch (t) {
  1271. case EggGroup::BO_unspecified:
  1272. return out << "unspecified";
  1273. case EggGroup::BO_zero:
  1274. return out << "zero";
  1275. case EggGroup::BO_one:
  1276. return out << "one";
  1277. case EggGroup::BO_incoming_color:
  1278. return out << "incomfing_color";
  1279. case EggGroup::BO_one_minus_incoming_color:
  1280. return out << "one_minus_incoming_color";
  1281. case EggGroup::BO_fbuffer_color:
  1282. return out << "fbuffer_color";
  1283. case EggGroup::BO_one_minus_fbuffer_color:
  1284. return out << "one_minus_fbuffer_color";
  1285. case EggGroup::BO_incoming_alpha:
  1286. return out << "incoming_alpha";
  1287. case EggGroup::BO_one_minus_incoming_alpha:
  1288. return out << "one_minus_incoming_alpha";
  1289. case EggGroup::BO_fbuffer_alpha:
  1290. return out << "fbuffer_alpha";
  1291. case EggGroup::BO_one_minus_fbuffer_alpha:
  1292. return out << "one_minus_fbuffer_alpha";
  1293. case EggGroup::BO_constant_color:
  1294. return out << "constant_color";
  1295. case EggGroup::BO_one_minus_constant_color:
  1296. return out << "one_minus_constant_color";
  1297. case EggGroup::BO_constant_alpha:
  1298. return out << "constant_alpha";
  1299. case EggGroup::BO_one_minus_constant_alpha:
  1300. return out << "one_minus_constant_alpha";
  1301. case EggGroup::BO_incoming_color_saturate:
  1302. return out << "incoming_color_saturate";
  1303. case EggGroup::BO_color_scale:
  1304. return out << "color_scale";
  1305. case EggGroup::BO_one_minus_color_scale:
  1306. return out << "one_minus_color_scale";
  1307. case EggGroup::BO_alpha_scale:
  1308. return out << "alpha_scale";
  1309. case EggGroup::BO_one_minus_alpha_scale:
  1310. return out << "one_minus_alpha_scale";
  1311. }
  1312. return out << "**invalid EggGroup::BlendOperand(" << (int)t << ")**";
  1313. }