2009-10-08 22:29:54 +08:00
/* OpenSceneGraph example, osgvertexattributes.
*
* Permission is hereby granted , free of charge , to any person obtaining a copy
* of this software and associated documentation files ( the " Software " ) , to deal
* in the Software without restriction , including without limitation the rights
* to use , copy , modify , merge , publish , distribute , sublicense , and / or sell
* copies of the Software , and to permit persons to whom the Software is
* furnished to do so , subject to the following conditions :
*
* THE SOFTWARE IS PROVIDED " AS IS " , WITHOUT WARRANTY OF ANY KIND , EXPRESS OR
* IMPLIED , INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY ,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT . IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM , DAMAGES OR OTHER
* LIABILITY , WHETHER IN AN ACTION OF CONTRACT , TORT OR OTHERWISE , ARISING FROM ,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE .
*/
# include <osgUtil/ShaderGen>
# include <osgDB/ReadFile>
# include <osgDB/WriteFile>
# include <osgViewer/Viewer>
2009-10-21 22:14:22 +08:00
# include <osgViewer/ViewerEventHandlers>
2009-10-11 14:05:19 +08:00
# include <osgGA/TrackballManipulator>
2009-10-08 22:29:54 +08:00
class ConvertToVertexAttibArrays : public osg : : NodeVisitor
{
public :
typedef std : : pair < unsigned int , std : : string > AttributeAlias ;
ConvertToVertexAttibArrays ( ) :
osg : : NodeVisitor ( osg : : NodeVisitor : : TRAVERSE_ALL_CHILDREN )
{
2009-10-17 00:26:27 +08:00
_manualVertexAliasing = false ;
2009-10-08 22:29:54 +08:00
// mappings taken from http://www.opengl.org/registry/specs/NV/vertex_program.txt
_vertexAlias = AttributeAlias ( 0 , " osg_Vertex " ) ;
_normalAlias = AttributeAlias ( 2 , " osg_Normal " ) ;
_colorAlias = AttributeAlias ( 3 , " osg_Color " ) ;
_secondaryColorAlias = AttributeAlias ( 4 , " osg_SecondaryColor " ) ;
_fogCoordAlias = AttributeAlias ( 5 , " osg_FogCoord " ) ;
_texCoordAlias [ 0 ] = AttributeAlias ( 8 , " osg_MultiTexCoord0 " ) ;
_texCoordAlias [ 1 ] = AttributeAlias ( 9 , " osg_MultiTexCoord1 " ) ;
_texCoordAlias [ 2 ] = AttributeAlias ( 10 , " osg_MultiTexCoord2 " ) ;
_texCoordAlias [ 3 ] = AttributeAlias ( 11 , " osg_MultiTexCoord3 " ) ;
_texCoordAlias [ 4 ] = AttributeAlias ( 12 , " osg_MultiTexCoord4 " ) ;
_texCoordAlias [ 5 ] = AttributeAlias ( 13 , " osg_MultiTexCoord5 " ) ;
_texCoordAlias [ 6 ] = AttributeAlias ( 14 , " osg_MultiTexCoord6 " ) ;
_texCoordAlias [ 7 ] = AttributeAlias ( 15 , " osg_MultiTexCoord7 " ) ;
}
2009-10-09 18:39:55 +08:00
void bindAttribute ( osg : : Program & program , const AttributeAlias & alias )
2009-10-08 23:58:23 +08:00
{
2009-10-09 18:39:55 +08:00
program . addBindAttribLocation ( alias . second , alias . first ) ;
}
2009-10-09 21:39:11 +08:00
void replaceAndBindAttrib ( osg : : Program & program , std : : string & source , const std : : string & originalStr , const AttributeAlias & alias , const std : : string & declarationPrefix )
2009-10-09 18:39:55 +08:00
{
if ( replace ( source , originalStr , alias . second ) )
{
source . insert ( 0 , declarationPrefix + alias . second + std : : string ( " ; \n " ) ) ;
2009-10-17 00:26:27 +08:00
if ( _manualVertexAliasing ) bindAttribute ( program , alias ) ;
2009-10-09 18:39:55 +08:00
}
}
2009-10-09 21:39:11 +08:00
void replaceBuiltInUniform ( std : : string & source , const std : : string & originalStr , const std : : string & newStr , const std : : string & declarationPrefix )
{
if ( replace ( source , originalStr , newStr ) )
{
source . insert ( 0 , declarationPrefix + newStr + std : : string ( " ; \n " ) ) ;
}
}
2009-10-09 18:39:55 +08:00
void convertVertexShader ( osg : : Program & program , osg : : Shader & shader )
{
std : : string source = shader . getShaderSource ( ) ;
2009-10-09 00:23:40 +08:00
// replace ftransform as it only works with built-ins
replace ( source , " ftransform() " , " gl_ModelViewProjectionMatrix * gl_Vertex " ) ;
2009-10-17 00:26:27 +08:00
# if 1
2009-10-09 21:39:11 +08:00
replaceAndBindAttrib ( program , source , " gl_Normal " , _normalAlias , " attribute vec3 " ) ;
replaceAndBindAttrib ( program , source , " gl_Vertex " , _vertexAlias , " attribute vec4 " ) ;
replaceAndBindAttrib ( program , source , " gl_Color " , _colorAlias , " attribute vec4 " ) ;
replaceAndBindAttrib ( program , source , " gl_SecondaryColor " , _secondaryColorAlias , " attribute vec4 " ) ;
replaceAndBindAttrib ( program , source , " gl_FogCoord " , _fogCoordAlias , " attribute float " ) ;
2009-10-09 00:23:40 +08:00
2009-10-09 21:39:11 +08:00
replaceAndBindAttrib ( program , source , " gl_MultiTexCoord0 " , _texCoordAlias [ 0 ] , " attribute vec4 " ) ;
replaceAndBindAttrib ( program , source , " gl_MultiTexCoord1 " , _texCoordAlias [ 1 ] , " attribute vec4 " ) ;
replaceAndBindAttrib ( program , source , " gl_MultiTexCoord2 " , _texCoordAlias [ 2 ] , " attribute vec4 " ) ;
replaceAndBindAttrib ( program , source , " gl_MultiTexCoord3 " , _texCoordAlias [ 3 ] , " attribute vec4 " ) ;
replaceAndBindAttrib ( program , source , " gl_MultiTexCoord4 " , _texCoordAlias [ 4 ] , " attribute vec4 " ) ;
replaceAndBindAttrib ( program , source , " gl_MultiTexCoord5 " , _texCoordAlias [ 5 ] , " attribute vec4 " ) ;
replaceAndBindAttrib ( program , source , " gl_MultiTexCoord6 " , _texCoordAlias [ 6 ] , " attribute vec4 " ) ;
replaceAndBindAttrib ( program , source , " gl_MultiTexCoord7 " , _texCoordAlias [ 7 ] , " attribute vec4 " ) ;
2009-10-17 00:26:27 +08:00
# endif
2009-10-09 18:39:55 +08:00
2009-10-17 00:26:27 +08:00
# if 1
2009-10-09 21:39:11 +08:00
// replace built in uniform
replaceBuiltInUniform ( source , " gl_ModelViewMatrix " , " osg_ModeViewMatrix " , " uniform mat4 " ) ;
replaceBuiltInUniform ( source , " gl_ModelViewProjectionMatrix " , " osg_ModelViewProjectionMatrix " , " uniform mat4 " ) ;
replaceBuiltInUniform ( source , " gl_ProjectionMatrix " , " osg_ProjectionMatrix " , " uniform mat4 " ) ;
2009-10-09 18:39:55 +08:00
# endif
shader . setShaderSource ( source ) ;
}
2009-10-09 00:23:40 +08:00
2009-10-09 18:39:55 +08:00
void convertFragmentShader ( osg : : Program & program , osg : : Shader & shader )
{
2009-10-08 23:58:23 +08:00
}
virtual void reset ( )
{
_visited . clear ( ) ;
}
void apply ( osg : : Node & node )
{
if ( _visited . count ( & node ) ! = 0 ) return ;
_visited . insert ( & node ) ;
if ( node . getStateSet ( ) ) apply ( * ( node . getStateSet ( ) ) ) ;
traverse ( node ) ;
}
2009-10-08 22:29:54 +08:00
void apply ( osg : : Geode & geode )
{
2009-10-08 23:58:23 +08:00
if ( _visited . count ( & geode ) ! = 0 ) return ;
_visited . insert ( & geode ) ;
if ( geode . getStateSet ( ) ) apply ( * ( geode . getStateSet ( ) ) ) ;
2009-10-08 22:29:54 +08:00
for ( unsigned int i = 0 ; i < geode . getNumDrawables ( ) ; + + i )
{
2009-10-08 23:58:23 +08:00
if ( geode . getDrawable ( i ) - > getStateSet ( ) ) apply ( * ( geode . getDrawable ( i ) - > getStateSet ( ) ) ) ;
2009-10-08 22:29:54 +08:00
osg : : Geometry * geom = geode . getDrawable ( i ) - > asGeometry ( ) ;
if ( geom ) apply ( * geom ) ;
}
}
2009-10-09 18:39:55 +08:00
bool replace ( std : : string & str , const std : : string & original_phrase , const std : : string & new_phrase )
2009-10-08 23:58:23 +08:00
{
2009-10-09 18:39:55 +08:00
bool replacedStr = false ;
2009-10-08 23:58:23 +08:00
std : : string : : size_type pos = 0 ;
while ( ( pos = str . find ( original_phrase , pos ) ) ! = std : : string : : npos )
{
std : : string : : size_type endOfPhrasePos = pos + original_phrase . size ( ) ;
if ( endOfPhrasePos < str . size ( ) )
{
char c = str [ endOfPhrasePos ] ;
if ( ( c > = ' 0 ' & & c < = ' 9 ' ) | |
( c > = ' a ' & & c < = ' z ' ) | |
( c > = ' A ' & & c < = ' Z ' ) )
{
pos = endOfPhrasePos ;
continue ;
}
}
2009-10-09 18:39:55 +08:00
replacedStr = true ;
2009-10-08 23:58:23 +08:00
str . replace ( pos , original_phrase . size ( ) , new_phrase ) ;
}
2009-10-09 18:39:55 +08:00
return replacedStr ;
2009-10-08 23:58:23 +08:00
}
2009-10-09 18:39:55 +08:00
void apply ( osg : : Program & program , osg : : Shader & shader )
2009-10-08 23:58:23 +08:00
{
if ( _visited . count ( & shader ) ! = 0 ) return ;
_visited . insert ( & shader ) ;
osg : : notify ( osg : : NOTICE ) < < " Shader " < < shader . getTypename ( ) < < " ----before----------- " < < std : : endl ;
osg : : notify ( osg : : NOTICE ) < < shader . getShaderSource ( ) < < std : : endl ;
2009-10-09 18:39:55 +08:00
if ( shader . getType ( ) = = osg : : Shader : : VERTEX ) convertVertexShader ( program , shader ) ;
else if ( shader . getType ( ) = = osg : : Shader : : FRAGMENT ) convertFragmentShader ( program , shader ) ;
2009-10-08 23:58:23 +08:00
osg : : notify ( osg : : NOTICE ) < < " --after----------- " < < std : : endl ;
osg : : notify ( osg : : NOTICE ) < < shader . getShaderSource ( ) < < std : : endl ;
osg : : notify ( osg : : NOTICE ) < < " --------------------- " < < std : : endl ;
}
void apply ( osg : : StateSet & stateset )
{
if ( _visited . count ( & stateset ) ! = 0 ) return ;
_visited . insert ( & stateset ) ;
2009-10-17 00:26:27 +08:00
return ;
2009-10-08 23:58:23 +08:00
osg : : notify ( osg : : NOTICE ) < < " Found stateset " < < & stateset < < std : : endl ;
osg : : Program * program = dynamic_cast < osg : : Program * > ( stateset . getAttribute ( osg : : StateAttribute : : PROGRAM ) ) ;
if ( program )
{
osg : : notify ( osg : : NOTICE ) < < " Found Program " < < program < < std : : endl ;
for ( unsigned int i = 0 ; i < program - > getNumShaders ( ) ; + + i )
{
2009-10-09 18:39:55 +08:00
apply ( * program , * ( program - > getShader ( i ) ) ) ;
2009-10-08 23:58:23 +08:00
}
2009-10-09 18:39:55 +08:00
2009-10-08 23:58:23 +08:00
}
}
2009-10-08 22:29:54 +08:00
void apply ( osg : : Geometry & geom )
{
2009-10-09 18:39:55 +08:00
geom . setUseDisplayList ( false ) ;
2009-10-17 00:26:27 +08:00
if ( ! _manualVertexAliasing ) return ;
2009-10-08 22:29:54 +08:00
osg : : notify ( osg : : NOTICE ) < < " Found geometry " < < & geom < < std : : endl ;
if ( geom . getVertexArray ( ) )
{
setVertexAttrib ( geom , _vertexAlias , geom . getVertexArray ( ) , false , osg : : Geometry : : BIND_PER_VERTEX ) ;
geom . setVertexArray ( 0 ) ;
}
if ( geom . getNormalArray ( ) )
{
2009-10-17 00:26:27 +08:00
setVertexAttrib ( geom , _normalAlias , geom . getNormalArray ( ) , true , geom . getNormalBinding ( ) ) ;
2009-10-08 22:29:54 +08:00
geom . setNormalArray ( 0 ) ;
}
if ( geom . getColorArray ( ) )
{
2009-10-09 18:39:55 +08:00
setVertexAttrib ( geom , _colorAlias , geom . getColorArray ( ) , false , geom . getColorBinding ( ) ) ;
2009-10-08 22:29:54 +08:00
geom . setColorArray ( 0 ) ;
}
if ( geom . getSecondaryColorArray ( ) )
{
2009-10-09 18:39:55 +08:00
setVertexAttrib ( geom , _secondaryColorAlias , geom . getSecondaryColorArray ( ) , false , geom . getSecondaryColorBinding ( ) ) ;
2009-10-08 22:29:54 +08:00
geom . setSecondaryColorArray ( 0 ) ;
}
if ( geom . getFogCoordArray ( ) )
{
// should we normalize the FogCoord array? Don't think so...
2009-10-17 00:26:27 +08:00
setVertexAttrib ( geom , _fogCoordAlias , geom . getFogCoordArray ( ) , false , geom . getFogCoordBinding ( ) ) ;
2009-10-08 22:29:54 +08:00
geom . setFogCoordArray ( 0 ) ;
}
unsigned int maxNumTexCoords = geom . getNumTexCoordArrays ( ) ;
if ( maxNumTexCoords > 8 )
{
osg : : notify ( osg : : NOTICE ) < < " Warning: Ignoring " < < maxNumTexCoords - 8 < < " texture coordinate arrays, only 8 are currently supported in vertex attribute conversion code. " < < std : : endl ;
maxNumTexCoords = 8 ;
}
for ( unsigned int i = 0 ; i < maxNumTexCoords ; + + i )
{
if ( geom . getTexCoordArray ( i ) )
{
2009-10-09 18:39:55 +08:00
setVertexAttrib ( geom , _texCoordAlias [ i ] , geom . getTexCoordArray ( i ) , false , osg : : Geometry : : BIND_PER_VERTEX ) ;
2009-10-08 22:29:54 +08:00
geom . setTexCoordArray ( i , 0 ) ;
}
else
{
osg : : notify ( osg : : NOTICE ) < < " Found empty TexCoordArray( " < < i < < " ) " < < std : : endl ;
}
}
}
void setVertexAttrib ( osg : : Geometry & geom , const AttributeAlias & alias , osg : : Array * array , bool normalize , osg : : Geometry : : AttributeBinding binding )
{
unsigned int index = alias . first ;
const std : : string & name = alias . second ;
array - > setName ( name ) ;
geom . setVertexAttribArray ( index , array ) ;
geom . setVertexAttribNormalize ( index , normalize ) ;
geom . setVertexAttribBinding ( index , binding ) ;
osg : : notify ( osg : : NOTICE ) < < " vertex attrib( " < < name < < " , index= " < < index < < " , normalize= " < < normalize < < " binding= " < < binding < < " ) " < < std : : endl ;
}
2009-10-08 23:58:23 +08:00
typedef std : : set < osg : : Object * > Visited ;
Visited _visited ;
2009-10-17 00:26:27 +08:00
bool _manualVertexAliasing ;
2009-10-08 22:29:54 +08:00
AttributeAlias _vertexAlias ;
AttributeAlias _normalAlias ;
AttributeAlias _colorAlias ;
AttributeAlias _secondaryColorAlias ;
AttributeAlias _fogCoordAlias ;
AttributeAlias _texCoordAlias [ 8 ] ;
} ;
2009-11-04 19:03:13 +08:00
osg : : Node * createSimpleTestModel ( )
{
osg : : Group * group = new osg : : Group ;
osg : : Geode * geode = new osg : : Geode ;
group - > addChild ( geode ) ;
osg : : Geometry * geometry = new osg : : Geometry ;
geode - > addDrawable ( geometry ) ;
osg : : Vec3Array * vertices = new osg : : Vec3Array ;
vertices - > push_back ( osg : : Vec3 ( 0.0 , 0.0 , 0.0 ) ) ;
vertices - > push_back ( osg : : Vec3 ( 0.0 , 0.0 , 1.0 ) ) ;
vertices - > push_back ( osg : : Vec3 ( 1.0 , 0.0 , 0.0 ) ) ;
vertices - > push_back ( osg : : Vec3 ( 1.0 , 0.0 , 1.0 ) ) ;
geometry - > setVertexArray ( vertices ) ;
geometry - > addPrimitiveSet ( new osg : : DrawArrays ( GL_TRIANGLE_STRIP , 0 , 4 ) ) ;
char vertexShaderSource [ ] =
" void main(void) \n "
" { \n "
" gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex; \n "
" } \n " ;
char fragmentShaderSource [ ] =
" void main(void) \n "
" { \n "
" gl_FragColor = vec4(1.0,1.0,0.0,1.0); \n "
" } \n " ;
osg : : Program * program = new osg : : Program ;
program - > addShader ( new osg : : Shader ( osg : : Shader : : VERTEX , vertexShaderSource ) ) ;
program - > addShader ( new osg : : Shader ( osg : : Shader : : FRAGMENT , fragmentShaderSource ) ) ;
geometry - > getOrCreateStateSet ( ) - > setAttribute ( program ) ;
return group ;
}
2009-10-08 22:29:54 +08:00
int main ( int argc , char * argv [ ] )
{
// use an ArgumentParser object to manage the program arguments.
osg : : ArgumentParser arguments ( & argc , argv ) ;
// construct the viewer.
osgViewer : : Viewer viewer ( arguments ) ;
std : : string outputFileName ;
while ( arguments . read ( " -o " , outputFileName ) ) { }
2009-11-04 19:03:13 +08:00
osg : : ref_ptr < osg : : Node > loadedModel ;
2009-10-08 22:29:54 +08:00
bool runConvertToVertexAttributes = true ;
2009-11-04 19:03:13 +08:00
if ( arguments . read ( " --simple " ) | | arguments . read ( " --s " ) )
2009-10-08 22:29:54 +08:00
{
2009-11-04 19:03:13 +08:00
loadedModel = createSimpleTestModel ( ) ;
2009-10-08 22:29:54 +08:00
}
2009-11-04 19:03:13 +08:00
else
2009-10-08 22:29:54 +08:00
{
2009-11-04 19:03:13 +08:00
bool runShaderGen = true ;
while ( arguments . read ( " --shader-gen " ) ) { runShaderGen = true ; }
while ( arguments . read ( " --no-shader-gen " ) ) { runShaderGen = false ; }
2009-10-08 22:29:54 +08:00
2009-11-04 19:03:13 +08:00
while ( arguments . read ( " --vertex-attrib " ) ) { runConvertToVertexAttributes = true ; }
while ( arguments . read ( " --no-vertex-attrib " ) ) { runConvertToVertexAttributes = false ; }
2009-10-08 22:29:54 +08:00
2009-11-04 19:03:13 +08:00
loadedModel = osgDB : : readNodeFiles ( arguments ) ;
if ( ! loadedModel . get ( ) )
{
osg : : notify ( osg : : NOTICE ) < < " No model loaded, please specify a model filename. " < < std : : endl ;
return 1 ;
}
if ( runShaderGen )
{
// convert fixed function pipeline to shaders
osgUtil : : ShaderGenVisitor sgv ;
loadedModel - > accept ( sgv ) ;
}
if ( runConvertToVertexAttributes )
{
// find any conventional vertex, colour, normal and tex coords arrays and convert to vertex attributes
ConvertToVertexAttibArrays ctvaa ;
loadedModel - > accept ( ctvaa ) ;
}
}
if ( ! loadedModel ) return 1 ;
2009-10-08 22:29:54 +08:00
if ( ! outputFileName . empty ( ) )
{
osgDB : : writeNodeFile ( * loadedModel , outputFileName ) ;
return 0 ;
}
// add a viewport to the viewer and attach the scene graph.
viewer . setSceneData ( loadedModel . get ( ) ) ;
2009-10-11 14:05:19 +08:00
viewer . setCameraManipulator ( new osgGA : : TrackballManipulator ( ) ) ;
2009-10-21 22:14:22 +08:00
// add the stats handler
viewer . addEventHandler ( new osgViewer : : StatsHandler ) ;
2009-10-11 14:05:19 +08:00
viewer . realize ( ) ;
2009-10-17 00:26:27 +08:00
if ( runConvertToVertexAttributes )
2009-10-11 14:05:19 +08:00
{
2009-10-17 00:26:27 +08:00
// switch on the uniforms that track the modelview and projection matrices
osgViewer : : Viewer : : Windows windows ;
viewer . getWindows ( windows ) ;
for ( osgViewer : : Viewer : : Windows : : iterator itr = windows . begin ( ) ;
itr ! = windows . end ( ) ;
+ + itr )
{
( * itr ) - > getState ( ) - > setUseModelViewAndProjectionUniforms ( true ) ;
( * itr ) - > getState ( ) - > setUseVertexAttributeAliasing ( true ) ;
}
2009-10-11 14:05:19 +08:00
}
2009-10-08 22:29:54 +08:00
return viewer . run ( ) ;
}