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