Source

Coin / src / fields / SoSFNode.cpp

Full commit
Morten Eriksen 08431c9 
Marius Kintel 3ba6b41 




























Morten Eriksen 08431c9 

Morten Eriksen e72636a 
Morten Eriksen d264f29 

Morten Eriksen e72636a 



Morten Eriksen 9f77b77 
Morten Eriksen e72636a 
Morten Eriksen 08431c9 

Morten Eriksen ebd19cc 
Morten Eriksen 08431c9 

Morten Eriksen ebd19cc 








Morten Eriksen 08431c9 

Morten Eriksen 9f77b77 


Morten Eriksen 6e80840 
Morten Eriksen 9f77b77 
Morten Eriksen ebd19cc 
Lars J. Aas eed39cc 
Tom Fredrik Blen… e73c0c5 

Morten Eriksen ebd19cc 

Morten Eriksen 456c584 
Morten Eriksen ebd19cc 
Morten Eriksen 08431c9 
Morten Eriksen d81f386 
Peder Blekken 7ef43f8 
Morten Eriksen 08431c9 



Lars J. Aas 92263e4 
Morten Eriksen 08431c9 
Morten Eriksen ebd19cc 

Morten Eriksen b1f6849 
Morten Eriksen 08431c9 

Morten Eriksen ebd19cc 
Morten Eriksen 08431c9 


Morten Eriksen d87e67e 
Morten Eriksen 08431c9 

Morten Eriksen ca8c805 




Morten Eriksen 08431c9 


Morten Eriksen 6e80840 
Morten Eriksen 3c915a0 
Morten Eriksen 6e80840 
Morten Eriksen 08431c9 

Morten Eriksen ca8c805 
Morten Eriksen 08431c9 

Morten Eriksen f190fee 
Morten Eriksen 08431c9 


Morten Eriksen ca8c805 

Morten Eriksen ebd19cc 










Morten Eriksen 32eb55e 

Peder Blekken f1dc8ca 
Morten Eriksen 82100f9 


Morten Eriksen 6e80840 
Morten Eriksen 3c915a0 







Morten Eriksen 6e80840 
Morten Eriksen 7e3ac07 

Morten Eriksen 82100f9 




Morten Eriksen 6e80840 
Morten Eriksen 3c915a0 




Morten Eriksen 6e80840 
Morten Eriksen 82100f9 
Morten Eriksen ebd19cc 

















Morten Eriksen 08431c9 


Morten Eriksen ebd19cc 
Tom Fredrik Blen… 87e6e7a 
Morten Eriksen 60488f3 
Morten Eriksen 5db1ba6 



Tom Fredrik Blen… 87e6e7a 


















Tom Fredrik Blen… 1609ce9 
Morten Eriksen 3712ad8 

Morten Eriksen ebd19cc 
Morten Eriksen 60488f3 
Morten Eriksen ebd19cc 
Tom Fredrik Blen… 87e6e7a 


Morten Eriksen ebd19cc 
Morten Eriksen 08431c9 

Morten Eriksen ebd19cc 
Morten Eriksen 08431c9 
Morten Eriksen e55111a 
Morten Eriksen 08431c9 
Peder Blekken 3fa1078 

Morten Eriksen d81f386 


Tom Fredrik Blen… e73c0c5 
Morten Eriksen d81f386 
Morten Eriksen e72636a 

Tom Fredrik Blen… e73c0c5 
Morten Eriksen e72636a 
Morten Eriksen 448968f 
Tom Fredrik Blen… e73c0c5 
Morten Eriksen 448968f 
Morten Eriksen d81f386 
Morten Eriksen 448968f 
Morten Eriksen d81f386 
Morten Eriksen 456c584 

Morten Eriksen ebd19cc 
Morten Eriksen 60488f3 
Morten Eriksen 456c584 
Morten Eriksen ebd19cc 
Morten Eriksen b1f6849 
Morten Eriksen ebd19cc 








Morten Eriksen 448968f 
Peder Blekken 3fa1078 






Tom Fredrik Blen… e73c0c5 
Peder Blekken 3fa1078 

Tom Fredrik Blen… e73c0c5 
Peder Blekken 3fa1078 


Tom Fredrik Blen… e73c0c5 
Peder Blekken 3fa1078 
Morten Eriksen ebd19cc 

