Переглянути джерело

parse portal syntax in egg files

David Rose 21 роки тому
батько
коміт
9c8037ad62

+ 24 - 0
panda/src/egg/eggGroup.I

@@ -466,6 +466,30 @@ get_direct_flag() const {
 }
 }
 
 
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: EggGroup::set_portal_flag
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE void EggGroup::
+set_portal_flag(bool flag) {
+  if (flag) {
+    _flags2 |= F2_portal_flag;
+  } else {
+    _flags2 &= ~F2_portal_flag;
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: EggGroup::get_portal_flag
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+INLINE bool EggGroup::
+get_portal_flag() const {
+  return ((_flags2 & F2_portal_flag) != 0);
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: EggGroup::set_collide_mask
 //     Function: EggGroup::set_collide_mask
 //       Access: Public
 //       Access: Public

+ 4 - 0
panda/src/egg/eggGroup.cxx

@@ -209,6 +209,10 @@ write(ostream &out, int indent_level) const {
   write_tags(out, indent_level + 2);
   write_tags(out, indent_level + 2);
   write_render_mode(out, indent_level + 2);
   write_render_mode(out, indent_level + 2);
 
 
+  if (get_portal_flag()) {
+    indent(out, indent_level) << "<Portal> { 1 }\n";
+  }
+
   // We have to write the children nodes before we write the vertex
   // We have to write the children nodes before we write the vertex
   // references, since we might be referencing a vertex that's defined
   // references, since we might be referencing a vertex that's defined
   // in one of those children nodes!
   // in one of those children nodes!

+ 4 - 0
panda/src/egg/eggGroup.h

@@ -174,6 +174,9 @@ PUBLISHED:
   INLINE void set_direct_flag(bool flag);
   INLINE void set_direct_flag(bool flag);
   INLINE bool get_direct_flag() const;
   INLINE bool get_direct_flag() const;
 
 
+  INLINE void set_portal_flag(bool flag);
+  INLINE bool get_portal_flag() const;
+
   INLINE void set_collide_mask(CollideMask mask);
   INLINE void set_collide_mask(CollideMask mask);
   INLINE void clear_collide_mask();
   INLINE void clear_collide_mask();
   INLINE bool has_collide_mask() const;
   INLINE bool has_collide_mask() const;
@@ -264,6 +267,7 @@ private:
     F2_billboard_center      = 0x00000008,
     F2_billboard_center      = 0x00000008,
 
 
     F2_dcs_type              = 0x00000030,
     F2_dcs_type              = 0x00000030,
+    F2_portal_flag           = 0x00000040,
   };
   };
 
 
   int _flags;
   int _flags;

+ 3 - 3
panda/src/egg/lexer.cxx.prebuilt

@@ -710,11 +710,11 @@ char *yytext;
 #include "config_egg.h"
 #include "config_egg.h"
 #include "parser.h"
 #include "parser.h"
 
 
-#include <indent.h>
-#include <notify.h>
+#include "indent.h"
+#include "notify.h"
 
 
 #include <math.h>
 #include <math.h>
-#include <pandabase.h>
+#include "pandabase.h"
 
 
 extern "C" int eggyywrap(void);  // declared below.
 extern "C" int eggyywrap(void);  // declared below.
 
 

+ 133 - 131
panda/src/egg/parser.cxx.prebuilt

@@ -431,25 +431,25 @@ static const short yyrline[] =
      456,   483,   485,   579,   587,   606,   606,   642,   644,   654,
      456,   483,   485,   579,   587,   606,   606,   642,   644,   654,
      654,   666,   666,   711,   716,   720,   724,   728,   729,   730,
      654,   666,   666,   711,   716,   720,   724,   728,   729,   730,
      731,   739,   757,   762,   770,   787,   792,   800,   817,   822,
      731,   739,   757,   762,   770,   787,   792,   800,   817,   822,
-     830,   847,   847,   867,   867,   888,   888,   909,   911,   975,
-     987,   992,   999,  1005,  1018,  1025,  1038,  1044,  1050,  1056,
-    1061,  1067,  1068,  1069,  1070,  1083,  1113,  1115,  1136,  1136,
-    1152,  1154,  1155,  1156,  1157,  1158,  1159,  1160,  1163,  1169,
-    1175,  1181,  1187,  1193,  1197,  1203,  1207,  1209,  1230,  1230,
-    1249,  1251,  1252,  1253,  1254,  1257,  1263,  1269,  1275,  1278,
-    1280,  1298,  1331,  1336,  1360,  1372,  1378,  1394,  1394,  1413,
-    1413,  1432,  1432,  1451,  1451,  1470,  1470,  1490,  1492,  1493,
-    1494,  1495,  1496,  1497,  1498,  1499,  1557,  1559,  1560,  1561,
-    1562,  1563,  1564,  1565,  1566,  1567,  1568,  1569,  1575,  1576,
-    1639,  1641,  1642,  1643,  1644,  1645,  1646,  1647,  1648,  1649,
-    1650,  1718,  1735,  1775,  1792,  1797,  1805,  1822,  1827,  1835,
-    1852,  1868,  1899,  1917,  1937,  1957,  1963,  1973,  1980,  1998,
-    2014,  2035,  2035,  2057,  2057,  2079,  2081,  2085,  2089,  2093,
-    2097,  2111,  2111,  2132,  2134,  2146,  2159,  2159,  2180,  2182,
-    2199,  2212,  2212,  2233,  2235,  2250,  2264,  2269,  2282,  2287,
-    2300,  2321,  2342,  2366,  2372,  2383,  2395,  2401,  2411,  2416,
-    2429,  2434,  2438,  2450,  2455,  2470,  2475,  2488,  2490,  2504,
-    2511,  2517,  2533,  2542,  2548
+     830,   847,   847,   867,   867,   888,   888,   909,   911,   977,
+     989,   994,  1001,  1007,  1020,  1027,  1040,  1046,  1052,  1058,
+    1063,  1069,  1070,  1071,  1072,  1085,  1115,  1117,  1138,  1138,
+    1154,  1156,  1157,  1158,  1159,  1160,  1161,  1162,  1165,  1171,
+    1177,  1183,  1189,  1195,  1199,  1205,  1209,  1211,  1232,  1232,
+    1251,  1253,  1254,  1255,  1256,  1259,  1265,  1271,  1277,  1280,
+    1282,  1300,  1333,  1338,  1362,  1374,  1380,  1396,  1396,  1415,
+    1415,  1434,  1434,  1453,  1453,  1472,  1472,  1492,  1494,  1495,
+    1496,  1497,  1498,  1499,  1500,  1501,  1559,  1561,  1562,  1563,
+    1564,  1565,  1566,  1567,  1568,  1569,  1570,  1571,  1577,  1578,
+    1641,  1643,  1644,  1645,  1646,  1647,  1648,  1649,  1650,  1651,
+    1652,  1720,  1737,  1777,  1794,  1799,  1807,  1824,  1829,  1837,
+    1854,  1870,  1901,  1919,  1939,  1959,  1965,  1975,  1982,  2000,
+    2016,  2037,  2037,  2059,  2059,  2081,  2083,  2087,  2091,  2095,
+    2099,  2113,  2113,  2134,  2136,  2148,  2161,  2161,  2182,  2184,
+    2201,  2214,  2214,  2235,  2237,  2252,  2266,  2271,  2284,  2289,
+    2302,  2323,  2344,  2368,  2374,  2385,  2397,  2403,  2413,  2418,
+    2431,  2436,  2440,  2452,  2457,  2472,  2477,  2490,  2492,  2506,
+    2513,  2519,  2535,  2544,  2550
 };
 };
 #endif
 #endif
 
 
@@ -2304,13 +2304,15 @@ case 68:
     group->set_from_collide_mask(group->get_from_collide_mask() | ulong_value);
     group->set_from_collide_mask(group->get_from_collide_mask() | ulong_value);
   } else if (cmp_nocase_uh(name, "into_collide_mask") == 0) {
   } else if (cmp_nocase_uh(name, "into_collide_mask") == 0) {
     group->set_into_collide_mask(group->get_into_collide_mask() | ulong_value);
     group->set_into_collide_mask(group->get_into_collide_mask() | ulong_value);
+  } else if (cmp_nocase_uh(name, "portal") == 0) {
+    group->set_portal_flag(value != 0);
   } else {
   } else {
     eggyywarning("Unknown group scalar " + name);
     eggyywarning("Unknown group scalar " + name);
   }
   }
 }
 }
     break;
     break;
 case 69:
 case 69:
