1 /**************************************************************************\
2 * Copyright (c) Kongsberg Oil & Gas Technologies AS
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met:
8 *
9 * Redistributions of source code must retain the above copyright notice,
10 * this list of conditions and the following disclaimer.
11 *
12 * Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * Neither the name of the copyright holder nor the names of its
17 * contributors may be used to endorse or promote products derived from
18 * this software without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24 * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 \**************************************************************************/
32
33 // This is an internal class for holding user extension nodes from .iv
34 // files. The header file for this node is not exported at ``make
35 // install'', and the class is not documented for application
36 // programmers.
37
38 // FIXME: copy operations doesn't work as expected on this node. I
39 // think both the copyContents() and addToCopyDict() methods needs to
40 // be overridden. 20000404 mortene.
41
42 #include "nodes/SoUnknownNode.h"
43
44 #include <Inventor/SoInput.h>
45 #include <Inventor/SoOutput.h>
46 #include <Inventor/actions/SoGLRenderAction.h>
47 #include <Inventor/actions/SoGetBoundingBoxAction.h>
48 #include <Inventor/actions/SoPickAction.h>
49 #include <Inventor/actions/SoSearchAction.h>
50 #include <Inventor/actions/SoWriteAction.h>
51 #include <Inventor/errors/SoDebugError.h>
52 #include <Inventor/errors/SoReadError.h>
53 #include <Inventor/fields/SoSFNode.h>
54 #include <Inventor/misc/SoChildList.h>
55 #include <Inventor/nodes/SoGroup.h>
56 #include <Inventor/C/tidbits.h>
57
58 #include "io/SoWriterefCounter.h"
59 #include "io/SoInputP.h"
60 #include "tidbitsp.h"
61
62 // *************************************************************************
63
64 class SoUnknownNodeP {
65 public:
66 SbName classname;
67 SoChildList * privatechildren, * alternate;
68 };
69
70 // *************************************************************************
71
72 // The following code is used instead of SO_NODE_SOURCE() to let
73 // SoUnknownNodes have dynamic handling of SoFieldData objects.
74
75 PRIVATE_NODE_TYPESYSTEM_SOURCE(SoUnknownNode);
76
getFieldData(void) const77 const SoFieldData * SoUnknownNode::getFieldData(void) const
78 {
79 return this->classfielddata;
80 }
81
82 void *
createInstance(void)83 SoUnknownNode::createInstance(void)
84 {
85 return new SoUnknownNode;
86 }
87
88 #define PRIVATE(p) ((p)->pimpl)
89
90 // Node implementation starts "proper".
91
SoUnknownNode(void)92 SoUnknownNode::SoUnknownNode(void)
93 {
94 PRIVATE(this) = new SoUnknownNodeP;
95
96 /* Catch attempts to use a node class which has not been initialized. */
97 assert(SoUnknownNode::classTypeId != SoType::badType());
98 /* Initialize a fielddata container for the instance. */
99 this->classfielddata = new SoFieldData;
100
101 this->isBuiltIn = FALSE;
102 PRIVATE(this)->privatechildren = NULL;
103 PRIVATE(this)->alternate = new SoChildList(this, 1);
104 }
105
~SoUnknownNode()106 SoUnknownNode::~SoUnknownNode()
107 {
108 for (int i=0; i < this->classfielddata->getNumFields(); i++)
109 delete this->classfielddata->getField(this, i);
110
111 delete this->classfielddata;
112 delete PRIVATE(this)->privatechildren;
113 delete PRIVATE(this)->alternate;
114 delete PRIVATE(this);
115 }
116
117 // doc in super
118 void
initClass(void)119 SoUnknownNode::initClass(void)
120 {
121 /* Make sure we only initialize once. */
122 assert(SoUnknownNode::classTypeId == SoType::badType());
123 /* Make sure superclass gets initialized before subclass. */
124 assert(inherited::getClassTypeId() != SoType::badType());
125
126 /* Set up entry in the type system. */
127 SoUnknownNode::classTypeId =
128 SoType::createType(inherited::getClassTypeId(),
129 "UnknownNode",
130 &SoUnknownNode::createInstance,
131 SoNode::nextActionMethodIndex++);
132 coin_atexit((coin_atexit_f*)SoUnknownNode::atexit_cleanup, CC_ATEXIT_NORMAL);
133 }
134
135 void
atexit_cleanup(void)136 SoUnknownNode::atexit_cleanup(void)
137 {
138 SoUnknownNode::classTypeId STATIC_SOTYPE_INIT;
139 }
140
141 SbBool
readInstance(SoInput * in,unsigned short flags)142 SoUnknownNode::readInstance(SoInput * in, unsigned short flags)
143 {
144 if (SoInputP::debug()) {
145 SoDebugError::postInfo("SoUnknownNode::readInstance",
146 "Reading extension node ``%s'' as SoUnknownNode.",
147 PRIVATE(this)->classname.getString());
148 }
149
150
151 SbBool notbuiltin;
152 // The "error on unknown field" is FALSE, in case we are a group
153 // node with children specified in the file.
154 if (!this->classfielddata->read(in, this, FALSE, notbuiltin)) return FALSE;
155
156 if (notbuiltin == FALSE) {
157 SoReadError::post(in, "Node type ``%s'' not recognized.",
158 PRIVATE(this)->classname.getString());
159 return FALSE;
160 }
161
162 // Set pointer to alternateRep node, if SoSFNode field with this
163 // name is present.
164 int i;
165 for (i=0; i < this->classfielddata->getNumFields(); i++) {
166 if (this->classfielddata->getFieldName(i) == "alternateRep") {
167 SoSFNode * f = (SoSFNode *)this->classfielddata->getField(this, i);
168 if (f->isOfType(SoSFNode::getClassTypeId())) {
169 #if COIN_DEBUG && 0 // debug
170 SoDebugError::postInfo("SoUnknownNode::readInstance",
171 "found alternate representation");
172 #endif // debug
173 if (!f->getValue()) break;
174 PRIVATE(this)->alternate->truncate(0);
175 PRIVATE(this)->alternate->append(f->getValue());
176 }
177 break;
178 }
179 }
180
181 // Read children, if necessary.
182 if (!in->isBinary() || (flags & SoBase::IS_GROUP)) {
183 SoGroup * g = new SoGroup;
184 g->ref();
185 if (!g->readChildren(in)) {
186 g->unref();
187 return FALSE;
188 }
189
190 #if COIN_DEBUG && 0 // debug
191 SoDebugError::postInfo("SoUnknownNode::readInstance",
192 "read %d children successfully",
193 g->getNumChildren());
194 #endif // debug
195
196 delete PRIVATE(this)->privatechildren;
197 PRIVATE(this)->privatechildren = new SoChildList(this, * g->getChildren());
198 g->unref();
199 }
200
201 // Check that all field descriptions did actually get a value
202 // set. It is not a fatal error if this didn't happen, but: 1) on
203 // subsequent write operations, information will be lost, and 2) the
204 // field value will probably be completely random because we're
205 // reading from uninitialized memory.
206 if (SoInputP::debug()) {
207 for (i=0; i < this->classfielddata->getNumFields(); i++) {
208 const SoField * f = this->classfielddata->getField(this, i);
209 if (f->isDefault()) {
210 SoReadError::post(in, "Field ``%s'' in extension node ``%s'' not "
211 "given any value.",
212 this->classfielddata->getFieldName(i).getString(),
213 PRIVATE(this)->classname.getString());
214 }
215 }
216 }
217
218 return TRUE;
219 }
220
221 // The name used for the nodes of this type in scene file.
222 void
setNodeClassName(const SbName & name)223 SoUnknownNode::setNodeClassName(const SbName & name)
224 {
225 PRIVATE(this)->classname = name;
226 }
227
228 // Overridden from SoBase.
229 const char *
getFileFormatName(void) const230 SoUnknownNode::getFileFormatName(void) const
231 {
232 return PRIVATE(this)->classname.getString();
233 }
234
235 // Overridden from SoNode. SoChildList contains either 0 or 1
236 // elements, depending on if an alternate representation was
237 // specified.
238 SoChildList *
getChildren(void) const239 SoUnknownNode::getChildren(void) const
240 {
241 return PRIVATE(this)->alternate;
242 }
243
244 // Write action method is overridden from SoNode to handle children.
245 void
write(SoWriteAction * action)246 SoUnknownNode::write(SoWriteAction * action)
247 {
248 SoOutput * out = action->getOutput();
249 if (out->getStage() == SoOutput::COUNT_REFS) {
250 inherited::write(action);
251 // Only increase number of writereferences to the top level node
252 // in a tree which is used multiple times.
253 if (!SoWriterefCounter::instance(out)->hasMultipleWriteRefs(this))
254 if (PRIVATE(this)->privatechildren) PRIVATE(this)->privatechildren->traverse(action);
255 }
256 else if (out->getStage() == SoOutput::WRITE) {
257 if (this->writeHeader(out, PRIVATE(this)->privatechildren ? TRUE : FALSE, FALSE))
258 return;
259 this->getFieldData()->write(out, this);
260 if (out->isBinary())
261 if (PRIVATE(this)->privatechildren) out->write(PRIVATE(this)->privatechildren->getLength());
262 if (PRIVATE(this)->privatechildren) PRIVATE(this)->privatechildren->traverse(action);
263 this->writeFooter(out);
264 }
265 else assert(0 && "unknown stage");
266 }
267
268 // Action methods overridden from SoNode to traverse alternateRep (and
269 // below, if alternateRep is a group node).
270
271 void
search(SoSearchAction * action)272 SoUnknownNode::search(SoSearchAction * action)
273 {
274 inherited::search(action);
275 if (action->isFound()) return;
276 PRIVATE(this)->alternate->traverse(action);
277 }
278
279 void
GLRender(SoGLRenderAction * action)280 SoUnknownNode::GLRender(SoGLRenderAction * action)
281 {
282 PRIVATE(this)->alternate->traverse(action);
283 }
284
285 void
getBoundingBox(SoGetBoundingBoxAction * action)286 SoUnknownNode::getBoundingBox(SoGetBoundingBoxAction * action)
287 {
288 PRIVATE(this)->alternate->traverse(action);
289 }
290
291 void
pick(SoPickAction * action)292 SoUnknownNode::pick(SoPickAction * action)
293 {
294 PRIVATE(this)->alternate->traverse(action);
295 }
296
297 SoNode *
addToCopyDict(void) const298 SoUnknownNode::addToCopyDict(void) const
299 {
300 // This function is copied from SoNode::addToCopyDict() and
301 // modified to handle the private children.
302
303 #if COIN_DEBUG && 0 // debug
304 SoDebugError::postInfo("SoUnknownNode::addToCopyDict",
305 "Name: %s", PRIVATE(this)->classname.getString());
306 #endif // debug
307
308 SoNode * cp = (SoNode *)SoFieldContainer::checkCopy(this);
309 if (!cp) {
310 cp = new SoUnknownNode;
311 SoFieldContainer::addCopy(this, cp);
312
313 if (PRIVATE(this)->privatechildren) {
314 for (int i = 0; i < PRIVATE(this)->privatechildren->getLength(); i++) {
315 (void) (*(PRIVATE(this)->privatechildren))[i]->addToCopyDict();
316 }
317 }
318 }
319
320 return cp;
321 }
322
323 void
copyContents(const SoFieldContainer * from,SbBool copyconnections)324 SoUnknownNode::copyContents(const SoFieldContainer * from,
325 SbBool copyconnections)
326 {
327 int i;
328 const SoUnknownNode * src = (const SoUnknownNode *) from;
329 this->setNodeClassName(PRIVATE(src)->classname);
330
331 const SoFieldData * srcdata = src->getFieldData();
332 SoFieldData * dstdata = (SoFieldData*) this->getFieldData();
333
334 for (i = 0; i < srcdata->getNumFields(); i++) {
335 const SoField * srcfield = srcdata->getField(src, i);
336 SoField * dstfield = (SoField*) srcfield->getTypeId().createInstance();
337
338 // add new field to field data
339 dstfield->setContainer(this);
340 dstdata->addField(this, srcdata->getFieldName(i), dstfield);
341 // copy field contents
342 dstfield->copyFrom(*srcfield);
343 // copy flags
344 dstfield->setIgnored(srcfield->isIgnored());
345 dstfield->setDefault(srcfield->isDefault());
346 dstfield->enableNotify(srcfield->isNotifyEnabled());
347 // fix complex fields (node, engine, and path fields)
348 dstfield->fixCopy(copyconnections);
349 // handle connections
350 if (copyconnections && srcfield->isConnected()) {
351 dstfield->copyConnection(dstfield);
352 }
353 }
354 if (PRIVATE(src)->privatechildren == NULL) return;
355
356 if (PRIVATE(this)->privatechildren == NULL) {
357 PRIVATE(this)->privatechildren = new SoChildList(this);
358 }
359
360 // copy private children, which we added to the copy dict in
361 // addToCopyDict()
362 for (i = 0; i < PRIVATE(src)->privatechildren->getLength(); i++) {
363 SoNode * copy = (SoNode*)
364 this->findCopy((*(PRIVATE(src)->privatechildren))[i],
365 copyconnections);
366 assert(copy && "unexpected error");
367 PRIVATE(this)->privatechildren->append(copy);
368 }
369 }
370
371 #undef PRIVATE
372