3 * Copyright (C) 2006-2007 Mathias Froehlich
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as
7 * published by the Free Software Foundation; either version 2 of the
8 * License, or (at your option) any later version.
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
23 # include <simgear_config.h>
26 #include "SGClipGroup.hxx"
28 #include <osg/ClipPlane>
29 #include <osg/NodeCallback>
30 #include <osg/StateSet>
31 #include <osg/Version>
33 #include <osgUtil/RenderBin>
34 #include <osgUtil/RenderLeaf>
35 #include <osgUtil/CullVisitor>
37 class SGClipGroup::ClipRenderBin : public osgUtil::RenderBin {
39 virtual osg::Object* cloneType() const
40 { return new ClipRenderBin(); }
41 virtual osg::Object* clone(const osg::CopyOp& copyop) const
42 { return new ClipRenderBin; }
43 virtual bool isSameKindAs(const osg::Object* obj) const
44 { return dynamic_cast<const ClipRenderBin*>(obj)!=0L; }
45 virtual const char* libraryName() const
47 virtual const char* className() const
48 { return "ClipRenderBin"; }
50 virtual void drawImplementation(osg::RenderInfo& renderInfo,
51 osgUtil::RenderLeaf*& previous)
53 osg::State* state = renderInfo.getState();
55 state->applyModelViewMatrix(mModelView.get());
56 for (unsigned i = 0; i < mClipPlanes.size(); ++i) {
57 osg::StateAttribute::GLMode planeNum;
58 planeNum = GL_CLIP_PLANE0 + mClipPlanes[i]->getClipPlaneNum();
59 state->applyMode(planeNum, false);
60 glClipPlane(planeNum, mClipPlanes[i]->getClipPlane().ptr());
63 osgUtil::RenderBin::drawImplementation(renderInfo, previous);
67 { mClipPlanes.resize(0); }
69 std::vector<osg::ref_ptr<osg::ClipPlane> > mClipPlanes;
70 osg::ref_ptr<osg::RefMatrix> mModelView;
73 struct SGClipGroup::ClipBinRegistrar
78 ::addRenderBinPrototype("ClipRenderBin",
79 new SGClipGroup::ClipRenderBin);
81 static ClipBinRegistrar registrar;
84 SGClipGroup::ClipBinRegistrar SGClipGroup::ClipBinRegistrar::registrar;
86 class SGClipGroup::CullCallback : public osg::NodeCallback {
88 virtual void operator()(osg::Node* node, osg::NodeVisitor* nv)
90 osgUtil::CullVisitor* cullVisitor;
91 cullVisitor = dynamic_cast<osgUtil::CullVisitor*>(nv);
94 osgUtil::RenderBin* renderBin = cullVisitor->getCurrentRenderBin();
95 ClipRenderBin* clipBin = dynamic_cast<ClipRenderBin*>(renderBin);
96 SGClipGroup* clipGroup;
97 clipGroup = dynamic_cast<SGClipGroup*>(node);
98 if (clipGroup && clipBin) {
99 clipBin->mClipPlanes = clipGroup->mClipPlanes;
100 clipBin->mModelView = cullVisitor->getModelViewMatrix();
104 // note, callback is responsible for scenegraph traversal so
105 // they must call traverse(node,nv) to ensure that the
106 // scene graph subtree (and associated callbacks) are traversed.
112 static osg::Vec4d clipPlane(const osg::Vec2& p0, const osg::Vec2& p1)
114 osg::Vec2d v(p1[0] - p0[0], p1[1] - p0[1]);
115 return osg::Vec4d(v[1], -v[0], 0, v[0]*p0[1] - v[1]*p0[0]);
119 SGClipGroup::SGClipGroup()
121 getOrCreateStateSet()->setRenderBinDetails(0, "ClipRenderBin");
122 setCullCallback(new CullCallback);
125 SGClipGroup::SGClipGroup(const SGClipGroup& clip, const osg::CopyOp& copyop) :
126 osg::Group(clip, copyop)
128 for (unsigned i = 0; i < mClipPlanes.size(); ++i) {
129 osg::StateAttribute* sa = copyop(mClipPlanes[i].get());
130 mClipPlanes.push_back(static_cast<osg::ClipPlane*>(sa));
135 SGClipGroup::computeBound() const
137 return _initialBound;
141 SGClipGroup::addClipPlane(unsigned num, const SGVec2d& p0,
144 osg::Vec2d v(p1[0] - p0[0], p1[1] - p0[1]);
145 osg::Vec4d planeEquation(v[1], -v[0], 0, v[0]*p0[1] - v[1]*p0[0]);
146 osg::ClipPlane* clipPlane = new osg::ClipPlane(num, planeEquation);
147 getStateSet()->setAssociatedModes(clipPlane, osg::StateAttribute::ON);
148 mClipPlanes.push_back(clipPlane);
152 SGClipGroup::setDrawArea(const SGVec2d& lowerLeft,
153 const SGVec2d& upperRight)
155 setDrawArea(lowerLeft,
156 SGVec2d(lowerLeft[0], upperRight[1]),
157 SGVec2d(upperRight[0], lowerLeft[1]),
162 SGClipGroup::setDrawArea(const SGVec2d& bottomLeft,
163 const SGVec2d& topLeft,
164 const SGVec2d& bottomRight,
165 const SGVec2d& topRight)
167 #if (OPENSCENEGRAPH_MAJOR_VERSION > 2) || (OPENSCENEGRAPH_MINOR_VERSION > 2)
168 for (unsigned i = 0; i < mClipPlanes.size(); ++i)
169 getStateSet()->removeAssociatedModes(mClipPlanes[i].get());
171 mClipPlanes.resize(0);
172 addClipPlane(2, bottomLeft, topLeft);
173 addClipPlane(3, topLeft, topRight);
174 addClipPlane(4, topRight, bottomRight);
175 addClipPlane(5, bottomRight, bottomLeft);
176 _initialBound.init();
177 _initialBound.expandBy(osg::Vec3(bottomLeft[0], bottomLeft[1], 0));
178 _initialBound.expandBy(osg::Vec3(topLeft[0], topLeft[1], 0));
179 _initialBound.expandBy(osg::Vec3(bottomRight[0], bottomRight[1], 0));
180 _initialBound.expandBy(osg::Vec3(topRight[0], topRight[1], 0));
181 _boundingSphere = _initialBound;
182 _boundingSphereComputed = true;