/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield * * This library is open source and may be redistributed and/or modified under * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or * (at your option) any later version. The full license is in LICENSE file * included with this distribution, and on the openscenegraph.org website. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * OpenSceneGraph Public License for more details. */ #include #include #include using namespace osg; Shape::~Shape() { } ShapeVisitor::~ShapeVisitor() { } ConstShapeVisitor::~ConstShapeVisitor() { } Sphere::~Sphere() { } Box::~Box() { } Cone::~Cone() { } Cylinder::~Cylinder() { } Capsule::~Capsule() { } InfinitePlane::~InfinitePlane() { } TriangleMesh::~TriangleMesh() { } ConvexHull::~ConvexHull() { } HeightField::HeightField(): _columns(0), _rows(0), _origin(0.0f,0.0f,0.0f), _dx(1.0f), _dy(1.0f), _skirtHeight(0.0f), _borderWidth(0) { _heights = new FloatArray; } HeightField::HeightField(const HeightField& mesh,const CopyOp& copyop): Shape(mesh,copyop), _columns(mesh._columns), _rows(mesh._rows), _origin(mesh._origin), _dx(mesh._dx), _dy(mesh._dy), _skirtHeight(mesh._skirtHeight), _borderWidth(mesh._borderWidth), _heights(new FloatArray(*mesh._heights)) { } HeightField::~HeightField() { } void HeightField::allocate(unsigned int numColumns,unsigned int numRows) { if (_columns!=numColumns || _rows!=numRows) { _heights->resize(numColumns*numRows); } _columns=numColumns; _rows=numRows; } Vec3 HeightField::getNormal(unsigned int c,unsigned int r) const { // four point normal generation. float dz_dx; if (c==0) { dz_dx = (getHeight(c+1,r)-getHeight(c,r))/getXInterval(); } else if (c==getNumColumns()-1) { dz_dx = (getHeight(c,r)-getHeight(c-1,r))/getXInterval(); } else // assume 0(geometry->getVertexArray()); _normals = dynamic_cast(geometry->getNormalArray()); _texcoords = dynamic_cast(geometry->getTexCoordArray(0)); bool requiresClearOfPrimitiveSets = false; if (!_vertices || _vertices->getBinding()!=Array::BIND_PER_VERTEX) { requiresClearOfPrimitiveSets = true; _vertices = new Vec3Array(Array::BIND_PER_VERTEX); _geometry->setVertexArray(_vertices.get()); } if (!_normals || (_normals->getBinding()!=Array::BIND_PER_VERTEX || _vertices->size()!=_normals->size())) { requiresClearOfPrimitiveSets = true; _normals = new Vec3Array(Array::BIND_PER_VERTEX); _geometry->setNormalArray(_normals.get()); } if (!_texcoords || (_texcoords->getBinding()!=Array::BIND_PER_VERTEX || _vertices->size()!=_texcoords->size())) { requiresClearOfPrimitiveSets = true; _texcoords = new Vec2Array(Array::BIND_PER_VERTEX); _geometry->setTexCoordArray(0, _texcoords.get()); } if (requiresClearOfPrimitiveSets && !_geometry->getPrimitiveSetList().empty()) { OSG_NOTICE<<"Warning: BuildShapeGeometryVisitor() Geometry contains compatible arrays, resetting before shape build."<getPrimitiveSetList().clear(); } _mode = 0; _start_index = 0; } void BuildShapeGeometryVisitor::setMatrix(const Matrixd& m) { _matrix = m; _inverse.invert(m); _inverse.setTrans(0.0,0.0,0.0); } void BuildShapeGeometryVisitor::Begin(GLenum mode) { _mode = mode; _start_index = _vertices->size(); } void BuildShapeGeometryVisitor::End() { if (_start_index>=_vertices->size()) return; _geometry->addPrimitiveSet(new DrawArrays(_mode, _start_index, _vertices->size()-_start_index)); for(unsigned int i=_start_index; i<_vertices->size(); ++i) { Vec3& v = (*_vertices)[i]; v = v * _matrix; Vec3& n = (*_normals)[i]; n = _inverse * n; n.normalize(); } _vertices->dirty(); _normals->dirty(); _texcoords->dirty(); _geometry->dirtyGLObjects(); _start_index = _vertices->size(); } void BuildShapeGeometryVisitor::drawCylinderBody(unsigned int numSegments, float radius, float height) { const float angleDelta = 2.0f*PIf/(float)numSegments; const float texCoordDelta = 1.0f/(float)numSegments; const float r = radius; const float h = height; float basez = -h*0.5f; float topz = h*0.5f; float angle = 0.0f; float texCoord = 0.0f; bool drawFrontFace = _hints ? _hints->getCreateFrontFace() : true; bool drawBackFace = _hints ? _hints->getCreateBackFace() : false; // The only difference between the font & back face loops is that the // normals are inverted and the order of the vertex pairs is reversed. // The code is mostly duplicated in order to hoist the back/front face // test out of the loop for efficiency Begin(GL_QUAD_STRIP); if (drawFrontFace) { for(unsigned int bodyi=0; bodyigetCreateFrontFace() : true; bool drawBackFace = _hints ? _hints->getCreateBackFace() : false; float angleDelta = PIf*2.0f/(float)numSegments; float texCoordHorzDelta = 1.0f/(float)numSegments; float lBase=-PIf*0.5f + (top?(lDelta*(numRows/2)):0.0f); float rBase=(top?(cosf(lBase)*radius):0.0f); float zBase=(top?(sinf(lBase)*radius):-radius); float vBase=(top?(vDelta*(numRows/2)):0.0f); float nzBase=(top?(sinf(lBase)):-1.0f); float nRatioBase=(top?(cosf(lBase)):0.0f); unsigned int rowbegin = top?numRows/2:0; unsigned int rowend = top?numRows:numRows/2; for(unsigned int rowi=rowbegin; rowigetCreateFrontFace() : true; bool drawBackFace = _hints ? _hints->getCreateBackFace() : false; setMatrix(Matrixd::translate(sphere.getCenter().x(),sphere.getCenter().y(),sphere.getCenter().z())); unsigned int numSegments = 40; unsigned int numRows = 20; float ratio = (_hints ? _hints->getDetailRatio() : 1.0f); if (ratio > 0.0f && ratio != 1.0f) { numRows = (unsigned int) (numRows * ratio); if (numRows < MIN_NUM_ROWS) numRows = MIN_NUM_ROWS; numSegments = (unsigned int) (numSegments * ratio); if (numSegments < MIN_NUM_SEGMENTS) numSegments = MIN_NUM_SEGMENTS; } float lDelta = PIf/(float)numRows; float vDelta = 1.0f/(float)numRows; float angleDelta = PIf*2.0f/(float)numSegments; float texCoordHorzDelta = 1.0f/(float)numSegments; if (drawBackFace) { float lBase=-PIf*0.5f; float rBase=0.0f; float zBase=-sphere.getRadius(); float vBase=0.0f; float nzBase=-1.0f; float nRatioBase=0.0f; for(unsigned int rowi=0; rowigetCreateBody() : true); bool createTop = (_hints ? _hints->getCreateTop() : true); bool createBottom = (_hints ? _hints->getCreateBottom() : true); float dx = box.getHalfLengths().x(); float dy = box.getHalfLengths().y(); float dz = box.getHalfLengths().z(); setMatrix(box.computeRotationMatrix() * Matrixd::translate(box.getCenter())); Begin(GL_QUADS); if (createBody) { // -ve y plane Normal3f(0.0f,-1.0f,0.0f); TexCoord2f(0.0f,1.0f); Vertex3f(-dx,-dy,dz); Normal3f(0.0f,-1.0f,0.0f); TexCoord2f(0.0f,0.0f); Vertex3f(-dx,-dy,-dz); Normal3f(0.0f,-1.0f,0.0f); TexCoord2f(1.0f,0.0f); Vertex3f(dx,-dy,-dz); Normal3f(0.0f,-1.0f,0.0f); TexCoord2f(1.0f,1.0f); Vertex3f(dx,-dy,dz); // +ve y plane Normal3f(0.0f,1.0f,0.0f); TexCoord2f(0.0f,1.0f); Vertex3f(dx,dy,dz); Normal3f(0.0f,1.0f,0.0f); TexCoord2f(0.0f,0.0f); Vertex3f(dx,dy,-dz); Normal3f(0.0f,1.0f,0.0f); TexCoord2f(1.0f,0.0f); Vertex3f(-dx,dy,-dz); Normal3f(0.0f,1.0f,0.0f); TexCoord2f(1.0f,1.0f); Vertex3f(-dx,dy,dz); // +ve x plane Normal3f(1.0f,0.0f,0.0f); TexCoord2f(0.0f,1.0f); Vertex3f(dx,-dy,dz); Normal3f(1.0f,0.0f,0.0f); TexCoord2f(0.0f,0.0f); Vertex3f(dx,-dy,-dz); Normal3f(1.0f,0.0f,0.0f); TexCoord2f(1.0f,0.0f); Vertex3f(dx,dy,-dz); Normal3f(1.0f,0.0f,0.0f); TexCoord2f(1.0f,1.0f); Vertex3f(dx,dy,dz); // -ve x plane Normal3f(-1.0f,0.0f,0.0f); TexCoord2f(0.0f,1.0f); Vertex3f(-dx,dy,dz); Normal3f(-1.0f,0.0f,0.0f); TexCoord2f(0.0f,0.0f); Vertex3f(-dx,dy,-dz); Normal3f(-1.0f,0.0f,0.0f); TexCoord2f(1.0f,0.0f); Vertex3f(-dx,-dy,-dz); Normal3f(-1.0f,0.0f,0.0f); TexCoord2f(1.0f,1.0f); Vertex3f(-dx,-dy,dz); } if (createTop) { // +ve z plane Normal3f(0.0f,0.0f,1.0f); TexCoord2f(0.0f,1.0f); Vertex3f(-dx,dy,dz); Normal3f(0.0f,0.0f,1.0f); TexCoord2f(0.0f,0.0f); Vertex3f(-dx,-dy,dz); Normal3f(0.0f,0.0f,1.0f); TexCoord2f(1.0f,0.0f); Vertex3f(dx,-dy,dz); Normal3f(0.0f,0.0f,1.0f); TexCoord2f(1.0f,1.0f); Vertex3f(dx,dy,dz); } if (createBottom) { // -ve z plane Normal3f(0.0f,0.0f,-1.0f); TexCoord2f(0.0f,1.0f); Vertex3f(dx,dy,-dz); Normal3f(0.0f,0.0f,-1.0f); TexCoord2f(0.0f,0.0f); Vertex3f(dx,-dy,-dz); Normal3f(0.0f,0.0f,-1.0f); TexCoord2f(1.0f,0.0f); Vertex3f(-dx,-dy,-dz); Normal3f(0.0f,0.0f,-1.0f); TexCoord2f(1.0f,1.0f); Vertex3f(-dx,dy,-dz); } End(); } void BuildShapeGeometryVisitor::apply(const Cone& cone) { setMatrix(cone.computeRotationMatrix() * Matrixd::translate(cone.getCenter())); // evaluate hints bool createBody = (_hints ? _hints->getCreateBody() : true); bool createBottom = (_hints ? _hints->getCreateBottom() : true); unsigned int numSegments = 40; unsigned int numRows = 10; float ratio = (_hints ? _hints->getDetailRatio() : 1.0f); if (ratio > 0.0f && ratio != 1.0f) { numRows = (unsigned int) (numRows * ratio); if (numRows < MIN_NUM_ROWS) numRows = MIN_NUM_ROWS; numSegments = (unsigned int) (numSegments * ratio); if (numSegments < MIN_NUM_SEGMENTS) numSegments = MIN_NUM_SEGMENTS; } float r = cone.getRadius(); float h = cone.getHeight(); float normalz = r/(sqrtf(r*r+h*h)); float normalRatio = 1.0f/(sqrtf(1.0f+normalz*normalz)); normalz *= normalRatio; float angleDelta = 2.0f*PIf/(float)numSegments; float texCoordHorzDelta = 1.0/(float)numSegments; float texCoordRowDelta = 1.0/(float)numRows; float hDelta = cone.getHeight()/(float)numRows; float rDelta = cone.getRadius()/(float)numRows; float topz=cone.getHeight()+cone.getBaseOffset(); float topr=0.0f; float topv=1.0f; float basez=topz-hDelta; float baser=rDelta; float basev=topv-texCoordRowDelta; float angle; float texCoord; if (createBody) { for(unsigned int rowi=0; rowigetCreateBody() : true); bool createTop = (_hints ? _hints->getCreateTop() : true); bool createBottom = (_hints ? _hints->getCreateBottom() : true); unsigned int numSegments = 40; float ratio = (_hints ? _hints->getDetailRatio() : 1.0f); if (ratio > 0.0f && ratio != 1.0f) { numSegments = (unsigned int) (numSegments * ratio); if (numSegments < MIN_NUM_SEGMENTS) numSegments = MIN_NUM_SEGMENTS; } // cylinder body if (createBody) drawCylinderBody(numSegments, cylinder.getRadius(), cylinder.getHeight()); float angleDelta = 2.0f*PIf/(float)numSegments; float texCoordDelta = 1.0f/(float)numSegments; float r = cylinder.getRadius(); float h = cylinder.getHeight(); float basez = -h*0.5f; float topz = h*0.5f; float angle = 0.0f; float texCoord = 0.0f; // cylinder top if (createTop) { Begin(GL_TRIANGLE_FAN); Normal3f(0.0f,0.0f,1.0f); TexCoord2f(0.5f,0.5f); Vertex3f(0.0f,0.0f,topz); angle = 0.0f; texCoord = 0.0f; for(unsigned int topi=0; topigetCreateBody() : true); bool createTop = (_hints ? _hints->getCreateTop() : true); bool createBottom = (_hints ? _hints->getCreateBottom() : true); unsigned int numSegments = 40; unsigned int numRows = 20; float ratio = (_hints ? _hints->getDetailRatio() : 1.0f); if (ratio > 0.0f && ratio != 1.0f) { numSegments = (unsigned int) (numSegments * ratio); if (numSegments < MIN_NUM_SEGMENTS) numSegments = MIN_NUM_SEGMENTS; numRows = (unsigned int) (numRows * ratio); if (numRows < MIN_NUM_ROWS) numRows = MIN_NUM_ROWS; } // if numRows is odd the top and bottom halves of sphere won't match, so bump up to the next event numRows if ((numRows%2)!=0) ++numRows; // capsule cylindrical body if (createBody) drawCylinderBody(numSegments, capsule.getRadius(), capsule.getHeight()); // capsule top cap if (createTop) drawHalfSphere(numSegments, numRows, capsule.getRadius(), SphereTopHalf, capsule.getHeight()/2.0f); // capsule bottom cap if (createBottom) drawHalfSphere(numSegments, numRows, capsule.getRadius(), SphereBottomHalf, -capsule.getHeight()/2.0f); } void BuildShapeGeometryVisitor::apply(const InfinitePlane&) { OSG_NOTICE<<"Warning: BuildShapeGeometryVisitor::apply(const InfinitePlane& plane) not yet implemented. "<getNumElements();i+=3) { const Vec3& v1=(*vertices)[indices->index(i)]; const Vec3& v2=(*vertices)[indices->index(i+1)]; const Vec3& v3=(*vertices)[indices->index(i+2)]; Vec3 normal = (v2-v1)^(v3-v2); normal.normalize(); Normal(normal); Vertex(v1); Normal(normal); Vertex(v2); Normal(normal); Vertex(v3); } End(); } } void BuildShapeGeometryVisitor::apply(const ConvexHull& hull) { apply((const TriangleMesh&)hull); } void BuildShapeGeometryVisitor::apply(const HeightField& field) { if (field.getNumColumns()==0 || field.getNumRows()==0) return; setMatrix(field.computeRotationMatrix() * Matrixd::translate(field.getOrigin())); float dx = field.getXInterval(); float dy = field.getYInterval(); float du = 1.0f/((float)field.getNumColumns()-1.0f); float dv = 1.0f/((float)field.getNumRows()-1.0f); float vBase = 0.0f; Vec3 vertTop; Vec3 normTop; Vec3 vertBase; Vec3 normBase; if (field.getSkirtHeight()!=0.0f) { Begin(GL_QUAD_STRIP); float u = 0.0f; // draw bottom skirt unsigned int col; vertTop.y() = 0.0f; for(col=0;colaccept(*this); } } Geometry* osg::convertShapeToGeometry(const Shape& shape, const TessellationHints* hints) { ref_ptr geometry = new Geometry; BuildShapeGeometryVisitor buildGeometry(geometry.get(), hints); shape.accept( buildGeometry ); return geometry.release(); } Geometry* osg::convertShapeToGeometry(const Shape& shape, const TessellationHints* hints, const Vec4& color, Array::Binding colorBinding) { ref_ptr geometry = convertShapeToGeometry(shape, hints); unsigned int numColors = 0; switch(colorBinding) { case(Array::BIND_OVERALL): numColors = 1; break; case(Array::BIND_PER_VERTEX): numColors = geometry->getVertexArray()->getNumElements(); break; case(Array::BIND_PER_PRIMITIVE_SET): numColors = geometry->getPrimitiveSetList().size(); break; default: break; } if (numColors>0) { ref_ptr colors = new Vec4Array(colorBinding); geometry->setColorArray(colors.get()); for(unsigned int i=0; ipush_back(color); } } return geometry.release(); }