Morten Eriksen 6e80840 
















Morten Eriksen ebd19cc 





Peder Blekken 4f1cdfb 



Morten Eriksen 6e80840 


Morten Eriksen 448968f 
Morten Eriksen 6e80840 
Morten Eriksen e72636a 
Peder Blekken 4f1cdfb 
Peder Blekken 453d723 
Peder Blekken 4f1cdfb 
Tom Fredrik Blen… e73c0c5 
Morten Eriksen 6e80840 
Morten Eriksen e72636a 
Morten Eriksen 6e80840 
Morten Eriksen e72636a 
Morten Eriksen 6e80840 
Morten Eriksen ebd19cc 







Morten Eriksen e72636a 




Tom Fredrik Blen… e73c0c5 
Morten Eriksen e72636a 

Tom Fredrik Blen… e73c0c5 
Morten Eriksen e72636a 





Morten Eriksen ebd19cc 

Morten Eriksen 08431c9 
Morten Eriksen 9f77b77 

Morten Eriksen 6e80840 
Morten Eriksen e72636a 
Lars J. Aas eed39cc 


Morten Eriksen d264f29 


Lars J. Aas eed39cc 








Morten Eriksen d264f29 






Eigil Samset 19be53e 
Morten Eriksen d264f29 

Tom Fredrik Blen… 013327d 
Morten Eriksen d264f29 








Lars J. Aas eed39cc 
/**************************************************************************\
 * Copyright (c) Kongsberg Oil & Gas Technologies AS
 * All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 * 
 * Redistributions of source code must retain the above copyright notice,
 * this list of conditions and the following disclaimer.
 * 
 * Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution.
 * 
 * Neither the name of the copyright holder nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
\**************************************************************************/

// Important note: this sourcefile was in full generated by the
// Coin/scripts/templant script from the code in SFNodeEnginePath.tpl
// (except the test suite cases at the end).

///////////////////////////////////////////////////////////////////////////


//$ BEGIN TEMPLATE SFNodeEnginePath(NODE, Node, node)

/*!
  \class SoSFNode SoSFNode.h Inventor/fields/SoSFNode.h
  \brief The SoSFNode class is a container for a single node.
  \ingroup fields

  This field container stores a pointer to a Coin node. It takes care
  of the necessary functionality for handling copy, import and export
  operations.

  Note that the node pointer stored in a field instance of this type
  may be a \c NULL pointer.

  \sa SoNode, SoMFNode

*/

// Type-specific define to be able to do #ifdef tests on type.  (Note:
// used to check the header file wrapper define, but that doesn't work
// with --enable-compact build.)
#define COIN_INTERNAL_SOSFNODE

#include <Inventor/fields/SoSFNode.h>

#include "SbBasicP.h"

#include <Inventor/SoInput.h>
#include <Inventor/SoOutput.h>
#include <Inventor/actions/SoWriteAction.h>
#include <Inventor/errors/SoReadError.h>
#include <Inventor/nodes/SoNode.h>
#include <Inventor/engines/SoEngine.h>
#include <Inventor/SoOutput.h>
#if COIN_DEBUG
#include <Inventor/errors/SoDebugError.h>
#endif // COIN_DEBUG

#include "fields/SoSubFieldP.h"

// Can't use SO_SFIELD_SOURCE() because we need to modify setValue()
// to ref and unref the passed node.
SO_SFIELD_REQUIRED_SOURCE(SoSFNode);


// Override from parent class.
void
SoSFNode::initClass(void)
{
  SO_SFIELD_INTERNAL_INIT_CLASS(SoSFNode);
}

// (Declarations hidden in SO_[S|M]FIELD_HEADER macro in header file,
// so don't use Doxygen commenting.)
#ifndef DOXYGEN_SKIP_THIS

/* Constructor, sets initial node pointer to a \c NULL pointer. */
SoSFNode::SoSFNode(void)
{
  this->value = NULL;
#ifdef COIN_INTERNAL_SOSFPATH
  this->head = NULL;
#endif // COIN_INTERNAL_SOSFPATH
}

/* Destructor, dereferences the current node pointer if necessary. */
SoSFNode::~SoSFNode(void)
{
  this->enableNotify(FALSE);
  this->setValue(NULL);
}

#endif // DOXYGEN_SKIP_THIS


