void SoBrepPointSet::renderHighlight(SoGLRenderAction *action)
{
    SoState * state = action->getState();
    state->push();
    float ps = SoPointSizeElement::get(state);
    if (ps < 4.0f) SoPointSizeElement::set(state, this, 4.0f);

    SoLazyElement::setEmissive(state, &this->highlightColor);
    SoOverrideElement::setEmissiveColorOverride(state, this, true);
    SoLazyElement::setDiffuse(state, this,1, &this->highlightColor,&this->colorpacker);
    SoOverrideElement::setDiffuseColorOverride(state, this, true);

    const SoCoordinateElement * coords;
    const SbVec3f * normals;

    this->getVertexData(state, coords, normals, false);

    SoMaterialBundle mb(action);
    mb.sendFirst(); // make sure we have the correct material

    int32_t id = this->highlightIndex.getValue();
    if (id < this->startIndex.getValue() || id >= coords->getNum()) {
        SoDebugError::postWarning("SoBrepPointSet::renderHighlight", "highlightIndex out of range");
    }
    else {
        renderShape(static_cast<const SoGLCoordinateElement*>(coords), &id, 1);
    }
    state->pop();
}
// doc from parent
void
SoFCSelection::GLRenderInPath(SoGLRenderAction * action)
{
#ifdef NO_FRONTBUFFER
    // check if preselection is active
    HighlightModes mymode = (HighlightModes) this->highlightMode.getValue();
    bool preselected = highlighted && mymode == AUTO;
    SoState * state = action->getState();
    state->push();
    if (preselected || this->highlightMode.getValue() == ON || this->selected.getValue() == SELECTED) {
        this->setOverride(action);
    }
    inherited::GLRenderInPath(action);
    state->pop();
#else
    // Set up state for locate highlighting (if necessary)
    GLint oldDepthFunc;
    SbBool drawHighlighted = preRender(action, oldDepthFunc);

    // now invoke the parent method
    inherited::GLRenderInPath(action);

    // Restore old depth buffer model if needed
    if (drawHighlighted || highlighted)
        glDepthFunc((GLenum)oldDepthFunc);

    // Clean up state if needed
    if (drawHighlighted)
        action->getState()->pop();
#endif
}
void SoBrepPointSet::renderSelection(SoGLRenderAction *action)
{
    SoState * state = action->getState();
    state->push();
    float ps = SoPointSizeElement::get(state);
    if (ps < 4.0f) SoPointSizeElement::set(state, this, 4.0f);

    SoLazyElement::setEmissive(state, &this->selectionColor);
    SoOverrideElement::setEmissiveColorOverride(state, this, true);
    SoLazyElement::setDiffuse(state, this,1, &this->selectionColor,&this->colorpacker);
    SoOverrideElement::setDiffuseColorOverride(state, this, true);

    const SoCoordinateElement * coords;
    const SbVec3f * normals;
    const int32_t * cindices;
    int numcindices;

    this->getVertexData(state, coords, normals, false);

    SoMaterialBundle mb(action);
    mb.sendFirst(); // make sure we have the correct material

    cindices = this->selectionIndex.getValues(0);
    numcindices = this->selectionIndex.getNum();

    if (!validIndexes(coords, this->startIndex.getValue(), cindices, numcindices)) {
        SoDebugError::postWarning("SoBrepPointSet::renderSelection", "selectionIndex out of range");
    }
    else {
        renderShape(static_cast<const SoGLCoordinateElement*>(coords), cindices, numcindices);
    }
    state->pop();
}
void SoBrepEdgeSet::renderHighlight(SoGLRenderAction *action)
{
    SoState * state = action->getState();
    state->push();
  //SoLineWidthElement::set(state, this, 4.0f);

    SoLazyElement::setEmissive(state, &this->highlightColor);
    SoOverrideElement::setEmissiveColorOverride(state, this, TRUE);
    SoLazyElement::setDiffuse(state, this,1, &this->highlightColor,&this->colorpacker1);
    SoOverrideElement::setDiffuseColorOverride(state, this, TRUE);
    SoLazyElement::setLightModel(state, SoLazyElement::BASE_COLOR);

    const SoCoordinateElement * coords;
    const SbVec3f * normals;
    const int32_t * cindices;
    int numcindices;
    const int32_t * nindices;
    const int32_t * tindices;
    const int32_t * mindices;
    SbBool normalCacheUsed;

    this->getVertexData(state, coords, normals, cindices, nindices,
        tindices, mindices, numcindices, FALSE, normalCacheUsed);

    SoMaterialBundle mb(action);
    mb.sendFirst(); // make sure we have the correct material

    int num = (int)this->hl.size();
    if (num > 0) {
        const int32_t* id = &(this->hl[0]);
        renderShape(static_cast<const SoGLCoordinateElement*>(coords), id, num);
    }
    state->pop();
}
Exemple #5
0
void SoBrepPointSet::renderHighlight(SoGLRenderAction *action)
{
    SoState * state = action->getState();
    state->push();
    float ps = SoPointSizeElement::get(state);
    if (ps < 4.0f) SoPointSizeElement::set(state, this, 4.0f);

    SoLazyElement::setEmissive(state, &this->highlightColor);
    SoOverrideElement::setEmissiveColorOverride(state, this, TRUE);
    SoLazyElement::setDiffuse(state, this,1, &this->highlightColor,&this->colorpacker);
    SoOverrideElement::setDiffuseColorOverride(state, this, TRUE);

    const SoCoordinateElement * coords;
    const SbVec3f * normals;

    this->getVertexData(state, coords, normals, FALSE);

    SoMaterialBundle mb(action);
    mb.sendFirst(); // make sure we have the correct material

    int32_t id = this->highlightIndex.getValue();

    renderShape(static_cast<const SoGLCoordinateElement*>(coords), &id, 1);
    state->pop();
}
/**
 * Renders the probe with text label and a bullet at the base point.
 */
