diff --git a/Make/makedirdefs b/Make/makedirdefs index c4c9f3f32..6e4ea9a48 100644 --- a/Make/makedirdefs +++ b/Make/makedirdefs @@ -31,6 +31,7 @@ PLUGIN_DIRS = \ dds\ dw\ flt\ + gdal\ lib3ds\ logo\ lwo\ diff --git a/examples/osgshaders/GL2Scene.cpp b/examples/osgshaders/GL2Scene.cpp index f2b072ffd..611703430 100644 --- a/examples/osgshaders/GL2Scene.cpp +++ b/examples/osgshaders/GL2Scene.cpp @@ -11,7 +11,7 @@ */ /* file: examples/osgshaders/GL2Scene.cpp - * author: Mike Weiblen 2003-07-14 + * author: Mike Weiblen 2003-09-30 * * Compose a scene of several instances of a model, with a different * OpenGL Shading Language shader applied to each. @@ -23,49 +23,159 @@ #include #include #include +#include +#include #include +#include +#include +#include +#include #include #include #include #include +#include "GL2Scene.h" +#include "Noise.h" /////////////////////////////////////////////////////////////////////////// -// OpenGL Shading Language source code for the "microshader" example. +/////////////////////////////////////////////////////////////////////////// + +static osg::Image* +make3DNoiseImage(int texSize) +{ + osg::Image* image = new osg::Image; + image->setImage(texSize, texSize, texSize, + 4, GL_RGBA, GL_UNSIGNED_BYTE, + new unsigned char[4 * texSize * texSize * texSize], + osg::Image::USE_NEW_DELETE); + + const int startFrequency = 4; + const int numOctaves = 4; + + int f, i, j, k, inc; + double ni[3]; + double inci, incj, inck; + int frequency = startFrequency; + GLubyte *ptr; + double amp = 0.5; + + osg::notify(osg::INFO) << "creating 3D noise texture... "; + + for (f = 0, inc = 0; f < numOctaves; ++f, frequency *= 2, ++inc, amp *= 0.5) + { + SetNoiseFrequency(frequency); + ptr = image->data(); + ni[0] = ni[1] = ni[2] = 0; + + inci = 1.0 / (texSize / frequency); + for (i = 0; i < texSize; ++i, ni[0] += inci) + { + incj = 1.0 / (texSize / frequency); + for (j = 0; j < texSize; ++j, ni[1] += incj) + { + inck = 1.0 / (texSize / frequency); + for (k = 0; k < texSize; ++k, ni[2] += inck, ptr += 4) + { + *(ptr+inc) = (GLubyte) (((noise3(ni) + 1.0) * amp) * 128.0); + } + } + } + } + + osg::notify(osg::INFO) << "DONE" << std::endl; + return image; +} + +static osg::Texture3D* +make3DNoiseTexture(int texSize ) +{ + osg::Texture3D* noiseTexture = new osg::Texture3D; + noiseTexture->setFilter(osg::Texture3D::MIN_FILTER, osg::Texture3D::LINEAR); + noiseTexture->setFilter(osg::Texture3D::MAG_FILTER, osg::Texture3D::LINEAR); + noiseTexture->setWrap(osg::Texture3D::WRAP_S, osg::Texture3D::REPEAT); + noiseTexture->setWrap(osg::Texture3D::WRAP_T, osg::Texture3D::REPEAT); + noiseTexture->setWrap(osg::Texture3D::WRAP_R, osg::Texture3D::REPEAT); + noiseTexture->setImage( make3DNoiseImage(texSize) ); + return noiseTexture; +} + +/////////////////////////////////////////////////////////////////////////// + +static osg::Image* +make1DSineImage( int texSize ) +{ + const float PI = 3.1415927; + + osg::Image* image = new osg::Image; + image->setImage(texSize, 1, 1, + 4, GL_RGBA, GL_UNSIGNED_BYTE, + new unsigned char[4 * texSize], + osg::Image::USE_NEW_DELETE); + + GLubyte* ptr = image->data(); + float inc = 2. * PI / (float)texSize; + for(int i = 0; i < texSize; i++) + { + *ptr++ = (GLubyte)((sinf(i * inc) * 0.5 + 0.5) * 255.); + *ptr++ = 0; + *ptr++ = 0; + *ptr++ = 1; + } + return image; +} + +static osg::Texture1D* +make1DSineTexture( int texSize ) +{ + osg::Texture1D* sineTexture = new osg::Texture1D; + sineTexture->setWrap(osg::Texture1D::WRAP_S, osg::Texture1D::REPEAT); + sineTexture->setFilter(osg::Texture1D::MIN_FILTER, osg::Texture1D::LINEAR); + sineTexture->setFilter(osg::Texture1D::MAG_FILTER, osg::Texture1D::LINEAR); + sineTexture->setImage( make1DSineImage(texSize) ); + return sineTexture; +} + +/////////////////////////////////////////////////////////////////////////// + +static osg::Node* createGlobe() +{ + osg::Geode* geode = new osg::Geode(); + osg::StateSet* stateset = geode->getOrCreateStateSet(); + + osg::Texture2D* texture = new osg::Texture2D; + texture->setImage( osgDB::readImageFile("Images/land_shallow_topo_2048.jpg") ); + stateset->setTextureAttributeAndModes(0, texture, osg::StateAttribute::ON); + + geode->addDrawable(new osg::ShapeDrawable(new osg::Sphere(osg::Vec3(0,0,0), 2.0f))); + + return geode; +} + +/////////////////////////////////////////////////////////////////////////// +// OpenGL Shading Language source code for the "microshader" example, +// which simply colors a fragment based on its location. static const char *microshaderVertSource = { - "varying vec3 color;" + "varying vec4 color;" "void main(void)" "{" + "color = gl_Vertex;" "gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;" - "color = gl_Vertex.zyx * 1.0;" "}" }; static const char *microshaderFragSource = { - "varying vec3 color;" + "varying vec4 color;" "void main(void)" "{" - "gl_FragColor = vec4(color, 1.0);" + "gl_FragColor = color;" "}" }; /////////////////////////////////////////////////////////////////////////// -static osg::Group* rootNode; -static osg::Node* masterModel; - -// Add a reference to the masterModel at the specified translation, and -// return its StateSet so we can easily attach StateAttributes. -static osg::StateSet* -CloneMaster(float x, float y, float z ) -{ - osg::PositionAttitudeTransform* xform = new osg::PositionAttitudeTransform(); - xform->setPosition(osg::Vec3(x, y, z)); - xform->addChild(masterModel); - rootNode->addChild(xform); - return xform->getOrCreateStateSet(); -} +static osg::ref_ptr rootNode; // Create some geometry upon which to render GL2 shaders. static osg::Geode* @@ -78,96 +188,231 @@ CreateModel() return geode; } -// read vert & frag shader source code from a pair of files. -static void -LoadShaderSource( osgGL2::ProgramObject* progObj, std::string baseFileName ) +// Add a reference to the masterModel at the specified translation, and +// return its StateSet so we can easily attach StateAttributes. +static osg::StateSet* +ModelInstance() { - std::string vertFileName = osgDB::findDataFile(baseFileName + ".vert"); - if( vertFileName.length() != 0 ) - { - osgGL2::ShaderObject* vertObj = new osgGL2::ShaderObject( osgGL2::ShaderObject::VERTEX ); - vertObj->loadShaderSourceFromFile( vertFileName.c_str() ); - progObj->addShader( vertObj ); - } - else - { - osg::notify(osg::WARN) << "Warning: file \"" << baseFileName+".vert" << "\" not found." << std::endl; - } + static float zvalue = 0.0f; + static osg::Node* masterModel = CreateModel(); - std::string fragFileName = osgDB::findDataFile(baseFileName + ".frag"); - if( fragFileName.length() != 0 ) + osg::PositionAttitudeTransform* xform = new osg::PositionAttitudeTransform(); + xform->setPosition(osg::Vec3( 0.0f, -1.0f, zvalue )); + zvalue = zvalue + 2.2f; + xform->addChild(masterModel); + rootNode->addChild(xform); + return xform->getOrCreateStateSet(); +} + +// load source from a file. +static void +LoadShaderSource( osgGL2::ShaderObject* obj, const std::string& fileName ) +{ + std::string fqFileName = osgDB::findDataFile(fileName); + if( fqFileName.length() != 0 ) { - osgGL2::ShaderObject* fragObj = new osgGL2::ShaderObject( osgGL2::ShaderObject::FRAGMENT ); - fragObj->loadShaderSourceFromFile( fragFileName.c_str() ); - progObj->addShader( fragObj ); + obj->loadShaderSourceFromFile( fqFileName.c_str() ); } else { - osg::notify(osg::WARN) << "Warning: file \"" << baseFileName+".frag" << "\" not found." << std::endl; + osg::notify(osg::WARN) << "File \"" << fileName << "\" not found." << std::endl; } } + +/////////////////////////////////////////////////////////////////////////// +// rude but convenient globals + +static osgGL2::ProgramObject* BlockyProgObj; +static osgGL2::ShaderObject* BlockyVertObj; +static osgGL2::ShaderObject* BlockyFragObj; + +static osgGL2::ProgramObject* ErodedProgObj; +static osgGL2::ShaderObject* ErodedVertObj; +static osgGL2::ShaderObject* ErodedFragObj; + +static osgGL2::ProgramObject* MarbleProgObj; +static osgGL2::ShaderObject* MarbleVertObj; +static osgGL2::ShaderObject* MarbleFragObj; + +/////////////////////////////////////////////////////////////////////////// + +// TODO encapsulate inside an osgFX effect. +class AnimateCallback: public osg::NodeCallback +{ + public: + AnimateCallback( osgGL2::ProgramObject* progObj ) : + osg::NodeCallback(), + _enabled(true) + {} + + virtual void operator() ( osg::Node* node, osg::NodeVisitor* nv ) + { + if( _enabled ) + { + float angle = 2.0 * nv->getFrameStamp()->getReferenceTime(); + float sine = sinf( angle ); // -1 -> 1 + float v01 = 0.5f * sine + 0.5f; // 0 -> 1 + float v10 = 1.0f - v01; // 1 -> 0 + + ErodedProgObj->setUniform( "Offset", osg::Vec3(0.505f, 0.8f*v01, 0.0f) ); + + MarbleProgObj->setUniform( "Offset", osg::Vec3(0.505f, 0.8f*v01, 0.0f) ); + + BlockyProgObj->setUniform( "Sine", sine ); + BlockyProgObj->setUniform( "Color1", osg::Vec3(v10, 0.0f, 0.0f) ); + BlockyProgObj->setUniform( "Color2", osg::Vec3(v01, v01, v10) ); + } + traverse(node, nv); + } + + private: + bool _enabled; +}; + /////////////////////////////////////////////////////////////////////////// // Compose a scenegraph with examples of GL2 shaders -#define ZGRID 2.2 - -osg::Node* -GL2Scene() +osg::ref_ptr +GL2Scene::buildScene() { - osg::StateSet* ss; - osgGL2::ProgramObject* progObj; + osg::Texture3D* noiseTexture = make3DNoiseTexture( 32 /*128*/ ); + osg::Texture1D* sineTexture = make1DSineTexture( 32 /*1024*/ ); - // the rootNode of our created graph. - rootNode = new osg::Group; - ss = rootNode->getOrCreateStateSet(); - - // attach an "empty" ProgramObject to the rootNode as a default - // StateAttribute. An empty ProgramObject (ie without any attached - // ShaderObjects) is a special case, which means to use the + // the root of our scenegraph. + // attach an "empty" ProgramObject to the rootNode, which will act as + // the default StateAttribute. An empty ProgramObject (ie without any + // attached ShaderObjects) is a special case, which means to use the // OpenGL 1.x "fixed functionality" rendering pipeline. - progObj = new osgGL2::ProgramObject; - ss->setAttributeAndModes(progObj, osg::StateAttribute::ON); + rootNode = new osg::Group; + rootNode->setUpdateCallback( new AnimateCallback(0) ); + { + // TODO this definition of a "default ProgramObject state" will not + // be necessary when the OSG core has proper support for the unique + // requirements of ProgramObject. + osg::StateSet* ss = rootNode->getOrCreateStateSet(); + osgGL2::ProgramObject* progObj = new osgGL2::ProgramObject; + _progObjList.push_back( progObj ); + ss->setAttributeAndModes(progObj, osg::StateAttribute::ON); + } - // put the unadorned masterModel at the origin for comparison. - masterModel = CreateModel(); - rootNode->addChild(masterModel); + // the simple Microshader (its source appears earlier in this file) + { + osg::StateSet* ss = ModelInstance(); + osgGL2::ProgramObject* progObj = new osgGL2::ProgramObject; + _progObjList.push_back( progObj ); + progObj->addShader( new osgGL2::ShaderObject( + osgGL2::ShaderObject::VERTEX, microshaderVertSource ) ); + progObj->addShader( new osgGL2::ShaderObject( + osgGL2::ShaderObject::FRAGMENT, microshaderFragSource ) ); + ss->setAttributeAndModes( progObj, osg::StateAttribute::ON ); + } + + // the "blocky" shader, a simple animation test + { + osg::StateSet* ss = ModelInstance(); + BlockyProgObj = new osgGL2::ProgramObject; + _progObjList.push_back( BlockyProgObj ); + BlockyVertObj = new osgGL2::ShaderObject( osgGL2::ShaderObject::VERTEX ); + BlockyFragObj = new osgGL2::ShaderObject( osgGL2::ShaderObject::FRAGMENT ); + BlockyProgObj->addShader( BlockyFragObj ); + BlockyProgObj->addShader( BlockyVertObj ); + ss->setAttributeAndModes(BlockyProgObj, osg::StateAttribute::ON); + } + + // the "eroded" shader, uses a noise texture to discard fragments + { + osg::StateSet* ss = ModelInstance(); + ss->setTextureAttributeAndModes(6, noiseTexture, osg::StateAttribute::ON); + ErodedProgObj = new osgGL2::ProgramObject; + _progObjList.push_back( ErodedProgObj ); + ErodedVertObj = new osgGL2::ShaderObject( osgGL2::ShaderObject::VERTEX ); + ErodedFragObj = new osgGL2::ShaderObject( osgGL2::ShaderObject::FRAGMENT ); + ErodedProgObj->addShader( ErodedFragObj ); + ErodedProgObj->addShader( ErodedVertObj ); + ss->setAttributeAndModes(ErodedProgObj, osg::StateAttribute::ON); + } + + // the "marble" shader, uses two textures + { + osg::StateSet* ss = ModelInstance(); + ss->setTextureAttributeAndModes(1, noiseTexture, osg::StateAttribute::ON); + ss->setTextureAttributeAndModes(2, sineTexture, osg::StateAttribute::ON); + MarbleProgObj = new osgGL2::ProgramObject; + _progObjList.push_back( MarbleProgObj ); + MarbleVertObj = new osgGL2::ShaderObject( osgGL2::ShaderObject::VERTEX ); + MarbleFragObj = new osgGL2::ShaderObject( osgGL2::ShaderObject::FRAGMENT ); + MarbleProgObj->addShader( MarbleFragObj ); + MarbleProgObj->addShader( MarbleVertObj ); + ss->setAttributeAndModes(MarbleProgObj, osg::StateAttribute::ON); + } + + // regular GL 1.x texturing for comparison. + if( 0 ) { + osg::StateSet* ss = ModelInstance(); + osg::Texture2D* tex0 = new osg::Texture2D; + tex0->setImage( osgDB::readImageFile( "images/3dl-ge100.png" ) ); + ss->setTextureAttributeAndModes(0, tex0, osg::StateAttribute::ON); + } + + reloadShaderSource(); // add logo overlays - //rootNode->addChild( osgDB::readNodeFile( "3dl_ogl.logo" ) ); - - // - // create references to the masterModel and attach shaders - // - - // apply the simple microshader example - // (the shader sources are hardcoded above in this .cpp file) - ss = CloneMaster(0,0,ZGRID*1); - progObj = new osgGL2::ProgramObject; - progObj->addShader( new osgGL2::ShaderObject( osgGL2::ShaderObject::VERTEX, microshaderVertSource ) ); - progObj->addShader( new osgGL2::ShaderObject( osgGL2::ShaderObject::FRAGMENT, microshaderFragSource ) ); - ss->setAttributeAndModes(progObj, osg::StateAttribute::ON); - - // load the "specular brick" shader from a pair of source files. - ss = CloneMaster(0,0,ZGRID*2); - progObj = new osgGL2::ProgramObject; - LoadShaderSource( progObj, "shaders/brick" ); - ss->setAttributeAndModes(progObj, osg::StateAttribute::ON); - - // load the "gold screen" shader from a pair of source files. - ss = CloneMaster(0,0,ZGRID*3); - progObj = new osgGL2::ProgramObject; - LoadShaderSource( progObj, "shaders/screen" ); - ss->setAttributeAndModes(progObj, osg::StateAttribute::ON); + // rootNode->addChild( osgDB::readNodeFile( "3dl_ogl.logo" ) ); return rootNode; } +/////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////// -void -GL2Update() +GL2Scene::GL2Scene() { - /* TODO : update uniform values for shader animation */ + _rootNode = buildScene(); + _shadersEnabled = true; +} + +GL2Scene::~GL2Scene() +{ +} + +// mew 2003-09-19 : This way of configuring the shaders is temporary, +// pending a move to an osgFX-based approach. +void +GL2Scene::reloadShaderSource() +{ + osg::notify(osg::WARN) << "reloadShaderSource()" << std::endl; + + LoadShaderSource( BlockyVertObj, "shaders/blocky.vert" ); + LoadShaderSource( BlockyFragObj, "shaders/blocky.frag" ); + + LoadShaderSource( ErodedVertObj, "shaders/eroded.vert" ); + LoadShaderSource( ErodedFragObj, "shaders/eroded.frag" ); + ErodedProgObj->setUniform( "LightPosition", osg::Vec3(0.0f, 0.0f, 4.0f) ); + ErodedProgObj->setUniform( "Scale", 1.0f ); + ErodedProgObj->setUniform( "sampler3d", 6 ); + + LoadShaderSource( MarbleVertObj, "shaders/marble.vert" ); + LoadShaderSource( MarbleFragObj, "shaders/marble.frag" ); + MarbleProgObj->setUniform( "Noise", 1 ); + MarbleProgObj->setUniform( "Sine", 2 ); +} + + +// mew 2003-09-19 : TODO Need to revisit how to better control +// osgGL2::ProgramObject enable state in OSG core. glProgramObjects are +// different enough from other GL state that StateSet::setAttributeAndModes() +// doesn't fit well, so came up with a local implementation. +void +GL2Scene::toggleShaderEnable() +{ + _shadersEnabled = ! _shadersEnabled; + osg::notify(osg::WARN) << "shader enable = " << + ((_shadersEnabled) ? "ON" : "OFF") << std::endl; + for( unsigned int i = 0; i < _progObjList.size(); i++ ) + { + _progObjList[i]->enable( _shadersEnabled ); + } } /*EOF*/ diff --git a/examples/osgshaders/GL2Scene.h b/examples/osgshaders/GL2Scene.h new file mode 100644 index 000000000..2c01462a5 --- /dev/null +++ b/examples/osgshaders/GL2Scene.h @@ -0,0 +1,50 @@ +/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2003 Robert Osfield + * Copyright (C) 2003 3Dlabs Inc. Ltd. + * + * This application is open source and may be redistributed and/or modified + * freely and without restriction, both in commericial and non commericial applications, + * as long as this copyright notice is maintained. + * + * This application is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +*/ + +/* file: examples/osgshaders/GL2Scene.h + * author: Mike Weiblen 2003-09-18 + * + * See http://www.3dlabs.com/opengl2/ for more information regarding + * the OpenGL Shading Language. +*/ + +#include +#include +#include + +#include + +class GL2Scene : public osg::Referenced +{ + public: + GL2Scene(); + + osg::ref_ptr getRootNode() { return _rootNode; } + void reloadShaderSource(); + void toggleShaderEnable(); + + protected: + ~GL2Scene(); + + private: /*methods*/ + osg::ref_ptr buildScene(); + + private: /*data*/ + osg::ref_ptr _rootNode; + std::vector _progObjList; + bool _shadersEnabled; +}; + +typedef osg::ref_ptr GL2ScenePtr; + +/*EOF*/ + diff --git a/examples/osgshaders/GNUmakefile b/examples/osgshaders/GNUmakefile index 2bd193ac6..7bece7866 100644 --- a/examples/osgshaders/GNUmakefile +++ b/examples/osgshaders/GNUmakefile @@ -3,6 +3,7 @@ include $(TOPDIR)/Make/makedefs CXXFILES =\ GL2Scene.cpp \ + Noise.cpp \ osgshaders.cpp LIBS += -losgProducer -lProducer -losgText -losgGL2 -losgGA -losgDB -losgUtil -losg $(GL_LIBS) $(X_LIBS) $(OTHER_LIBS) diff --git a/examples/osgshaders/Noise.cpp b/examples/osgshaders/Noise.cpp new file mode 100644 index 000000000..4ac82e826 --- /dev/null +++ b/examples/osgshaders/Noise.cpp @@ -0,0 +1,269 @@ +/************************************************************************ + * * + * Copyright (C) 2002 3Dlabs Inc. Ltd. * + * * +/************************************************************************/ + +#include +#include + +/* Coherent noise function over 1, 2 or 3 dimensions */ +/* (copyright Ken Perlin) */ + +#define MAXB 0x100 +#define N 0x1000 +#define NP 12 /* 2^N */ +#define NM 0xfff + +#define s_curve(t) ( t * t * (3. - 2. * t) ) +#define lerp(t, a, b) ( a + t * (b - a) ) +#define setup(i,b0,b1,r0,r1)\ + t = vec[i] + N;\ + b0 = ((int)t) & BM;\ + b1 = (b0+1) & BM;\ + r0 = t - (int)t;\ + r1 = r0 - 1.; +#define at2(rx,ry) ( rx * q[0] + ry * q[1] ) +#define at3(rx,ry,rz) ( rx * q[0] + ry * q[1] + rz * q[2] ) + +static void initNoise(void); + +static int p[MAXB + MAXB + 2]; +static double g3[MAXB + MAXB + 2][3]; +static double g2[MAXB + MAXB + 2][2]; +static double g1[MAXB + MAXB + 2]; + +int start; +int B; +int BM; + + +void SetNoiseFrequency(int frequency) +{ + start = 1; + B = frequency; + BM = B-1; +} + +double noise1(double arg) +{ + int bx0, bx1; + double rx0, rx1, sx, t, u, v, vec[1]; + + vec[0] = arg; + if (start) { + start = 0; + initNoise(); + } + + setup(0,bx0,bx1,rx0,rx1); + + sx = s_curve(rx0); + u = rx0 * g1[ p[ bx0 ] ]; + v = rx1 * g1[ p[ bx1 ] ]; + + return(lerp(sx, u, v)); +} + +double noise2(double vec[2]) +{ + int bx0, bx1, by0, by1, b00, b10, b01, b11; + double rx0, rx1, ry0, ry1, *q, sx, sy, a, b, t, u, v; + int i, j; + + if (start) { + start = 0; + initNoise(); + } + + setup(0, bx0,bx1, rx0,rx1); + setup(1, by0,by1, ry0,ry1); + + i = p[ bx0 ]; + j = p[ bx1 ]; + + b00 = p[ i + by0 ]; + b10 = p[ j + by0 ]; + b01 = p[ i + by1 ]; + b11 = p[ j + by1 ]; + + sx = s_curve(rx0); + sy = s_curve(ry0); + + q = g2[ b00 ] ; u = at2(rx0,ry0); + q = g2[ b10 ] ; v = at2(rx1,ry0); + a = lerp(sx, u, v); + + q = g2[ b01 ] ; u = at2(rx0,ry1); + q = g2[ b11 ] ; v = at2(rx1,ry1); + b = lerp(sx, u, v); + + return lerp(sy, a, b); +} + +double noise3(double vec[3]) +{ + int bx0, bx1, by0, by1, bz0, bz1, b00, b10, b01, b11; + double rx0, rx1, ry0, ry1, rz0, rz1, *q, sy, sz, a, b, c, d, t, u, v; + int i, j; + + if (start) { + start = 0; + initNoise(); + } + + setup(0, bx0,bx1, rx0,rx1); + setup(1, by0,by1, ry0,ry1); + setup(2, bz0,bz1, rz0,rz1); + + i = p[ bx0 ]; + j = p[ bx1 ]; + + b00 = p[ i + by0 ]; + b10 = p[ j + by0 ]; + b01 = p[ i + by1 ]; + b11 = p[ j + by1 ]; + + t = s_curve(rx0); + sy = s_curve(ry0); + sz = s_curve(rz0); + + q = g3[ b00 + bz0 ] ; u = at3(rx0,ry0,rz0); + q = g3[ b10 + bz0 ] ; v = at3(rx1,ry0,rz0); + a = lerp(t, u, v); + + q = g3[ b01 + bz0 ] ; u = at3(rx0,ry1,rz0); + q = g3[ b11 + bz0 ] ; v = at3(rx1,ry1,rz0); + b = lerp(t, u, v); + + c = lerp(sy, a, b); + + q = g3[ b00 + bz1 ] ; u = at3(rx0,ry0,rz1); + q = g3[ b10 + bz1 ] ; v = at3(rx1,ry0,rz1); + a = lerp(t, u, v); + + q = g3[ b01 + bz1 ] ; u = at3(rx0,ry1,rz1); + q = g3[ b11 + bz1 ] ; v = at3(rx1,ry1,rz1); + b = lerp(t, u, v); + + d = lerp(sy, a, b); + + //fprintf(stderr, "%f\n", lerp(sz, c, d)); + + return lerp(sz, c, d); +} + +void normalize2(double v[2]) +{ + double s; + + s = sqrt(v[0] * v[0] + v[1] * v[1]); + v[0] = v[0] / s; + v[1] = v[1] / s; +} + +void normalize3(double v[3]) +{ + double s; + + s = sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]); + v[0] = v[0] / s; + v[1] = v[1] / s; + v[2] = v[2] / s; +} + +void initNoise(void) +{ + int i, j, k; + + srand(30757); + for (i = 0 ; i < B ; i++) { + p[i] = i; + g1[i] = (double)((rand() % (B + B)) - B) / B; + + for (j = 0 ; j < 2 ; j++) + g2[i][j] = (double)((rand() % (B + B)) - B) / B; + normalize2(g2[i]); + + for (j = 0 ; j < 3 ; j++) + g3[i][j] = (double)((rand() % (B + B)) - B) / B; + normalize3(g3[i]); + } + + while (--i) { + k = p[i]; + p[i] = p[j = rand() % B]; + p[j] = k; + } + + for (i = 0 ; i < B + 2 ; i++) { + p[B + i] = p[i]; + g1[B + i] = g1[i]; + for (j = 0 ; j < 2 ; j++) + g2[B + i][j] = g2[i][j]; + for (j = 0 ; j < 3 ; j++) + g3[B + i][j] = g3[i][j]; + } +} + +/* --- My harmonic summing functions - PDB --------------------------*/ + +/* + In what follows "alpha" is the weight when the sum is formed. + Typically it is 2, As this approaches 1 the function is noisier. + "beta" is the harmonic scaling/spacing, typically 2. +*/ + +double PerlinNoise1D(double x,double alpha,double beta,int n) +{ + int i; + double val,sum = 0; + double p,scale = 1; + + p = x; + for (i=0;i +#include +#include #include #include #include +#include -#define GL2SCENE -osg::Node* GL2Scene(); -void GL2Update(); +#include "GL2Scene.h" + +using namespace osg; + +/////////////////////////////////////////////////////////////////////////// + +class KeyHandler: public osgGA::GUIEventHandler +{ + public: + KeyHandler( GL2ScenePtr gl2Scene ) : + _gl2Scene(gl2Scene) + {} + + bool handle( const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& ) + { + if( ea.getEventType() != osgGA::GUIEventAdapter::KEYDOWN ) + return false; + + switch( ea.getKey() ) + { + case 'x': + _gl2Scene->reloadShaderSource(); + return true; + case 'y': + _gl2Scene->toggleShaderEnable(); + return true; + } + return false; + } + + private: + GL2ScenePtr _gl2Scene; +}; + +/////////////////////////////////////////////////////////////////////////// int main( int argc, char **argv ) { - // use an ArgumentParser object to manage the program arguments. - osg::ArgumentParser arguments(&argc,argv); - - // set up the usage document, in case we need to print out how to use this program. - arguments.getApplicationUsage()->setApplicationName(arguments.getApplicationName()); - arguments.getApplicationUsage()->setDescription(arguments.getApplicationName()+" is the standard OpenSceneGraph example which loads and visualises 3d models."); - arguments.getApplicationUsage()->setCommandLineUsage(arguments.getApplicationName()+" [options] filename ..."); - arguments.getApplicationUsage()->addCommandLineOption("-h or --help","Display this information"); + ArgumentParser args(&argc,argv); + // set up the usage document + args.getApplicationUsage()->setApplicationName(args.getApplicationName()); + args.getApplicationUsage()->setDescription(args.getApplicationName() + + " demonstrates the OpenGL Shading Language using osgGL2"); + args.getApplicationUsage()->setCommandLineUsage(args.getApplicationName()); + args.getApplicationUsage()->addCommandLineOption("-h or --help","Display this information"); + + args.getApplicationUsage()->addKeyboardMouseBinding( "x", "Reload and recompile shader source files." ); + args.getApplicationUsage()->addKeyboardMouseBinding( "y", "Toggle shader enable" ); // construct the viewer. - osgProducer::Viewer viewer(arguments); + osgProducer::Viewer viewer(args); + viewer.setUpViewer( osgProducer::Viewer::STANDARD_SETTINGS ); + viewer.getUsage( *args.getApplicationUsage() ); - // set up the value with sensible default event handlers. - viewer.setUpViewer(osgProducer::Viewer::STANDARD_SETTINGS); - - // get details on keyboard and mouse bindings used by the viewer. - viewer.getUsage(*arguments.getApplicationUsage()); - - // if user request help write it out to cout. - if (arguments.read("-h") || arguments.read("--help")) + if( args.read("-h") || args.read("--help") ) { - arguments.getApplicationUsage()->write(std::cout); + args.getApplicationUsage()->write(std::cout); return 1; } // any option left unread are converted into errors to write out later. - arguments.reportRemainingOptionsAsUnrecognized(); - - // report any errors if they have occured when parsing the program aguments. - if (arguments.errors()) + args.reportRemainingOptionsAsUnrecognized(); + if( args.errors() ) { - arguments.writeErrorMessages(std::cout); - return 1; - } - -#ifdef GL2SCENE //( - osg::ref_ptr loadedModel = GL2Scene(); -#else //)( - if (arguments.argc()<=1) - { - arguments.getApplicationUsage()->write(std::cout,osg::ApplicationUsage::COMMAND_LINE_OPTION); + args.writeErrorMessages(std::cout); return 1; } - // read the scene from the list of file specified commandline args. - osg::ref_ptr loadedModel = osgDB::readNodeFiles(arguments); + // create the scene + notify(NOTICE) << "osgGL2 version " << osgGL2GetVersion() << std::endl; + GL2ScenePtr gl2Scene = new GL2Scene; - // if no model has been successfully loaded report failure. - if (!loadedModel) - { - std::cout << arguments.getApplicationName() <<": No data loaded" << std::endl; - return 1; - } - - - // optimize the scene graph, remove rendundent nodes and state etc. - osgUtil::Optimizer optimizer; - optimizer.optimize(loadedModel.get()); -#endif //) - - // set the scene to render - viewer.setSceneData(loadedModel.get()); - - // create the windows and run the threads. + viewer.setSceneData( gl2Scene->getRootNode().get() ); + viewer.getEventHandlerList().push_front( new KeyHandler(gl2Scene) ); viewer.realize(); - while( !viewer.done() ) { - // wait for all cull and draw threads to complete. viewer.sync(); - - // update the scene by traversing it with the the update visitor which will - // call all node update callbacks and animations. viewer.update(); -#ifdef GL2SCENE //( - GL2Update(); -#endif //) - - // fire off the cull and draw traversals of the scene. viewer.frame(); - } - - // wait for all cull and draw threads to complete before exit. viewer.sync(); - return 0; } +/*EOF*/ + diff --git a/include/osgGL2/Extensions b/include/osgGL2/Extensions index cb15e1650..3f08af25c 100644 --- a/include/osgGL2/Extensions +++ b/include/osgGL2/Extensions @@ -11,7 +11,7 @@ */ /* file: include/osgGL2/Extensions - * author: Mike Weiblen 2003-07-14 + * author: Mike Weiblen 2003-09-12 * * See http://www.3dlabs.com/opengl2/ for more information regarding * the OpenGL Shading Language. @@ -152,17 +152,17 @@ class OSGGL2_EXPORT Extensions : public osg::Referenced void glUniform2i(GLint location, GLint v0, GLint v1) const; void glUniform3i(GLint location, GLint v0, GLint v1, GLint v2) const; void glUniform4i(GLint location, GLint v0, GLint v1, GLint v2, GLint v3) const; - void glUniform1fv(GLint location, GLsizei count, GLfloat *value) const; - void glUniform2fv(GLint location, GLsizei count, GLfloat *value) const; - void glUniform3fv(GLint location, GLsizei count, GLfloat *value) const; - void glUniform4fv(GLint location, GLsizei count, GLfloat *value) const; - void glUniform1iv(GLint location, GLsizei count, GLint *value) const; - void glUniform2iv(GLint location, GLsizei count, GLint *value) const; - void glUniform3iv(GLint location, GLsizei count, GLint *value) const; - void glUniform4iv(GLint location, GLsizei count, GLint *value) const; - void glUniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, GLfloat *value) const; - void glUniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, GLfloat *value) const; - void glUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, GLfloat *value) const; + void glUniform1fv(GLint location, GLsizei count, const GLfloat *value) const; + void glUniform2fv(GLint location, GLsizei count, const GLfloat *value) const; + void glUniform3fv(GLint location, GLsizei count, const GLfloat *value) const; + void glUniform4fv(GLint location, GLsizei count, const GLfloat *value) const; + void glUniform1iv(GLint location, GLsizei count, const GLint *value) const; + void glUniform2iv(GLint location, GLsizei count, const GLint *value) const; + void glUniform3iv(GLint location, GLsizei count, const GLint *value) const; + void glUniform4iv(GLint location, GLsizei count, const GLint *value) const; + void glUniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) const; + void glUniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) const; + void glUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) const; GLint glGetUniformLocation(GLhandleARB programObject, const GLcharARB *name) const; GLint glGetAttribLocation(GLhandleARB programObj, const GLcharARB *name) const; void glGetActiveUniform(GLhandleARB programObj, GLuint index, GLsizei maxLength, GLsizei *length, GLint *size, GLint *type, GLcharARB *name) const; diff --git a/include/osgGL2/ProgramObject b/include/osgGL2/ProgramObject index 53e76bb93..b912c4153 100644 --- a/include/osgGL2/ProgramObject +++ b/include/osgGL2/ProgramObject @@ -11,7 +11,7 @@ */ /* file: include/osgGL2/ProgramObject - * author: Mike Weiblen 2003-07-14 + * author: Mike Weiblen 2003-09-18 * * See http://www.3dlabs.com/opengl2/ for more information regarding * the OpenGL Shading Language. @@ -25,26 +25,32 @@ #include #include #include +#include +#include +#include #include #include +#include #include +#include namespace osgGL2 { - - -/////////////////////////////////////////////////////////////////////////// +class ProgramObject; +typedef osg::ref_ptr ProgramObjectPtr; class ShaderObject; +typedef osg::ref_ptr ShaderObjectPtr; + +/////////////////////////////////////////////////////////////////////////// /** Encapsulates the OpenGL Shading Language ProgramObject */ class OSGGL2_EXPORT ProgramObject : public osg::StateAttribute { public: - ProgramObject(); /** Copy constructor using CopyOp to manage deep vs shallow copy.*/ @@ -74,10 +80,29 @@ class OSGGL2_EXPORT ProgramObject : public osg::StateAttribute // data access methods. - /** Force a relink on next apply() of associated glProgramObject. */ - void dirtyProgramObject(); + /** Force a relink on next apply() of associated glProgramObject. */ + void dirtyProgramObject(); - void addShader( ShaderObject* shader ); + /** Force a recompile of all ShaderObjects on next apply(). */ + void dirtyShaderObjects(); + + /** Set whether rendering of ProgramObject is enabled or disabled */ + void enable( bool enabled ) { _enabled = enabled; } + + /** Attach a ShaderObject to this ProgramObject */ + void addShader( ShaderObject* shadObj ); + + void setUniform( const char* uniformName, int value ); + void setUniform( const char* uniformName, float value ); + void setUniform( const char* uniformName, osg::Vec2 value ); + void setUniform( const char* uniformName, osg::Vec3 value ); + void setUniform( const char* uniformName, osg::Vec4 value ); + + inline void setSampler( const char* uniformName, int value ) + { + // emphatic alias for setUniform(int) + setUniform( uniformName, static_cast(value) ); + } /** use deleteObject instead of glDeleteObject to allow * GL2 Objects to cached until they can be deleted @@ -89,50 +114,52 @@ class OSGGL2_EXPORT ProgramObject : public osg::StateAttribute * in the OpenGL context related to contextID.*/ static void flushDeletedGL2Objects(unsigned int contextID,double currentTime, double& availableTime); + protected: - - virtual ~ProgramObject(); - - typedef std::vector< osg::ref_ptr > ShaderObjectList; - ShaderObjectList _shaderObjectList; - - - class OSGGL2_EXPORT PerContextProgObj : public osg::Referenced + class PerContextProgObj : public osg::Referenced { public: - PerContextProgObj(const ProgramObject* parent, Extensions* extensions); + PerContextProgObj(const ProgramObject* progObj, unsigned int contextID); PerContextProgObj(const PerContextProgObj& rhs); - GLhandleARB& getHandle() {return _handle;} + GLhandleARB& getHandle() {return _glProgObjHandle;} bool isDirty() const {return _dirty;} void markAsDirty() {_dirty = true; } - void markAsClean() {_dirty = false;} - bool build() const; + void build(); void use() const; - void markAsAttached() {_unattached = false;} - bool isUnattached() const {return _unattached;} + void updateUniforms( const UniformValueList& univalList ); + void applyUniformValues(); - protected: - PerContextProgObj() {}; + void printInfoLog(osg::NotifySeverity severity) const; + + protected: /*methods*/ + PerContextProgObj(); ~PerContextProgObj(); - const ProgramObject* _parent; + protected: /*data*/ + const ProgramObject* _progObj; osg::ref_ptr _extensions; - GLhandleARB _handle; + GLhandleARB _glProgObjHandle; bool _dirty; - bool _unattached; + UniformValueList _univalList; + const unsigned int _contextID; }; - typedef osg::buffered_value< osg::ref_ptr > PCPOList; - mutable PCPOList _pcpoList; - + protected: /*methods*/ + virtual ~ProgramObject(); PerContextProgObj* getPCPO(unsigned int contextID) const; + void updateUniforms( int frameNumber ) const; + protected: /*data*/ + bool _enabled; + std::vector< ShaderObjectPtr > _shaderObjectList; + mutable osg::buffered_value< osg::ref_ptr > _pcpoList; + mutable int _frameNumberOfLastPCPOUpdate; + mutable UniformValueList _univalList; }; - /////////////////////////////////////////////////////////////////////////// /** Encapsulates the OpenGL Shading Language ShaderObject */ @@ -159,51 +186,57 @@ class OSGGL2_EXPORT ShaderObject : public osg::Object void setShaderSource( const char* sourceText ); inline const std::string& getShaderSource() const {return _shaderSource; } bool loadShaderSourceFromFile( const char* fileName ); - Type getType() const { return _type; } + inline Type getType() const { return _type; } + const char* getTypename() const; /** Force a recompile on next apply() of associated glShaderObject. */ void dirtyShaderObject(); - bool build(unsigned int contextID) const; + void build(unsigned int contextID) const; void attach(unsigned int contextID, GLhandleARB progObj) const; + protected: - - virtual ~ShaderObject(); - - std::string _shaderSource; - Type _type; - - class OSGGL2_EXPORT PerContextShaderObj : public osg::Referenced + class PerContextShaderObj : public osg::Referenced { public: - PerContextShaderObj(const ShaderObject* parent, Extensions* extensions); + PerContextShaderObj(const ShaderObject* shadObj, unsigned int contextID); PerContextShaderObj(const PerContextShaderObj& rhs); - GLhandleARB& getHandle() {return _handle;} + GLhandleARB& getHandle() {return _glShaderObjHandle;} bool isDirty() const {return _dirty;} void markAsDirty() {_dirty = true; } - void markAsClean() {_dirty = false;} - bool build(); + void build(); - void attach(GLhandleARB progObj); + void attach(GLhandleARB progObj) const; - protected: - PerContextShaderObj() {}; + void printInfoLog(osg::NotifySeverity severity) const; + + protected: /*methods*/ + PerContextShaderObj(); ~PerContextShaderObj(); - const ShaderObject* _parent; + protected: /*data*/ + const ShaderObject* _shadObj; osg::ref_ptr _extensions; - GLhandleARB _handle; + GLhandleARB _glShaderObjHandle; bool _dirty; + const unsigned int _contextID; }; - typedef osg::buffered_value< osg::ref_ptr > PCSOList; - mutable PCSOList _pcsoList; - + protected: /*methods*/ + virtual ~ShaderObject(); PerContextShaderObj* getPCSO(unsigned int contextID) const; + friend void ProgramObject::addShader( ShaderObject* shadObj ); // to access addProgObjRef() + void addProgObjRef( ProgramObject* progObj ); + + protected: /*data*/ + Type _type; + std::string _shaderSource; + std::vector< ProgramObjectPtr > _programObjectList; + mutable osg::buffered_value< osg::ref_ptr > _pcsoList; }; } diff --git a/include/osgGL2/UniformValue b/include/osgGL2/UniformValue new file mode 100644 index 000000000..70202f06e --- /dev/null +++ b/include/osgGL2/UniformValue @@ -0,0 +1,88 @@ +/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2003 Robert Osfield + * Copyright (C) 2003 3Dlabs Inc. Ltd. + * + * This application is open source and may be redistributed and/or modified + * freely and without restriction, both in commericial and non commericial + * applications, as long as this copyright notice is maintained. + * + * This application is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +*/ + +/* file: include/osgGL2/UniformValue + * author: Mike Weiblen 2003-09-18 + * + * See http://www.3dlabs.com/opengl2/ for more information regarding + * the OpenGL Shading Language. +*/ + +#ifndef OSGGL2_UNIFORMVALUE +#define OSGGL2_UNIFORMVALUE 1 + +#include +#include +#include +#include +#include + +#include + +#include + + +namespace osgGL2 { + +/////////////////////////////////////////////////////////////////////////// + +/** An abstract class to encapsulate a new value for a glUniform. + * osgGL2::ProgramObject.setUniform() constructs and sends a UniformValue + * to all its PCPOs (per-context glProgramObjects) to set the value of a + * glUniform; that value is propogated to the glProgramObjects during the + * next osgGL2::ProgramObject.apply(). + * This class is for internal use by osgGL2::ProgramObject. + */ + +class UniformValue : public osg::Referenced +{ + public: + virtual void apply( Extensions *ext, const GLhandleARB progObj ) const = 0; + + protected: + UniformValue( const char* uniformName ) : _name( uniformName ) {}; + virtual ~UniformValue() {}; + + int getLocation( Extensions *ext, const GLhandleARB progObj ) const; + + std::string _name; +}; + +typedef std::vector< osg::ref_ptr > UniformValueList; + + +/////////////////////////////////////////////////////////////////////////// + +#define META_UniformValue( typeName ) \ +class UniformValue_##typeName : public UniformValue \ +{ \ + public: \ + UniformValue_##typeName( const char* uniformName, typeName value ); \ + virtual void apply( Extensions *ext, const GLhandleARB progObj ) const; \ + protected: \ + typeName _value; \ +} + +META_UniformValue( int ); +META_UniformValue( float ); + +using namespace osg; +META_UniformValue( Vec2 ); +META_UniformValue( Vec3 ); +META_UniformValue( Vec4 ); + +} + +#endif + +/*EOF*/ + diff --git a/src/osgGL2/Extensions.cpp b/src/osgGL2/Extensions.cpp index 88770f34f..60ad5bc5c 100644 --- a/src/osgGL2/Extensions.cpp +++ b/src/osgGL2/Extensions.cpp @@ -11,7 +11,7 @@ */ /* file: src/osgGL2/Extensions.cpp - * author: Mike Weiblen 2003-07-14 + * author: Mike Weiblen 2003-09-12 * * See http://www.3dlabs.com/opengl2/ for more information regarding * the OpenGL Shading Language. @@ -477,11 +477,11 @@ void Extensions::glUniform4i(GLint location, GLint v0, GLint v1, GLint v2, GLint } } -void Extensions::glUniform1fv(GLint location, GLsizei count, GLfloat *value) const +void Extensions::glUniform1fv(GLint location, GLsizei count, const GLfloat *value) const { if (_glUniform1fv) { - typedef void (APIENTRY * Uniform1fvProc) (GLint location, GLsizei count, GLfloat *value); + typedef void (APIENTRY * Uniform1fvProc) (GLint location, GLsizei count, const GLfloat *value); ((Uniform1fvProc)_glUniform1fv)(location, count, value); } else @@ -490,11 +490,11 @@ void Extensions::glUniform1fv(GLint location, GLsizei count, GLfloat *value) con } } -void Extensions::glUniform2fv(GLint location, GLsizei count, GLfloat *value) const +void Extensions::glUniform2fv(GLint location, GLsizei count, const GLfloat *value) const { if (_glUniform2fv) { - typedef void (APIENTRY * Uniform2fvProc) (GLint location, GLsizei count, GLfloat *value); + typedef void (APIENTRY * Uniform2fvProc) (GLint location, GLsizei count, const GLfloat *value); ((Uniform2fvProc)_glUniform2fv)(location, count, value); } else @@ -503,11 +503,11 @@ void Extensions::glUniform2fv(GLint location, GLsizei count, GLfloat *value) con } } -void Extensions::glUniform3fv(GLint location, GLsizei count, GLfloat *value) const +void Extensions::glUniform3fv(GLint location, GLsizei count, const GLfloat *value) const { if (_glUniform3fv) { - typedef void (APIENTRY * Uniform3fvProc) (GLint location, GLsizei count, GLfloat *value); + typedef void (APIENTRY * Uniform3fvProc) (GLint location, GLsizei count, const GLfloat *value); ((Uniform3fvProc)_glUniform3fv)(location, count, value); } else @@ -516,11 +516,11 @@ void Extensions::glUniform3fv(GLint location, GLsizei count, GLfloat *value) con } } -void Extensions::glUniform4fv(GLint location, GLsizei count, GLfloat *value) const +void Extensions::glUniform4fv(GLint location, GLsizei count, const GLfloat *value) const { if (_glUniform4fv) { - typedef void (APIENTRY * Uniform4fvProc) (GLint location, GLsizei count, GLfloat *value); + typedef void (APIENTRY * Uniform4fvProc) (GLint location, GLsizei count, const GLfloat *value); ((Uniform4fvProc)_glUniform4fv)(location, count, value); } else @@ -529,11 +529,11 @@ void Extensions::glUniform4fv(GLint location, GLsizei count, GLfloat *value) con } } -void Extensions::glUniform1iv(GLint location, GLsizei count, GLint *value) const +void Extensions::glUniform1iv(GLint location, GLsizei count, const GLint *value) const { if (_glUniform1iv) { - typedef void (APIENTRY * Uniform1ivProc) (GLint location, GLsizei count, GLint *value); + typedef void (APIENTRY * Uniform1ivProc) (GLint location, GLsizei count, const GLint *value); ((Uniform1ivProc)_glUniform1iv)(location, count, value); } else @@ -542,11 +542,11 @@ void Extensions::glUniform1iv(GLint location, GLsizei count, GLint *value) const } } -void Extensions::glUniform2iv(GLint location, GLsizei count, GLint *value) const +void Extensions::glUniform2iv(GLint location, GLsizei count, const GLint *value) const { if (_glUniform2iv) { - typedef void (APIENTRY * Uniform2ivProc) (GLint location, GLsizei count, GLint *value); + typedef void (APIENTRY * Uniform2ivProc) (GLint location, GLsizei count, const GLint *value); ((Uniform2ivProc)_glUniform2iv)(location, count, value); } else @@ -555,11 +555,11 @@ void Extensions::glUniform2iv(GLint location, GLsizei count, GLint *value) const } } -void Extensions::glUniform3iv(GLint location, GLsizei count, GLint *value) const +void Extensions::glUniform3iv(GLint location, GLsizei count, const GLint *value) const { if (_glUniform3iv) { - typedef void (APIENTRY * Uniform3ivProc) (GLint location, GLsizei count, GLint *value); + typedef void (APIENTRY * Uniform3ivProc) (GLint location, GLsizei count, const GLint *value); ((Uniform3ivProc)_glUniform3iv)(location, count, value); } else @@ -568,11 +568,11 @@ void Extensions::glUniform3iv(GLint location, GLsizei count, GLint *value) const } } -void Extensions::glUniform4iv(GLint location, GLsizei count, GLint *value) const +void Extensions::glUniform4iv(GLint location, GLsizei count, const GLint *value) const { if (_glUniform4iv) { - typedef void (APIENTRY * Uniform4ivProc) (GLint location, GLsizei count, GLint *value); + typedef void (APIENTRY * Uniform4ivProc) (GLint location, GLsizei count, const GLint *value); ((Uniform4ivProc)_glUniform4iv)(location, count, value); } else @@ -581,11 +581,11 @@ void Extensions::glUniform4iv(GLint location, GLsizei count, GLint *value) const } } -void Extensions::glUniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, GLfloat *value) const +void Extensions::glUniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) const { if (_glUniformMatrix2fv) { - typedef void (APIENTRY * UniformMatrix2fvProc) (GLint location, GLsizei count, GLboolean transpose, GLfloat *value); + typedef void (APIENTRY * UniformMatrix2fvProc) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); ((UniformMatrix2fvProc)_glUniformMatrix2fv)(location, count, transpose, value); } else @@ -594,11 +594,11 @@ void Extensions::glUniformMatrix2fv(GLint location, GLsizei count, GLboolean tra } } -void Extensions::glUniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, GLfloat *value) const +void Extensions::glUniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) const { if (_glUniformMatrix3fv) { - typedef void (APIENTRY * UniformMatrix3fvProc) (GLint location, GLsizei count, GLboolean transpose, GLfloat *value); + typedef void (APIENTRY * UniformMatrix3fvProc) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); ((UniformMatrix3fvProc)_glUniformMatrix3fv)(location, count, transpose, value); } else @@ -607,11 +607,11 @@ void Extensions::glUniformMatrix3fv(GLint location, GLsizei count, GLboolean tra } } -void Extensions::glUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, GLfloat *value) const +void Extensions::glUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) const { if (_glUniformMatrix4fv) { - typedef void (APIENTRY * UniformMatrix4fvProc) (GLint location, GLsizei count, GLboolean transpose, GLfloat *value); + typedef void (APIENTRY * UniformMatrix4fvProc) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value); ((UniformMatrix4fvProc)_glUniformMatrix4fv)(location, count, transpose, value); } else diff --git a/src/osgGL2/GNUmakefile b/src/osgGL2/GNUmakefile index b0c73db20..061a23685 100644 --- a/src/osgGL2/GNUmakefile +++ b/src/osgGL2/GNUmakefile @@ -5,7 +5,8 @@ include $(TOPDIR)/Make/makedefs CXXFILES = \ Extensions.cpp \ Version.cpp \ - ProgramObject.cpp + ProgramObject.cpp\ + UniformValue.cpp DEF += -DOSGGL2_LIBRARY diff --git a/src/osgGL2/ProgramObject.cpp b/src/osgGL2/ProgramObject.cpp index 0667b05d2..40d94bc53 100644 --- a/src/osgGL2/ProgramObject.cpp +++ b/src/osgGL2/ProgramObject.cpp @@ -12,7 +12,7 @@ */ /* file: src/osgGL2/ProgramObject.cpp - * author: Mike Weiblen 2003-07-14 + * author: Mike Weiblen 2003-09-18 * * See http://www.3dlabs.com/opengl2/ for more information regarding * the OpenGL Shading Language. @@ -22,16 +22,18 @@ #include #include -#include #include +#include #include +#include #include #include using namespace osgGL2; + /////////////////////////////////////////////////////////////////////////// // static cache of deleted GL2 objects which may only // by actually deleted in the correct GL context. @@ -63,8 +65,12 @@ void ProgramObject::flushDeletedGL2Objects(unsigned int contextID,double /*curre { const Extensions* extensions = Extensions::Get(contextID,true); - if (!extensions->isShaderObjectsSupported()) - return; + if (!extensions->isShaderObjectsSupported()) + { + // can we really get here? + osg::notify(osg::WARN) << "flushDeletedGL2Objects not supported by OpenGL driver" << std::endl; + return; + } GL2ObjectList& vpObjectList = citr->second; @@ -81,25 +87,33 @@ void ProgramObject::flushDeletedGL2Objects(unsigned int contextID,double /*curre availableTime -= elapsedTime; } + /////////////////////////////////////////////////////////////////////////// // osgGL2::ProgramObject /////////////////////////////////////////////////////////////////////////// ProgramObject::ProgramObject() { + // To ensure all PCPOs consistently get the same values, we must + // postpone updates until all PCPOs have been created. + // They are created during ProgramObject::apply(), so let a frame + // go by before sending the updates. + _frameNumberOfLastPCPOUpdate = 1; + _enabled = true; } ProgramObject::ProgramObject(const ProgramObject& rhs, const osg::CopyOp& copyop): osg::StateAttribute(rhs, copyop) { + osg::notify(osg::FATAL) << "how got here?" << std::endl; } // virtual ProgramObject::~ProgramObject() { - for( unsigned int cxt=0; cxt<_pcpoList.size(); ++cxt ) + for( unsigned int cxt=0; cxt < _pcpoList.size(); ++cxt ) { if( ! _pcpoList[cxt] ) continue; @@ -112,10 +126,10 @@ ProgramObject::~ProgramObject() } -// mark each PCPO (per-context ProgramObject) as needing a relink +// mark all PCPOs as needing a relink void ProgramObject::dirtyProgramObject() { - for( unsigned int cxt=0; cxt<_pcpoList.size(); ++cxt ) + for( unsigned int cxt=0; cxt < _pcpoList.size(); ++cxt ) { if( ! _pcpoList[cxt] ) continue; @@ -124,58 +138,95 @@ void ProgramObject::dirtyProgramObject() } } -void ProgramObject::addShader( ShaderObject* shader ) + +// mark all attached ShaderObjects as needing a rebuild +void ProgramObject::dirtyShaderObjects() { - _shaderObjectList.push_back(shader); + for( unsigned int i=0; i < _shaderObjectList.size() ; ++i ) + { + _shaderObjectList[i]->dirtyShaderObject(); + } +} + + +void ProgramObject::addShader( ShaderObject* shadObj ) +{ + _shaderObjectList.push_back( shadObj ); + shadObj->addProgObjRef( this ); dirtyProgramObject(); } +void ProgramObject::setUniform( const char* uniformName, int value ) +{ + _univalList.push_back( new UniformValue_int( uniformName, value ) ); +} + +void ProgramObject::setUniform( const char* uniformName, float value ) +{ + _univalList.push_back( new UniformValue_float( uniformName, value ) ); +} + +void ProgramObject::setUniform( const char* uniformName, osg::Vec2 value ) +{ + _univalList.push_back( new UniformValue_Vec2( uniformName, value ) ); +} + +void ProgramObject::setUniform( const char* uniformName, osg::Vec3 value ) +{ + _univalList.push_back( new UniformValue_Vec3( uniformName, value ) ); +} + +void ProgramObject::setUniform( const char* uniformName, osg::Vec4 value ) +{ + _univalList.push_back( new UniformValue_Vec4( uniformName, value ) ); +} + + void ProgramObject::apply(osg::State& state) const { const unsigned int contextID = state.getContextID(); const Extensions* extensions = Extensions::Get(contextID,true); - if (!extensions->isShaderObjectsSupported()) - return; - - // if there are no ShaderObjects attached (ie it is "empty"), - // indicates to use GL 1.x "fixed functionality" rendering. - if( _shaderObjectList.size() == 0 ) + // if there are no ShaderObjects on this ProgramObject, + // use GL 1.x "fixed functionality" rendering. + if( !_enabled || _shaderObjectList.empty() ) { - // glProgramObject handle 0 == GL 1.x fixed functionality - extensions->glUseProgramObject( 0 ); + if( extensions->isShaderObjectsSupported() ) + { + extensions->glUseProgramObject( 0 ); + } return; } - PerContextProgObj* pcpo = getPCPO( contextID ); - - // if the first apply(), attach glShaderObjects to the glProgramObject - if( pcpo->isUnattached() ) + if( ! extensions->isShaderObjectsSupported() ) { - for( unsigned int i=0; i < _shaderObjectList.size() ; ++i ) - { - if( ! _shaderObjectList[i] ) continue; - _shaderObjectList[i]->attach( contextID, pcpo->getHandle() ); - } - pcpo->markAsAttached(); + osg::notify(osg::WARN) << "ARB_shader_objects not supported by OpenGL driver" << std::endl; + return; } - // if we're dirty, build all attached objects, then build ourself + const osg::FrameStamp* frameStamp = state.getFrameStamp(); + const int frameNumber = (frameStamp) ? frameStamp->getFrameNumber() : -1; + + updateUniforms( frameNumber ); + + PerContextProgObj* pcpo = getPCPO( contextID ); + if( pcpo->isDirty() ) { for( unsigned int i=0; i < _shaderObjectList.size() ; ++i ) { - if( ! _shaderObjectList[i] ) continue; _shaderObjectList[i]->build( contextID ); } - - if( pcpo->build() ) - pcpo->markAsClean(); + pcpo->build(); } + // make this glProgramObject part of current GL state pcpo->use(); + + // consume any pending setUniform messages + pcpo->applyUniformValues(); } @@ -183,49 +234,121 @@ ProgramObject::PerContextProgObj* ProgramObject::getPCPO(unsigned int contextID) { if( ! _pcpoList[contextID].valid() ) { - _pcpoList[contextID] = new PerContextProgObj( this, Extensions::Get(contextID,true) ); + _pcpoList[contextID] = new PerContextProgObj( this, contextID ); + + // attach all PCSOs to this new PCPO + for( unsigned int i=0; i < _shaderObjectList.size() ; ++i ) + { + _shaderObjectList[i]->attach( contextID, _pcpoList[contextID]->getHandle() ); + } } return _pcpoList[contextID].get(); } + +void ProgramObject::updateUniforms( int frameNumber ) const +{ + if( frameNumber <= _frameNumberOfLastPCPOUpdate ) + return; + + _frameNumberOfLastPCPOUpdate = frameNumber; + + if( _univalList.empty() ) + return; + + for( unsigned int cxt=0; cxt < _pcpoList.size(); ++cxt ) + { + if( ! _pcpoList[cxt] ) continue; + + PerContextProgObj* pcpo = _pcpoList[cxt].get(); + pcpo->updateUniforms( _univalList ); + } + _univalList.clear(); +} + + /////////////////////////////////////////////////////////////////////////// // PCPO : OSG abstraction of the per-context Program Object -ProgramObject::PerContextProgObj::PerContextProgObj(const ProgramObject* parent, Extensions* extensions) : - osg::Referenced() +ProgramObject::PerContextProgObj::PerContextProgObj(const ProgramObject* progObj, unsigned int contextID ) : + osg::Referenced(), + _contextID( contextID ) { - _parent = parent; - _extensions = extensions; - _handle= _extensions->glCreateProgramObject(); + _progObj = progObj; + _extensions = Extensions::Get( _contextID, true ); + _glProgObjHandle = _extensions->glCreateProgramObject(); markAsDirty(); - _unattached = true; } ProgramObject::PerContextProgObj::PerContextProgObj(const PerContextProgObj& rhs) : - osg::Referenced() + osg::Referenced(), + _contextID( rhs._contextID ) { - _parent = rhs._parent; + _progObj = rhs._progObj; _extensions = rhs._extensions; - _handle= rhs._handle; + _glProgObjHandle = rhs._glProgObjHandle ; _dirty = rhs._dirty; - _unattached = rhs._unattached; } ProgramObject::PerContextProgObj::~PerContextProgObj() { } -bool ProgramObject::PerContextProgObj::build() const +void ProgramObject::PerContextProgObj::build() { - _extensions->glLinkProgram(_handle); - return true; + int linked; + + _extensions->glLinkProgram( _glProgObjHandle ); + _extensions->glGetObjectParameteriv(_glProgObjHandle, + GL_OBJECT_LINK_STATUS_ARB, &linked); + + _dirty = (linked == 0); + if( _dirty ) + { + osg::notify(osg::WARN) << "glLinkProgram FAILED:" << std::endl; + printInfoLog(osg::WARN); + } } + void ProgramObject::PerContextProgObj::use() const { - _extensions->glUseProgramObject( _handle ); + _extensions->glUseProgramObject( _glProgObjHandle ); } +void ProgramObject::PerContextProgObj::updateUniforms( const UniformValueList& univalList ) +{ + // TODO: should the incoming list be appended rather than assigned? + _univalList = univalList; +} + +void ProgramObject::PerContextProgObj::applyUniformValues() +{ + Extensions *ext = _extensions.get(); + for( unsigned int i=0; i < _univalList.size() ; ++i ) + { + _univalList[i]->apply( ext, _glProgObjHandle ); + } + _univalList.clear(); +} + + +void ProgramObject::PerContextProgObj::printInfoLog(osg::NotifySeverity severity) const +{ + int blen = 0; // length of buffer to allocate + int slen = 0; // strlen GL actually wrote to buffer + + _extensions->glGetObjectParameteriv(_glProgObjHandle, GL_OBJECT_INFO_LOG_LENGTH_ARB , &blen); + if (blen > 1) + { + GLcharARB* infoLog = new GLcharARB[blen]; + _extensions->glGetInfoLog(_glProgObjHandle, blen, &slen, infoLog); + osg::notify(severity) << infoLog << std::endl; + delete infoLog; + } +} + + /////////////////////////////////////////////////////////////////////////// // osgGL2::ShaderObject /////////////////////////////////////////////////////////////////////////// @@ -260,13 +383,19 @@ ShaderObject::~ShaderObject() // mark each PCSO (per-context Shader Object) as needing a recompile void ShaderObject::dirtyShaderObject() { - for( unsigned int cxt=0; cxt<_pcsoList.size(); ++cxt ) + for( unsigned int cxt=0; cxt < _pcsoList.size(); ++cxt ) { if( ! _pcsoList[cxt] ) continue; PerContextShaderObj* pcso = _pcsoList[cxt].get(); pcso->markAsDirty(); } + + // mark attached ProgramObjects dirty as well + for( unsigned int i=0; i < _programObjectList.size(); ++i ) + { + _programObjectList[i]->dirtyProgramObject(); + } } void ShaderObject::setShaderSource( const char* sourceText ) @@ -302,17 +431,25 @@ bool ShaderObject::loadShaderSourceFromFile( const char* fileName ) } +const char* ShaderObject::getTypename() const +{ + switch( getType() ) + { + case VERTEX: return "Vertex"; + case FRAGMENT: return "Fragment"; + default: return "UNKNOWN"; + } +} -bool ShaderObject::build(unsigned int contextID ) const + +void ShaderObject::build(unsigned int contextID ) const { PerContextShaderObj* pcso = getPCSO( contextID ); if( pcso->isDirty() ) { - if( pcso->build() ) - pcso->markAsClean(); + pcso->build(); } - return true; /*TODO*/ } @@ -320,34 +457,44 @@ ShaderObject::PerContextShaderObj* ShaderObject::getPCSO(unsigned int contextID) { if( ! _pcsoList[contextID].valid() ) { - _pcsoList[contextID] = new PerContextShaderObj( this, Extensions::Get(contextID,true) ); + _pcsoList[contextID] = new PerContextShaderObj( this, contextID ); } return _pcsoList[contextID].get(); } + void ShaderObject::attach(unsigned int contextID, GLhandleARB progObj) const { getPCSO( contextID )->attach( progObj ); } + +void ShaderObject::addProgObjRef( ProgramObject* progObj ) +{ + _programObjectList.push_back( progObj ); +} + + /////////////////////////////////////////////////////////////////////////// // PCSO : OSG abstraction of the per-context Shader Object -ShaderObject::PerContextShaderObj::PerContextShaderObj(const ShaderObject* parent, Extensions* extensions) : - osg::Referenced() +ShaderObject::PerContextShaderObj::PerContextShaderObj(const ShaderObject* shadObj, unsigned int contextID) : + osg::Referenced(), + _contextID( contextID ) { - _parent = parent; - _extensions = extensions; - _handle = _extensions->glCreateShaderObject( parent->getType() ); + _shadObj = shadObj; + _extensions = Extensions::Get( _contextID, true ); + _glShaderObjHandle = _extensions->glCreateShaderObject( shadObj->getType() ); markAsDirty(); } ShaderObject::PerContextShaderObj::PerContextShaderObj(const PerContextShaderObj& rhs) : - osg::Referenced() + osg::Referenced(), + _contextID( rhs._contextID ) { - _parent = rhs._parent; + _shadObj = rhs._shadObj; _extensions = rhs._extensions; - _handle = rhs._handle; + _glShaderObjHandle = rhs._glShaderObjHandle; _dirty = rhs._dirty; } @@ -355,21 +502,42 @@ ShaderObject::PerContextShaderObj::~PerContextShaderObj() { } -bool ShaderObject::PerContextShaderObj::build() +void ShaderObject::PerContextShaderObj::build() { - const char* sourceText = _parent->getShaderSource().c_str(); + int compiled; + const char* sourceText = _shadObj->getShaderSource().c_str(); - _extensions->glShaderSource( _handle, 1, &sourceText, NULL ); - _extensions->glCompileShader( _handle ); + _extensions->glShaderSource( _glShaderObjHandle, 1, &sourceText, NULL ); + _extensions->glCompileShader( _glShaderObjHandle ); + _extensions->glGetObjectParameteriv(_glShaderObjHandle, + GL_OBJECT_COMPILE_STATUS_ARB, &compiled); - // _extensions->glAttachObject( _handle, vertShaderObject ); - - return true; + _dirty = (compiled == 0); + if( _dirty ) + { + osg::notify(osg::WARN) << _shadObj->getTypename() << " glCompileShader FAILED:" << std::endl; + printInfoLog(osg::WARN); + } } -void ShaderObject::PerContextShaderObj::attach(GLhandleARB progObj) +void ShaderObject::PerContextShaderObj::attach(GLhandleARB progObj) const { - _extensions->glAttachObject(progObj, _handle); + _extensions->glAttachObject( progObj, _glShaderObjHandle ); +} + +void ShaderObject::PerContextShaderObj::printInfoLog(osg::NotifySeverity severity) const +{ + int blen = 0; // length of buffer to allocate + int slen = 0; // strlen GL actually wrote to buffer + + _extensions->glGetObjectParameteriv(_glShaderObjHandle, GL_OBJECT_INFO_LOG_LENGTH_ARB , &blen); + if (blen > 1) + { + GLcharARB* infoLog = new GLcharARB[blen]; + _extensions->glGetInfoLog(_glShaderObjHandle, blen, &slen, infoLog); + osg::notify(severity) << infoLog << std::endl; + delete infoLog; + } } /*EOF*/ diff --git a/src/osgGL2/UniformValue.cpp b/src/osgGL2/UniformValue.cpp new file mode 100644 index 000000000..ef8217815 --- /dev/null +++ b/src/osgGL2/UniformValue.cpp @@ -0,0 +1,98 @@ +/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2003 Robert Osfield + * Copyright (C) 2003 3Dlabs Inc. Ltd. + * + * This application is open source and may be redistributed and/or modified + * freely and without restriction, both in commericial and non commericial + * applications, as long as this copyright notice is maintained. + * + * This application is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +*/ + +/* file: src/osgGL2/UniformValue + * author: Mike Weiblen 2003-09-12 + * + * See http://www.3dlabs.com/opengl2/ for more information regarding + * the OpenGL Shading Language. +*/ + +#include + +#include +#include + +using namespace osgGL2; +using namespace osg; + +int UniformValue::getLocation( Extensions *ext, const GLhandleARB progObj ) const +{ + GLint loc = ext->glGetUniformLocation( progObj, _name.c_str() ); + if( loc == -1 ) + { + osg::notify(osg::INFO) << "Uniform \"" << _name << + "\" not found in ProgramObject" << std::endl; + } + return loc; +} + +/////////////////////////////////////////////////////////////////////////// + +#define META_UniformValueCtor( typeName ) \ +UniformValue_##typeName::UniformValue_##typeName( const char* uniformName, typeName value ) : \ + UniformValue( uniformName ) \ +{ _value = value; } \ + + +META_UniformValueCtor( int ); +void UniformValue_int::apply( Extensions *ext, const GLhandleARB progObj ) const +{ + int loc = getLocation( ext, progObj ); + if( loc != -1 ) + { + ext->glUniform1i( loc, _value ); + } +} + +META_UniformValueCtor( float ); +void UniformValue_float::apply( Extensions *ext, const GLhandleARB progObj ) const +{ + int loc = getLocation( ext, progObj ); + if( loc != -1 ) + { + ext->glUniform1f( loc, _value ); + } +} + +META_UniformValueCtor( Vec2 ); +void UniformValue_Vec2::apply( Extensions *ext, const GLhandleARB progObj ) const +{ + int loc = getLocation( ext, progObj ); + if( loc != -1 ) + { + ext->glUniform2fv( loc, 1, _value.ptr() ); + } +} + +META_UniformValueCtor( Vec3 ); +void UniformValue_Vec3::apply( Extensions *ext, const GLhandleARB progObj ) const +{ + int loc = getLocation( ext, progObj ); + if( loc != -1 ) + { + ext->glUniform3fv( loc, 1, _value.ptr() ); + } +} + +META_UniformValueCtor( Vec4 ); +void UniformValue_Vec4::apply( Extensions *ext, const GLhandleARB progObj ) const +{ + int loc = getLocation( ext, progObj ); + if( loc != -1 ) + { + ext->glUniform4fv( loc, 1, _value.ptr() ); + } +} + +/*EOF*/ + diff --git a/src/osgGL2/Version.cpp b/src/osgGL2/Version.cpp index b96c34f08..240d15178 100644 --- a/src/osgGL2/Version.cpp +++ b/src/osgGL2/Version.cpp @@ -2,7 +2,7 @@ const char* osgGL2GetVersion() { - return "0.1.0"; + return "0.2.3"; } diff --git a/src/osgPlugins/obj/ReaderWriterOBJ.cpp b/src/osgPlugins/obj/ReaderWriterOBJ.cpp index c6920dfca..86494cdd2 100644 --- a/src/osgPlugins/obj/ReaderWriterOBJ.cpp +++ b/src/osgPlugins/obj/ReaderWriterOBJ.cpp @@ -581,10 +581,12 @@ osg::Drawable* ReaderWriterOBJ::makeDrawable_useSeperateIndices(GLMmodel* obj, G geom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::TRIANGLES,0,ntris*3)); } - - osgUtil::SmoothingVisitor tsv; - tsv.smooth(*geom); + if (obj->numnormals==0) + { + osgUtil::SmoothingVisitor tsv; + tsv.smooth(*geom); + } return geom; }