// No need to document readValue() and writeValue() here, as the
// necessary information is provided by the documentation of the
// parent classes.
#ifndef DOXYGEN_SKIP_THIS

// Store the \a newval node pointer in this field. If \a newval is not
// \c NULL, will add 1 to the reference count of the node.
void
SoSFNode::setValue(SoNode * newval)
{
  // Don't use getValue() to find oldptr, since this might trigger a
  // recursive evaluation call if the field is connected.
  SoNode * oldptr = this->value;
  if (oldptr == newval) return;

  if (oldptr) {
#ifdef COIN_INTERNAL_SOSFPATH
    SoNode * h = oldptr->getHead();
    // The path should be audited by us at all times. So don't use
    // SoSFPath to wrap SoTempPath or SoLightPath, for instance.
    assert(h==this->head && "Path head changed without notification!");
    if (h) {
      h->removeAuditor(this, SoNotRec::FIELD);
      h->unref();
    }
#endif // COIN_INTERNAL_SOSFPATH
    oldptr->removeAuditor(this, SoNotRec::FIELD);
    oldptr->unref();
  }

  if (newval) {
    newval->addAuditor(this, SoNotRec::FIELD);
    newval->ref();
#ifdef COIN_INTERNAL_SOSFPATH
    this->head = newval->getHead();
    if (this->head) {
      this->head->addAuditor(this, SoNotRec::FIELD);
      this->head->ref();
    }
#endif // COIN_INTERNAL_SOSFPATH
  }

  this->value = newval;
  this->valueChanged();
}

// Compares to see if the \a field points to the same node as this
// field does, and returns \c TRUE if this is the case.
//
// Be aware that this method does \e not check for node/subgraph
// equality if the pointers are not the same, so \c FALSE is returned
// even though the contents of the node/subgraph are equal.
SbBool
SoSFNode::operator==(const SoSFNode & field) const
{
  return (this->getValue() == field.getValue());
}

// Import node.
SbBool
SoSFNode::readValue(SoInput * in)
{
  SoBase * baseptr;
  SbBool isVRMLspecialCase = FALSE;

  // Note: do *not* simply check for baseptr==NULL here, as that is a
  // valid condition for VRML97 files, where nodes can indeed be
  // explicitly given as a NULL value. See the 'vrml97nullchild' test
  // case near the end of this file for a valid case that would fail.
  if(in->isFileVRML1() || in->isFileVRML2()) {
    SbName name;
    in->read(name, TRUE);
    if (name == "NULL") {
      baseptr = NULL;
      isVRMLspecialCase = TRUE;
    }
    else {
      in->putBack(name.getString());
    }
  }

  if (!isVRMLspecialCase) {
    if (!SoBase::read(in, baseptr, SoNode::getClassTypeId())) return FALSE;
    if (baseptr == NULL) {
      SoReadError::post(in, "Invalid node specification");
      return FALSE;
    }
  }

  if (in->eof()) {
    SoReadError::post(in, "Premature end of file");
    return FALSE;
  }

  if (baseptr != NULL) {
    this->setValue(coin_safe_cast<SoNode *>(baseptr));
  }
  return TRUE;
}

// Export node.
void
SoSFNode::writeValue(SoOutput * out) const
{
  // NB: This code is common for SoSFNode, SoSFPath and SoSFEngine.
  // That's why we check the base type before writing.
  SoBase * base = this->getValue();
  if (base) {
    if (base->isOfType(SoNode::getClassTypeId())) {
      coin_assert_cast<SoNode *>(base)->writeInstance(out);
    }
    else if (base->isOfType(SoPath::getClassTypeId())) {
      SoWriteAction wa(out);
      wa.continueToApply(coin_assert_cast<SoPath *>(base));
    }
    else if (base->isOfType(SoEngine::getClassTypeId())) {
      coin_assert_cast<SoEngine *>(base)->writeInstance(out);
    }
    else {
      assert(0 && "strange internal error");
    }
  }
  else {
    // This actually works for both ASCII and binary formats.
    out->write("NULL");
  }
}

#endif // DOXYGEN_SKIP_THIS


