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