1 /* -*-c++-*- */
2 /* osgEarth - Dynamic map generation toolkit for OpenSceneGraph
3  * Copyright 2008-2010 Pelican Mapping
4  * http://osgearth.org
5  *
6  * osgEarth is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU Lesser General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public License
17  * along with this program.  If not, see <http://www.gnu.org/licenses/>
18  */
19 #include "Common"
20 #include "AMRGeometry"
21 #include <osg/State>
22 #include <osg/Uniform>
23 #include <osgEarth/Notify>
24 
25 #define LC "[AMRGeometry] "
26 
27 // --------------------------------------------------------------------------
28 
29 #include "AMRShaders.h"
30 
31 // --------------------------------------------------------------------------
32 
AMRTriangle()33 AMRTriangle::AMRTriangle()
34 {
35     _stateSet = new osg::StateSet();
36 
37     // should this be INT_SAMPLER_2D?
38     _stateSet->getOrCreateUniform( "tex0", osg::Uniform::INT )->set( 0 );
39 }
40 
41 #define SET_UNIFORM(X,Y,Z) \
42     _stateSet->getOrCreateUniform( X , Y )->set( Z )
43 
44 
AMRTriangle(const MeshNode & n0,const osg::Vec2 & t0,const MeshNode & n1,const osg::Vec2 & t1,const MeshNode & n2,const osg::Vec2 & t2)45 AMRTriangle::AMRTriangle(const MeshNode& n0, const osg::Vec2& t0,
46                          const MeshNode& n1, const osg::Vec2& t1,
47                          const MeshNode& n2, const osg::Vec2& t2) :
48 _node0(n0), _node1(n1), _node2(n2)
49 {
50     _stateSet = new osg::StateSet();
51     // should this be INT_SAMPLER_2D?
52     SET_UNIFORM( "tex0", osg::Uniform::INT, 0 );
53 
54     SET_UNIFORM( "c0", osg::Uniform::FLOAT_VEC3, _node0._geodeticCoord );
55     SET_UNIFORM( "c1", osg::Uniform::FLOAT_VEC3, _node1._geodeticCoord );
56     SET_UNIFORM( "c2", osg::Uniform::FLOAT_VEC3, _node2._geodeticCoord );
57 
58     SET_UNIFORM( "v0", osg::Uniform::FLOAT_VEC3, _node0._vertex );
59     SET_UNIFORM( "v1", osg::Uniform::FLOAT_VEC3, _node1._vertex );
60     SET_UNIFORM( "v2", osg::Uniform::FLOAT_VEC3, _node2._vertex );
61 
62     SET_UNIFORM( "t0", osg::Uniform::FLOAT_VEC2, t0 );
63     SET_UNIFORM( "t1", osg::Uniform::FLOAT_VEC2, t1 );
64     SET_UNIFORM( "t2", osg::Uniform::FLOAT_VEC2, t2 );
65 
66     SET_UNIFORM( "n0", osg::Uniform::FLOAT_VEC3, _node0._normal );
67     SET_UNIFORM( "n1", osg::Uniform::FLOAT_VEC3, _node1._normal );
68     SET_UNIFORM( "n2", osg::Uniform::FLOAT_VEC3, _node2._normal );
69 
70     SET_UNIFORM( "r0", osg::Uniform::FLOAT_VEC4, _node0._geodeticRot.asVec4() );
71     SET_UNIFORM( "r1", osg::Uniform::FLOAT_VEC4, _node1._geodeticRot.asVec4() );
72     SET_UNIFORM( "r2", osg::Uniform::FLOAT_VEC4, _node2._geodeticRot.asVec4() );
73 }
74 
75 void
expand(osg::BoundingBox & box)76 AMRTriangle::expand( osg::BoundingBox& box )
77 {
78     box.expandBy( _node0._vertex );
79     box.expandBy( _node1._vertex );
80     box.expandBy( _node2._vertex );
81 }
82 
83 // --------------------------------------------------------------------------
84 
AMRDrawable()85 AMRDrawable::AMRDrawable()
86 {
87     _stateSet = new osg::StateSet();
88 }
89 
90 // --------------------------------------------------------------------------
91 
AMRGeometry()92 AMRGeometry::AMRGeometry()
93 {
94     initShaders();
95     initPatterns();
96 
97     //this->setBound( osg::BoundingBox(-1e10, -1e10, -1e10, 1e10, 1e10, 1e10) );
98 }
99 
AMRGeometry(const AMRGeometry & rhs,const osg::CopyOp & op)100 AMRGeometry::AMRGeometry( const AMRGeometry& rhs, const osg::CopyOp& op ) :
101 osg::Drawable( rhs, op ) //osg::Geometry( rhs, op )
102 {
103     //todo
104     setInitialBound( osg::BoundingBox(-1e10, -1e10, -1e10, 1e10, 1e10, 1e10) );
105 }
106 
107 osg::BoundingBox
computeBound() const108 AMRGeometry::computeBound() const
109 {
110     osg::BoundingBox box;
111     for( AMRDrawableList::const_iterator i = _drawList.begin(); i != _drawList.end(); ++i )
112     {
113         const AMRTriangleList& prims = i->get()->_triangles;
114         for( AMRTriangleList::const_iterator j = prims.begin(); j != prims.end(); ++j )
115         {
116             j->get()->expand( box );
117         }
118     }
119     return box;
120 }
121 
122 void
clearDrawList()123 AMRGeometry::clearDrawList()
124 {
125     if ( _drawList.size() > 0 )
126     {
127         _drawList.clear();
128         dirtyBound();
129     }
130 }
131 
132 void
setDrawList(const AMRDrawableList & drawList)133 AMRGeometry::setDrawList( const AMRDrawableList& drawList )
134 {
135     _drawList = drawList;
136     dirtyBound();
137 }
138 
139 void
initShaders()140 AMRGeometry::initShaders()
141 {
142     // initialize the shader program.
143     _program = new osg::Program();
144     _program->setName( "AMRGeometry" );
145 
146     osg::Shader* vertexShader = new osg::Shader( osg::Shader::VERTEX,
147         //std::string( source_vertShaderMain_flatMethod )
148         std::string( source_vertShaderMain_geocentricMethod ) +
149         std::string( source_geodeticToXYZ ) +
150         std::string( source_rotVecToGeodetic )
151         //std::string( source_vertShaderMain_latLonMethod )
152         //std::string( source_vertShaderMain_slerpMethod )
153         );
154 
155     vertexShader->setName( "AMR Vert Shader" );
156     _program->addShader( vertexShader );
157 
158     osg::Shader* fragmentShader = new osg::Shader( osg::Shader::FRAGMENT,
159         std::string( source_fragShaderMain )
160         );
161 
162     fragmentShader->setName( "AMR Frag Shader" );
163     _program->addShader( fragmentShader );
164 
165     // the shader program:
166     this->getOrCreateStateSet()->setAttribute( _program.get(), osg::StateAttribute::ON );
167 }
168 
169 static void
toBarycentric(const osg::Vec3 & p1,const osg::Vec3 & p2,const osg::Vec3 & p3,const osg::Vec3 & in,osg::Vec3 & outVert,osg::Vec2 & outTex)170 toBarycentric(const osg::Vec3& p1, const osg::Vec3& p2, const osg::Vec3& p3,
171               const osg::Vec3& in,
172               osg::Vec3& outVert, osg::Vec2& outTex )
173 {
174     //from: http://forums.cgsociety.org/archive/index.php/t-275372.html
175     osg::Vec3
176         v1 = in - p1,
177         v2 = in - p2,
178         v3 = in - p3;
179 
180     double
181         area1 = 0.5 * (v2 ^ v3).length(),
182         area2 = 0.5 * (v1 ^ v3).length(),
183         area3 = 0.5 * (v1 ^ v2).length();
184 
185     double fullArea = area1 + area2 + area3;
186 
187     double u = area1/fullArea;
188     double v = area2/fullArea;
189     double w = area3/fullArea;
190 
191     outVert.set( u, v, w );
192 
193     // tex coords
194     osg::Vec2 t1( p1.x(), p1.y() );
195     osg::Vec2 t2( p2.x(), p2.y() );
196     osg::Vec2 t3( p3.x(), p3.y() );
197     outTex = t1*w + t2*v + t3*u;
198 }
199 
200 
201 void
initPatterns()202 AMRGeometry::initPatterns()
203 {
204     _numPatternVerts = 0;
205     _numPatternElements = 0;
206     _numPatternStrips = 0;
207     _numPatternTriangles = 0;
208 
209     this->setUseVertexBufferObjects( true );
210     this->setUseDisplayList( false );
211 
212     _patternVBO = new osg::VertexBufferObject();
213 
214     _verts = new osg::Vec3Array();
215     _verts->setVertexBufferObject( _patternVBO.get() );
216 
217     _texCoords = new osg::Vec2Array();
218     _texCoords->setVertexBufferObject( _patternVBO.get() );
219 
220     // build a right-triangle pattern. (0,0) is the lower-left (90d),
221     // (0,1) is the lower right (45d) and (1,0) is the upper-left (45d)
222     osg::Vec3f p1(0,0,0), p2(0,1,0), p3(1,0,0);
223 
224     for( int r=AMR_PATCH_ROWS-1; r >=0; --r )
225     {
226         int cols = AMR_PATCH_ROWS-r;
227         //OE_INFO << "ROW " << r << std::endl;
228         for( int c=0; c<cols; ++c )
229         {
230             osg::Vec3 point( (float)c/(float)(AMR_PATCH_ROWS-1), (float)r/(float)(AMR_PATCH_ROWS-1), 0 );
231             osg::Vec3 baryVert;
232             osg::Vec2 baryTex;
233             toBarycentric( p1, p2, p3, point, baryVert, baryTex );
234             _verts->push_back( baryVert );
235             _texCoords->push_back( baryTex );
236         }
237     }
238     _numPatternVerts = _verts->size();
239 
240     unsigned short off = 0;
241     unsigned short rowptr = off;
242 
243     _patternEBO = new osg::ElementBufferObject();
244 
245     for( int r=1; r<AMR_PATCH_ROWS; ++r )
246     {
247         rowptr += r;
248         osg::DrawElementsUShort* e = new osg::DrawElementsUShort( GL_TRIANGLE_STRIP );
249         e->setElementBufferObject( _patternEBO.get() );
250 
251         for( int c=0; c<=r; ++c )
252         {
253             e->push_back( rowptr + c );
254             if ( c < r )
255                 e->push_back( rowptr + c - r );
256         }
257         OE_INFO << std::endl;
258         _pattern.push_back( e );
259 
260         _numPatternStrips++;
261         _numPatternElements += e->size();
262         _numPatternTriangles += (e->size()-1)/2;
263     }
264 
265     OE_INFO << LC
266         << "Pattern: "   << std::dec
267         << "verts="      << _numPatternVerts
268         << ", strips="   << _numPatternStrips
269         << ", tris="     << _numPatternTriangles
270         << ", elements=" << _numPatternElements
271         << std::endl;
272 }
273 
274 static int s_numTemplates = 0;
275 
276 void
drawImplementation(osg::RenderInfo & renderInfo) const277 AMRGeometry::drawImplementation( osg::RenderInfo& renderInfo ) const
278 {
279     osg::State& state = *renderInfo.getState();
280 
281     // bind the VBO:
282     state.setVertexPointer( _verts.get() );
283 
284     // bind the texture coordinate arrrays:
285     state.setTexCoordPointer( 0, _texCoords.get() );
286 
287     // this will enable the amr geometry's stateset (and activate the Program)
288     state.pushStateSet( this->getStateSet() );
289     //state.pushStateSet(0L);
290     //_program->apply( state );
291 
292     int numTemplates = 0;
293 
294     for( AMRDrawableList::const_iterator i = _drawList.begin(); i != _drawList.end(); ++i )
295     {
296         const AMRDrawable* drawable = i->get();
297 
298         // apply the drawable's state changes:
299         state.pushStateSet( drawable->_stateSet.get() );
300 
301         for( AMRTriangleList::const_iterator j = drawable->_triangles.begin(); j != drawable->_triangles.end(); ++j )
302         {
303             const AMRTriangle* dtemplate = j->get();
304 
305             // apply the primitive's state changes:
306             state.apply( dtemplate->_stateSet.get() );
307 
308             // render the pattern (a collection of primitive sets)
309             for( Pattern::const_iterator p = _pattern.begin(); p != _pattern.end(); ++p )
310             {
311                 p->get()->draw( state, true );
312             }
313 
314             numTemplates++;
315         }
316 
317         state.popStateSet();
318     }
319 
320     if ( s_numTemplates != numTemplates )
321     {
322         s_numTemplates = numTemplates;
323         OE_INFO << LC << std::dec
324             << "templates="  << numTemplates
325             << ", verts="    << numTemplates*_numPatternVerts
326             << ", strips="   << numTemplates*_numPatternStrips
327             << ", tris="     << numTemplates*_numPatternTriangles
328             << ", elements=" << numTemplates*_numPatternElements
329             << std::endl;
330     }
331 
332     // unbind the buffer objects.
333     state.unbindVertexBufferObject();
334     state.unbindElementBufferObject();
335 
336     // undo the program.
337     state.popStateSet();
338 }
339