// Overridden from parent to propagate write reference counting to
// node.
void
SoSFNode::countWriteRefs(SoOutput * out) const
{
  inherited::countWriteRefs(out);

  SoBase * base = this->getValue();
  if (base == NULL) return;

  // NB: This code is common for SoSFNode, SoSFPath and SoSFEngine.
  // That's why we check the base type before writing/counting

  if (base->isOfType(SoNode::getClassTypeId())) {
    coin_assert_cast<SoNode *>(base)->writeInstance(out);
  }
  else if (base->isOfType(SoEngine::getClassTypeId())) {
    coin_assert_cast<SoEngine *>(base)->addWriteReference(out);
  }
  else if (base->isOfType(SoPath::getClassTypeId())) {
    SoWriteAction wa(out);
    wa.continueToApply(coin_assert_cast<SoPath *>(base));
  }
}

// Override from parent to update our node pointer
// reference. This is necessary so we do the Right Thing with regard
// to the copyconnections flag.
//
// Note that we have to unplug auditing and the reference counter
// addition we made during the copy process.
//
// For reference for future debugging sessions, copying of this field
// goes like this:
//
//    - copyFrom() is called (typically from SoFieldData::overlay())
//    - copyFrom() calls operator=()
//    - operator=() calls setValue()
//    - we have a local copy (ie not from SoSubField.h) of setValue()
//      that sets up auditing and references the item
//
// <mortene@sim.no>
void
SoSFNode::fixCopy(SbBool copyconnections)
{
  SoNode * n = this->getValue();
  if (!n) return;

#if COIN_DEBUG
  n->assertAlive();
#endif // COIN_DEBUG

  // The setValue() call below will automatically de-audit and un-ref
  // the old pointer-value reference we have, *before* re-inserting a
  // copy.

#if defined(COIN_INTERNAL_SOSFNODE) || defined(COIN_INTERNAL_SOSFENGINE)
  SoFieldContainer * fc = SoFieldContainer::findCopy(n, copyconnections);
#if COIN_DEBUG
  if (fc) fc->assertAlive();
#endif // COIN_DEBUG
  if (fc) this->setValue(coin_assert_cast<SoNode *>(fc));
#endif // COIN_INTERNAL_SOSFNODE || COIN_INTERNAL_SOSFENGINE

#ifdef COIN_INTERNAL_SOSFPATH
  this->setValue(n->copy());
#endif // COIN_INTERNAL_SOSFPATH
}

// Override from SoField to check node pointer.
SbBool
SoSFNode::referencesCopy(void) const
{
  if (inherited::referencesCopy()) return TRUE;

  SoBase * n = this->getValue();
  if (!n) return FALSE;

  if (n->isOfType(SoNode::getClassTypeId()) ||
      n->isOfType(SoEngine::getClassTypeId())) {
    if (SoFieldContainer::checkCopy(coin_assert_cast<SoFieldContainer *>(n))) return TRUE;
  }
  else if (n->isOfType(SoPath::getClassTypeId())) {
    SoPath * p = coin_assert_cast<SoPath *>(n);
    if (p->getHead() == NULL) return FALSE;
    if (SoFieldContainer::checkCopy(p->getHead())) return TRUE;
  }
  else {
    assert(0 && "strange internal error");
  }

  return FALSE;
}

// Kill the type-specific define.
#undef COIN_INTERNAL_SOSFNODE
//$ END TEMPLATE SFNodeEnginePath

#ifdef COIN_TEST_SUITE

#include <cstring>
#include <Inventor/nodes/SoNode.h>

BOOST_AUTO_TEST_CASE(initialized)
{
  SoSFNode field;
  BOOST_CHECK_MESSAGE(SoSFNode::getClassTypeId() != SoType::badType(),
                      "SoSFNode class not initialized");
  BOOST_CHECK_MESSAGE(field.getTypeId() != SoType::badType(),
                      "missing class initialization");
}

BOOST_AUTO_TEST_CASE(vrml97nullchild)
{
  // NULL values for children must be allowed, or we break VRML97
  // support.  -mortene.
  char scene[] = "#VRML V2.0 utf8\n\nAppearance { material NULL }";

  SoInput * in = new SoInput;
  in->setBuffer(reinterpret_cast<const void*>(scene), strlen(scene));
  SoNode * g = NULL;
  const SbBool readok = SoDB::read(in, g);
  delete in;

  BOOST_CHECK_MESSAGE(readok,
                      "failed to read VRML97 with NULL child in graph");
  if (g) {
    g->ref();
    g->unref();
  }
}

#endif // COIN_TEST_SUITE