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 #ifdef HAVE_CONFIG_H
34 #include <config.h>
35 #endif // HAVE_CONFIG_H
36 
37 #ifdef HAVE_VRML97
38 
39 /*!
40   \class SoVRMLInline SoVRMLInline.h Inventor/VRMLnodes/SoVRMLInline.h
41   \brief The SoVRMLInline class is used to insert VRML files into a scene.
42 
43   \ingroup VRMLnodes
44 
45   \WEB3DCOPYRIGHT
46 
47   \verbatim
48   Inline {
49     exposedField MFString url        []
50     field        SFVec3f  bboxCenter 0 0 0     # (-,)
51     field        SFVec3f  bboxSize   -1 -1 -1  # (0,) or -1,-1,-1
52   }
53   \endverbatim
54 
55   The Inline node is a grouping node that reads its children data from
56   a location in the World Wide Web. Exactly when its children are read
57   and displayed is not defined (e.g. reading the children may be
58   delayed until the Inline node's bounding box is visible to the
59   viewer). The url field specifies the URL containing the children. An
60   Inline node with an empty URL does nothing.
61 
62   Each specified URL shall refer to a valid VRML file that contains a
63   list of children nodes, prototypes, and routes at the top level as
64   described in 4.6.5, Grouping and children nodes.
65 
66   The results are undefined if the URL refers to a file that is not
67   VRML or if the VRML file contains non-children nodes at the top
68   level.
69 
70   If multiple URLs are specified, the browser may display a URL of a
71   lower preference VRML file while it is obtaining, or if it is unable
72   to obtain, the higher preference VRML file. Details on the url field
73   and preference order can be found in 4.5, VRML and the World Wide
74   Web
75   (<http://www.web3d.org/documents/specifications/14772/V2.0/part1/concepts.html#4.5>).
76 
77   The results are undefined if the contents of the URL change after it
78   has been loaded.
79 
80   The bboxCenter and bboxSize fields specify a bounding box that
81   encloses the Inline node's children. This is a hint that may be used
82   for optimization purposes. The results are undefined if the
83   specified bounding box is smaller than the actual bounding box of
84   the children at any time. A default bboxSize value, (-1, -1, -1),
85   implies that the bounding box is not specified and if needed shall
86   be calculated by the browser. A description of the bboxCenter and
87   bboxSize fields is in 4.6.4, Bounding boxes
88   (<http://www.web3d.org/documents/specifications/14772/V2.0/part1/concepts.html#4.6.4>).
89 
90 */
91 
92 /*!
93   SoSFVec3f SoVRMLInline::bboxCenter
94   Center of bounding box.
95 */
96 
97 /*!
98   SoSFVec3f SoVRMLInline::bboxSize
99   Size of bounding box.
100 */
101 
102 /*!
103   SoMFString SoVRMLInline::url
104   The VRML file URL.
105 */
106 
107 /*!
108   enum SoVRMLInline::BboxVisibility
109   Used to enumerate bounding box visibility settings.
110 */
111 
112 /*!
113   \var SoVRMLInline::BboxVisibility SoVRMLInline::NEVER
114   Never display bounding box.
115 */
116 
117 /*!
118   \var SoVRMLInline::BboxVisibility SoVRMLInline::UNTIL_LOADED
119   Display bounding box until file is loaded.
120 */
121 
122 /*!
123   \var SoVRMLInline::BboxVisibility SoVRMLInline::ALWAYS
124   Always display bounding box.
125 */
126 
127 /*! \file SoVRMLInline.h */
128 #include <Inventor/VRMLnodes/SoVRMLInline.h>
129 #include "coindefs.h"
130 
131 #include <cstdlib>
132 
133 #include <Inventor/VRMLnodes/SoVRMLMacros.h>
134 #include <Inventor/nodes/SoSeparator.h>
135 #include <Inventor/SbColor.h>
136 #include <Inventor/SoInput.h>
137 #include <Inventor/SoDB.h>
138 #include <Inventor/SbBox3f.h>
139 #include <Inventor/errors/SoReadError.h>
140 #include <Inventor/actions/SoActions.h>
141 #include <Inventor/actions/SoSearchAction.h>
142 #include <Inventor/actions/SoGLRenderAction.h>
143 #include <Inventor/actions/SoGetBoundingBoxAction.h>
144 #include <Inventor/misc/SoChildList.h>
145 #include <Inventor/sensors/SoFieldSensor.h>
146 #include <Inventor/elements/SoGLLazyElement.h>
147 #include <Inventor/elements/SoGLMultiTextureEnabledElement.h>
148 #include <Inventor/system/gl.h>
149 
150 #include "nodes/SoSubNodeP.h"
151 #include "tidbitsp.h"
152 
153 class SoVRMLInlineP {
154 public:
155   SbString fullurlname;
156   SbBool isrequested;
157   SoChildList * children;
158   SoFieldSensor * urlsensor;
159 };
160 
161 static SoVRMLInline::BboxVisibility
162 sovrmlinline_bboxvisibility = SoVRMLInline::UNTIL_LOADED;
163 static SoVRMLInlineFetchURLCB * sovrmlinline_fetchurlcb = NULL;
164 static void * sovrmlinline_fetchurlcbclosure;
165 
166 static SbColor * sovrmlinline_bboxcolor = NULL;
167 static SbBool sovrmlinline_readassofile = TRUE;
168 
169 static void
sovrmlinline_cleanup(void)170 sovrmlinline_cleanup(void)
171 {
172   delete sovrmlinline_bboxcolor;
173   sovrmlinline_bboxcolor = NULL;
174   sovrmlinline_bboxvisibility = SoVRMLInline::UNTIL_LOADED;
175   sovrmlinline_fetchurlcb = NULL;
176   sovrmlinline_readassofile = TRUE;
177 }
178 
179 SO_NODE_SOURCE(SoVRMLInline);
180 
181 // Doc in parent
182 void
initClass(void)183 SoVRMLInline::initClass(void)
184 {
185   SO_NODE_INTERNAL_INIT_CLASS(SoVRMLInline, SO_VRML97_NODE_TYPE);
186   sovrmlinline_bboxcolor = new SbColor(0.8f, 0.8f, 0.8f);
187   coin_atexit((coin_atexit_f*) sovrmlinline_cleanup, CC_ATEXIT_NORMAL);
188   SoAudioRenderAction::addMethod(SoVRMLInline::getClassTypeId(),
189                                  SoAudioRenderAction::callDoAction);
190 }
191 
192 #define PRIVATE(obj) ((obj)->pimpl)
193 
194 /*!
195   Constructor
196 */
SoVRMLInline(void)197 SoVRMLInline::SoVRMLInline(void)
198 {
199   PRIVATE(this) = new SoVRMLInlineP;
200   PRIVATE(this)->isrequested = FALSE;
201   PRIVATE(this)->children = new SoChildList(this);
202 
203   SO_VRMLNODE_INTERNAL_CONSTRUCTOR(SoVRMLInline);
204 
205   SO_VRMLNODE_ADD_FIELD(bboxCenter, (0.0f, 0.0f, 0.0f));
206   SO_VRMLNODE_ADD_FIELD(bboxSize, (-1.0f, -1.0f, -1.0f));
207   SO_VRMLNODE_ADD_EMPTY_EXPOSED_MFIELD(url);
208 
209   PRIVATE(this)->urlsensor = new SoFieldSensor(SoVRMLInline::urlFieldModified, this);
210   PRIVATE(this)->urlsensor->setPriority(0); // immediate sensor
211   PRIVATE(this)->urlsensor->attach(& this->url);
212 }
213 
214 /*!
215   Destructor.
216 */
~SoVRMLInline()217 SoVRMLInline::~SoVRMLInline()
218 {
219   delete PRIVATE(this)->urlsensor;
220   delete PRIVATE(this)->children;
221   delete PRIVATE(this);
222 }
223 
224 /*!
225   Sets the full (non-relative) URL name.
226 */
227 void
setFullURLName(const SbString & urlref)228 SoVRMLInline::setFullURLName(const SbString & urlref)
229 {
230   PRIVATE(this)->fullurlname = urlref;
231 }
232 
233 /*!
234   Returns the full URL name.
235 */
236 const SbString &
getFullURLName(void)237 SoVRMLInline::getFullURLName(void)
238 {
239   return PRIVATE(this)->fullurlname;
240 }
241 
242 /*!
243   Returns a copy of the children.
244 */
245 SoGroup *
copyChildren(void) const246 SoVRMLInline::copyChildren(void) const
247 {
248   if (PRIVATE(this)->children->getLength() == 0) return NULL;
249   assert(PRIVATE(this)->children->getLength() == 1);
250   SoNode * rootcopy = (*(PRIVATE(this)->children))[0]->copy();
251   assert(rootcopy->isOfType(SoGroup::getClassTypeId()));
252   return (SoGroup *)rootcopy;
253 }
254 
255 // Doc in parent
256 SoChildList *
getChildren(void) const257 SoVRMLInline::getChildren(void) const
258 {
259   return PRIVATE(this)->children;
260 }
261 
262 /*!
263   Request URL data.
264 */
265 void
requestURLData(void)266 SoVRMLInline::requestURLData(void)
267 {
268   PRIVATE(this)->isrequested = TRUE;
269   if (sovrmlinline_fetchurlcb) {
270     sovrmlinline_fetchurlcb(PRIVATE(this)->fullurlname,
271                             sovrmlinline_fetchurlcbclosure,
272                             this);
273   }
274 }
275 
276 /*!
277   Returns TRUE if the URL data has been requested.
278 */
279 SbBool
isURLDataRequested(void) const280 SoVRMLInline::isURLDataRequested(void) const
281 {
282   return PRIVATE(this)->isrequested;
283 }
284 
285 /*!
286   Returns TRUE if the data has been loaded.
287 */
288 SbBool
isURLDataHere(void) const289 SoVRMLInline::isURLDataHere(void) const
290 {
291   return this->getChildData() != NULL;
292 }
293 
294 /*!
295   Cancel the URL data request.
296 */
297 void
cancelURLDataRequest(void)298 SoVRMLInline::cancelURLDataRequest(void)
299 {
300   PRIVATE(this)->isrequested = FALSE;
301 }
302 
303 /*!
304   Sets the child data. Can be used by the URL fetch callback.
305 */
306 void
setChildData(SoNode * urldata)307 SoVRMLInline::setChildData(SoNode * urldata)
308 {
309   PRIVATE(this)->isrequested = FALSE;
310   PRIVATE(this)->children->truncate(0);
311   if (urldata) {
312     PRIVATE(this)->children->append(urldata);
313   }
314 }
315 
316 /*!
317   Returns the child data (the scene loaded from the url).
318 */
319 SoNode *
getChildData(void) const320 SoVRMLInline::getChildData(void) const
321 {
322   if (PRIVATE(this)->children->getLength()) {
323     return (*PRIVATE(this)->children)[0];
324   }
325   return NULL;
326 }
327 
328 /*!
329   Sets the callback used to handle URL loading.
330 */
331 void
setFetchURLCallBack(SoVRMLInlineFetchURLCB * f,void * closure)332 SoVRMLInline::setFetchURLCallBack(SoVRMLInlineFetchURLCB * f,
333                                   void * closure)
334 {
335   sovrmlinline_fetchurlcb = f;
336   sovrmlinline_fetchurlcbclosure = closure;
337 }
338 
339 /*!
340   Sets the bounding box visibility strategy.
341 */
342 void
setBoundingBoxVisibility(BboxVisibility b)343 SoVRMLInline::setBoundingBoxVisibility(BboxVisibility b)
344 {
345   sovrmlinline_bboxvisibility = b;
346 }
347 
348 /*!
349   Returns the bounding box visibility strategy.
350 */
351 SoVRMLInline::BboxVisibility
getBoundingBoxVisibility(void)352 SoVRMLInline::getBoundingBoxVisibility(void)
353 {
354   return sovrmlinline_bboxvisibility;
355 }
356 
357 /*!
358   Sets the color of the bounding box.
359 */
360 void
setBoundingBoxColor(SbColor & color)361 SoVRMLInline::setBoundingBoxColor(SbColor & color)
362 {
363   sovrmlinline_bboxcolor->setValue(color[0], color[1], color[2]);
364 }
365 
366 /*!
367   Returns the color of the bounding box.
368 */
369 SbColor &
getBoundingBoxColor(void)370 SoVRMLInline::getBoundingBoxColor(void)
371 {
372   return *sovrmlinline_bboxcolor;
373 }
374 
375 /*!
376   Sets whether Inline nodes should be treated as a normal Inventor SoFile node.
377 */
378 void
setReadAsSoFile(SbBool enable)379 SoVRMLInline::setReadAsSoFile(SbBool enable)
380 {
381   sovrmlinline_readassofile = enable;
382 }
383 
384 /*!
385   Returns whether Inline nodes is read as SoFile nodes.
386 */
387 SbBool
getReadAsSoFile(void)388 SoVRMLInline::getReadAsSoFile(void)
389 {
390   return sovrmlinline_readassofile;
391 }
392 
393 // Doc in parent
394 void
doAction(SoAction * action)395 SoVRMLInline::doAction(SoAction * action)
396 {
397   int numindices;
398   const int * indices;
399   if (action->getPathCode(numindices, indices) == SoAction::IN_PATH) {
400     PRIVATE(this)->children->traverseInPath(action, numindices, indices);
401   }
402   else {
403     PRIVATE(this)->children->traverse(action);
404   }
405 }
406 
407 // Doc in parent
408 void
callback(SoCallbackAction * action)409 SoVRMLInline::callback(SoCallbackAction * action)
410 {
411   SoVRMLInline::doAction((SoAction*)action);
412 }
413 
414 // Doc in parent
415 void
GLRender(SoGLRenderAction * action)416 SoVRMLInline::GLRender(SoGLRenderAction * action)
417 {
418   BboxVisibility vis = sovrmlinline_bboxvisibility;
419   SbVec3f size = this->bboxSize.getValue();
420   SoNode * child = this->getChildData();
421   if ((size[0] >= 0.0f && size[1] >= 0.0f && size[2] >= 0.0f) &&
422       ((vis == ALWAYS) ||
423        (vis == UNTIL_LOADED && child == NULL))) {
424     SoState * state = action->getState();
425     state->push();
426 
427     SoGLMultiTextureEnabledElement::disableAll(state);
428 
429     uint32_t packedcolor = sovrmlinline_bboxcolor->getPackedValue();
430     SoGLLazyElement::sendLightModel(state, SoLazyElement::BASE_COLOR);
431     SoGLLazyElement::sendPackedDiffuse(state, packedcolor);
432 
433     SbVec3f center = this->bboxCenter.getValue();
434     SbVec3f minv = center - size*0.5f;
435     SbVec3f maxv = center + size*0.5f;
436 
437     SbVec3f p[8];
438     for (int i = 0; i < 8; i++) {
439       p[i][0] = i & 1 ? minv[0] : maxv[0];
440       p[i][1] = i & 2 ? minv[1] : maxv[1];
441       p[i][2] = i & 4 ? minv[2] : maxv[2];
442     }
443 
444     glBegin(GL_LINE_LOOP);
445     glVertex3fv(p[0].getValue());
446     glVertex3fv(p[1].getValue());
447     glVertex3fv(p[3].getValue());
448     glVertex3fv(p[2].getValue());
449     glEnd();
450 
451     glBegin(GL_LINE_LOOP);
452     glVertex3fv(p[4].getValue());
453     glVertex3fv(p[5].getValue());
454     glVertex3fv(p[7].getValue());
455     glVertex3fv(p[6].getValue());
456     glEnd();
457 
458     glBegin(GL_LINES);
459 
460     glVertex3fv(p[0].getValue());
461     glVertex3fv(p[4].getValue());
462 
463     glVertex3fv(p[2].getValue());
464     glVertex3fv(p[6].getValue());
465 
466     glVertex3fv(p[3].getValue());
467     glVertex3fv(p[7].getValue());
468 
469     glVertex3fv(p[1].getValue());
470     glVertex3fv(p[5].getValue());
471 
472     glEnd();
473     state->pop();
474   }
475   SoVRMLInline::doAction(action);
476 }
477 
478 // Doc in parent
479 void
getBoundingBox(SoGetBoundingBoxAction * action)480 SoVRMLInline::getBoundingBox(SoGetBoundingBoxAction * action)
481 {
482   SbVec3f size = this->bboxSize.getValue();
483   if (size[0] > 0.0f || size[1] > 0.0f || size[2] > 0) {
484     size[0] = SbMax(size[0], 0.0f);
485     size[1] = SbMax(size[1], 0.0f);
486     size[2] = SbMax(size[2], 0.0f);
487     SbVec3f center = this->bboxCenter.getValue();
488     size *= 0.5f;
489     SbBox3f box(center[0]-size[0],
490                 center[1]-size[1],
491                 center[2]-size[2],
492                 center[0]+size[0],
493                 center[1]+size[1],
494                 center[2]+size[2]);
495     if (!box.isEmpty()) {
496       action->extendBy(box);
497       action->setCenter(center, TRUE);
498     }
499   }
500   else {
501     int numindices;
502     const int * indices;
503     int lastchildindex;
504 
505     if (action->getPathCode(numindices, indices) == SoAction::IN_PATH)
506       lastchildindex = indices[numindices-1];
507     else
508       lastchildindex = this->getChildren()->getLength() - 1;
509 
510     assert(lastchildindex < this->getChildren()->getLength());
511 
512     // Initialize accumulation variables.
513     SbVec3f acccenter(0.0f, 0.0f, 0.0f);
514     int numcenters = 0;
515 
516     for (int i = 0; i <= lastchildindex; i++) {
517       this->getChildren()->traverse(action, i);
518 
519       // If center point is set, accumulate.
520       if (action->isCenterSet()) {
521         acccenter += action->getCenter();
522         numcenters++;
523         action->resetCenter();
524       }
525     }
526 
527     if (numcenters != 0)
528       action->setCenter(acccenter / float(numcenters), FALSE);
529   }
530 }
531 
532 // Doc in parent
533 void
getMatrix(SoGetMatrixAction * action)534 SoVRMLInline::getMatrix(SoGetMatrixAction * action)
535 {
536   SoVRMLInline::doAction((SoAction*)action);
537 }
538 
539 // Doc in parent
540 void
handleEvent(SoHandleEventAction * action)541 SoVRMLInline::handleEvent(SoHandleEventAction * action)
542 {
543   SoVRMLInline::doAction((SoAction*)action);
544 }
545 
546 // Doc in parent
547 void
search(SoSearchAction * action)548 SoVRMLInline::search(SoSearchAction * action)
549 {
550   SoNode::search(action);
551   if (action->isFound()) return;
552 
553   SoVRMLInline::doAction(action);
554 }
555 
556 // Doc in parent
557 void
pick(SoPickAction * action)558 SoVRMLInline::pick(SoPickAction * action)
559 {
560   SoVRMLInline::doAction((SoAction*)action);
561 }
562 
563 // Doc in parent
564 void
getPrimitiveCount(SoGetPrimitiveCountAction * action)565 SoVRMLInline::getPrimitiveCount(SoGetPrimitiveCountAction * action)
566 {
567   SoVRMLInline::doAction((SoAction*)action);
568 }
569 
570 void
addBoundingBoxChild(SbVec3f COIN_UNUSED_ARG (center),SbVec3f COIN_UNUSED_ARG (size))571 SoVRMLInline::addBoundingBoxChild(SbVec3f COIN_UNUSED_ARG(center),
572                                   SbVec3f COIN_UNUSED_ARG(size))
573 {
574   // FIXME: implement
575 }
576 
577 // Doc in parent
578 SbBool
readInstance(SoInput * in,unsigned short flags)579 SoVRMLInline::readInstance(SoInput * in,
580                            unsigned short flags)
581 {
582   SbBool ret = TRUE;
583 
584   PRIVATE(this)->urlsensor->detach();
585   if (sovrmlinline_readassofile) {
586     PRIVATE(this)->fullurlname.makeEmpty();
587     ret = inherited::readInstance(in, flags);
588     ret = ret && this->readLocalFile(in);
589   }
590   else {
591     ret = inherited::readInstance(in, flags);
592     if (ret) this->requestURLData();
593   }
594   PRIVATE(this)->urlsensor->attach(&this->url);
595 
596   return ret;
597 }
598 
599 // Doc in parent
600 void
copyContents(const SoFieldContainer * from,SbBool copyconnections)601 SoVRMLInline::copyContents(const SoFieldContainer * from,
602                            SbBool copyconnections)
603 {
604   PRIVATE(this)->children->truncate(0);
605   inherited::copyContents(from, copyconnections);
606 
607   SoVRMLInline * inlinenode = (SoVRMLInline *)from;
608   PRIVATE(this)->fullurlname = inlinenode->pimpl->fullurlname;
609   // the request will go to the original node, not this one.
610   PRIVATE(this)->isrequested = FALSE;
611 
612   if (inlinenode->pimpl->children->getLength() == 0) return;
613 
614   assert(inlinenode->pimpl->children->getLength() == 1);
615 
616   SoNode * cp = (SoNode *)
617     SoFieldContainer::findCopy((*(inlinenode->pimpl->children))[0],
618                                copyconnections);
619   PRIVATE(this)->children->append(cp);
620 }
621 
622 /*!
623   Read the (local) file named in the SoVRMLInline::url field.
624 */
625 SbBool
readLocalFile(SoInput * in)626 SoVRMLInline::readLocalFile(SoInput * in)
627 {
628   if (this->url.getNum() == 0) {
629     return TRUE;
630   }
631 
632   SbString filename = this->url[0];
633 
634   // If we can't find file, ignore it. Note that this does not match
635   // the way Inventor works, which will make the whole read process
636   // exit with a failure code.
637   if (!in->pushFile(filename.getString())) return TRUE;
638 
639   PRIVATE(this)->fullurlname = in->getCurFileName();
640 
641   SoSeparator * node = SoDB::readAll(in);
642 
643   if (node) {
644     PRIVATE(this)->children->truncate(0);
645     PRIVATE(this)->children->append((SoNode *)node);
646   }
647   else {
648     if (in->getCurFileName() == PRIVATE(this)->fullurlname) {
649       // Take care of popping the file off the stack. This is a bit
650       // "hack-ish", but its done this way instead of loosening the
651       // protection of SoInput::popFile().
652       char dummy;
653       while (!in->eof() && in->get(dummy)) {}
654       assert(in->eof());
655 
656       // Make sure the stack is really popped on EOF. Popping happens
657       // when attempting to read when the current file in the stack is
658       // at EOF.
659       SbBool gotchar = in->get(dummy);
660       if (gotchar) in->putBack(dummy);
661     }
662 
663     // Note that we handle this differently than Inventor, which lets
664     // the whole import fail.
665     SoReadError::post(in, "Unable to read Inline file: ``%s''",
666                       filename.getString());
667   }
668 
669   return TRUE;
670 }
671 
672 // Callback for the field sensor.
673 void
urlFieldModified(void * userdata,SoSensor * COIN_UNUSED_ARG (sensor))674 SoVRMLInline::urlFieldModified(void * userdata, SoSensor * COIN_UNUSED_ARG(sensor))
675 {
676   SoVRMLInline * thisp = (SoVRMLInline *)userdata;
677   SoInput in;
678   thisp->pimpl->fullurlname.makeEmpty();
679   if (sovrmlinline_readassofile) {
680     (void)thisp->readLocalFile(&in);
681   }
682   else {
683     thisp->requestURLData();
684   }
685 }
686 
687 #undef PRIVATE
688 
689 #endif // HAVE_VRML97
690