void SoRegPoint::GLRender(SoGLRenderAction *action)
{
    if (shouldGLRender(action))
    {
        SoState*  state = action->getState();
        state->push();
        SoMaterialBundle mb(action);
        SoTextureCoordinateBundle tb(action, true, false);
        SoLazyElement::setLightModel(state, SoLazyElement::BASE_COLOR);
        mb.sendFirst();  // make sure we have the correct material

        SbVec3f p1 = base.getValue();
        SbVec3f p2 = p1 + normal.getValue() * length.getValue();
        
        glLineWidth(1.0f);
        glColor3fv(color.getValue().getValue());
        glBegin(GL_LINE_STRIP);
            glVertex3d(p1[0], p1[1], p1[2]);
            glVertex3d(p2[0], p2[1], p2[2]);
        glEnd();
        glPointSize(5.0f);
        glBegin(GL_POINTS);
            glVertex3fv(p1.getValue());
        glEnd();
        glPointSize(2.0f);
        glBegin(GL_POINTS);
            glVertex3fv(p2.getValue());
        glEnd();

        root->GLRender(action);
        state->pop();
    }
}
Exemple #7
0
// Doc in parent
void
SoVRMLGroup::getPrimitiveCount(SoGetPrimitiveCountAction * action)
{
  SoState * state = action->getState();
  state->push();
  inherited::getPrimitiveCount(action);
  state->pop();
}
Exemple #8
0
// Doc in parent
void
SoVRMLGroup::doAction(SoAction * action)
{
  SoState * state = action->getState();
  state->push();
  inherited::doAction(action);
  state->pop();
}
Exemple #9
0
// Doc from superclass.
void
SoGeoSeparator::GLRenderInPath(SoGLRenderAction * action)
{
  SoState * state = action->getState();
  state->push();
  this->applyTransformation((SoAction*) action);
  SoSeparator::GLRenderInPath(action);
  state->pop();
}
Exemple #10
0
void
SoVRMLShape::GLRender(SoGLRenderAction * action)
{
  SoState * state = action->getState();
  state->push();

  if ((this->appearance.getValue() == NULL) ||
      (((SoVRMLAppearance*)this->appearance.getValue())->material.getValue() == NULL)) {
    SoLazyElement::setLightModel(state, SoLazyElement::BASE_COLOR);
  }

  int numindices;
  const int * indices;
  SoAction::PathCode pathcode = action->getPathCode(numindices, indices);

  SoNode ** childarray = (SoNode**) this->getChildren()->getArrayPtr();

  if (pathcode == SoAction::IN_PATH) {
    int lastchild = indices[numindices - 1];
    for (int i = 0; i <= lastchild && !action->hasTerminated(); i++) {
      SoNode * child = childarray[i];
      action->pushCurPath(i, child);
      if (action->getCurPathCode() != SoAction::OFF_PATH ||
          child->affectsState()) {
        if (!action->abortNow()) {
          SoNodeProfiling profiling;
          profiling.preTraversal(action);
          child->GLRender(action);
          profiling.postTraversal(action);
        }
        else {
          SoCacheElement::invalidate(state);
        }
      }
      action->popCurPath(pathcode);
    }
  }
  else {
    action->pushCurPath();
    int n = this->getChildren()->getLength();
    for (int i = 0; i < n && !action->hasTerminated(); i++) {
      action->popPushCurPath(i, childarray[i]);
      if (action->abortNow()) {
        // only cache if we do a full traversal
        SoCacheElement::invalidate(state);
        break;
      }
      SoNodeProfiling profiling;
      profiling.preTraversal(action);
      childarray[i]->GLRender(action);
      profiling.postTraversal(action);
    }
    action->popCurPath();
  }
  state->pop();
}
Exemple #11
0
// Doc from superclass.
void
SoGeoSeparator::getPrimitiveCount(SoGetPrimitiveCountAction * action)
{
  SoState * state = action->getState();
  state->push();

  this->applyTransformation((SoAction *)action);
  SoSeparator::getPrimitiveCount(action);

  state->pop();
}
Exemple #12
0
// Doc from superclass.
void
SoGeoSeparator::rayPick(SoRayPickAction * action)
{
  SoState * state = action->getState();
  state->push();
  
  this->applyTransformation((SoAction *)action);
  SoSeparator::rayPick(action);

  state->pop();
}
Exemple #13
0
// Doc in parent
void
SoVRMLGroup::callback(SoCallbackAction * action)
{
  SoState * state = action->getState();
  state->push();
  // culling planes should normally not be set, but can be set
  // manually by the application programmer to optimize callback
  // action traversal.
  if (!this->cullTest(state)) { inherited::callback(action); }
  state->pop();
}
Exemple #14
0
// Doc in parent
void
SoVRMLGroup::GLRenderInPath(SoGLRenderAction * action)
{
  int numindices;
  const int * indices;
  
  SoAction::PathCode pathcode = action->getPathCode(numindices, indices);
  
  if (pathcode == SoAction::IN_PATH) {
    SoState * state = action->getState();
    SoNode ** childarray = (SoNode**) this->getChildren()->getArrayPtr();
    state->push();
    int childidx = 0;
    for (int i = 0; i < numindices; i++) {
      for (; childidx < indices[i] && !action->hasTerminated(); childidx++) {
        SoNode * offpath = childarray[childidx];
        if (offpath->affectsState()) {
          action->pushCurPath(childidx, offpath);
          if (!action->abortNow()) {
            SoNodeProfiling profiling;
            profiling.preTraversal(action);
            offpath->GLRenderOffPath(action);
            profiling.postTraversal(action);
          }
          else {
            SoCacheElement::invalidate(state);
          }
          action->popCurPath(pathcode);
        }
      }
      SoNode * inpath = childarray[childidx];
      action->pushCurPath(childidx, inpath);
      if (!action->abortNow()) {
        SoNodeProfiling profiling;
        profiling.preTraversal(action);
        inpath->GLRenderInPath(action);
        profiling.postTraversal(action);
      }
      else {
        SoCacheElement::invalidate(state);
      }
      action->popCurPath(pathcode);
      childidx++;
    }
    state->pop();
  }
  else {
    // we got to the end of the path
    assert(action->getCurPathCode() == SoAction::BELOW_PATH);
    this->GLRenderBelowPath(action);
  }
}
SbBool
SoFCSelection::preRender(SoGLRenderAction *action, GLint &oldDepthFunc)
//
////////////////////////////////////////////////////////////////////////
{
    // If not performing locate highlighting, just return.
    if (highlightMode.getValue() == OFF)
        return FALSE;

    SoState *state = action->getState();

    // ??? prevent caching at this level - for some reason the
    // ??? SoWindowElement::copyMatchInfo() method get called, which should
    // ??? never be called. We are not caching this node correctly yet....
    //SoCacheElement::invalidate(state);

    SbBool drawHighlighted = (highlightMode.getValue() == ON || isHighlighted(action) || selected.getValue() == SELECTED);

    if (drawHighlighted) {
        // prevent diffuse & emissive color from leaking out...
        state->push();
        SbColor col;
        if (selected.getValue() == SELECTED)
            col = colorSelection.getValue();
        else
            col = colorHighlight.getValue();

        // Emissive Color
        SoLazyElement::setEmissive(state, &col);
        SoOverrideElement::setEmissiveColorOverride(state, this, TRUE);

        // Diffuse Color
        if (style.getValue() == EMISSIVE_DIFFUSE) {
            SoLazyElement::setDiffuse(state, this, 1, &col, &colorpacker);
            SoOverrideElement::setDiffuseColorOverride(state, this, TRUE);
        }
    }

    // Draw on top of other things at same z-buffer depth if:
    // [a] we're highlighted
    // [b] this is the highlighting pass. This occurs when changing from
    //     non-hilit to lit OR VICE VERSA.
    // Otherwise, leave it alone...
    if (drawHighlighted || highlighted) {
        glGetIntegerv(GL_DEPTH_FUNC, &oldDepthFunc);
        if (oldDepthFunc != GL_LEQUAL)
            glDepthFunc(GL_LEQUAL);
    }

    return drawHighlighted;
}
void
SoBoxHighlightRenderAction::drawBoxes(SoPath * pathtothis, const SoPathList * pathlist)
{
  int i;
  int thispos = reclassify_cast<SoFullPath *>(pathtothis)->getLength()-1;
  assert(thispos >= 0);
  PRIVATE(this)->postprocpath->setHead(pathtothis->getHead()); // reset

  for (i = 1; i < thispos; i++) {
    PRIVATE(this)->postprocpath->append(pathtothis->getIndex(i));
  }

  // we need to disable accumulation buffer antialiasing while
  // rendering selected objects
  int oldnumpasses = this->getNumPasses();
  this->setNumPasses(1);

  SoState * thestate = this->getState();
  thestate->push();

  for (i = 0; i < pathlist->getLength(); i++) {
    SoFullPath * path = reclassify_cast<SoFullPath *>((*pathlist)[i]);
    PRIVATE(this)->postprocpath->append(path->getHead());
    for (int j = 1; j < path->getLength(); j++) {
      PRIVATE(this)->postprocpath->append(path->getIndex(j));
    }

    // Previously SoGLRenderAction was used to draw the bounding boxes
    // of shapes in selection paths, by overriding renderstyle state
    // elements to lines drawstyle and simply doing:
    //
    //   SoGLRenderAction::apply(PRIVATE(this)->postprocpath); // Bug
    //
    // This could have the unwanted side effect of rendering
    // non-selected shapes, as they could be part of the path (due to
    // being placed below SoGroup nodes (instead of SoSeparator
    // nodes)) up to the selected shape.
    //
    //
    // A better approach turned out to be to soup up and draw only the
    // bounding boxes of the selected shapes:
    PRIVATE(this)->drawHighlightBox(PRIVATE(this)->postprocpath);

    // Remove temporary path from path buffer
    PRIVATE(this)->postprocpath->truncate(thispos);
  }

  this->setNumPasses(oldnumpasses);
  thestate->pop();
}
Exemple #17
0
void
SoVRMLShape::getBoundingBox(SoGetBoundingBoxAction * action)
{
  SoState * state = action->getState();
  state->push();
  int numindices;
  const int * indices;
  if (action->getPathCode(numindices, indices) == SoAction::IN_PATH) {
    this->getChildren()->traverseInPath(action, numindices, indices);
  }
  else {
    this->getChildren()->traverse(action); // traverse all children
  }
  state->pop();
}
Exemple #18
0
// Doc from superclass.
void
SoGeoSeparator::getBoundingBox(SoGetBoundingBoxAction * action)
{
  SoState * state = action->getState();
  state->push();
  SbMatrix m = this->getTransform(state);

  SoModelMatrixElement::mult(state,
                             this,
                             SoModelMatrixElement::get(state).inverse());
  SoModelMatrixElement::mult(state,
                             this,
                             m);

  SoSeparator::getBoundingBox(action);
  state->pop();
}
void SoBrepEdgeSet::renderSelection(SoGLRenderAction *action)
{
    int numSelected =  this->selectionIndex.getNum();
    if (numSelected == 0) return;

    SoState * state = action->getState();
    state->push();
  //SoLineWidthElement::set(state, this, 4.0f);

    SoLazyElement::setEmissive(state, &this->selectionColor);
    SoOverrideElement::setEmissiveColorOverride(state, this, true);
    SoLazyElement::setDiffuse(state, this,1, &this->selectionColor,&this->colorpacker2);
    SoOverrideElement::setDiffuseColorOverride(state, this, true);
    SoLazyElement::setLightModel(state, SoLazyElement::BASE_COLOR);

    const SoCoordinateElement * coords;
    const SbVec3f * normals;
    const int32_t * cindices;
    int numcindices;
    const int32_t * nindices;
    const int32_t * tindices;
    const int32_t * mindices;
    SbBool normalCacheUsed;

    this->getVertexData(state, coords, normals, cindices, nindices,
        tindices, mindices, numcindices, false, normalCacheUsed);

    SoMaterialBundle mb(action);
    mb.sendFirst(); // make sure we have the correct material

    int num = (int)this->sl.size();
    if (num > 0) {
        cindices = &(this->sl[0]);
        numcindices = (int)this->sl.size();
        if (!validIndexes(coords, this->sl)) {
            SoDebugError::postWarning("SoBrepEdgeSet::renderSelection", "selectionIndex out of range");
        }
        else {
            renderShape(static_cast<const SoGLCoordinateElement*>(coords), cindices, numcindices);
        }
    }
    state->pop();
}
void
SoXipPlot2Columns::GLRender( SoGLRenderAction* action )
{
    SoXipPlot2Element::add(
        action->getState(),
        this,
        label.getValue(),
        borderColor.getValue(),
        faceColor.getValue() );

    SoState* state = action->getState();

    state->push();

    // Make sure the DrawStyle is set to FILLED
    SoDrawStyleElement::set( state, SoDrawStyleElement::FILLED );

    SoBaseKit::GLRender( action );

    state->pop();
}
void
SoXipPlot2Ruler::GLRender( SoGLRenderAction* action )
{
	SoState* state = action->getState();
	if( !state )
		return ;

	state->push();

	mBBox = SoXipPlot2AreaElement::getBBox( state );

	int numValues = value.getNum();
	mCoord->point.setNum( 2 * numValues );
	mLineSet->numVertices.setNum( numValues );

	if( type.getValue() == HORIZONTAL )
	{
		for( int i = 0; i < numValues; ++ i )
		{
			mCoord->point.set1Value(     2*i, SbVec3f( mBBox.getMin()[0], value[i], 0 ) );
			mCoord->point.set1Value( 1 + 2*i, SbVec3f( mBBox.getMax()[0], value[i], 0 ) );
			mLineSet->numVertices.set1Value( i, 2 );
		}
	}
	else
	{
		for( int i = 0; i < numValues; ++ i )
		{
			mCoord->point.set1Value(     2*i, SbVec3f( value[i], mBBox.getMin()[1], 0 ) );
			mCoord->point.set1Value( 1 + 2*i, SbVec3f( value[i], mBBox.getMax()[1], 0 ) );
			mLineSet->numVertices.set1Value( i, 2 );
		}
	}
	
	action->traverse( mCoord );
	action->traverse( mLineSet );

	state->pop();
}
Exemple #22
0
void SoWidgetShape::generatePrimitives(SoAction *action)
{
    if (this->image.isNull()) return;

    SoState *state = action->getState();
    state->push();

    SbVec2s size;
    SbVec3f v0, v1, v2, v3;
    this->getQuad(action->getState(), v0, v1, v2, v3);

    SbVec3f n = (v1-v0).cross(v2-v0);
    n.normalize();

    this->beginShape(action, SoShape::QUADS);
    SoPrimitiveVertex vertex;
    vertex.setNormal(n);

    vertex.setTextureCoords(SbVec2f(0,0));
    vertex.setPoint(v0);
    this->shapeVertex(&vertex);

    vertex.setTextureCoords(SbVec2f(1,0));
    vertex.setPoint(v1);
    this->shapeVertex(&vertex);

    vertex.setTextureCoords(SbVec2f(1,1));
    vertex.setPoint(v2);
    this->shapeVertex(&vertex);

    vertex.setTextureCoords(SbVec2f(0,1));
    vertex.setPoint(v3);
    this->shapeVertex(&vertex);

    this->endShape();

    state->pop();
}
Exemple #23
0
void
SoVRMLShape::doAction(SoAction * action)
{
  SoState * state = action->getState();

  if (state->isElementEnabled(SoLazyElement::getClassStackIndex())) {
    if ((this->appearance.getValue() == NULL) ||
        (((SoVRMLAppearance*)this->appearance.getValue())->material.getValue() == NULL)) {
      SoLazyElement::setLightModel(state, SoLazyElement::BASE_COLOR);
    }
  }

  state->push();
  int numindices;
  const int * indices;
  if (action->getPathCode(numindices, indices) == SoAction::IN_PATH) {
    this->getChildren()->traverseInPath(action, numindices, indices);
  }
  else {
    this->getChildren()->traverse(action); // traverse all children
  }
  state->pop();
}
// private convenience method
void
SoFCSelection::turnoffcurrent(SoAction * action)
{
#ifdef NO_FRONTBUFFER
    if (SoFCSelection::currenthighlight &&
        SoFCSelection::currenthighlight->getLength()) {
        SoNode * tail = SoFCSelection::currenthighlight->getTail();
        if (tail->isOfType(SoFCSelection::getClassTypeId())) {
            ((SoFCSelection*)tail)->highlighted = FALSE;
            ((SoFCSelection*)tail)->touch(); // force scene redraw
            if (action) ((SoFCSelection*)tail)->redrawHighlighted(action, FALSE);
        }
    }
    if (SoFCSelection::currenthighlight) {
        SoFCSelection::currenthighlight->unref();
        SoFCSelection::currenthighlight = NULL;
    }
#else
    if (currenthighlight == NULL)
        return;

    SoNode *tail = currenthighlight->getTail();
    if (tail->isOfType(SoFCSelection::getClassTypeId())) {

        // don't redraw if we already are in the middle of rendering
        // (processing events during render abort might cause this)
        SoState *state = action->getState();
        if (state && state->getDepth() == 1)
            ((SoFCSelection *)tail)->redrawHighlighted(action, FALSE);
    }
    else {
        // Just get rid of the path. It's no longer valid for redraw.
        currenthighlight->unref();
        currenthighlight = NULL;
    }
#endif
}
Exemple #25
0
//
// internal method which checks if convex cache needs to be
// used or (re)created. Returns TRUE if convex cache must be
// used. PRIVATE(this)->convexCache is then guaranteed to be != NULL.
//
SbBool
SoVRMLIndexedFaceSet::useConvexCache(SoAction * action, 
                                     const SbVec3f * normals, 
                                     const int32_t * nindices,
                                     const SbBool normalsfromcache)
{
  SoState * state = action->getState();
  if (this->convex.getValue())
    return FALSE;

  if (PRIVATE(this)->concavestatus == STATUS_UNKNOWN) {
    const int32_t * ptr = this->coordIndex.getValues(0);
    const int32_t * endptr = ptr + this->coordIndex.getNum();
    int cnt = 0;
    PRIVATE(this)->concavestatus = STATUS_CONVEX;
    while (ptr < endptr) {
      if (*ptr++ >= 0) cnt++;
      else {
        if (cnt > 3) { PRIVATE(this)->concavestatus = STATUS_CONCAVE; break; }
        cnt = 0;
      }
    }
  }
  if (PRIVATE(this)->concavestatus == STATUS_CONVEX) return FALSE;

  PRIVATE(this)->readLockConvexCache();

  if (PRIVATE(this)->convexCache && PRIVATE(this)->convexCache->isValid(state)) {
    // check if convex cache has normal indices. The convex cache
    // might be generated without normals.
    if (normals == NULL || PRIVATE(this)->convexCache->getNormalIndices()) {
      return TRUE;
    }
  }

  PRIVATE(this)->readUnlockConvexCache();
  PRIVATE(this)->writeLockConvexCache();

  if (PRIVATE(this)->convexCache) PRIVATE(this)->convexCache->unref();
  SbBool storedinvalid = SoCacheElement::setInvalid(FALSE);

  // need to send matrix if we have some weird transformation
  SbMatrix modelmatrix = SoModelMatrixElement::get(state);
  if (modelmatrix[3][0] == 0.0f &&
      modelmatrix[3][1] == 0.0f &&
      modelmatrix[3][2] == 0.0f &&
      modelmatrix[3][3] == 1.0f) modelmatrix = SbMatrix::identity();

  // push to create cache dependencies
  state->push();
  PRIVATE(this)->convexCache = new SoConvexDataCache(state);
  PRIVATE(this)->convexCache->ref();
  SoCacheElement::set(state, PRIVATE(this)->convexCache);

  SoVRMLVertexShape::doAction(action);

  const SoCoordinateElement * coords;
  const int32_t * cindices;
  const SbVec3f * dummynormals;
  int numindices;
  const int32_t * dummynindices;
  const int32_t * tindices;
  const int32_t * mindices;
  SbBool dummy;

  this->getVertexData(state, coords, dummynormals, cindices,
                      dummynindices, tindices, mindices, numindices,
                      FALSE, dummy);

  Binding mbind = this->findMaterialBinding(state);
  Binding nbind = normals ? this->findNormalBinding(state) : OVERALL;
  
  if (normalsfromcache && nbind == PER_VERTEX) {
    nbind = PER_VERTEX_INDEXED;
  }

  if (mbind == PER_VERTEX) {
    mbind = PER_VERTEX_INDEXED;
    mindices = tindices;
  }
  if (nbind == PER_VERTEX) {
    nbind = PER_VERTEX_INDEXED;
    nindices = cindices;
  }

  Binding tbind = PER_VERTEX_INDEXED;
  if (tindices == NULL) tindices = cindices;

  if (nbind == PER_VERTEX_INDEXED && nindices == NULL) {
    nindices = cindices;
  }
  if (mbind == PER_VERTEX_INDEXED && mindices == NULL) {
    mindices = cindices;
  }
  PRIVATE(this)->convexCache->generate(coords, modelmatrix,
                              cindices, numindices,
                              mindices, nindices, tindices,
                              (SoConvexDataCache::Binding)mbind,
                              (SoConvexDataCache::Binding)nbind,
                              (SoConvexDataCache::Binding)tbind);
  
  PRIVATE(this)->writeUnlockConvexCache();

  state->pop();
  SoCacheElement::setInvalid(storedinvalid);

  PRIVATE(this)->readLockConvexCache();

  return TRUE;
}
Exemple #26
0
// Doc in parent
void
SoVRMLIndexedFaceSet::generatePrimitives(SoAction * action)
{
  if (this->coordIndex.getNum() < 3) return;

  SoState * state = action->getState();

  state->push();
  SoVRMLVertexShape::doAction(action);

  Binding mbind = this->findMaterialBinding(state);
  Binding nbind = this->findNormalBinding(state);

  const SoCoordinateElement * coords;
  const SbVec3f * normals;
  const int32_t * cindices;
  int numindices;
  const int32_t * nindices;
  const int32_t * tindices;
  const int32_t * mindices;
  SbBool doTextures;
  SbBool sendNormals;
  SbBool normalCacheUsed;

  sendNormals = TRUE; // always generate normals

  this->getVertexData(state, coords, normals, cindices,
                      nindices, tindices, mindices, numindices,
                      sendNormals, normalCacheUsed);

  if (!sendNormals) {
    nbind = OVERALL;
    normals = NULL;
    nindices = NULL;
  }
  else if (normalCacheUsed && nbind == PER_VERTEX) {
    nbind = PER_VERTEX_INDEXED;
  }
  else if (normalCacheUsed && nbind == PER_FACE_INDEXED) {
    nbind = PER_FACE;
  }

  if (mbind == PER_VERTEX) {
    mbind = PER_VERTEX_INDEXED;
    mindices = cindices;
  }
  if (nbind == PER_VERTEX) {
    nbind = PER_VERTEX_INDEXED;
    nindices = cindices;
  }

  SoTextureCoordinateBundle tb(action, FALSE, FALSE);
  doTextures = tb.needCoordinates();

  Binding tbind = NONE;
  if (doTextures) {
    if (tb.isFunction() && !tb.needIndices()) {
      tbind = NONE;
      tindices = NULL;
    }
    else {
      tbind = PER_VERTEX_INDEXED;
      if (tindices == NULL) tindices = cindices;
    }
  }
  
  SbBool convexcacheused = FALSE;
  if (this->useConvexCache(action, normals, nindices, normalCacheUsed)) {
    cindices = PRIVATE(this)->convexCache->getCoordIndices();
    numindices = PRIVATE(this)->convexCache->getNumCoordIndices();
    mindices = PRIVATE(this)->convexCache->getMaterialIndices();
    nindices = PRIVATE(this)->convexCache->getNormalIndices();
    tindices = PRIVATE(this)->convexCache->getTexIndices();

    if (mbind == PER_VERTEX) mbind = PER_VERTEX_INDEXED;
    else if (mbind == PER_FACE) mbind = PER_FACE_INDEXED;
    if (nbind == PER_VERTEX) nbind = PER_VERTEX_INDEXED;
    else if (nbind == PER_FACE) nbind = PER_FACE_INDEXED;

    if (tbind != NONE) tbind = PER_VERTEX_INDEXED;
    convexcacheused = TRUE;
  }

  int texidx = 0;
  TriangleShape mode = POLYGON;
  TriangleShape newmode;
  const int32_t *viptr = cindices;
  const int32_t *viendptr = viptr + numindices;
  int32_t v1, v2, v3, v4, v5 = 0; // v5 init unnecessary, but kills a compiler warning.

  SoPrimitiveVertex vertex;
  SoPointDetail pointDetail;
  SoFaceDetail faceDetail;

  vertex.setDetail(&pointDetail);

  SbVec3f dummynormal(0,0,1);
  const SbVec3f *currnormal = &dummynormal;
  if (normals) currnormal = normals;
  vertex.setNormal(*currnormal);

  int matnr = 0;
  int normnr = 0;

  while (viptr + 2 < viendptr) {
    v1 = *viptr++;
    v2 = *viptr++;
    v3 = *viptr++;
    assert(v1 >= 0 && v2 >= 0 && v3 >= 0);
    v4 = viptr < viendptr ? *viptr++ : -1;
    if (v4  < 0) newmode = TRIANGLES;
    else {
      v5 = viptr < viendptr ? *viptr++ : -1;
      if (v5 < 0) newmode = QUADS;
      else newmode = POLYGON;
    }
    if (newmode != mode) {
      if (mode != POLYGON) this->endShape();
      mode = newmode;
      this->beginShape(action, mode, &faceDetail);
    }
    else if (mode == POLYGON) this->beginShape(action, POLYGON, &faceDetail);

    // vertex 1 can't use DO_VERTEX
    if (mbind == PER_VERTEX || mbind == PER_FACE) {
      pointDetail.setMaterialIndex(matnr);
      vertex.setMaterialIndex(matnr++);
    }
    else if (mbind == PER_VERTEX_INDEXED || mbind == PER_FACE_INDEXED) {
      pointDetail.setMaterialIndex(*mindices);
      vertex.setMaterialIndex(*mindices++);
    }
    if (nbind == PER_VERTEX || nbind == PER_FACE) {
      pointDetail.setNormalIndex(normnr);
      currnormal = &normals[normnr++];
      vertex.setNormal(*currnormal);
    }
    else if (nbind == PER_FACE_INDEXED || nbind == PER_VERTEX_INDEXED) {
      pointDetail.setNormalIndex(*nindices);
      currnormal = &normals[*nindices++];
      vertex.setNormal(*currnormal);
    }

    if (tb.isFunction()) {
      vertex.setTextureCoords(tb.get(coords->get3(v1), *currnormal));
      if (tb.needIndices()) pointDetail.setTextureCoordIndex(tindices ? *tindices++ : texidx++);
    }
    else if (tbind != NONE) {
      pointDetail.setTextureCoordIndex(tindices ? *tindices : texidx);
      vertex.setTextureCoords(tb.get(tindices ? *tindices++ : texidx++));
    }
    pointDetail.setCoordinateIndex(v1);
    vertex.setPoint(coords->get3(v1));
    this->shapeVertex(&vertex);

    DO_VERTEX(v2);
    DO_VERTEX(v3);

    if (mode != TRIANGLES) {
      DO_VERTEX(v4);
      if (mode == POLYGON) {
        DO_VERTEX(v5);
        v1 = viptr < viendptr ? *viptr++ : -1;
        while (v1 >= 0) {
          DO_VERTEX(v1);
          v1 = viptr < viendptr ? *viptr++ : -1;
        }
        this->endShape();
      }
    }
    faceDetail.incFaceIndex();
    if (mbind == PER_VERTEX_INDEXED) {
      mindices++;
    }
    if (nbind == PER_VERTEX_INDEXED) {
      nindices++;
    }
    if (tindices) tindices++;
  }
  if (mode != POLYGON) this->endShape();

  if (normalCacheUsed) {
    this->readUnlockNormalCache();
  }
  if (convexcacheused) {
    PRIVATE(this)->readUnlockConvexCache();
  }
  state->pop();
}
Exemple #27
0
// Doc in parent
void
SoVRMLIndexedFaceSet::GLRender(SoGLRenderAction * action)
{
  if (this->coordIndex.getNum() < 3 || this->coord.getValue() == NULL) return;
  SoState * state = action->getState();

  state->push();
  // update state with coordinates, normals and texture information
  SoVRMLVertexShape::GLRender(action);

  if (!this->shouldGLRender(action)) { 
    state->pop();
    return;
  }

  this->setupShapeHints(state, this->ccw.getValue(), this->solid.getValue());

  Binding mbind = this->findMaterialBinding(state);
  Binding nbind = this->findNormalBinding(state);

  const SoCoordinateElement * coords;
  const SbVec3f * normals;
  const int32_t * cindices;
  int numindices;
  const int32_t * nindices;
  const int32_t * tindices;
  const int32_t * mindices;
  SbBool doTextures;
  SbBool normalCacheUsed;
  SoMaterialBundle mb(action);
  SoTextureCoordinateBundle tb(action, TRUE, FALSE);
  doTextures = tb.needCoordinates();

  SbBool sendNormals = !mb.isColorOnly() || tb.isFunction();

  this->getVertexData(state, coords, normals, cindices,
                      nindices, tindices, mindices, numindices,
                      sendNormals, normalCacheUsed);

  if (!sendNormals) {
    nbind = OVERALL;
    normals = NULL;
    nindices = NULL;
  }
  else if (nbind == OVERALL) {
    if (normals) glNormal3fv(normals[0].getValue());
    else glNormal3f(0.0f, 0.0f, 1.0f);
  }
  else if (normalCacheUsed && nbind == PER_VERTEX) {
    nbind = PER_VERTEX_INDEXED;
  }
  else if (normalCacheUsed && nbind == PER_FACE_INDEXED) {
    nbind = PER_FACE;
  }

  if (mbind == PER_VERTEX) {
    mbind = PER_VERTEX_INDEXED;
    mindices = cindices;
  }
  if (nbind == PER_VERTEX) {
    nbind = PER_VERTEX_INDEXED;
    nindices = cindices;
  }

  Binding tbind = NONE;
  if (doTextures) {
    if (tb.isFunction() && !tb.needIndices()) {
      tbind = NONE;
      tindices = NULL;
    }
    else {
      tbind = PER_VERTEX_INDEXED;
      if (tindices == NULL) tindices = cindices;
    }
  }
  SbBool convexcacheused = FALSE;

  if (this->useConvexCache(action, normals, nindices, normalCacheUsed)) {
    cindices = PRIVATE(this)->convexCache->getCoordIndices();
    numindices = PRIVATE(this)->convexCache->getNumCoordIndices();
    mindices = PRIVATE(this)->convexCache->getMaterialIndices();
    nindices = PRIVATE(this)->convexCache->getNormalIndices();
    tindices = PRIVATE(this)->convexCache->getTexIndices();

    if (mbind == PER_VERTEX) mbind = PER_VERTEX_INDEXED;
    else if (mbind == PER_FACE) mbind = PER_FACE_INDEXED;
    if (nbind == PER_VERTEX) nbind = PER_VERTEX_INDEXED;
    else if (nbind == PER_FACE) nbind = PER_FACE_INDEXED;

    if (tbind != NONE) tbind = PER_VERTEX_INDEXED;
    convexcacheused = TRUE;
  }

  mb.sendFirst(); // make sure we have the correct material

  SoGLLazyElement * lelem = NULL;
  const uint32_t contextid = action->getCacheContext();

  SbBool dova = 
    SoVBO::shouldRenderAsVertexArrays(state, contextid, numindices) &&
    !convexcacheused && !normalCacheUsed &&
    ((nbind == OVERALL) || ((nbind == PER_VERTEX_INDEXED) && ((nindices == cindices) || (nindices == NULL)))) &&
    ((tbind == NONE && !tb.needCoordinates()) || 
     ((tbind == PER_VERTEX_INDEXED) && ((tindices == cindices) || (tindices == NULL)))) &&
    ((mbind == NONE) || ((mbind == PER_VERTEX_INDEXED) && ((mindices == cindices) || (mindices == NULL)))) &&
    SoGLDriverDatabase::isSupported(sogl_glue_instance(state), SO_GL_VERTEX_ARRAY);

  const SoGLVBOElement * vboelem = SoGLVBOElement::getInstance(state);
  SoVBO * colorvbo = NULL;

  if (dova && (mbind != OVERALL)) {
    dova = FALSE;
    if ((mbind == PER_VERTEX_INDEXED) && ((mindices == cindices) || (mindices == NULL))) {
      lelem = (SoGLLazyElement*) SoLazyElement::getInstance(state);
      colorvbo = vboelem->getColorVBO();
      if (colorvbo) dova = TRUE;
      else {
        // we might be able to do VA-rendering, but need to check the
        // diffuse color type first.
        if (!lelem->isPacked() && lelem->getNumTransparencies() <= 1) {
          dova = TRUE;
        }
      }
    }
  }
  SbBool didrenderasvbo = FALSE;
  if (dova) {
    SbBool dovbo = this->startVertexArray(action,
                                          coords,
                                          (nbind != OVERALL) ? normals : NULL,
                                          doTextures,
                                          mbind != OVERALL);
    didrenderasvbo = dovbo;
    LOCK_VAINDEXER(this);
    if (PRIVATE(this)->vaindexer == NULL) {
      SoVertexArrayIndexer * indexer = new SoVertexArrayIndexer;
      int i = 0;
      while (i < numindices) {
        int cnt = 0;
        while (i + cnt < numindices && cindices[i+cnt] >= 0) cnt++;
        
        switch (cnt) {
        case 3:
          indexer->addTriangle(cindices[i],cindices[i+1], cindices[i+2]);
          break;
        case 4:
          indexer->addQuad(cindices[i],cindices[i+1],cindices[i+2],cindices[i+3]);
          break;
        default:
          if (cnt > 4) {
            indexer->beginTarget(GL_POLYGON);
            for (int j = 0; j < cnt; j++) {
              indexer->targetVertex(GL_POLYGON, cindices[i+j]);
            }
            indexer->endTarget(GL_POLYGON);
          }
        }
        i += cnt + 1;
      }
      indexer->close();
      if (indexer->getNumVertices()) {
        PRIVATE(this)->vaindexer = indexer;
      }
      else {
        delete indexer;
      }
#if 0
      fprintf(stderr,"XXX: create VRML VertexArrayIndexer: %d\n", indexer->getNumVertices());
#endif
    }

    if (PRIVATE(this)->vaindexer) {
      PRIVATE(this)->vaindexer->render(sogl_glue_instance(state), dovbo, contextid);
    }
    UNLOCK_VAINDEXER(this);
    this->finishVertexArray(action,
                            dovbo,
                            (nbind != OVERALL),
                            doTextures,
                            mbind != OVERALL);
  }
  else {
    SoVertexAttributeBundle vab(action, TRUE);
    SbBool doattribs = vab.doAttributes();

    SoVertexAttributeBindingElement::Binding attribbind = 
      SoVertexAttributeBindingElement::get(state);

    if (!doattribs) { 
      // for overall attribute binding we check for doattribs before
      // sending anything in SoGL::FaceSet::GLRender
      attribbind = SoVertexAttributeBindingElement::OVERALL;
    }

    sogl_render_faceset((SoGLCoordinateElement *)coords,
                        cindices,
                        numindices,
                        normals,
                        nindices,
                        &mb,
                        mindices,
                        &tb,
                        tindices,
                        &vab,
                        (int)nbind,
                        (int)mbind,
                        (int)attribbind,
                        doTextures ? 1 : 0,
                        doattribs ? 1 : 0);

  }
  if (normalCacheUsed) {
    this->readUnlockNormalCache();
  }

  if (convexcacheused) {
    PRIVATE(this)->readUnlockConvexCache();
  }

  // send approx number of triangles for autocache handling
  sogl_autocache_update(state, this->coordIndex.getNum() / 4, didrenderasvbo);

  state->pop();
}
void
CvrIndexedSetRenderBaseP::GLRender(SoGLRenderAction * action,
                                   const float offset,
                                   const SbBool clipGeometry)
{


  // FIXME: Support for 'offset' must be implemented. (20040628
  // handegar)
  if (offset != 0) {
    static SbBool flag = FALSE;
    if (!flag) {
      SoDebugError::postWarning("CvrIndexedSetRenderBaseP::GLRender",
                                "Support for offset > 0 not implemented yet.");
      flag = TRUE;
    }
  }

  const cc_glglue * glue = cc_glglue_instance(action->getCacheContext());
  if (!cc_glglue_has_3d_textures(glue)) {
    static SbBool flag = FALSE;
    if (!flag) {
      SoDebugError::postWarning("CvrIndexedSetRenderBaseP::GLRender",
                                "Your OpenGL driver does not support 3D "
                                "textures, which is needed for rendering "
                                "SoVolumeIndexedFaceSet and "
                                "SoVolumeIndexedTriangleStripSet "
                                "nodes");
      flag = TRUE;
    }
    return;
  }

  SoState * state = action->getState();

  const CvrVoxelBlockElement * vbelem = CvrVoxelBlockElement::getInstance(state);
  if (vbelem == NULL) { return; }

  // This must be done, as we want to control stuff in the GL state
  // machine. Without it, state changes could trigger outside our
  // control.
  state->push();

  SbMatrix volumetransform;
  CvrUtil::getTransformFromVolumeBoxDimensions(vbelem, volumetransform);
  SoModelMatrixElement::mult(state, this->master, volumetransform);

  const SbVec3s & dims = vbelem->getVoxelCubeDimensions();
  SbVec3f origo(-((float) dims[0]) / 2.0f, -((float) dims[1]) / 2.0f, -((float) dims[2]) / 2.0f);

  // This must be done, as we want to control stuff in the GL state
  // machine. Without it, state changes could trigger outside our
  // control.
  SoGLLazyElement::getInstance(state)->send(state, SoLazyElement::ALL_MASK);

  glPushAttrib(GL_ALL_ATTRIB_BITS);
  glEnable(GL_TEXTURE_3D);
  glEnable(GL_DEPTH_TEST);

  // FIXME: Should there be support for other blending methods aswell? (20040630 handegar)
  glEnable(GL_BLEND);
  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

  if (!this->cube) { this->cube = new Cvr3DTexCube(action); }

  const SoTransferFunctionElement * tfelement = SoTransferFunctionElement::getInstance(state);
  const CvrCLUT * c = CvrVoxelChunk::getCLUT(tfelement, CvrCLUT::ALPHA_AS_IS);
  if (this->clut != c) {
    this->cube->setPalette(c);
    this->clut = c;
  }

  // Fetch texture quality
  float texturequality = SoTextureQualityElement::get(state);
  GLenum interp;
  if (texturequality >= 0.1f) { interp = GL_LINEAR; }
  else { interp = GL_NEAREST; }
  CvrGLInterpolationElement::set(state, interp);

  // Fetch vertices and normals from the stack
  const SoCoordinateElement * coords;
  const SbVec3f * normals;
  const int32_t * cindices;
  int numindices;
  const int32_t * nindices;
  const int32_t * tindices;
  const int32_t * mindices;
  SbBool doTextures;
  SbBool normalCacheUsed;

  doTextures = FALSE; // No need for texture coordinates
  SbBool sendNormals = FALSE; // No need for normals

  this->getVertexData(state, coords, normals, cindices,
                      nindices, tindices, mindices, numindices,
                      sendNormals, normalCacheUsed);

  const SbVec3f * vertexarray;
  SoVertexProperty * vertprop = (SoVertexProperty *) this->master->vertexProperty.getValue();
  if (vertprop != NULL) {
    vertexarray = vertprop->vertex.getValues(0);
  }
  else vertexarray = coords->getArrayPtr3();

  if (normals == NULL) glDisable(GL_LIGHTING);

  const Cvr3DTexCube::IndexedSetType type = ((this->type == FACESET) ?
                                             Cvr3DTexCube::INDEXEDFACE_SET :
                                             Cvr3DTexCube::INDEXEDTRIANGLESTRIP_SET);

  this->cube->renderIndexedSet(action, vertexarray, cindices, numindices, type);

  glPopAttrib();


  // 'un-Transform' model matrix before rendering clip geometry.
  state->pop();


  // Render the geometry which are outside the volume cube as polygons.
  if (clipGeometry) {

    // Is there a clipplane left for us to use?
    GLint maxclipplanes = 0;
    glGetIntegerv(GL_MAX_CLIP_PLANES, &maxclipplanes);
    const SoClipPlaneElement * elem = SoClipPlaneElement::getInstance(state);
    if (elem->getNum() > (maxclipplanes-1)) {
      static SbBool flag = FALSE;
      if (!flag) {
        flag = TRUE;
        SoDebugError::postWarning("CvrIndexedSetRenderBaseP::GLRender",
                                  "\"clipGeometry TRUE\": Not enough clip planes available. (max=%d)",
                                  maxclipplanes);
      }
      return;
    }

    if (this->parentnodeid != this->master->getNodeId()) { // Changed recently?
      SoVertexProperty * vertprop = (SoVertexProperty *) this->master->vertexProperty.getValue();
      if (vertprop != NULL) this->clipgeometryshape->vertexProperty.setValue(vertprop);

      this->clipgeometryshape->coordIndex.setNum(this->master->coordIndex.getNum());
      this->clipgeometryshape->materialIndex.setNum(this->master->materialIndex.getNum());

      int32_t * idst = this->clipgeometryshape->coordIndex.startEditing();
      int32_t * mdst = this->clipgeometryshape->materialIndex.startEditing();

      int i=0;
      for (i=0;i<this->master->coordIndex.getNum();++i)
        *idst++ = this->master->coordIndex[i];
      for (i=0;i<this->master->materialIndex.getNum();++i)
        *mdst++ = this->master->materialIndex[i];
      // No need to copy texture coords as the face set shall always be untextured.

      this->parentnodeid = this->master->getNodeId();
      this->clipgeometryshape->coordIndex.finishEditing();
      this->clipgeometryshape->materialIndex.finishEditing();
    }

    SbPlane cubeplanes[6];
    SbVec3f a, b, c;

    // FIXME: Its really not necessary to calculate the clip planes
    // for each frame unless the volume has changed. This should be
    // optimized somehow.(20040629 handegar)
    volumetransform.multVecMatrix(SbVec3f(origo + SbVec3f(0.0f, dims[1], 0.0f)), a);
    volumetransform.multVecMatrix(SbVec3f(origo + SbVec3f(0.0f, dims[1], dims[2])), b);
    volumetransform.multVecMatrix(SbVec3f(origo + SbVec3f(dims[0], dims[1], 0.0f)), c);
    cubeplanes[0] = SbPlane(a, b, c); // Top

    volumetransform.multVecMatrix(SbVec3f(origo), a);
    volumetransform.multVecMatrix(SbVec3f(origo + SbVec3f(dims[0], 0.0f, 0.0f)), b);
    volumetransform.multVecMatrix(SbVec3f(origo + SbVec3f(0.0f, 0.0f, dims[2])), c);
    cubeplanes[1] = SbPlane(a, b, c); // Bottom
   
    volumetransform.multVecMatrix(SbVec3f(origo), a);
    volumetransform.multVecMatrix(SbVec3f(origo + SbVec3f(0.0f, dims[1], 0.0f)), b);
    volumetransform.multVecMatrix(SbVec3f(origo + SbVec3f(dims[0], 0.0f, 0.0f)), c);
    cubeplanes[2] = SbPlane(a, b, c); // Back

    volumetransform.multVecMatrix(SbVec3f(origo + SbVec3f(0.0f, 0.0f, dims[2])), a);
    volumetransform.multVecMatrix(SbVec3f(origo + SbVec3f(dims[0], 0.0f, dims[2])), b);
    volumetransform.multVecMatrix(SbVec3f(origo + SbVec3f(0.0f, dims[1], dims[2])), c);
    cubeplanes[3] = SbPlane(a, b, c); // Front

    volumetransform.multVecMatrix(SbVec3f(origo + SbVec3f(dims[0], 0.0f, 0.0f)), a);
    volumetransform.multVecMatrix(SbVec3f(origo + SbVec3f(dims[0], dims[1], 0.0f)), b);
    volumetransform.multVecMatrix(SbVec3f(origo + SbVec3f(dims[0], 0.0f, dims[2])), c);
    cubeplanes[4] = SbPlane(a, b, c); // Right

    volumetransform.multVecMatrix(SbVec3f(origo), a);
    volumetransform.multVecMatrix(SbVec3f(origo + SbVec3f(0.0f, 0.0f, dims[2])), b);
    volumetransform.multVecMatrix(SbVec3f(origo + SbVec3f(0.0f, dims[1], 0.0f)), c);
    cubeplanes[5] = SbPlane(a, b, c); // Left
    
    for (int i=0;i<6;++i) {
      state->push();
      // FIXME: It would have been nice to have a 'remove' or a 'replace'
      // method in the SoClipPlaneElement so that we wouldn't have to
      // push and pop the state. (20040630 handegar)
      SoClipPlaneElement::add(state, this->master, cubeplanes[i]);            
      this->clipgeometryshape->GLRender(action);
      state->pop();
    }
    
  }
}
void SoBrepFaceSet::renderSelection(SoGLRenderAction *action)
{
    int numSelected =  this->selectionIndex.getNum();
    const int32_t* selected = this->selectionIndex.getValues(0);
    if (numSelected == 0) return;

    SoState * state = action->getState();
    state->push();

    SoLazyElement::setEmissive(state, &this->selectionColor);
    SoOverrideElement::setEmissiveColorOverride(state, this, TRUE);
#if 0 // disables shading effect
    SoLazyElement::setDiffuse(state, this,1, &this->selectionColor,&this->colorpacker);
    SoOverrideElement::setDiffuseColorOverride(state, this, TRUE);
    SoLazyElement::setLightModel(state, SoLazyElement::BASE_COLOR);
#endif

    Binding mbind = this->findMaterialBinding(state);
    Binding nbind = this->findNormalBinding(state);

    const SoCoordinateElement * coords;
    const SbVec3f * normals;
    const int32_t * cindices;
    int numindices;
    const int32_t * nindices;
    const int32_t * tindices;
    const int32_t * mindices;
    const int32_t * pindices;
    SbBool doTextures;
    SbBool normalCacheUsed;

    SoMaterialBundle mb(action);
    SoTextureCoordinateBundle tb(action, TRUE, FALSE);
    doTextures = tb.needCoordinates();
    SbBool sendNormals = !mb.isColorOnly() || tb.isFunction();

    this->getVertexData(state, coords, normals, cindices,
                        nindices, tindices, mindices, numindices,
                        sendNormals, normalCacheUsed);

    mb.sendFirst(); // make sure we have the correct material

    // just in case someone forgot
    if (!mindices) mindices = cindices;
    if (!nindices) nindices = cindices;
    pindices = this->partIndex.getValues(0);

    // materials
    mbind = OVERALL;
    doTextures = FALSE;

    for (int i=0; i<numSelected; i++) {
        int id = selected[i];

        // coords
        int length = (int)pindices[id]*4;
        int start=0;
        for (int j=0; j<id; j++)
            start+=(int)pindices[j];
        start *= 4;

        // normals
        const SbVec3f * normals_s = normals;
        const int32_t * nindices_s = nindices;
        if (nbind == PER_VERTEX_INDEXED)
            nindices_s = &(nindices[start]);
        else if (nbind == PER_VERTEX)
            normals_s = &(normals[start]);
        else
            nbind = OVERALL;

        renderShape(static_cast<const SoGLCoordinateElement*>(coords), &(cindices[start]), length,
                    &(pindices[id]), 1, normals_s, nindices_s, &mb, mindices, &tb, tindices, nbind, mbind, doTextures?1:0);
    }
    state->pop();
}
void SoBrepFaceSet::generatePrimitives(SoAction * action)
{
    //TODO
#if 0
    inherited::generatePrimitives(action);
#else
    //This is highly experimental!!!

    if (this->coordIndex.getNum() < 3) return;

    SoState * state = action->getState();

    if (this->vertexProperty.getValue()) {
        state->push();
        this->vertexProperty.getValue()->doAction(action);
    }

    Binding mbind = this->findMaterialBinding(state);
    Binding nbind = this->findNormalBinding(state);

    const SoCoordinateElement * coords;
    const SbVec3f * normals;
    const int32_t * cindices;
    int numindices;
    const int32_t * nindices;
    const int32_t * tindices;
    const int32_t * mindices;
    SbBool doTextures;
    SbBool sendNormals;
    SbBool normalCacheUsed;

    sendNormals = TRUE; // always generate normals

    this->getVertexData(state, coords, normals, cindices,
                        nindices, tindices, mindices, numindices,
                        sendNormals, normalCacheUsed);

    SoTextureCoordinateBundle tb(action, FALSE, FALSE);
    doTextures = tb.needCoordinates();

    if (!sendNormals) nbind = OVERALL;
    else if (normalCacheUsed && nbind == PER_VERTEX) {
        nbind = PER_VERTEX_INDEXED;
    }
    else if (normalCacheUsed && nbind == PER_FACE_INDEXED) {
        nbind = PER_FACE;
    }

    if (this->getNodeType() == SoNode::VRML1) {
        // For VRML1, PER_VERTEX means per vertex in shape, not PER_VERTEX
        // on the state.
        if (mbind == PER_VERTEX) {
            mbind = PER_VERTEX_INDEXED;
            mindices = cindices;
        }
        if (nbind == PER_VERTEX) {
            nbind = PER_VERTEX_INDEXED;
            nindices = cindices;
        }
    }

    Binding tbind = NONE;
    if (doTextures) {
        if (tb.isFunction() && !tb.needIndices()) {
            tbind = NONE;
            tindices = NULL;
        }
        // FIXME: just call inherited::areTexCoordsIndexed() instead of
        // the if-check? 20020110 mortene.
        else if (SoTextureCoordinateBindingElement::get(state) ==
                 SoTextureCoordinateBindingElement::PER_VERTEX) {
            tbind = PER_VERTEX;
            tindices = NULL;
        }
        else {
            tbind = PER_VERTEX_INDEXED;
            if (tindices == NULL) tindices = cindices;
        }
    }

    if (nbind == PER_VERTEX_INDEXED && nindices == NULL) {
        nindices = cindices;
    }
    if (mbind == PER_VERTEX_INDEXED && mindices == NULL) {
        mindices = cindices;
    }

    int texidx = 0;
    TriangleShape mode = POLYGON;
    TriangleShape newmode;
    const int32_t *viptr = cindices;
    const int32_t *viendptr = viptr + numindices;
    const int32_t *piptr = this->partIndex.getValues(0);
    int num_partindices = this->partIndex.getNum();
    const int32_t *piendptr = piptr + num_partindices;
    int32_t v1, v2, v3, v4, v5 = 0, pi; // v5 init unnecessary, but kills a compiler warning.

    SoPrimitiveVertex vertex;
    SoPointDetail pointDetail;
    SoFaceDetail faceDetail;

    vertex.setDetail(&pointDetail);

    SbVec3f dummynormal(0,0,1);
    const SbVec3f *currnormal = &dummynormal;
    if (normals) currnormal = normals;
    vertex.setNormal(*currnormal);

    int matnr = 0;
    int normnr = 0;
    int trinr = 0;
    pi = piptr < piendptr ? *piptr++ : -1;
    while (pi == 0) {
        // It may happen that a part has no triangles
        pi = piptr < piendptr ? *piptr++ : -1;
        if (mbind == PER_PART)
            matnr++;
        else if (mbind == PER_PART_INDEXED)
            mindices++;
    }

    while (viptr + 2 < viendptr) {
        v1 = *viptr++;
        v2 = *viptr++;
        v3 = *viptr++;
        if (v1 < 0 || v2 < 0 || v3 < 0) {
            break;
        }
        v4 = viptr < viendptr ? *viptr++ : -1;
        if (v4  < 0) newmode = TRIANGLES;
        else {
            v5 = viptr < viendptr ? *viptr++ : -1;
            if (v5 < 0) newmode = QUADS;
            else newmode = POLYGON;
        }
        if (newmode != mode) {
            if (mode != POLYGON) this->endShape();
            mode = newmode;
            this->beginShape(action, mode, &faceDetail);
        }
        else if (mode == POLYGON) this->beginShape(action, POLYGON, &faceDetail);

        // vertex 1 can't use DO_VERTEX
        if (mbind == PER_PART) {
            if (trinr == 0) {
                pointDetail.setMaterialIndex(matnr);
                vertex.setMaterialIndex(matnr++);
            }
        }
        else if (mbind == PER_PART_INDEXED) {
            if (trinr == 0) {
                pointDetail.setMaterialIndex(*mindices);
                vertex.setMaterialIndex(*mindices++);
            }
        }
        else if (mbind == PER_VERTEX || mbind == PER_FACE) {
            pointDetail.setMaterialIndex(matnr);
            vertex.setMaterialIndex(matnr++);
        }
        else if (mbind == PER_VERTEX_INDEXED || mbind == PER_FACE_INDEXED) {
            pointDetail.setMaterialIndex(*mindices);
            vertex.setMaterialIndex(*mindices++);
        }
        if (nbind == PER_VERTEX || nbind == PER_FACE) {
            pointDetail.setNormalIndex(normnr);
            currnormal = &normals[normnr++];
            vertex.setNormal(*currnormal);
        }
        else if (nbind == PER_FACE_INDEXED || nbind == PER_VERTEX_INDEXED) {
            pointDetail.setNormalIndex(*nindices);
            currnormal = &normals[*nindices++];
            vertex.setNormal(*currnormal);
        }

        if (tb.isFunction()) {
            vertex.setTextureCoords(tb.get(coords->get3(v1), *currnormal));
            if (tb.needIndices()) pointDetail.setTextureCoordIndex(tindices ? *tindices++ : texidx++);
        }
        else if (tbind != NONE) {
            pointDetail.setTextureCoordIndex(tindices ? *tindices : texidx);
            vertex.setTextureCoords(tb.get(tindices ? *tindices++ : texidx++));
        }
        pointDetail.setCoordinateIndex(v1);
        vertex.setPoint(coords->get3(v1));
        this->shapeVertex(&vertex);

        DO_VERTEX(v2);
        DO_VERTEX(v3);

        if (mode != TRIANGLES) {
            DO_VERTEX(v4);
            if (mode == POLYGON) {
                DO_VERTEX(v5);
                v1 = viptr < viendptr ? *viptr++ : -1;
                while (v1 >= 0) {
                    DO_VERTEX(v1);
                    v1 = viptr < viendptr ? *viptr++ : -1;
                }
                this->endShape();
            }
        }
        faceDetail.incFaceIndex();
        if (mbind == PER_VERTEX_INDEXED) {
            mindices++;
        }
        if (nbind == PER_VERTEX_INDEXED) {
            nindices++;
        }
        if (tindices) tindices++;

        trinr++;
        if (pi == trinr) {
            pi = piptr < piendptr ? *piptr++ : -1;
            while (pi == 0) {
                // It may happen that a part has no triangles
                pi = piptr < piendptr ? *piptr++ : -1;
                if (mbind == PER_PART)
                    matnr++;
                else if (mbind == PER_PART_INDEXED)
                    mindices++;
            }
            trinr = 0;
        }
    }
    if (mode != POLYGON) this->endShape();

    if (normalCacheUsed) {
        this->readUnlockNormalCache();
    }

    if (this->vertexProperty.getValue()) {
        state->pop();
    }
#endif
}