Panda3D
vrmlNodeType.cxx
1 /**************************************************
2  * VRML 2.0 Parser
3  * Copyright (C) 1996 Silicon Graphics, Inc.
4  *
5  * Author(s) : Gavin Bell
6  * Daniel Woods (first port)
7  **************************************************
8  */
9 
10 //
11 // The VrmlNodeType class is responsible for storing information about node
12 // or prototype types.
13 //
14 
15 #include "vrmlNodeType.h"
16 #include "vrmlNode.h"
17 #include "vrmlParser.h"
18 #include "pnotify.h"
19 #include "indent.h"
20 
21 #include <stdio.h> // for sprintf()
22 
23 using std::ostream;
24 
25 
26 //
27 // Static list of node types.
28 //
29 plist<VrmlNodeType*> VrmlNodeType::typeList;
30 
31 static ostream &
32 output_array(ostream &out, const MFArray *mf,
33  int type, int indent_level, int items_per_row) {
34  if (mf->empty()) {
35  out << "[ ]";
36  } else {
37  out << "[";
38  MFArray::const_iterator mi;
39  int col = 0;
40  for (mi = mf->begin(); mi != mf->end(); ++mi) {
41  if (col == 0) {
42  out << "\n";
43  indent(out, indent_level + 2);
44  }
45  output_value(out, (*mi), type, indent_level + 2);
46  if (++col >= items_per_row) {
47  col = 0;
48  } else {
49  out << " ";
50  }
51  }
52  out << "\n";
53  indent(out, indent_level) << "]";
54  }
55  return out;
56 }
57 
58 ostream &
59 output_value(ostream &out, const VrmlFieldValue &value, int type,
60  int indent) {
61  switch (type) {
62  case SFBOOL:
63  return out << (value._sfbool ? "TRUE" : "FALSE");
64 
65  case SFFLOAT:
66  case SFTIME:
67  return out << value._sffloat;
68 
69  case SFINT32:
70  return out << value._sfint32;
71 
72  case SFSTRING:
73  {
74  out << '"';
75  for (const char *p = value._sfstring; *p != '\0'; p++) {
76  if (*p == '"') {
77  out << "\\\"";
78  } else {
79  out << *p;
80  }
81  }
82  return out << '"';
83  }
84 
85  case SFVEC2F:
86  return out << value._sfvec[0] << " " << value._sfvec[1];
87 
88  case SFCOLOR:
89  case SFVEC3F:
90  return out << value._sfvec[0] << " " << value._sfvec[1] << " "
91  << value._sfvec[2];
92 
93  case SFROTATION:
94  return out << value._sfvec[0] << " " << value._sfvec[1] << " "
95  << value._sfvec[2] << " " << value._sfvec[3];
96 
97  case SFNODE:
98  switch (value._sfnode._type) {
99  case SFNodeRef::T_null:
100  return out << "NULL";
101 
102  case SFNodeRef::T_unnamed:
103  nassertr(value._sfnode._p != nullptr, out);
104  value._sfnode._p->output(out, indent);
105  return out;
106 
107  case SFNodeRef::T_def:
108  out << "DEF " << value._sfnode._name << " ";
109  value._sfnode._p->output(out, indent);
110  return out;
111 
112  case SFNodeRef::T_use:
113  return out << "USE " << value._sfnode._name;
114  }
115  return out << "(invalid)";
116 
117  case SFIMAGE:
118  return out << "(image)";
119 
120  case MFCOLOR:
121  return output_array(out, value._mf, SFCOLOR, indent, 1);
122 
123  case MFFLOAT:
124  return output_array(out, value._mf, SFFLOAT, indent, 5);
125 
126  case MFINT32:
127  return output_array(out, value._mf, SFINT32, indent, 10);
128 
129  case MFROTATION:
130  return output_array(out, value._mf, SFROTATION, indent, 1);
131 
132  case MFSTRING:
133  return output_array(out, value._mf, SFSTRING, indent, 1);
134 
135  case MFVEC2F:
136  return output_array(out, value._mf, SFVEC2F, indent, 1);
137 
138  case MFVEC3F:
139  return output_array(out, value._mf, SFVEC3F, indent, 1);
140 
141  case MFNODE:
142  return output_array(out, value._mf, SFNODE, indent, 1);
143  }
144 
145  return out << "(unknown)";
146 }
147 
148 VrmlNodeType::VrmlNodeType(const char *nm)
149 {
150  nassertv(nm != nullptr);
151  name = strdup(nm);
152 }
153 
154 VrmlNodeType::~VrmlNodeType()
155 {
156  free(name);
157 
158  // Free strings duplicated when fields/eventIns/eventOuts added:
159  plist<NameTypeRec*>::iterator i;
160 
161  for (i = eventIns.begin(); i != eventIns.end(); i++) {
162  NameTypeRec *r = *i;
163  free(r->name);
164  delete r;
165  }
166  for (i = eventOuts.begin(); i != eventOuts.end(); i++) {
167  NameTypeRec *r = *i;
168  free(r->name);
169  delete r;
170  }
171  for (i = fields.begin(); i != fields.end(); i++) {
172  NameTypeRec *r = *i;
173  free(r->name);
174  delete r;
175  }
176 }
177 
178 void
179 VrmlNodeType::addToNameSpace(VrmlNodeType *_type)
180 {
181  if (find(_type->getName()) != nullptr) {
182  std::cerr << "PROTO " << _type->getName() << " already defined\n";
183  return;
184  }
185  typeList.push_front(_type);
186 }
187 
188 //
189 // One list is used to store all the node types. Nested namespaces are
190 // separated by NULL elements.
191 // This isn't terribly efficient, but it is nice and simple.
192 //
193 void
194 VrmlNodeType::pushNameSpace()
195 {
196  typeList.push_front(nullptr);
197 }
198 
199 void
200 VrmlNodeType::popNameSpace()
201 {
202  // Remove everything up to and including the next NULL marker:
204  for (i = typeList.begin(); i != typeList.end();) {
205  VrmlNodeType *nodeType = *i;
206  ++i;
207  typeList.pop_front();
208 
209  if (nodeType == nullptr) {
210  break;
211  }
212  else {
213  // NOTE: Instead of just deleting the VrmlNodeTypes, you will
214  // probably want to reference count or garbage collect them, since
215  // any nodes created as part of the PROTO implementation will
216  // probably point back to their VrmlNodeType structure.
217  delete nodeType;
218  }
219  }
220 }
221 
222 const VrmlNodeType *
223 VrmlNodeType::find(const char *_name)
224 {
225  // Look through the type stack:
227  for (i = typeList.begin(); i != typeList.end(); i++) {
228  const VrmlNodeType *nt = *i;
229  if (nt != nullptr && strcmp(nt->getName(),_name) == 0) {
230  return nt;
231  }
232  }
233  return nullptr;
234 }
235 
236 void
237 VrmlNodeType::addEventIn(const char *name, int type,
238  const VrmlFieldValue *dflt)
239 {
240  add(eventIns, name, type, dflt);
241 };
242 void
243 VrmlNodeType::addEventOut(const char *name, int type,
244  const VrmlFieldValue *dflt)
245 {
246  add(eventOuts, name, type, dflt);
247 };
248 void
249 VrmlNodeType::addField(const char *name, int type,
250  const VrmlFieldValue *dflt)
251 {
252  add(fields, name, type, dflt);
253 };
254 void
255 VrmlNodeType::addExposedField(const char *name, int type,
256  const VrmlFieldValue *dflt)
257 {
258  char tmp[1000];
259  add(fields, name, type, dflt);
260  sprintf(tmp, "set_%s", name);
261  add(eventIns, tmp, type, dflt);
262  sprintf(tmp, "%s_changed", name);
263  add(eventOuts, tmp, type, dflt);
264 };
265 
266 void
267 VrmlNodeType::add(plist<NameTypeRec*> &recs, const char *name, int type,
268  const VrmlFieldValue *dflt)
269 {
270  NameTypeRec *r = new NameTypeRec;
271  r->name = strdup(name);
272  r->type = type;
273  if (dflt != nullptr) {
274  r->dflt = *dflt;
275  } else {
276  memset(&r->dflt, 0, sizeof(r->dflt));
277  }
278  recs.push_front(r);
279 }
280 
282 VrmlNodeType::hasEventIn(const char *name) const
283 {
284  return has(eventIns, name);
285 }
286 
288 VrmlNodeType::hasEventOut(const char *name) const
289 {
290  return has(eventOuts, name);
291 }
292 
294 VrmlNodeType::hasField(const char *name) const
295 {
296  return has(fields, name);
297 }
298 
300 VrmlNodeType::hasExposedField(const char *name) const
301 {
302  // Must have field "name", eventIn "set_name", and eventOut
303  // "name_changed", all with same type:
304  char tmp[1000];
305  const NameTypeRec *base, *set_name, *name_changed;
306 
307  base = has(fields, name);
308 
309  sprintf(tmp, "set_%s\n", name);
310  nassertr(strlen(tmp) < 1000, nullptr);
311  set_name = has(eventIns, tmp);
312 
313  sprintf(tmp, "%s_changed\n", name);
314  nassertr(strlen(tmp) < 1000, nullptr);
315  name_changed = has(eventOuts, tmp);
316 
317  if (base == nullptr || set_name == nullptr || name_changed == nullptr) {
318  return nullptr;
319  }
320 
321  if (base->type != set_name->type || base->type != name_changed->type) {
322  return nullptr;
323  }
324 
325  return base;
326 }
327 
329 VrmlNodeType::has(const plist<NameTypeRec*> &recs, const char *name) const
330 {
331  plist<NameTypeRec*>::const_iterator i;
332  for (i = recs.begin(); i != recs.end(); i++) {
333  if (strcmp((*i)->name, name) == 0)
334  return (*i);
335  }
336  return nullptr;
337 }
338 
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
std::ostream & indent(std::ostream &out, int indent_level)
A handy function for doing text formatting.
Definition: indent.cxx:20
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.