// -*-c++-*- /* * Autcad DXF writer for Open Scene Graph * * Copyright (C) 2009 Martin Beckett mgb@mgbeckett.com * * Based on OBJ writer plugin by Ulrich Hertlein * * The Open Scene Graph (OSG) is a cross platform C++/OpenGL library for * real-time rendering of large 3D photo-realistic models. * The OSG homepage is http://www.openscenegraph.org/ */ #include #include #include #include "DXFWriterNodeVisitor.h" // ROBERT - is there any need for a value visitor like this or is it just overkill? /** writes all values of an array out to a stream, applies a matrix beforehand if necessary */ // I think this is a bit over the top for just a simple vertex array - but if anyone knwos different? /* class ValueVisitor : public osg::ValueVisitor { public: ValueVisitor(std::ostream& fout, const Layer &layer,const osg::Matrix& m = osg::Matrix::identity()) : osg::ValueVisitor(), _fout(fout), _layer(layer), _m(m) { //_applyMatrix = (_m != osg::Matrix::identity()); } virtual void apply(osg::Vec3 & inv) { osg::Vec3 point(inv) ; point = point * _m; _fout << "0 \nVERTEX\n 8\n"<<_layer._name<<"\n"; if ( _layer._color ) { _fout << "62\n"<<_layer._color<<"\n"; } _fout <<" 10\n"<getVertexArray())->at(i) * _m; _fout <(mode, count, indices); } virtual void drawElements(GLenum mode,GLsizei count,const GLushort* indices) { drawElementsImplementation(mode, count, indices); } virtual void drawElements(GLenum mode,GLsizei count,const GLuint* indices) { drawElementsImplementation(mode, count, indices); } protected: templatevoid drawElementsImplementation(GLenum mode, GLsizei count, const T* indices) { if (indices==0 || count==0) return; typedef const T* IndexPointer; switch(mode) { case(GL_TRIANGLES): { IndexPointer ilast = &indices[count]; for(IndexPointer iptr=indices;iptr _indexCache; osg::Geometry* _geo; Layer _layer; AcadColor _acad; // needed to lookup new colors osg::Matrix _m; bool _writeTriangleAs3DFace; }; void DxfPrimitiveIndexWriter::drawArrays(GLenum mode,GLint first,GLsizei count) { switch(mode) { case(GL_TRIANGLES): { unsigned int pos=first; for(GLsizei i=2;i::iterator itr=_layers.begin();itr!=_layers.end();itr++) { if (itr->_name == layerName ) { std::stringstream ss; ss << defaultvalue<< "_" << _layers.size(); layerName = ss.str(); break; } } //empty layer name is forbidden if (layerName.empty()) layerName = "0"; return layerName; } // Now deal with VertexArray directly //void DXFWriterNodeVisitor::processArray(osg::Array* array, const Layer &layer,const osg::Matrix& m) //{ // if (array == NULL) // return; // // ValueVisitor vv(_fout, layer,m); // for(unsigned int i = 0; i < array->getNumElements(); ++i) { // array->accept(i, vv); // } // // OSG_DEBUG << "processArray "<getNumElements() << " elements written" << std::endl; // //} void DXFWriterNodeVisitor::processStateSet(osg::StateSet* ss) { // anything to do if no material/texture? osg::PolygonMode * pm = dynamic_cast(ss->getAttribute(osg::StateAttribute::POLYGONMODE)); if (pm) { if (pm->getMode(osg::PolygonMode::FRONT)==osg::PolygonMode::LINE) _writeTriangleAs3DFace = false; } osg::Material * mat = dynamic_cast(ss->getAttribute(osg::StateAttribute::MATERIAL)); if (mat) { const osg::Vec4& color = mat->getDiffuse(osg::Material::FRONT); _layer._color = _acadColor.findColor(color.asABGR()>>8); } } void DXFWriterNodeVisitor::processGeometry(osg::Geometry* geo, osg::Matrix& m) { // We only want to create a new layer for geometry with something to draw if (geo->getVertexArray() && geo->getVertexArray()->getNumElements() ) { if ( _firstPass ) { // Must have unique layer names _layer._name = getLayerName( geo->getName().empty() ? geo->getParent(0)->getName() : geo->getName() ); OSG_DEBUG << "adding Layer " << _layer._name << std::endl; // if single colour include in header osg::Array::Binding colorBinding = osg::getBinding(geo->getColorArray()); if ( osg::Array::BIND_OVERALL == colorBinding ) { _layer._color = _acadColor.findColor(getNodeRGB(geo)); // per layer color } else if ( osg::Array::BIND_OFF== colorBinding ) { _layer._color = 0xff; // use white - or can we easily lookup in texture? } else { _layer._color = 0; // per point color } _layers.push_back(_layer); } else { _layer = _layers[_count++]; OSG_DEBUG << "writing Layer " << _layer._name << std::endl; processStateSet(_currentStateSet.get()); if ( geo->getNumPrimitiveSets() ) { for(unsigned int i = 0; i < geo->getNumPrimitiveSets(); ++i) { osg::PrimitiveSet* ps = geo->getPrimitiveSet(i); DxfPrimitiveIndexWriter pif(_fout, geo,_layer,_acadColor,m,_writeTriangleAs3DFace); ps->accept(pif); } } else { // Is array visitor necessary for only dealing with vertex arrays? //processArray(geo->getVertexArray(), _layer,m); if ( geo->getVertexArray() ) { osg::Vec3Array* data=static_cast(geo->getVertexArray()); for (unsigned int ii=0;iigetNumElements();ii++) { osg::Vec3 point = data->at(ii) * m; _fout << "0 \nVERTEX\n 8\n"<<_layer._name<<"\n"; if ( _layer._color ) { _fout << "62\n"<<_layer._color<<"\n"; } else { _fout << "62\n"<<_acadColor.findColor(getNodeRGB(geo,ii))<<"\n"; } _fout<<" 10\n"<asGeometry(); if ( g != NULL ) { pushStateSet(g->getStateSet()); processGeometry(g,m); popStateSet(g->getStateSet()); } } popStateSet(node.getStateSet()); } bool DXFWriterNodeVisitor::writeHeader(const osg::BoundingSphere &bound) { if ( _layers.empty() ) { return false; } _fout << "999\n written by OpenSceneGraph" << std::endl; _fout << "0\nSECTION\n2\nHEADER\n"; _fout << "9\n$ACADVER\n1\nAC1006\n"; // specify minimum autocad version AC1006=R10 _fout << "9\n$EXTMIN\n10\n"<::iterator itr=_layers.begin();itr!=_layers.end();itr++) { if ( itr->_color ) { _fout<<"0\nLAYER\n2\n"<_name<<"\n70\n0\n62\n"<_color<<"\n6\nContinuous\n"; // color by layer } else { _fout<<"0\nLAYER\n2\n"<_name<<"\n70\n0\n62\n255\n6\nContinuous\n"; // most apps won't read 24bit color without a color value in header } } _fout << "0\nENDTAB\n0\nENDSEC\n"; _fout << "0\nSECTION\n2\nENTITIES\n"; _firstPass=false; _count=0; return true; } void DXFWriterNodeVisitor::writeFooter() { _fout << "0\nENDSEC\n0\nEOF"; _fout << std::endl; }