-#line 976 "parser.yxx"
+#line 978 "parser.yxx"
 {
 {
   EggGroup *group = DCAST(EggGroup, egg_stack.back());
   EggGroup *group = DCAST(EggGroup, egg_stack.back());
   string strval = yyvsp[-1]._string;
   string strval = yyvsp[-1]._string;
@@ -2324,14 +2326,14 @@ case 69:
 }
 }
     break;
     break;
 case 70:
 case 70:
-#line 988 "parser.yxx"
+#line 990 "parser.yxx"
 {
 {
   EggGroup *group = DCAST(EggGroup, egg_stack.back());
   EggGroup *group = DCAST(EggGroup, egg_stack.back());
   group->set_billboard_center(LPoint3d(yyvsp[-3]._number, yyvsp[-2]._number, yyvsp[-1]._number));
   group->set_billboard_center(LPoint3d(yyvsp[-3]._number, yyvsp[-2]._number, yyvsp[-1]._number));
 }
 }
     break;
     break;
 case 71:
 case 71:
-#line 993 "parser.yxx"
+#line 995 "parser.yxx"
 {
 {
   EggGroup *group = DCAST(EggGroup, egg_stack.back());
   EggGroup *group = DCAST(EggGroup, egg_stack.back());
   string name = yyvsp[-4]._string;
   string name = yyvsp[-4]._string;
@@ -2340,7 +2342,7 @@ case 71:
 }
 }
     break;
     break;
 case 72:
 case 72:
-#line 1000 "parser.yxx"
+#line 1002 "parser.yxx"
 {
 {
   EggGroup *group = DCAST(EggGroup, egg_stack.back());
   EggGroup *group = DCAST(EggGroup, egg_stack.back());
   int value = (int)yyvsp[-1]._number;
   int value = (int)yyvsp[-1]._number;
@@ -2348,7 +2350,7 @@ case 72:
 }
 }
     break;
     break;
 case 73:
 case 73:
-#line 1006 "parser.yxx"
+#line 1008 "parser.yxx"
 {
 {
   // The special flavor of DCS, with { sync } or { nosync }.
   // The special flavor of DCS, with { sync } or { nosync }.
   EggGroup *group = DCAST(EggGroup, egg_stack.back());
   EggGroup *group = DCAST(EggGroup, egg_stack.back());
@@ -2363,7 +2365,7 @@ case 73:
 }
 }
     break;
     break;
 case 74:
 case 74:
-#line 1019 "parser.yxx"
+#line 1021 "parser.yxx"
 {
 {
   // The traditional flavor of DART, with { 0 } or { 1 }.
   // The traditional flavor of DART, with { 0 } or { 1 }.
   EggGroup *group = DCAST(EggGroup, egg_stack.back());
   EggGroup *group = DCAST(EggGroup, egg_stack.back());
@@ -2372,7 +2374,7 @@ case 74:
 }
 }
     break;
     break;
 case 75:
 case 75:
-#line 1026 "parser.yxx"
+#line 1028 "parser.yxx"
 {
 {
   // The special flavor of DART, with { sync } or { nosync }.
   // The special flavor of DART, with { sync } or { nosync }.
   EggGroup *group = DCAST(EggGroup, egg_stack.back());
   EggGroup *group = DCAST(EggGroup, egg_stack.back());
@@ -2387,7 +2389,7 @@ case 75:
 }
 }
     break;
     break;
 case 76:
 case 76:
-#line 1039 "parser.yxx"
+#line 1041 "parser.yxx"
 {
 {
   EggGroup *group = DCAST(EggGroup, egg_stack.back());
   EggGroup *group = DCAST(EggGroup, egg_stack.back());
   int value = (int)yyvsp[-1]._number;
   int value = (int)yyvsp[-1]._number;
@@ -2395,7 +2397,7 @@ case 76:
 }
 }
     break;
     break;
 case 77:
 case 77:
-#line 1045 "parser.yxx"
+#line 1047 "parser.yxx"
 {
 {
   EggGroup *group = DCAST(EggGroup, egg_stack.back());
   EggGroup *group = DCAST(EggGroup, egg_stack.back());
   string type = yyvsp[-1]._string;
   string type = yyvsp[-1]._string;
@@ -2403,7 +2405,7 @@ case 77:
 }
 }
     break;
     break;
 case 78:
 case 78:
-#line 1051 "parser.yxx"
+#line 1053 "parser.yxx"
 {
 {
   EggGroup *group = DCAST(EggGroup, egg_stack.back());
   EggGroup *group = DCAST(EggGroup, egg_stack.back());
   int value = (int)yyvsp[-1]._number;
   int value = (int)yyvsp[-1]._number;
@@ -2411,14 +2413,14 @@ case 78:
 }
 }
     break;
     break;
 case 79:
 case 79:
-#line 1057 "parser.yxx"
+#line 1059 "parser.yxx"
 {
 {
   EggGroup *group = DCAST(EggGroup, egg_stack.back());
   EggGroup *group = DCAST(EggGroup, egg_stack.back());
   group->set_tag(yyvsp[-3]._string, yyvsp[-1]._string);
   group->set_tag(yyvsp[-3]._string, yyvsp[-1]._string);
 }
 }
     break;
     break;
 case 80:
 case 80:
-#line 1062 "parser.yxx"
+#line 1064 "parser.yxx"
 {
 {
   EggGroup *group = DCAST(EggGroup, egg_stack.back());
   EggGroup *group = DCAST(EggGroup, egg_stack.back());
   int value = (int)yyvsp[-1]._number;
   int value = (int)yyvsp[-1]._number;
@@ -2426,13 +2428,13 @@ case 80:
 }
 }
     break;
     break;
 case 84:
 case 84:
-#line 1071 "parser.yxx"
+#line 1073 "parser.yxx"
 {
 {
   DCAST(EggGroup, egg_stack.back())->add_child(DCAST(EggNode, yyvsp[0]._egg));
   DCAST(EggGroup, egg_stack.back())->add_child(DCAST(EggNode, yyvsp[0]._egg));
 }
 }
     break;
     break;
 case 85:
 case 85:
-#line 1085 "parser.yxx"
+#line 1087 "parser.yxx"
 {
 {
   EggGroup *group = DCAST(EggGroup, egg_stack.back());
   EggGroup *group = DCAST(EggGroup, egg_stack.back());
   string strval = yyvsp[0]._string;
   string strval = yyvsp[0]._string;
@@ -2454,7 +2456,7 @@ case 85:
 }
 }
     break;
     break;
 case 87:
 case 87:
-#line 1116 "parser.yxx"
+#line 1118 "parser.yxx"
 {
 {
   EggGroup *group = DCAST(EggGroup, egg_stack.back());
   EggGroup *group = DCAST(EggGroup, egg_stack.back());
   string strval = yyvsp[0]._string;
   string strval = yyvsp[0]._string;
@@ -2468,55 +2470,55 @@ case 87:
 }
 }
     break;
     break;
 case 88:
 case 88:
-#line 1138 "parser.yxx"
+#line 1140 "parser.yxx"
 {
 {
   DCAST(EggGroup, egg_stack.back())->clear_transform();
   DCAST(EggGroup, egg_stack.back())->clear_transform();
 }
 }
     break;
     break;
 case 98:
 case 98:
-#line 1164 "parser.yxx"
+#line 1166 "parser.yxx"
 {
 {
   DCAST(EggGroup, egg_stack.back())->add_translate(LVector3d(yyvsp[-3]._number, yyvsp[-2]._number, yyvsp[-1]._number));
   DCAST(EggGroup, egg_stack.back())->add_translate(LVector3d(yyvsp[-3]._number, yyvsp[-2]._number, yyvsp[-1]._number));
 }
 }
     break;
     break;
 case 99:
 case 99:
-#line 1170 "parser.yxx"
+#line 1172 "parser.yxx"
 {
 {
   DCAST(EggGroup, egg_stack.back())->add_rotx(yyvsp[-1]._number);
   DCAST(EggGroup, egg_stack.back())->add_rotx(yyvsp[-1]._number);
 }
 }
     break;
     break;
 case 100:
 case 100:
-#line 1176 "parser.yxx"
+#line 1178 "parser.yxx"
 {
 {
   DCAST(EggGroup, egg_stack.back())->add_roty(yyvsp[-1]._number);
   DCAST(EggGroup, egg_stack.back())->add_roty(yyvsp[-1]._number);
 }
 }
     break;
     break;
 case 101:
 case 101:
-#line 1182 "parser.yxx"
+#line 1184 "parser.yxx"
 {
 {
   DCAST(EggGroup, egg_stack.back())->add_rotz(yyvsp[-1]._number);
   DCAST(EggGroup, egg_stack.back())->add_rotz(yyvsp[-1]._number);
 }
 }
     break;
     break;
 case 102:
 case 102:
-#line 1188 "parser.yxx"
+#line 1190 "parser.yxx"
 {
 {
   DCAST(EggGroup, egg_stack.back())->add_rotate(yyvsp[-4]._number, LVector3d(yyvsp[-3]._number, yyvsp[-2]._number, yyvsp[-1]._number));
   DCAST(EggGroup, egg_stack.back())->add_rotate(yyvsp[-4]._number, LVector3d(yyvsp[-3]._number, yyvsp[-2]._number, yyvsp[-1]._number));
 }
 }
     break;
     break;
 case 103:
 case 103:
-#line 1194 "parser.yxx"
+#line 1196 "parser.yxx"
 {
 {
   DCAST(EggGroup, egg_stack.back())->add_scale(LVecBase3d(yyvsp[-3]._number, yyvsp[-2]._number, yyvsp[-1]._number));
   DCAST(EggGroup, egg_stack.back())->add_scale(LVecBase3d(yyvsp[-3]._number, yyvsp[-2]._number, yyvsp[-1]._number));
 }
 }
     break;
     break;
 case 104:
 case 104:
-#line 1198 "parser.yxx"
+#line 1200 "parser.yxx"
 {
 {
   DCAST(EggGroup, egg_stack.back())->add_uniform_scale(yyvsp[-1]._number);
   DCAST(EggGroup, egg_stack.back())->add_uniform_scale(yyvsp[-1]._number);
 }
 }
     break;
     break;
 case 107:
 case 107:
