osgEarth 2.1.1
|
00001 /* -*-c++-*- */ 00002 /* osgEarth - Dynamic map generation toolkit for OpenSceneGraph 00003 * Copyright 2008-2010 Pelican Mapping 00004 * http://osgearth.org 00005 * 00006 * osgEarth is free software; you can redistribute it and/or modify 00007 * it under the terms of the GNU Lesser General Public License as published by 00008 * the Free Software Foundation; either version 2 of the License, or 00009 * (at your option) any later version. 00010 * 00011 * This program is distributed in the hope that it will be useful, 00012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00014 * GNU Lesser General Public License for more details. 00015 * 00016 * You should have received a copy of the GNU Lesser General Public License 00017 * along with this program. If not, see <http://www.gnu.org/licenses/> 00018 */ 00019 #include "Common" 00020 #include "AMRGeometry" 00021 #include <osg/State> 00022 #include <osg/Uniform> 00023 #include <osgEarth/Notify> 00024 00025 #define LC "[AMRGeometry] " 00026 00027 // -------------------------------------------------------------------------- 00028 00029 #include "AMRShaders.h" 00030 00031 // -------------------------------------------------------------------------- 00032 00033 AMRTriangle::AMRTriangle() 00034 { 00035 _stateSet = new osg::StateSet(); 00036 00037 // should this be INT_SAMPLER_2D? 00038 _stateSet->getOrCreateUniform( "tex0", osg::Uniform::INT )->set( 0 ); 00039 } 00040 00041 #define SET_UNIFORM(X,Y,Z) \ 00042 _stateSet->getOrCreateUniform( X , Y )->set( Z ) 00043 00044 00045 AMRTriangle::AMRTriangle(const MeshNode& n0, const osg::Vec2& t0, 00046 const MeshNode& n1, const osg::Vec2& t1, 00047 const MeshNode& n2, const osg::Vec2& t2) : 00048 _node0(n0), _node1(n1), _node2(n2) 00049 { 00050 _stateSet = new osg::StateSet(); 00051 // should this be INT_SAMPLER_2D? 00052 SET_UNIFORM( "tex0", osg::Uniform::INT, 0 ); 00053 00054 SET_UNIFORM( "c0", osg::Uniform::FLOAT_VEC3, _node0._geodeticCoord ); 00055 SET_UNIFORM( "c1", osg::Uniform::FLOAT_VEC3, _node1._geodeticCoord ); 00056 SET_UNIFORM( "c2", osg::Uniform::FLOAT_VEC3, _node2._geodeticCoord ); 00057 00058 SET_UNIFORM( "v0", osg::Uniform::FLOAT_VEC3, _node0._vertex ); 00059 SET_UNIFORM( "v1", osg::Uniform::FLOAT_VEC3, _node1._vertex ); 00060 SET_UNIFORM( "v2", osg::Uniform::FLOAT_VEC3, _node2._vertex ); 00061 00062 SET_UNIFORM( "t0", osg::Uniform::FLOAT_VEC2, t0 ); 00063 SET_UNIFORM( "t1", osg::Uniform::FLOAT_VEC2, t1 ); 00064 SET_UNIFORM( "t2", osg::Uniform::FLOAT_VEC2, t2 ); 00065 00066 SET_UNIFORM( "n0", osg::Uniform::FLOAT_VEC3, _node0._normal ); 00067 SET_UNIFORM( "n1", osg::Uniform::FLOAT_VEC3, _node1._normal ); 00068 SET_UNIFORM( "n2", osg::Uniform::FLOAT_VEC3, _node2._normal ); 00069 00070 SET_UNIFORM( "r0", osg::Uniform::FLOAT_VEC4, _node0._geodeticRot.asVec4() ); 00071 SET_UNIFORM( "r1", osg::Uniform::FLOAT_VEC4, _node1._geodeticRot.asVec4() ); 00072 SET_UNIFORM( "r2", osg::Uniform::FLOAT_VEC4, _node2._geodeticRot.asVec4() ); 00073 } 00074 00075 void 00076 AMRTriangle::expand( osg::BoundingBox& box ) 00077 { 00078 box.expandBy( _node0._vertex ); 00079 box.expandBy( _node1._vertex ); 00080 box.expandBy( _node2._vertex ); 00081 } 00082 00083 // -------------------------------------------------------------------------- 00084 00085 AMRDrawable::AMRDrawable() 00086 { 00087 _stateSet = new osg::StateSet(); 00088 } 00089 00090 // -------------------------------------------------------------------------- 00091 00092 AMRGeometry::AMRGeometry() 00093 { 00094 initShaders(); 00095 initPatterns(); 00096 00097 //this->setBound( osg::BoundingBox(-1e10, -1e10, -1e10, 1e10, 1e10, 1e10) ); 00098 } 00099 00100 AMRGeometry::AMRGeometry( const AMRGeometry& rhs, const osg::CopyOp& op ) : 00101 osg::Drawable( rhs, op ) //osg::Geometry( rhs, op ) 00102 { 00103 //todo 00104 setInitialBound( osg::BoundingBox(-1e10, -1e10, -1e10, 1e10, 1e10, 1e10) ); 00105 } 00106 00107 osg::BoundingBox 00108 AMRGeometry::computeBound() const 00109 { 00110 osg::BoundingBox box; 00111 for( AMRDrawableList::const_iterator i = _drawList.begin(); i != _drawList.end(); ++i ) 00112 { 00113 const AMRTriangleList& prims = i->get()->_triangles; 00114 for( AMRTriangleList::const_iterator j = prims.begin(); j != prims.end(); ++j ) 00115 { 00116 j->get()->expand( box ); 00117 } 00118 } 00119 return box; 00120 } 00121 00122 void 00123 AMRGeometry::clearDrawList() 00124 { 00125 if ( _drawList.size() > 0 ) 00126 { 00127 _drawList.clear(); 00128 dirtyBound(); 00129 } 00130 } 00131 00132 void 00133 AMRGeometry::setDrawList( const AMRDrawableList& drawList ) 00134 { 00135 _drawList = drawList; 00136 dirtyBound(); 00137 } 00138 00139 void 00140 AMRGeometry::initShaders() 00141 { 00142 // initialize the shader program. 00143 _program = new osg::Program(); 00144 _program->setName( "AMRGeometry" ); 00145 00146 osg::Shader* vertexShader = new osg::Shader( osg::Shader::VERTEX, 00147 //std::string( source_vertShaderMain_flatMethod ) 00148 std::string( source_vertShaderMain_geocentricMethod ) + 00149 std::string( source_geodeticToXYZ ) + 00150 std::string( source_rotVecToGeodetic ) 00151 //std::string( source_vertShaderMain_latLonMethod ) 00152 //std::string( source_vertShaderMain_slerpMethod ) 00153 ); 00154 00155 vertexShader->setName( "AMR Vert Shader" ); 00156 _program->addShader( vertexShader ); 00157 00158 osg::Shader* fragmentShader = new osg::Shader( osg::Shader::FRAGMENT, 00159 std::string( source_fragShaderMain ) 00160 ); 00161 00162 fragmentShader->setName( "AMR Frag Shader" ); 00163 _program->addShader( fragmentShader ); 00164 00165 // the shader program: 00166 this->getOrCreateStateSet()->setAttribute( _program.get(), osg::StateAttribute::ON ); 00167 } 00168 00169 static void 00170 toBarycentric(const osg::Vec3& p1, const osg::Vec3& p2, const osg::Vec3& p3, 00171 const osg::Vec3& in, 00172 osg::Vec3& outVert, osg::Vec2& outTex ) 00173 { 00174 //from: http://forums.cgsociety.org/archive/index.php/t-275372.html 00175 osg::Vec3 00176 v1 = in - p1, 00177 v2 = in - p2, 00178 v3 = in - p3; 00179 00180 double 00181 area1 = 0.5 * (v2 ^ v3).length(), 00182 area2 = 0.5 * (v1 ^ v3).length(), 00183 area3 = 0.5 * (v1 ^ v2).length(); 00184 00185 double fullArea = area1 + area2 + area3; 00186 00187 double u = area1/fullArea; 00188 double v = area2/fullArea; 00189 double w = area3/fullArea; 00190 00191 outVert.set( u, v, w ); 00192 00193 // tex coords 00194 osg::Vec2 t1( p1.x(), p1.y() ); 00195 osg::Vec2 t2( p2.x(), p2.y() ); 00196 osg::Vec2 t3( p3.x(), p3.y() ); 00197 outTex = t1*w + t2*v + t3*u; 00198 } 00199 00200 00201 void 00202 AMRGeometry::initPatterns() 00203 { 00204 _numPatternVerts = 0; 00205 _numPatternElements = 0; 00206 _numPatternStrips = 0; 00207 _numPatternTriangles = 0; 00208 00209 this->setUseVertexBufferObjects( true ); 00210 this->setUseDisplayList( false ); 00211 00212 _patternVBO = new osg::VertexBufferObject(); 00213 00214 _verts = new osg::Vec3Array(); 00215 _verts->setVertexBufferObject( _patternVBO.get() ); 00216 00217 _texCoords = new osg::Vec2Array(); 00218 _texCoords->setVertexBufferObject( _patternVBO.get() ); 00219 00220 // build a right-triangle pattern. (0,0) is the lower-left (90d), 00221 // (0,1) is the lower right (45d) and (1,0) is the upper-left (45d) 00222 osg::Vec3f p1(0,0,0), p2(0,1,0), p3(1,0,0); 00223 00224 for( int r=AMR_PATCH_ROWS-1; r >=0; --r ) 00225 { 00226 int cols = AMR_PATCH_ROWS-r; 00227 //OE_INFO << "ROW " << r << std::endl; 00228 for( int c=0; c<cols; ++c ) 00229 { 00230 osg::Vec3 point( (float)c/(float)(AMR_PATCH_ROWS-1), (float)r/(float)(AMR_PATCH_ROWS-1), 0 ); 00231 osg::Vec3 baryVert; 00232 osg::Vec2 baryTex; 00233 toBarycentric( p1, p2, p3, point, baryVert, baryTex ); 00234 _verts->push_back( baryVert ); 00235 _texCoords->push_back( baryTex ); 00236 } 00237 } 00238 _numPatternVerts = _verts->size(); 00239 00240 unsigned short off = 0; 00241 unsigned short rowptr = off; 00242 00243 _patternEBO = new osg::ElementBufferObject(); 00244 00245 for( int r=1; r<AMR_PATCH_ROWS; ++r ) 00246 { 00247 rowptr += r; 00248 osg::DrawElementsUShort* e = new osg::DrawElementsUShort( GL_TRIANGLE_STRIP ); 00249 e->setElementBufferObject( _patternEBO.get() ); 00250 00251 for( int c=0; c<=r; ++c ) 00252 { 00253 e->push_back( rowptr + c ); 00254 if ( c < r ) 00255 e->push_back( rowptr + c - r ); 00256 } 00257 OE_INFO << std::endl; 00258 _pattern.push_back( e ); 00259 00260 _numPatternStrips++; 00261 _numPatternElements += e->size(); 00262 _numPatternTriangles += (e->size()-1)/2; 00263 } 00264 00265 OE_INFO << LC 00266 << "Pattern: " << std::dec 00267 << "verts=" << _numPatternVerts 00268 << ", strips=" << _numPatternStrips 00269 << ", tris=" << _numPatternTriangles 00270 << ", elements=" << _numPatternElements 00271 << std::endl; 00272 } 00273 00274 static int s_numTemplates = 0; 00275 00276 void 00277 AMRGeometry::drawImplementation( osg::RenderInfo& renderInfo ) const 00278 { 00279 osg::State& state = *renderInfo.getState(); 00280 00281 // bind the VBO: 00282 state.setVertexPointer( _verts.get() ); 00283 00284 // bind the texture coordinate arrrays: 00285 state.setTexCoordPointer( 0, _texCoords.get() ); 00286 00287 // this will enable the amr geometry's stateset (and activate the Program) 00288 state.pushStateSet( this->getStateSet() ); 00289 //state.pushStateSet(0L); 00290 //_program->apply( state ); 00291 00292 int numTemplates = 0; 00293 00294 for( AMRDrawableList::const_iterator i = _drawList.begin(); i != _drawList.end(); ++i ) 00295 { 00296 const AMRDrawable* drawable = i->get(); 00297 00298 // apply the drawable's state changes: 00299 state.pushStateSet( drawable->_stateSet.get() ); 00300 00301 for( AMRTriangleList::const_iterator j = drawable->_triangles.begin(); j != drawable->_triangles.end(); ++j ) 00302 { 00303 const AMRTriangle* dtemplate = j->get(); 00304 00305 // apply the primitive's state changes: 00306 state.apply( dtemplate->_stateSet.get() ); 00307 00308 // render the pattern (a collection of primitive sets) 00309 for( Pattern::const_iterator p = _pattern.begin(); p != _pattern.end(); ++p ) 00310 { 00311 p->get()->draw( state, true ); 00312 } 00313 00314 numTemplates++; 00315 } 00316 00317 state.popStateSet(); 00318 } 00319 00320 if ( s_numTemplates != numTemplates ) 00321 { 00322 s_numTemplates = numTemplates; 00323 OE_INFO << LC << std::dec 00324 << "templates=" << numTemplates 00325 << ", verts=" << numTemplates*_numPatternVerts 00326 << ", strips=" << numTemplates*_numPatternStrips 00327 << ", tris=" << numTemplates*_numPatternTriangles 00328 << ", elements=" << numTemplates*_numPatternElements 00329 << std::endl; 00330 } 00331 00332 // unbind the buffer objects. 00333 state.unbindVertexBufferObject(); 00334 state.unbindElementBufferObject(); 00335 00336 // undo the program. 00337 state.popStateSet(); 00338 }