Panda3D
Loading...
Searching...
No Matches
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
23using std::ostream;
24
25
26//
27// Static list of node types.
28//
29plist<VrmlNodeType*> VrmlNodeType::typeList;
30
31static ostream &
32output_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
58ostream &
59output_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
148VrmlNodeType::VrmlNodeType(const char *nm)
149{
150 nassertv(nm != nullptr);
151 name = strdup(nm);
152}
153
154VrmlNodeType::~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
178void
179VrmlNodeType::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//
193void
194VrmlNodeType::pushNameSpace()
195{
196 typeList.push_front(nullptr);
197}
198
199void
200VrmlNodeType::popNameSpace()
201{
202 // Remove everything up to and including the next NULL marker:
203 plist<VrmlNodeType*>::iterator i;
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
222const VrmlNodeType *
223VrmlNodeType::find(const char *_name)
224{
225 // Look through the type stack:
226 plist<VrmlNodeType*>::iterator i;
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
236void
237VrmlNodeType::addEventIn(const char *name, int type,
238 const VrmlFieldValue *dflt)
239{
240 add(eventIns, name, type, dflt);
241};
242void
243VrmlNodeType::addEventOut(const char *name, int type,
244 const VrmlFieldValue *dflt)
245{
246 add(eventOuts, name, type, dflt);
247};
248void
249VrmlNodeType::addField(const char *name, int type,
250 const VrmlFieldValue *dflt)
251{
252 add(fields, name, type, dflt);
253};
254void
255VrmlNodeType::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
266void
267VrmlNodeType::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
282VrmlNodeType::hasEventIn(const char *name) const
283{
284 return has(eventIns, name);
285}
286
288VrmlNodeType::hasEventOut(const char *name) const
289{
290 return has(eventOuts, name);
291}
292
294VrmlNodeType::hasField(const char *name) const
295{
296 return has(fields, name);
297}
298
300VrmlNodeType::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
329VrmlNodeType::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
This is our own Panda specialization on the default STL list.
Definition plist.h:35
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.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.