-#line 1213 "parser.yxx"
+#line 1215 "parser.yxx"
 {
 {
   DCAST(EggGroup, egg_stack.back())->add_matrix
   DCAST(EggGroup, egg_stack.back())->add_matrix
     (LMatrix4d(yyvsp[-15]._number, yyvsp[-14]._number, yyvsp[-13]._number, yyvsp[-12]._number,
     (LMatrix4d(yyvsp[-15]._number, yyvsp[-14]._number, yyvsp[-13]._number, yyvsp[-12]._number,
@@ -2526,37 +2528,37 @@ case 107:
 }
 }
     break;
     break;
 case 108:
 case 108:
-#line 1232 "parser.yxx"
+#line 1234 "parser.yxx"
 {
 {
   matrix_2d = LMatrix3d::ident_mat();
   matrix_2d = LMatrix3d::ident_mat();
 }
 }
     break;
     break;
 case 109:
 case 109:
-#line 1236 "parser.yxx"
+#line 1238 "parser.yxx"
 {
 {
   DCAST(EggTexture, egg_stack.back())->set_transform(matrix_2d);
   DCAST(EggTexture, egg_stack.back())->set_transform(matrix_2d);
 }
 }
     break;
     break;
 case 115:
 case 115:
-#line 1258 "parser.yxx"
+#line 1260 "parser.yxx"
 {
 {
   matrix_2d *= LMatrix3d::translate_mat(yyvsp[-2]._number, yyvsp[-1]._number);
   matrix_2d *= LMatrix3d::translate_mat(yyvsp[-2]._number, yyvsp[-1]._number);
 }
 }
     break;
     break;
 case 116:
 case 116:
-#line 1264 "parser.yxx"
+#line 1266 "parser.yxx"
 {
 {
   matrix_2d *= LMatrix3d::rotate_mat(yyvsp[-1]._number);
   matrix_2d *= LMatrix3d::rotate_mat(yyvsp[-1]._number);
 }
 }
     break;
     break;
 case 117:
 case 117:
-#line 1270 "parser.yxx"
+#line 1272 "parser.yxx"
 {
 {
   matrix_2d *= LMatrix3d::scale_mat(yyvsp[-2]._number, yyvsp[-1]._number);
   matrix_2d *= LMatrix3d::scale_mat(yyvsp[-2]._number, yyvsp[-1]._number);
 }
 }
     break;
     break;
 case 120:
 case 120:
-#line 1283 "parser.yxx"
+#line 1285 "parser.yxx"
 {
 {
   matrix_2d *= LMatrix3d(yyvsp[-8]._number, yyvsp[-7]._number, yyvsp[-6]._number,
   matrix_2d *= LMatrix3d(yyvsp[-8]._number, yyvsp[-7]._number, yyvsp[-6]._number,
                          yyvsp[-5]._number, yyvsp[-4]._number, yyvsp[-3]._number,
                          yyvsp[-5]._number, yyvsp[-4]._number, yyvsp[-3]._number,
@@ -2564,7 +2566,7 @@ case 120:
 }
 }
     break;
     break;
 case 121:
 case 121:
-#line 1300 "parser.yxx"
+#line 1302 "parser.yxx"
 {
 {
   if (yyvsp[-2]._egg != (EggVertexPool *)NULL) {
   if (yyvsp[-2]._egg != (EggVertexPool *)NULL) {
     EggVertexPool *pool = DCAST(EggVertexPool, yyvsp[-2]._egg);
     EggVertexPool *pool = DCAST(EggVertexPool, yyvsp[-2]._egg);
@@ -2588,13 +2590,13 @@ case 121:
 }
 }
     break;
     break;
 case 122:
 case 122:
-#line 1333 "parser.yxx"
+#line 1335 "parser.yxx"
 {
 {
   yyval._number = 1.0;
   yyval._number = 1.0;
 }
 }
     break;
     break;
 case 123:
 case 123:
-#line 1337 "parser.yxx"
+#line 1339 "parser.yxx"
 {
 {
   string name = yyvsp[-3]._string;
   string name = yyvsp[-3]._string;
   double value = yyvsp[-1]._number;
   double value = yyvsp[-1]._number;
@@ -2610,86 +2612,86 @@ case 123:
 }
 }
     break;
     break;
 case 125:
 case 125:
-#line 1374 "parser.yxx"
+#line 1376 "parser.yxx"
 {
 {
   EggGroup *group = DCAST(EggGroup, egg_stack.back());
   EggGroup *group = DCAST(EggGroup, egg_stack.back());
   group->set_lod(EggSwitchConditionDistance(yyvsp[-8]._number, yyvsp[-7]._number, LPoint3d(yyvsp[-4]._number, yyvsp[-3]._number, yyvsp[-2]._number)));
   group->set_lod(EggSwitchConditionDistance(yyvsp[-8]._number, yyvsp[-7]._number, LPoint3d(yyvsp[-4]._number, yyvsp[-3]._number, yyvsp[-2]._number)));
 }
 }
     break;
     break;
 case 126:
 case 126:
-#line 1379 "parser.yxx"
+#line 1381 "parser.yxx"
 {
 {
   EggGroup *group = DCAST(EggGroup, egg_stack.back());
   EggGroup *group = DCAST(EggGroup, egg_stack.back());
   group->set_lod(EggSwitchConditionDistance(yyvsp[-9]._number, yyvsp[-8]._number, LPoint3d(yyvsp[-4]._number, yyvsp[-3]._number, yyvsp[-2]._number), yyvsp[-7]._number));
   group->set_lod(EggSwitchConditionDistance(yyvsp[-9]._number, yyvsp[-8]._number, LPoint3d(yyvsp[-4]._number, yyvsp[-3]._number, yyvsp[-2]._number), yyvsp[-7]._number));
 }
 }
     break;
     break;
 case 127:
 case 127:
-#line 1396 "parser.yxx"
+#line 1398 "parser.yxx"
 {
 {
   egg_stack.push_back(new EggPolygon(yyvsp[0]._string));
   egg_stack.push_back(new EggPolygon(yyvsp[0]._string));
 }
 }
     break;
     break;
 case 128:
 case 128:
-#line 1400 "parser.yxx"
+#line 1402 "parser.yxx"
 {
 {
   yyval._egg = egg_stack.back();
   yyval._egg = egg_stack.back();
   egg_stack.pop_back();
   egg_stack.pop_back();
 }
 }
     break;
     break;
 case 129:
 case 129:
-#line 1415 "parser.yxx"
+#line 1417 "parser.yxx"
 {
 {
   egg_stack.push_back(new EggPoint(yyvsp[0]._string));
   egg_stack.push_back(new EggPoint(yyvsp[0]._string));
 }
 }
     break;
     break;
 case 130:
 case 130:
-#line 1419 "parser.yxx"
+#line 1421 "parser.yxx"
 {
 {
   yyval._egg = egg_stack.back();
   yyval._egg = egg_stack.back();
   egg_stack.pop_back();
   egg_stack.pop_back();
 }
 }
     break;
     break;
 case 131:
 case 131:
-#line 1434 "parser.yxx"
+#line 1436 "parser.yxx"
 {
 {
   egg_stack.push_back(new EggLine(yyvsp[0]._string));
   egg_stack.push_back(new EggLine(yyvsp[0]._string));
 }
 }
     break;
     break;
 case 132:
 case 132:
-#line 1438 "parser.yxx"
+#line 1440 "parser.yxx"
 {
 {
   yyval._egg = egg_stack.back();
   yyval._egg = egg_stack.back();
   egg_stack.pop_back();
   egg_stack.pop_back();
 }
 }
     break;
     break;
 case 133:
 case 133:
-#line 1453 "parser.yxx"
+#line 1455 "parser.yxx"
 {
 {
   egg_stack.push_back(new EggNurbsSurface(yyvsp[0]._string));
   egg_stack.push_back(new EggNurbsSurface(yyvsp[0]._string));
 }
 }
     break;
     break;
 case 134:
 case 134:
-#line 1457 "parser.yxx"
+#line 1459 "parser.yxx"
 {
 {
   yyval._egg = egg_stack.back();
   yyval._egg = egg_stack.back();
   egg_stack.pop_back();
   egg_stack.pop_back();
 }
 }
     break;
     break;
 case 135:
 case 135:
-#line 1472 "parser.yxx"
+#line 1474 "parser.yxx"
 {
 {
   egg_stack.push_back(new EggNurbsCurve(yyvsp[0]._string));
   egg_stack.push_back(new EggNurbsCurve(yyvsp[0]._string));
 }
 }
     break;
     break;
 case 136:
 case 136:
-#line 1476 "parser.yxx"
+#line 1478 "parser.yxx"
 {
 {
   yyval._egg = egg_stack.back();
   yyval._egg = egg_stack.back();
   egg_stack.pop_back();
   egg_stack.pop_back();
 }
 }
     break;
     break;
 case 145:
 case 145:
-#line 1500 "parser.yxx"
+#line 1502 "parser.yxx"
 {
 {
   EggPrimitive *primitive = DCAST(EggPrimitive, egg_stack.back());
   EggPrimitive *primitive = DCAST(EggPrimitive, egg_stack.back());
   string name = yyvsp[-3]._string;
   string name = yyvsp[-3]._string;
@@ -2740,7 +2742,7 @@ case 145:
 }
 }
     break;
     break;
 case 157:
 case 157:
-#line 1570 "parser.yxx"
+#line 1572 "parser.yxx"
 {
 {
   EggNurbsCurve *curve = DCAST(EggNurbsCurve, yyvsp[0]._egg);
   EggNurbsCurve *curve = DCAST(EggNurbsCurve, yyvsp[0]._egg);
   EggNurbsSurface *nurbs = DCAST(EggNurbsSurface, egg_stack.back());
   EggNurbsSurface *nurbs = DCAST(EggNurbsSurface, egg_stack.back());
@@ -2748,7 +2750,7 @@ case 157:
 }
 }
     break;
     break;
 case 159:
 case 159:
-#line 1577 "parser.yxx"
+#line 1579 "parser.yxx"
 {
 {
   EggNurbsSurface *primitive = DCAST(EggNurbsSurface, egg_stack.back());
   EggNurbsSurface *primitive = DCAST(EggNurbsSurface, egg_stack.back());
   string name = yyvsp[-3]._string;
   string name = yyvsp[-3]._string;
@@ -2803,7 +2805,7 @@ case 159:
 }
 }
     break;
     break;
 case 170:
 case 170:
-#line 1651 "parser.yxx"
+#line 1653 "parser.yxx"
 {
 {
   EggNurbsCurve *primitive = DCAST(EggNurbsCurve, egg_stack.back());
   EggNurbsCurve *primitive = DCAST(EggNurbsCurve, egg_stack.back());
   string name = yyvsp[-3]._string;
   string name = yyvsp[-3]._string;
@@ -2864,7 +2866,7 @@ case 170:
 }
 }
     break;
     break;
 case 171:
 case 171:
-#line 1720 "parser.yxx"
+#line 1722 "parser.yxx"
 {
 {
   if (yyvsp[0]._egg != (EggTexture *)NULL) {
   if (yyvsp[0]._egg != (EggTexture *)NULL) {
     EggTexture *texture = DCAST(EggTexture, yyvsp[0]._egg);
     EggTexture *texture = DCAST(EggTexture, yyvsp[0]._egg);
@@ -2873,7 +2875,7 @@ case 171:
 }
 }
     break;
     break;
 case 172:
 case 172:
-#line 1737 "parser.yxx"
+#line 1739 "parser.yxx"
 {
 {
   EggTexture *texture = NULL;
   EggTexture *texture = NULL;
 
 
@@ -2905,7 +2907,7 @@ case 172:
 }
 }
     break;
     break;
 case 173:
 case 173:
-#line 1777 "parser.yxx"
+#line 1779 "parser.yxx"
 {
 {
   if (yyvsp[0]._egg != (EggMaterial *)NULL) {
   if (yyvsp[0]._egg != (EggMaterial *)NULL) {
     EggMaterial *material = DCAST(EggMaterial, yyvsp[0]._egg);
     EggMaterial *material = DCAST(EggMaterial, yyvsp[0]._egg);
@@ -2914,13 +2916,13 @@ case 173:
 }
 }
     break;
     break;
 case 174:
 case 174:
-#line 1794 "parser.yxx"
+#line 1796 "parser.yxx"
 {
 {
   DCAST(EggPrimitive, egg_stack.back())->set_normal(Normald(yyvsp[-2]._number, yyvsp[-1]._number, yyvsp[0]._number));
   DCAST(EggPrimitive, egg_stack.back())->set_normal(Normald(yyvsp[-2]._number, yyvsp[-1]._number, yyvsp[0]._number));
 }
 }
     break;
     break;
 case 175:
 case 175:
-#line 1798 "parser.yxx"
+#line 1800 "parser.yxx"
 {
 {
   bool inserted = DCAST(EggPrimitive, egg_stack.back())->_dnormals.
   bool inserted = DCAST(EggPrimitive, egg_stack.back())->_dnormals.
     insert(EggMorphNormal(yyvsp[-5]._string, LVector3d(yyvsp[-3]._number, yyvsp[-2]._number, yyvsp[-1]._number))).second;
     insert(EggMorphNormal(yyvsp[-5]._string, LVector3d(yyvsp[-3]._number, yyvsp[-2]._number, yyvsp[-1]._number))).second;
@@ -2930,7 +2932,7 @@ case 175:
 }
 }
     break;
     break;
 case 176:
 case 176:
-#line 1806 "parser.yxx"
+#line 1808 "parser.yxx"
 {
 {
   bool inserted = DCAST(EggPrimitive, egg_stack.back())->_dnormals.
   bool inserted = DCAST(EggPrimitive, egg_stack.back())->_dnormals.
     insert(EggMorphNormal(yyvsp[-4]._string, LVector3d(yyvsp[-3]._number, yyvsp[-2]._number, yyvsp[-1]._number))).second;
     insert(EggMorphNormal(yyvsp[-4]._string, LVector3d(yyvsp[-3]._number, yyvsp[-2]._number, yyvsp[-1]._number))).second;
@@ -2940,13 +2942,13 @@ case 176:
 }
 }
     break;
     break;
 case 177:
 case 177:
-#line 1824 "parser.yxx"
+#line 1826 "parser.yxx"
 {
 {
   DCAST(EggPrimitive, egg_stack.back())->set_color(Colorf(yyvsp[-3]._number, yyvsp[-2]._number, yyvsp[-1]._number, yyvsp[0]._number));
   DCAST(EggPrimitive, egg_stack.back())->set_color(Colorf(yyvsp[-3]._number, yyvsp[-2]._number, yyvsp[-1]._number, yyvsp[0]._number));
 }
 }
     break;
     break;
 case 178:
 case 178:
-#line 1828 "parser.yxx"
+#line 1830 "parser.yxx"
 {
 {
   bool inserted = DCAST(EggPrimitive, egg_stack.back())->_drgbas.
   bool inserted = DCAST(EggPrimitive, egg_stack.back())->_drgbas.
     insert(EggMorphColor(yyvsp[-6]._string, LVector4f(yyvsp[-4]._number, yyvsp[-3]._number, yyvsp[-2]._number, yyvsp[-1]._number))).second;
     insert(EggMorphColor(yyvsp[-6]._string, LVector4f(yyvsp[-4]._number, yyvsp[-3]._number, yyvsp[-2]._number, yyvsp[-1]._number))).second;
@@ -2956,7 +2958,7 @@ case 178:
 }
 }
     break;
     break;
 case 179:
 case 179:
-#line 1836 "parser.yxx"
+#line 1838 "parser.yxx"
 {
 {
   bool inserted = DCAST(EggPrimitive, egg_stack.back())->_drgbas.
   bool inserted = DCAST(EggPrimitive, egg_stack.back())->_drgbas.
     insert(EggMorphColor(yyvsp[-5]._string, LVector4f(yyvsp[-4]._number, yyvsp[-3]._number, yyvsp[-2]._number, yyvsp[-1]._number))).second;
     insert(EggMorphColor(yyvsp[-5]._string, LVector4f(yyvsp[-4]._number, yyvsp[-3]._number, yyvsp[-2]._number, yyvsp[-1]._number))).second;
@@ -2966,7 +2968,7 @@ case 179:
 }
 }
     break;
     break;
 case 180:
 case 180:
-#line 1854 "parser.yxx"
+#line 1856 "parser.yxx"
 {
 {
   EggPrimitive *primitive = DCAST(EggPrimitive, egg_stack.back());
   EggPrimitive *primitive = DCAST(EggPrimitive, egg_stack.back());
   int value = (int)yyvsp[0]._number;
   int value = (int)yyvsp[0]._number;
@@ -2974,7 +2976,7 @@ case 180:
 }
 }
     break;
     break;
 case 181:
 case 181:
-#line 1870 "parser.yxx"
+#line 1872 "parser.yxx"
 {
 {
   if (yyvsp[-2]._egg != (EggVertexPool *)NULL) {
   if (yyvsp[-2]._egg != (EggVertexPool *)NULL) {
     EggVertexPool *pool = DCAST(EggVertexPool, yyvsp[-2]._egg);
     EggVertexPool *pool = DCAST(EggVertexPool, yyvsp[-2]._egg);
@@ -2997,7 +2999,7 @@ case 181:
 }
 }
     break;
     break;
 case 182:
 case 182:
-#line 1901 "parser.yxx"
+#line 1903 "parser.yxx"
 {
 {
   EggNurbsSurface *nurbs = DCAST(EggNurbsSurface, egg_stack.back());
   EggNurbsSurface *nurbs = DCAST(EggNurbsSurface, egg_stack.back());
   int u_order = (int)yyvsp[-1]._number;
   int u_order = (int)yyvsp[-1]._number;
@@ -3007,7 +3009,7 @@ case 182:
 }
 }
     break;
     break;
 case 183:
 case 183:
-#line 1919 "parser.yxx"
+#line 1921 "parser.yxx"
 {
 {
   EggNurbsSurface *nurbs = DCAST(EggNurbsSurface, egg_stack.back());
   EggNurbsSurface *nurbs = DCAST(EggNurbsSurface, egg_stack.back());
   PTA_double nums = yyvsp[0]._number_list;
   PTA_double nums = yyvsp[0]._number_list;
@@ -3019,7 +3021,7 @@ case 183:
 }
 }
     break;
     break;
 case 184:
 case 184:
-#line 1939 "parser.yxx"
+#line 1941 "parser.yxx"
 {
 {
   EggNurbsSurface *nurbs = DCAST(EggNurbsSurface, egg_stack.back());
   EggNurbsSurface *nurbs = DCAST(EggNurbsSurface, egg_stack.back());
   PTA_double nums = yyvsp[0]._number_list;
   PTA_double nums = yyvsp[0]._number_list;
@@ -3031,14 +3033,14 @@ case 184:
 }
 }
     break;
     break;
 case 185:
 case 185:
-#line 1959 "parser.yxx"
+#line 1961 "parser.yxx"
 {
 {
   EggNurbsSurface *nurbs = DCAST(EggNurbsSurface, egg_stack.back());
   EggNurbsSurface *nurbs = DCAST(EggNurbsSurface, egg_stack.back());
   nurbs->_trims.push_back(EggNurbsSurface::Trim());
   nurbs->_trims.push_back(EggNurbsSurface::Trim());
 }
 }
     break;
     break;
 case 187:
 case 187:
-#line 1975 "parser.yxx"
+#line 1977 "parser.yxx"
 {
 {
   EggNurbsSurface *nurbs = DCAST(EggNurbsSurface, egg_stack.back());
   EggNurbsSurface *nurbs = DCAST(EggNurbsSurface, egg_stack.back());
   nassertr(!nurbs->_trims.empty(), 0);
   nassertr(!nurbs->_trims.empty(), 0);
@@ -3046,7 +3048,7 @@ case 187:
 }
 }
     break;
     break;
 case 188:
 case 188:
-#line 1981 "parser.yxx"
+#line 1983 "parser.yxx"
 {
 {
   EggNurbsSurface *nurbs = DCAST(EggNurbsSurface, egg_stack.back());
   EggNurbsSurface *nurbs = DCAST(EggNurbsSurface, egg_stack.back());
   nassertr(!nurbs->_trims.empty(), 0);
   nassertr(!nurbs->_trims.empty(), 0);
@@ -3056,7 +3058,7 @@ case 188:
 }
 }
     break;
     break;
 case 189:
 case 189:
-#line 2000 "parser.yxx"
+#line 2002 "parser.yxx"
 {
 {
   EggNurbsCurve *nurbs = DCAST(EggNurbsCurve, egg_stack.back());
   EggNurbsCurve *nurbs = DCAST(EggNurbsCurve, egg_stack.back());
   int order = (int)yyvsp[0]._number;
   int order = (int)yyvsp[0]._number;
@@ -3064,7 +3066,7 @@ case 189:
 }
 }
     break;
     break;
 case 190:
 case 190:
-#line 2016 "parser.yxx"
+#line 2018 "parser.yxx"
 {
 {
   EggNurbsCurve *nurbs = DCAST(EggNurbsCurve, egg_stack.back());
   EggNurbsCurve *nurbs = DCAST(EggNurbsCurve, egg_stack.back());
   PTA_double nums = yyvsp[0]._number_list;
   PTA_double nums = yyvsp[0]._number_list;
@@ -3076,7 +3078,7 @@ case 190:
 }
 }
     break;
     break;
 case 191:
 case 191:
-#line 2037 "parser.yxx"
+#line 2039 "parser.yxx"
 {
 {
   EggTable *table = new EggTable(yyvsp[0]._string);
   EggTable *table = new EggTable(yyvsp[0]._string);
   table->set_table_type(EggTable::TT_table);
   table->set_table_type(EggTable::TT_table);
@@ -3084,14 +3086,14 @@ case 191:
 }
 }
     break;
     break;
 case 192:
 case 192:
-#line 2043 "parser.yxx"
+#line 2045 "parser.yxx"
 {
 {
   yyval._egg = egg_stack.back();
   yyval._egg = egg_stack.back();
   egg_stack.pop_back();
   egg_stack.pop_back();
 }
 }
     break;
     break;
 case 193:
 case 193:
-#line 2059 "parser.yxx"
+#line 2061 "parser.yxx"
 {
 {
   EggTable *table = new EggTable(yyvsp[0]._string);
   EggTable *table = new EggTable(yyvsp[0]._string);
   table->set_table_type(EggTable::TT_bundle);
   table->set_table_type(EggTable::TT_bundle);
@@ -3099,58 +3101,58 @@ case 193:
 }
 }
     break;
     break;
 case 194:
 case 194:
-#line 2065 "parser.yxx"
+#line 2067 "parser.yxx"
 {
 {
   yyval._egg = egg_stack.back();
   yyval._egg = egg_stack.back();
   egg_stack.pop_back();
   egg_stack.pop_back();
 }
 }
     break;
     break;
 case 196:
 case 196:
-#line 2082 "parser.yxx"
+#line 2084 "parser.yxx"
 {
 {
   DCAST(EggTable, egg_stack.back())->add_child(DCAST(EggNode, yyvsp[0]._egg));
   DCAST(EggTable, egg_stack.back())->add_child(DCAST(EggNode, yyvsp[0]._egg));
 }
 }
     break;
     break;
 case 197:
 case 197:
-#line 2086 "parser.yxx"
+#line 2088 "parser.yxx"
 {
 {
   DCAST(EggTable, egg_stack.back())->add_child(DCAST(EggNode, yyvsp[0]._egg));
   DCAST(EggTable, egg_stack.back())->add_child(DCAST(EggNode, yyvsp[0]._egg));
 }
 }
     break;
     break;
 case 198:
 case 198:
-#line 2090 "parser.yxx"
+#line 2092 "parser.yxx"
 {
 {
   DCAST(EggTable, egg_stack.back())->add_child(DCAST(EggNode, yyvsp[0]._egg));
   DCAST(EggTable, egg_stack.back())->add_child(DCAST(EggNode, yyvsp[0]._egg));
 }
 }
     break;
     break;
 case 199:
 case 199:
-#line 2094 "parser.yxx"
+#line 2096 "parser.yxx"
 {
 {
   DCAST(EggTable, egg_stack.back())->add_child(DCAST(EggNode, yyvsp[0]._egg));
   DCAST(EggTable, egg_stack.back())->add_child(DCAST(EggNode, yyvsp[0]._egg));
 }
 }
     break;
     break;
 case 200:
 case 200:
-#line 2098 "parser.yxx"
+#line 2100 "parser.yxx"
 {
 {
   DCAST(EggTable, egg_stack.back())->add_child(DCAST(EggNode, yyvsp[0]._egg));
   DCAST(EggTable, egg_stack.back())->add_child(DCAST(EggNode, yyvsp[0]._egg));
 }
 }
     break;
     break;
 case 201:
 case 201:
-#line 2113 "parser.yxx"
+#line 2115 "parser.yxx"
 {
 {
   EggSAnimData *anim_data = new EggSAnimData(yyvsp[0]._string);
   EggSAnimData *anim_data = new EggSAnimData(yyvsp[0]._string);
   egg_stack.push_back(anim_data);
   egg_stack.push_back(anim_data);
 }
 }
     break;
     break;
 case 202:
 case 202:
-#line 2118 "parser.yxx"
+#line 2120 "parser.yxx"
 {
 {
   yyval._egg = egg_stack.back();
   yyval._egg = egg_stack.back();
   egg_stack.pop_back();
   egg_stack.pop_back();
 }
 }
     break;
     break;
 case 204:
 case 204:
-#line 2135 "parser.yxx"
+#line 2137 "parser.yxx"
 {
 {
   EggSAnimData *anim_data = DCAST(EggSAnimData, egg_stack.back());
   EggSAnimData *anim_data = DCAST(EggSAnimData, egg_stack.back());
   string name = yyvsp[-3]._string;
   string name = yyvsp[-3]._string;
@@ -3164,27 +3166,27 @@ case 204:
 }
 }
     break;
     break;
 case 205:
 case 205:
-#line 2147 "parser.yxx"
+#line 2149 "parser.yxx"
 {
 {
   DCAST(EggSAnimData, egg_stack.back())->set_data(yyvsp[-1]._number_list);
   DCAST(EggSAnimData, egg_stack.back())->set_data(yyvsp[-1]._number_list);
 }
 }
     break;
     break;
 case 206:
 case 206:
-#line 2161 "parser.yxx"
+#line 2163 "parser.yxx"
 {
 {
   EggXfmAnimData *anim_data = new EggXfmAnimData(yyvsp[0]._string);
   EggXfmAnimData *anim_data = new EggXfmAnimData(yyvsp[0]._string);
   egg_stack.push_back(anim_data);
   egg_stack.push_back(anim_data);
 }
 }
     break;
     break;
 case 207:
 case 207:
-#line 2166 "parser.yxx"
+#line 2168 "parser.yxx"
 {
 {
   yyval._egg = egg_stack.back();
   yyval._egg = egg_stack.back();
   egg_stack.pop_back();
   egg_stack.pop_back();
 }
 }
     break;
     break;
 case 209:
 case 209:
-#line 2183 "parser.yxx"
+#line 2185 "parser.yxx"
 {
 {
   EggXfmAnimData *anim_data = DCAST(EggXfmAnimData, egg_stack.back());
   EggXfmAnimData *anim_data = DCAST(EggXfmAnimData, egg_stack.back());
   string name = yyvsp[-3]._string;
   string name = yyvsp[-3]._string;
@@ -3203,27 +3205,27 @@ case 209:
 }
 }
     break;
     break;
 case 210:
 case 210:
-#line 2200 "parser.yxx"
+#line 2202 "parser.yxx"
 {
 {
   DCAST(EggXfmAnimData, egg_stack.back())->set_data(yyvsp[-1]._number_list);
   DCAST(EggXfmAnimData, egg_stack.back())->set_data(yyvsp[-1]._number_list);
 }
 }
     break;
     break;
 case 211:
 case 211:
-#line 2214 "parser.yxx"
+#line 2216 "parser.yxx"
 {
 {
   EggXfmSAnim *anim_group = new EggXfmSAnim(yyvsp[0]._string);
   EggXfmSAnim *anim_group = new EggXfmSAnim(yyvsp[0]._string);
   egg_stack.push_back(anim_group);
   egg_stack.push_back(anim_group);
 }
 }
     break;
     break;
 case 212:
 case 212:
-#line 2219 "parser.yxx"
+#line 2221 "parser.yxx"
 {
 {
   yyval._egg = egg_stack.back();
   yyval._egg = egg_stack.back();
   egg_stack.pop_back();
   egg_stack.pop_back();
 }
 }
     break;
     break;
 case 214:
 case 214:
-#line 2236 "parser.yxx"
+#line 2238 "parser.yxx"
 {
 {
   EggXfmSAnim *anim_group = DCAST(EggXfmSAnim, egg_stack.back());
   EggXfmSAnim *anim_group = DCAST(EggXfmSAnim, egg_stack.back());
   string name = yyvsp[-3]._string;
   string name = yyvsp[-3]._string;
@@ -3240,37 +3242,37 @@ case 214:
 }
 }
     break;
     break;
 case 215:
 case 215:
-#line 2251 "parser.yxx"
+#line 2253 "parser.yxx"
 {
 {
   DCAST(EggXfmSAnim, egg_stack.back())->add_child(DCAST(EggNode, yyvsp[0]._egg));
   DCAST(EggXfmSAnim, egg_stack.back())->add_child(DCAST(EggNode, yyvsp[0]._egg));
 }
 }
     break;
     break;
 case 216:
 case 216:
-#line 2266 "parser.yxx"
+#line 2268 "parser.yxx"
 {
 {
   yyval._number_list = PTA_double::empty_array(0);
   yyval._number_list = PTA_double::empty_array(0);
 }
 }
     break;
     break;
 case 217:
 case 217:
-#line 2270 "parser.yxx"
+#line 2272 "parser.yxx"
 {
 {
   yyval._number_list.push_back((double)yyvsp[0]._number);
   yyval._number_list.push_back((double)yyvsp[0]._number);
 }
 }
     break;
     break;
 case 218:
 case 218:
-#line 2284 "parser.yxx"
+#line 2286 "parser.yxx"
 {
 {
   yyval._number_list = PTA_double::empty_array(0);
   yyval._number_list = PTA_double::empty_array(0);
 }
 }
     break;
     break;
 case 219:
 case 219:
-#line 2288 "parser.yxx"
+#line 2290 "parser.yxx"
 {
 {
   yyval._number_list.push_back(yyvsp[0]._number);
   yyval._number_list.push_back(yyvsp[0]._number);
 }
 }
     break;
     break;
 case 220:
 case 220:
-#line 2302 "parser.yxx"
+#line 2304 "parser.yxx"
 {
 {
   string name = yyvsp[0]._string;
   string name = yyvsp[0]._string;
   Textures::iterator vpi = textures.find(name);
   Textures::iterator vpi = textures.find(name);
@@ -3283,7 +3285,7 @@ case 220:
 }
 }
     break;
     break;
 case 221:
 case 221:
-#line 2323 "parser.yxx"
+#line 2325 "parser.yxx"
 {
 {
   string name = yyvsp[0]._string;
   string name = yyvsp[0]._string;
   Materials::iterator vpi = materials.find(name);
   Materials::iterator vpi = materials.find(name);
@@ -3296,7 +3298,7 @@ case 221:
 }
 }
     break;
     break;
 case 222:
 case 222:
-#line 2344 "parser.yxx"
+#line 2346 "parser.yxx"
 {
 {
   string name = yyvsp[0]._string;
   string name = yyvsp[0]._string;
   VertexPools::iterator vpi = vertex_pools.find(name);
   VertexPools::iterator vpi = vertex_pools.find(name);
@@ -3311,69 +3313,69 @@ case 222:
 }
 }
     break;
     break;
 case 223:
 case 223:
-#line 2368 "parser.yxx"
+#line 2370 "parser.yxx"
 {
 {
   eggyyerror("Name required.");
   eggyyerror("Name required.");
   yyval._string = "";
   yyval._string = "";
 }
 }
     break;
     break;
 case 226:
 case 226:
-#line 2397 "parser.yxx"
+#line 2399 "parser.yxx"
 {
 {
   eggyyerror("String required.");
   eggyyerror("String required.");
   yyval._string = "";
   yyval._string = "";
 }
 }
     break;
     break;
 case 228:
 case 228:
-#line 2413 "parser.yxx"
+#line 2415 "parser.yxx"
 {
 {
   yyval._string = "";
   yyval._string = "";
 }
 }
     break;
     break;
 case 230:
 case 230:
-#line 2431 "parser.yxx"
+#line 2433 "parser.yxx"
 {
 {
   yyval._string = yyvsp[0]._string;
   yyval._string = yyvsp[0]._string;
 }
 }
     break;
     break;
 case 231:
 case 231:
-#line 2435 "parser.yxx"
+#line 2437 "parser.yxx"
 {
 {
   yyval._string = yyvsp[0]._string;
   yyval._string = yyvsp[0]._string;
 }
 }
     break;
     break;
 case 233:
 case 233:
-#line 2452 "parser.yxx"
+#line 2454 "parser.yxx"
 {
 {
   yyval._string = "";
   yyval._string = "";
 }
 }
     break;
     break;
 case 234:
 case 234:
-#line 2456 "parser.yxx"
+#line 2458 "parser.yxx"
 {
 {
   yyval._string = yyvsp[0]._string;
   yyval._string = yyvsp[0]._string;
 }
 }
     break;
     break;
 case 235:
 case 235:
-#line 2472 "parser.yxx"
+#line 2474 "parser.yxx"
 {
 {
   yyval._string = yyvsp[0]._string;
   yyval._string = yyvsp[0]._string;
 }
 }
     break;
     break;
 case 236:
 case 236:
-#line 2476 "parser.yxx"
+#line 2478 "parser.yxx"
 {
 {
   yyval._string = yyvsp[-1]._string + "\n" + yyvsp[0]._string;
   yyval._string = yyvsp[-1]._string + "\n" + yyvsp[0]._string;
 }
 }
     break;
     break;
 case 238:
 case 238:
-#line 2491 "parser.yxx"
+#line 2493 "parser.yxx"
 {
 {
   yyval._number = yyvsp[0]._ulong;
   yyval._number = yyvsp[0]._ulong;
 }
 }
     break;
     break;
 case 239:
 case 239:
-#line 2506 "parser.yxx"
+#line 2508 "parser.yxx"
 {
 {
   yyval._number = yyvsp[0]._number;
   yyval._number = yyvsp[0]._number;
   yyval._ulong = (unsigned long)yyvsp[0]._number;
   yyval._ulong = (unsigned long)yyvsp[0]._number;
@@ -3381,7 +3383,7 @@ case 239:
 }
 }
     break;
     break;
 case 240:
 case 240:
-#line 2512 "parser.yxx"
+#line 2514 "parser.yxx"
 {
 {
   yyval._number = yyvsp[0]._ulong;
   yyval._number = yyvsp[0]._ulong;
   yyval._ulong = yyvsp[0]._ulong;
   yyval._ulong = yyvsp[0]._ulong;
@@ -3389,7 +3391,7 @@ case 240:
 }
 }
     break;
     break;
 case 241:
 case 241:
-#line 2518 "parser.yxx"
+#line 2520 "parser.yxx"
 {
 {
   yyval._number = 0.0;
   yyval._number = 0.0;
   yyval._ulong = 0;
   yyval._ulong = 0;
@@ -3397,7 +3399,7 @@ case 241:
 }
 }
     break;
     break;
 case 242:
 case 242:
-#line 2535 "parser.yxx"
+#line 2537 "parser.yxx"
 {
 {
   int i = (int)yyvsp[0]._number;
   int i = (int)yyvsp[0]._number;
   if ((double)i != yyvsp[0]._number) {
   if ((double)i != yyvsp[0]._number) {
@@ -3407,7 +3409,7 @@ case 242:
 }
 }
     break;
     break;
 case 243:
 case 243:
-#line 2543 "parser.yxx"
+#line 2545 "parser.yxx"
 {
 {
   yyval._number = yyvsp[0]._ulong;
   yyval._number = yyvsp[0]._ulong;
 }
 }
@@ -3645,4 +3647,4 @@ yyreturn:
 #endif
 #endif
   return yyresult;
   return yyresult;
 }
 }
-#line 2550 "parser.yxx"
+#line 2552 "parser.yxx"

+ 2 - 0
panda/src/egg/parser.yxx

@@ -968,6 +968,8 @@ group_body:
     group->set_from_collide_mask(group->get_from_collide_mask() | ulong_value);
     group->set_from_collide_mask(group->get_from_collide_mask() | ulong_value);
   } else if (cmp_nocase_uh(name, "into_collide_mask") == 0) {
   } else if (cmp_nocase_uh(name, "into_collide_mask") == 0) {
     group->set_into_collide_mask(group->get_into_collide_mask() | ulong_value);
     group->set_into_collide_mask(group->get_into_collide_mask() | ulong_value);
+  } else if (cmp_nocase_uh(name, "portal") == 0) {
+    group->set_portal_flag(value != 0);
   } else {
   } else {
     eggyywarning("Unknown group scalar " + name);
     eggyywarning("Unknown group scalar " + name);
   }
   }

+ 69 - 0
panda/src/egg2pg/eggLoader.cxx

@@ -41,6 +41,7 @@
 #include "geomNode.h"
 #include "geomNode.h"
 #include "sequenceNode.h"
 #include "sequenceNode.h"
 #include "switchNode.h"
 #include "switchNode.h"
+#include "portalNode.h"
 #include "lodNode.h"
 #include "lodNode.h"
 #include "modelNode.h"
 #include "modelNode.h"
 #include "modelRoot.h"
 #include "modelRoot.h"
@@ -1614,6 +1615,19 @@ make_node(EggGroup *egg_group, PandaNode *parent) {
       make_node(*ci, node);
       make_node(*ci, node);
     }
     }
 
 
+  } else if (egg_group->get_portal_flag()) {
+    // Create a portal instead of a regular polyset.  Scan the
+    // children of this node looking for a polygon, similar to the
+    // collision polygon case, above.
+    PortalNode *pnode = new PortalNode(egg_group->get_name());
+    node = pnode;
+
+    set_portal_polygon(egg_group, pnode);
+    if (pnode->get_num_vertices() == 0) {
+      egg2pg_cat.warning()
+        << "Portal " << egg_group->get_name() << " has no vertices!\n";
+    }
+
   } else {
   } else {
     // A normal group; just create a normal node, and traverse.
     // A normal group; just create a normal node, and traverse.
     node = new PandaNode(egg_group->get_name());
     node = new PandaNode(egg_group->get_name());
@@ -1754,6 +1768,61 @@ make_node(EggGroupNode *egg_group, PandaNode *parent) {
   return node;
   return node;
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: EggLoader::set_portal_polygon
+//       Access: Private
+//  Description: Defines the PortalNode from the first polygon found
+//               within this group.
+////////////////////////////////////////////////////////////////////
+void EggLoader::
+set_portal_polygon(EggGroup *egg_group, PortalNode *pnode) {
+  pnode->clear_vertices();
+
+  EggPolygon *poly = find_first_polygon(egg_group);
+  if (poly != (EggPolygon *)NULL) {
+    LMatrix4d mat = poly->get_vertex_to_node();
+
+    EggPolygon::const_iterator vi;
+    for (vi = poly->begin(); vi != poly->end(); ++vi) {
+      Vertexd vert = (*vi)->get_pos3() * mat;
+      pnode->add_vertex(LCAST(float, vert));
+    }
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: EggLoader::find_first_polygon
+//       Access: Private
+//  Description: Returns the first EggPolygon found at or below the
+//               indicated node.
+////////////////////////////////////////////////////////////////////
+EggPolygon *EggLoader::
+find_first_polygon(EggGroup *egg_group) {
+  // Does this group have any polygons?
+  EggGroup::const_iterator ci;
+  for (ci = egg_group->begin(); ci != egg_group->end(); ++ci) {
+    if ((*ci)->is_of_type(EggPolygon::get_class_type())) {
+      // Yes!  Return the polygon.
+      return DCAST(EggPolygon, (*ci));
+    }
+  }
+
+  // Well, the group had no polygons; look for a child group that
+  // does.
+  for (ci = egg_group->begin(); ci != egg_group->end(); ++ci) {
+    if ((*ci)->is_of_type(EggGroup::get_class_type())) {
+      EggGroup *child_group = DCAST(EggGroup, *ci);
+      EggPolygon *found = find_first_polygon(child_group);
+      if (found != NULL) {
+        return found;
+      }
+    }
+  }
+
+  // We got nothing.
+  return NULL;
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: EggLoader::make_collision_solids
 //     Function: EggLoader::make_collision_solids
 //       Access: Private
 //       Access: Private

+ 4 - 0
panda/src/egg2pg/eggLoader.h

@@ -51,6 +51,7 @@ class CollisionSolid;
 class CollisionNode;
 class CollisionNode;
 class CollisionPlane;
 class CollisionPlane;
 class CollisionPolygon;
 class CollisionPolygon;
+class PortalNode;
 
 
 ///////////////////////////////////////////////////////////////////
 ///////////////////////////////////////////////////////////////////
 //       Class : EggLoader
 //       Class : EggLoader
@@ -109,6 +110,9 @@ private:
   PandaNode *make_node(EggTable *egg_table, PandaNode *parent);
   PandaNode *make_node(EggTable *egg_table, PandaNode *parent);
   PandaNode *make_node(EggGroupNode *egg_group, PandaNode *parent);
   PandaNode *make_node(EggGroupNode *egg_group, PandaNode *parent);
 
 
+  void set_portal_polygon(EggGroup *egg_group, PortalNode *pnode);
+  EggPolygon *find_first_polygon(EggGroup *egg_group);
+
   void make_collision_solids(EggGroup *start_group, EggGroup *egg_group,
   void make_collision_solids(EggGroup *start_group, EggGroup *egg_group,
                              CollisionNode *cnode);
                              CollisionNode *cnode);
   void make_collision_plane(EggGroup *egg_group, CollisionNode *cnode,
   void make_collision_plane(EggGroup *egg_group, CollisionNode *cnode,

+ 43 - 0
panda/src/pgraph/portalNode.I

@@ -124,3 +124,46 @@ INLINE bool PortalNode::
 get_portal_geom() const {
 get_portal_geom() const {
   return (_flags & F_portal_geom) != 0;
   return (_flags & F_portal_geom) != 0;
 }
 }
+
+////////////////////////////////////////////////////////////////////
+//     Function: PortalNode::clear_vertices
+//       Access: Published
+//  Description: Resets the vertices of the portal to the empty list.
+////////////////////////////////////////////////////////////////////
+INLINE void PortalNode::
+clear_vertices() {
+  _vertices.clear();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PortalNode::add_vertex
+//       Access: Published
+//  Description: Adds a new vertex to the portal polygon.  The
+//               vertices should be defined in a counterclockwise
+//               orientation when viewing through the portal.
+////////////////////////////////////////////////////////////////////
+INLINE void PortalNode::
+add_vertex(const LPoint3f &vertex) {
+  _vertices.push_back(vertex);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PortalNode::get_num_vertices
+//       Access: Published
+//  Description: Returns the number of vertices in the portal polygon.
+////////////////////////////////////////////////////////////////////
+INLINE int PortalNode::
+get_num_vertices() const {
+  return _vertices.size();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PortalNode::get_vertex
+//       Access: Published
+//  Description: Returns the nth vertex of the portal polygon.
+////////////////////////////////////////////////////////////////////
+INLINE const LPoint3f &PortalNode::
+get_vertex(int n) const {
+  nassertr(n >= 0 && n < (int)_vertices.size(), LPoint3f::zero());
+  return _vertices[n];
+}

+ 10 - 0
panda/src/pgraph/portalNode.h

@@ -23,6 +23,7 @@
 
 
 #include "portalMask.h"
 #include "portalMask.h"
 #include "pandaNode.h"
 #include "pandaNode.h"
+#include "pvector.h"
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //       Class : PortalNode 
 //       Class : PortalNode 
@@ -61,6 +62,12 @@ PUBLISHED:
   INLINE void set_portal_geom(bool flag);
   INLINE void set_portal_geom(bool flag);
   INLINE bool get_portal_geom() const;
   INLINE bool get_portal_geom() const;
 
 
+  INLINE void clear_vertices();
+  INLINE void add_vertex(const LPoint3f &vertex);
+
+  INLINE int get_num_vertices() const;
+  INLINE const LPoint3f &get_vertex(int n) const;
+
 protected:
 protected:
   virtual BoundingVolume *recompute_bound();
   virtual BoundingVolume *recompute_bound();
   virtual BoundingVolume *recompute_internal_bound();
   virtual BoundingVolume *recompute_internal_bound();
@@ -80,6 +87,9 @@ private:
   };
   };
   int _flags;
   int _flags;
 
 
+  typedef pvector<LPoint3f> Vertices;
+  Vertices _vertices;
+
 public:
 public:
   static void register_with_read_factory();
   static void register_with_read_factory();
   virtual void write_datagram(BamWriter *manager, Datagram &dg);
   virtual void write_datagram(BamWriter *manager, Datagram &dg);