void BrushByPlaneClipper::visit(const scene::INodePtr& node) const { // Don't clip invisible nodes if (!node->visible()) { return; } // Try to cast the instance onto a brush Brush* brush = Node_getBrush(node); // Return if not brush if (brush == NULL) { return; } Plane3 plane(_p0, _p1, _p2); if (!plane.isValid()) { return; } // greebo: Analyse the brush to find out which shader is the most used one getMostUsedTexturing(brush); BrushSplitType split = Brush_classifyPlane(*brush, _split == eFront ? -plane : plane); if (split.counts[ePlaneBack] && split.counts[ePlaneFront]) { // the plane intersects this brush if (_split == eFrontAndBack) { scene::INodePtr brushNode = GlobalBrushCreator().createBrush(); assert(brushNode != NULL); Brush* fragment = Node_getBrush(brushNode); assert(fragment != NULL); fragment->copy(*brush); FacePtr newFace = fragment->addPlane(_p0, _p1, _p2, _mostUsedShader, _mostUsedProjection); if (newFace != NULL && _split != eFront) { newFace->flipWinding(); } fragment->removeEmptyFaces(); ASSERT_MESSAGE(!fragment->empty(), "brush left with no faces after split"); // Mark this brush for insertion _insertList.insert(InsertMap::value_type(brushNode, node->getParent())); } FacePtr newFace = brush->addPlane(_p0, _p1, _p2, _mostUsedShader, _mostUsedProjection); if (newFace != NULL && _split == eFront) { newFace->flipWinding(); } brush->removeEmptyFaces(); ASSERT_MESSAGE(!brush->empty(), "brush left with no faces after split"); } // the plane does not intersect this brush else if (_split != eFrontAndBack && split.counts[ePlaneBack] != 0) { // the brush is "behind" the plane _deleteList.insert(node); } }
void BrushByPlaneClipper::split(const BrushPtrVector& brushes) { Plane3 plane(_p0, _p1, _p2); if (!plane.isValid()) { return; } for (BrushPtrVector::const_iterator i = brushes.begin(); i != brushes.end(); ++i) { const BrushNodePtr& node = *i; // Don't clip invisible nodes if (!node->visible()) { continue; } Brush& brush = node->getBrush(); scene::INodePtr parent = node->getParent(); if (!parent) { continue; } // greebo: Analyse the brush to find out which shader is the most used one getMostUsedTexturing(brush); BrushSplitType split = Brush_classifyPlane(brush, _split == eFront ? -plane : plane); if (split.counts[ePlaneBack] && split.counts[ePlaneFront]) { // the plane intersects this brush if (_split == eFrontAndBack) { scene::INodePtr fragmentNode = GlobalBrushCreator().createBrush(); assert(fragmentNode != NULL); // Put the fragment in the same layer as the brush it was clipped from // Do this before adding the fragment to the parent, since there is an // update algorithm setting the visibility of the fragment right there. scene::assignNodeToLayers(fragmentNode, node->getLayers()); // greebo: For copying the texture scale the new node needs to be inserted in the scene // otherwise the shaders cannot be captured and the scale is off // Insert the child into the designated parent scene::addNodeToContainer(fragmentNode, parent); // Select the child Node_setSelected(fragmentNode, true); Brush* fragment = Node_getBrush(fragmentNode); assert(fragment != NULL); fragment->copy(brush); FacePtr newFace = fragment->addPlane(_p0, _p1, _p2, _mostUsedShader, _mostUsedProjection); if (newFace != NULL && _split != eFront) { newFace->flipWinding(); } fragment->removeEmptyFaces(); ASSERT_MESSAGE(!fragment->empty(), "brush left with no faces after split"); } FacePtr newFace = brush.addPlane(_p0, _p1, _p2, _mostUsedShader, _mostUsedProjection); if (newFace != NULL && _split == eFront) { newFace->flipWinding(); } brush.removeEmptyFaces(); ASSERT_MESSAGE(!brush.empty(), "brush left with no faces after split"); } // the plane does not intersect this brush else if (_split != eFrontAndBack && split.counts[ePlaneBack] != 0) { // the brush is "behind" the plane // Remove the node from the scene scene::removeNodeFromParent(node); } } }