From 01a896ef5b5894f1026575c0d750fc6d0b07a394 Mon Sep 17 00:00:00 2001 From: timoore Date: Sat, 8 Aug 2009 10:19:56 +0000 Subject: [PATCH] New effects from Till Busch: crops, water, landmass As shown at LinuxTag, with modifications from Tim Moore: the base landmass texture is mixed with the steepness and snow effects. Till's new syntax for textures in effect files was also added. syntax for textures. Also, syntax for accessing internal textures, such as Till's 3D noise texture, was added. Several bugs in the effect inheritance algorithm were fixed. --- projects/VC7.1/SimGear.vcproj | 20 ++ simgear/scene/material/Effect.cxx | 205 +++------------- simgear/scene/material/EffectBuilder.cxx | 54 ++++ simgear/scene/material/EffectBuilder.hxx | 157 ++++++++++++ simgear/scene/material/Makefile.am | 7 +- simgear/scene/material/Noise.cxx | 287 ++++++++++++++++++++++ simgear/scene/material/Noise.hxx | 51 ++++ simgear/scene/material/TextureBuilder.cxx | 277 +++++++++++++++++++++ simgear/scene/material/TextureBuilder.hxx | 34 +++ simgear/scene/material/makeEffect.cxx | 40 ++- simgear/scene/material/mat.cxx | 9 +- simgear/scene/material/mat.hxx | 1 + 12 files changed, 945 insertions(+), 197 deletions(-) create mode 100644 simgear/scene/material/EffectBuilder.cxx create mode 100644 simgear/scene/material/EffectBuilder.hxx create mode 100644 simgear/scene/material/Noise.cxx create mode 100644 simgear/scene/material/Noise.hxx create mode 100644 simgear/scene/material/TextureBuilder.cxx create mode 100644 simgear/scene/material/TextureBuilder.hxx diff --git a/projects/VC7.1/SimGear.vcproj b/projects/VC7.1/SimGear.vcproj index 1c1bb2c8..36dc8e09 100755 --- a/projects/VC7.1/SimGear.vcproj +++ b/projects/VC7.1/SimGear.vcproj @@ -805,6 +805,12 @@ + + + + @@ -823,6 +829,20 @@ + + + + + + + + + + diff --git a/simgear/scene/material/Effect.cxx b/simgear/scene/material/Effect.cxx index a50dfd78..496d64f4 100644 --- a/simgear/scene/material/Effect.cxx +++ b/simgear/scene/material/Effect.cxx @@ -19,8 +19,10 @@ #endif #include "Effect.hxx" +#include "EffectBuilder.hxx" #include "Technique.hxx" #include "Pass.hxx" +#include "TextureBuilder.hxx" #include #include @@ -44,7 +46,10 @@ #include #include #include +#include #include +#include +#include #include #include #include @@ -142,56 +147,6 @@ struct InstallAttributeBuilder passAttrMap.insert(make_pair(name, new T)); } }; -// Simple tables of strings and OSG constants. The table intialization -// *must* be in alphabetical order. -template -struct EffectNameValue -{ - // Don't use std::pair because we want to use aggregate intialization. - - const char* first; - T second; - class Compare - { - private: - static bool compare(const char* lhs, const char* rhs) - { - return strcmp(lhs, rhs) < 0; - } - public: - bool operator()(const EffectNameValue& lhs, - const EffectNameValue& rhs) const - { - return compare(lhs.first, rhs.first); - } - bool operator()(const char* lhs, const EffectNameValue& rhs) const - { - return compare(lhs, rhs.first); - } - bool operator()(const EffectNameValue& lhs, const char* rhs) const - { - return compare (lhs.first, rhs); - } - }; -}; - -template -bool findAttr(const ENV (&attrs)[N], const SGPropertyNode* prop, T& result) -{ - if (!prop) - return false; - const char* name = prop->getStringValue(); - if (!name) - return false; - std::pair itrs - = std::equal_range(&attrs[0], &attrs[N], name, typename ENV::Compare()); - if (itrs.first == itrs.second) { - return false; - } else { - result = itrs.first->second; - return true; - } -} void buildPass(Effect* effect, Technique* tniq, const SGPropertyNode* prop, const osgDB::ReaderWriter::Options* options) @@ -235,35 +190,6 @@ osg::Vec4f getColor(const SGPropertyNode* prop) } } -// Given a property node from a pass, get its value either from it or -// from the effect parameters. -const SGPropertyNode* getEffectPropertyNode(Effect* effect, - const SGPropertyNode* prop) -{ - if (!prop) - return 0; - if (prop->nChildren() > 0) { - const SGPropertyNode* useProp = prop->getChild("use"); - if (!useProp || !effect->parametersProp) - return prop; - return effect->parametersProp->getNode(useProp->getStringValue()); - } - return prop; -} - -// Get a named child property from pass parameters or effect -// parameters. -const SGPropertyNode* getEffectPropertyChild(Effect* effect, - const SGPropertyNode* prop, - const char* name) -{ - const SGPropertyNode* child = prop->getChild(name); - if (!child) - return 0; - else - return getEffectPropertyNode(effect, child); -} - struct LightingBuilder : public PassAttributeBuilder { void buildAttribute(Effect* effect, Pass* pass, const SGPropertyNode* prop, @@ -467,25 +393,6 @@ struct AlphaTestBuilder : public PassAttributeBuilder InstallAttributeBuilder installAlphaTest("alpha-test"); -EffectNameValue filterModes[] = -{ - { "linear", Texture::LINEAR }, - { "linear-mipmap-linear", Texture::LINEAR_MIPMAP_LINEAR}, - { "linear-mipmap-nearest", Texture::LINEAR_MIPMAP_NEAREST}, - { "nearest", Texture::NEAREST}, - { "nearest-mipmap-linear", Texture::NEAREST_MIPMAP_LINEAR}, - { "nearest-mipmap-nearest", Texture::NEAREST_MIPMAP_NEAREST} -}; - -EffectNameValue wrapModes[] = -{ - {"clamp", Texture::CLAMP}, - {"clamp-to-border", Texture::CLAMP_TO_BORDER}, - {"clamp-to-edge", Texture::CLAMP_TO_EDGE}, - {"mirror", Texture::MIRROR}, - {"repeat", Texture::REPEAT} -}; - EffectNameValue texEnvModes[] = { {"add", TexEnv::ADD}, @@ -514,13 +421,6 @@ TexEnv* buildTexEnv(Effect* effect, const SGPropertyNode* prop) return env; } -typedef boost::tuple TexTuple; - -typedef map > TexMap; - -TexMap texMap; struct TextureUnitBuilder : PassAttributeBuilder { @@ -532,68 +432,7 @@ void TextureUnitBuilder::buildAttribute(Effect* effect, Pass* pass, const SGPropertyNode* prop, const osgDB::ReaderWriter::Options* options) { - // First, all the texture properties - const SGPropertyNode* pTexture2d = prop->getChild("texture2d"); - if (!pTexture2d) - return; - const SGPropertyNode* pImage - = getEffectPropertyChild(effect, pTexture2d, "image"); - if (!pImage) - return; - const char* imageName = pImage->getStringValue(); - Texture::FilterMode minFilter = Texture::LINEAR_MIPMAP_LINEAR; - findAttr(filterModes, getEffectPropertyChild(effect, pTexture2d, "filter"), - minFilter); - Texture::FilterMode magFilter = Texture::LINEAR; - findAttr(filterModes, getEffectPropertyChild(effect, pTexture2d, - "mag-filter"), - magFilter); - const SGPropertyNode* pWrapS - = getEffectPropertyChild(effect, pTexture2d, "wrap-s"); - Texture::WrapMode sWrap = Texture::CLAMP; - findAttr(wrapModes, pWrapS, sWrap); - const SGPropertyNode* pWrapT - = getEffectPropertyChild(effect, pTexture2d, "wrap-t"); - Texture::WrapMode tWrap = Texture::CLAMP; - findAttr(wrapModes, pWrapT, tWrap); - const SGPropertyNode* pWrapR - = getEffectPropertyChild(effect, pTexture2d, "wrap-r"); - Texture::WrapMode rWrap = Texture::CLAMP; - findAttr(wrapModes, pWrapR, rWrap); - TexTuple tuple(imageName, minFilter, magFilter, sWrap, tWrap, rWrap); - TexMap::iterator texIter = texMap.find(tuple); - Texture2D* texture = 0; - if (texIter != texMap.end()) { - texture = texIter->second.get(); - } else { - texture = new Texture2D; - osgDB::ReaderWriter::ReadResult result - = osgDB::Registry::instance()->readImage(imageName, options); - if (result.success()) { - osg::Image* image = result.getImage(); - texture->setImage(image); - int s = image->s(); - int t = image->t(); - - if (s <= t && 32 <= s) { - SGSceneFeatures::instance()->setTextureCompression(texture); - } else if (t < s && 32 <= t) { - SGSceneFeatures::instance()->setTextureCompression(texture); - } - texture->setMaxAnisotropy(SGSceneFeatures::instance() - ->getTextureFilter()); - } else { - SG_LOG(SG_INPUT, SG_ALERT, "failed to load effect texture file " - << imageName); - } - // texture->setDataVariance(osg::Object::STATIC); - texture->setFilter(Texture::MIN_FILTER, minFilter); - texture->setFilter(Texture::MAG_FILTER, magFilter); - texture->setWrap(Texture::WRAP_S, sWrap); - texture->setWrap(Texture::WRAP_T, tWrap); - texture->setWrap(Texture::WRAP_R, rWrap); - texMap.insert(make_pair(tuple, texture)); - } + // Decode the texture unit int unit = 0; const SGPropertyNode* pUnit = prop->getChild("unit"); @@ -609,6 +448,21 @@ void TextureUnitBuilder::buildAttribute(Effect* effect, Pass* pass, << lex.what()); } } + const SGPropertyNode* pType = prop->getChild("type"); + string type; + if (!pType) + type = "2d"; + else + type = pType->getStringValue(); + Texture* texture = 0; + try { + texture = TextureBuilder::buildFromType(effect, type, prop, + options); + } + catch (BuilderException& e) { + SG_LOG(SG_INPUT, SG_ALERT, "No image file for texture, using white "); + texture = StateAttributeFactory::instance()->getWhiteTexture(); + } pass->setTextureAttributeAndModes(unit, texture); const SGPropertyNode* envProp = prop->getChild("environment"); if (envProp) { @@ -618,6 +472,8 @@ void TextureUnitBuilder::buildAttribute(Effect* effect, Pass* pass, } } + + InstallAttributeBuilder textureUnitBuilder("texture-unit"); typedef map > ProgramMap; @@ -626,6 +482,18 @@ ProgramMap programMap; typedef map > ShaderMap; ShaderMap shaderMap; +void reload_shaders() +{ + for(ShaderMap::iterator sitr = shaderMap.begin(); sitr != shaderMap.end(); ++sitr) + { + Shader *shader = sitr->second.get(); + string fileName = osgDB::findDataFile(sitr->first); + if (!fileName.empty()) { + shader->loadShaderSourceFromFile(fileName); + } + } +} + struct ShaderProgramBuilder : PassAttributeBuilder { void buildAttribute(Effect* effect, Pass* pass, const SGPropertyNode* prop, @@ -662,6 +530,7 @@ void ShaderProgramBuilder::buildAttribute(Effect* effect, Pass* pass, program = pitr->second.get(); } else { program = new Program; + program->setName(programKey); // Add vertex shaders, then fragment shaders PropertyList& pvec = pVertShaders; Shader::Type stype = Shader::VERTEX; @@ -678,8 +547,8 @@ void ShaderProgramBuilder::buildAttribute(Effect* effect, Pass* pass, if (!fileName.empty()) { ref_ptr shader = new Shader(stype); if (shader->loadShaderSourceFromFile(fileName)) { - shaderMap.insert(make_pair(shaderName, shader)); program->addShader(shader.get()); + shaderMap.insert(make_pair(shaderName, shader)); } } } diff --git a/simgear/scene/material/EffectBuilder.cxx b/simgear/scene/material/EffectBuilder.cxx new file mode 100644 index 00000000..b1f09207 --- /dev/null +++ b/simgear/scene/material/EffectBuilder.cxx @@ -0,0 +1,54 @@ +#include "EffectBuilder.hxx" +#include "Effect.hxx" + +namespace simgear +{ + +// Given a property node from a pass, get its value either from it or +// from the effect parameters. +const SGPropertyNode* getEffectPropertyNode(Effect* effect, + const SGPropertyNode* prop) +{ + if (!prop) + return 0; + if (prop->nChildren() > 0) { + const SGPropertyNode* useProp = prop->getChild("use"); + if (!useProp || !effect->parametersProp) + return prop; + return effect->parametersProp->getNode(useProp->getStringValue()); + } + return prop; +} + +// Get a named child property from pass parameters or effect +// parameters. +const SGPropertyNode* getEffectPropertyChild(Effect* effect, + const SGPropertyNode* prop, + const char* name) +{ + const SGPropertyNode* child = prop->getChild(name); + if (!child) + return 0; + else + return getEffectPropertyNode(effect, child); +} + +BuilderException::BuilderException() +{ +} + +BuilderException::BuilderException(const char* message, const char* origin) + : sg_exception(message, origin) +{ +} + +BuilderException::BuilderException(const std::string& message, + const std::string& origin) + : sg_exception(message, origin) +{ +} + +BuilderException::~BuilderException() throw() +{ +} +} diff --git a/simgear/scene/material/EffectBuilder.hxx b/simgear/scene/material/EffectBuilder.hxx new file mode 100644 index 00000000..831c9fab --- /dev/null +++ b/simgear/scene/material/EffectBuilder.hxx @@ -0,0 +1,157 @@ +// Copyright (C) 2009 Tim Moore timoore@redhat.com +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library 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. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +#ifndef SIMGEAR_EFFECTBUILDER_HXX +#define SIMGEAR_EFFECTBUILDER_HXX 1 + +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + +/** + * Support classes for parsing effects. + */ + +namespace simgear +{ +class Effect; + +/** + * Builder that returns an object, probably an OSG object. + */ +template +class EffectBuilder : public SGReferenced +{ +public: + virtual ~EffectBuilder() {} + virtual T* build(Effect* effect, const SGPropertyNode*, + const osgDB::ReaderWriter::Options* options) = 0; + static T* buildFromType(Effect* effect, const std::string& type, + const SGPropertyNode*props, + const osgDB::ReaderWriter::Options* options) + { + BuilderMap& builderMap = getMap(); + typename BuilderMap::iterator iter = builderMap.find(type); + if (iter != builderMap.end()) + return iter->second->build(effect, props, options); + else + return 0; + } + struct Registrar; + friend struct Registrar; + struct Registrar + { + Registrar(const std::string& type, EffectBuilder* builder) + { + getMap().insert(std::make_pair(type, builder)); + } + }; +protected: + typedef std::map > BuilderMap; + struct BuilderMapSingleton : public simgear::Singleton + { + BuilderMap _map; + }; + static BuilderMap& getMap() + { + return BuilderMapSingleton::instance()->_map; + } +}; + +// Simple tables of strings and constants. The table intialization +// *must* be in alphabetical order. +template +struct EffectNameValue +{ + // Don't use std::pair because we want to use aggregate intialization. + + const char* first; + T second; + class Compare + { + private: + static bool compare(const char* lhs, const char* rhs) + { + return std::strcmp(lhs, rhs) < 0; + } + public: + bool operator()(const EffectNameValue& lhs, + const EffectNameValue& rhs) const + { + return compare(lhs.first, rhs.first); + } + bool operator()(const char* lhs, const EffectNameValue& rhs) const + { + return compare(lhs, rhs.first); + } + bool operator()(const EffectNameValue& lhs, const char* rhs) const + { + return compare (lhs.first, rhs); + } + }; +}; + +template +bool findAttr(const ENV (&attrs)[N], const SGPropertyNode* prop, T& result) +{ + if (!prop) + return false; + const char* name = prop->getStringValue(); + if (!name) + return false; + std::pair itrs + = std::equal_range(&attrs[0], &attrs[N], name, typename ENV::Compare()); + if (itrs.first == itrs.second) { + return false; + } else { + result = itrs.first->second; + return true; + } +} + +/** + * Given a property node from a pass, get its value either from it or + * from the effect parameters. + */ + +const SGPropertyNode* getEffectPropertyNode(Effect* effect, + const SGPropertyNode* prop); +/** + * Get a named child property from pass parameters or effect + * parameters. + */ +const SGPropertyNode* getEffectPropertyChild(Effect* effect, + const SGPropertyNode* prop, + const char* name); + +class BuilderException : public sg_exception +{ +public: + BuilderException(); + BuilderException(const char* message, const char* origin = 0); + BuilderException(const std::string& message, const std::string& = ""); + virtual ~BuilderException() throw(); +}; +} +#endif diff --git a/simgear/scene/material/Makefile.am b/simgear/scene/material/Makefile.am index aee10b42..031e4214 100644 --- a/simgear/scene/material/Makefile.am +++ b/simgear/scene/material/Makefile.am @@ -6,25 +6,30 @@ noinst_HEADERS = include_HEADERS = \ Effect.hxx \ + EffectBuilder.hxx \ EffectCullVisitor.hxx \ EffectGeode.hxx \ GLPredicate.hxx \ Pass.hxx \ Technique.hxx \ + TextureBuilder.hxx \ mat.hxx \ matlib.hxx \ matmodel.hxx libsgmaterial_a_SOURCES = \ Effect.cxx \ + EffectBuilder.cxx \ EffectCullVisitor.cxx \ EffectGeode.cxx \ GLPredicate.cxx \ Pass.cxx \ Technique.cxx \ + TextureBuilder.cxx \ makeEffect.cxx \ mat.cxx \ matlib.cxx \ - matmodel.cxx + matmodel.cxx \ + Noise.cxx INCLUDES = -I$(top_srcdir) diff --git a/simgear/scene/material/Noise.cxx b/simgear/scene/material/Noise.cxx new file mode 100644 index 00000000..23ecd790 --- /dev/null +++ b/simgear/scene/material/Noise.cxx @@ -0,0 +1,287 @@ +/* OpenSceneGraph example, osgshaders. +* +* 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. +*/ + +/************************************************************************ + * * + * 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 + +#include +#include + +#include "Noise.hxx" + +namespace simgear +{ +using namespace std; +using namespace osg; + +// Hack to force inclusion of TextureBuilder.cxx in library +osg::Texture* TextureBuilder::buildFromType(Effect* effect, const string& type, + const SGPropertyNode*props, + const osgDB::ReaderWriter::Options* + options) +{ + return EffectBuilder::buildFromType(effect, type, props, options); +} + +typedef boost::tuple TexTuple; + +namespace +{ +EffectNameValue filterModes[] = +{ + { "linear", Texture::LINEAR }, + { "linear-mipmap-linear", Texture::LINEAR_MIPMAP_LINEAR}, + { "linear-mipmap-nearest", Texture::LINEAR_MIPMAP_NEAREST}, + { "nearest", Texture::NEAREST}, + { "nearest-mipmap-linear", Texture::NEAREST_MIPMAP_LINEAR}, + { "nearest-mipmap-nearest", Texture::NEAREST_MIPMAP_NEAREST} +}; + +EffectNameValue wrapModes[] = +{ + {"clamp", Texture::CLAMP}, + {"clamp-to-border", Texture::CLAMP_TO_BORDER}, + {"clamp-to-edge", Texture::CLAMP_TO_EDGE}, + {"mirror", Texture::MIRROR}, + {"repeat", Texture::REPEAT} +}; + + + +TexTuple makeTexTuple(Effect* effect, const SGPropertyNode* props, + const osgDB::ReaderWriter::Options* options, + const string& texType) +{ + Texture::FilterMode minFilter = Texture::LINEAR_MIPMAP_LINEAR; + findAttr(filterModes, getEffectPropertyChild(effect, props, "filter"), + minFilter); + Texture::FilterMode magFilter = Texture::LINEAR; + findAttr(filterModes, getEffectPropertyChild(effect, props, + "mag-filter"), + magFilter); + const SGPropertyNode* pWrapS + = getEffectPropertyChild(effect, props, "wrap-s"); + Texture::WrapMode sWrap = Texture::CLAMP; + findAttr(wrapModes, pWrapS, sWrap); + const SGPropertyNode* pWrapT + = getEffectPropertyChild(effect, props, "wrap-t"); + Texture::WrapMode tWrap = Texture::CLAMP; + findAttr(wrapModes, pWrapT, tWrap); + const SGPropertyNode* pWrapR + = getEffectPropertyChild(effect, props, "wrap-r"); + Texture::WrapMode rWrap = Texture::CLAMP; + findAttr(wrapModes, pWrapR, rWrap); + const SGPropertyNode* pImage + = getEffectPropertyChild(effect, props, "image"); + string imageName; + if (pImage) + imageName = pImage->getStringValue(); + string absFileName = osgDB::findDataFile(imageName, options); + return TexTuple(absFileName, minFilter, magFilter, sWrap, tWrap, rWrap, + texType); +} + +void setAttrs(const TexTuple& attrs, Texture* tex, + const osgDB::ReaderWriter::Options* options) +{ + const string& imageName = attrs.get<0>(); + if (imageName.empty()) { + throw BuilderException("no image file"); + } else { + osgDB::ReaderWriter::ReadResult result + = osgDB::Registry::instance()->readImage(imageName, options); + if (result.success()) { + osg::Image* image = result.getImage(); + tex->setImage(GL_FRONT_AND_BACK, image); + int s = image->s(); + int t = image->t(); + if (s <= t && 32 <= s) { + SGSceneFeatures::instance()->setTextureCompression(tex); + } else if (t < s && 32 <= t) { + SGSceneFeatures::instance()->setTextureCompression(tex); + } + tex->setMaxAnisotropy(SGSceneFeatures::instance() + ->getTextureFilter()); + } else { + SG_LOG(SG_INPUT, SG_ALERT, "failed to load effect texture file " + << imageName); + } + } + // texture->setDataVariance(osg::Object::STATIC); + tex->setFilter(Texture::MIN_FILTER, attrs.get<1>()); + tex->setFilter(Texture::MAG_FILTER, attrs.get<2>()); + tex->setWrap(Texture::WRAP_S, attrs.get<3>()); + tex->setWrap(Texture::WRAP_T, attrs.get<4>()); + tex->setWrap(Texture::WRAP_R, attrs.get<5>()); +} +} + +template +class TexBuilder : public TextureBuilder +{ +public: + TexBuilder(const string& texType) : _type(texType) {} + Texture* build(Effect* effect, const SGPropertyNode*, + const osgDB::ReaderWriter::Options* options); +protected: + typedef map > TexMap; + TexMap texMap; + const string _type; +}; + +template +Texture* TexBuilder::build(Effect* effect, const SGPropertyNode* props, + const osgDB::ReaderWriter::Options* options) +{ + TexTuple attrs = makeTexTuple(effect, props, options, _type); + typename TexMap::iterator itr = texMap.find(attrs); + if (itr != texMap.end()) + return itr->second.get(); + T* tex = new T; + setAttrs(attrs, tex, options); + texMap.insert(make_pair(attrs, tex)); + return tex; +} + + +namespace +{ +TextureBuilder::Registrar install1D("1d", new TexBuilder("1d")); +TextureBuilder::Registrar install2D("2d", new TexBuilder("2d")); +TextureBuilder::Registrar install3D("3d", new TexBuilder("3d")); +} + +class WhiteTextureBuilder : public TextureBuilder +{ +public: + Texture* build(Effect* effect, const SGPropertyNode*, + const osgDB::ReaderWriter::Options* options); +}; + +Texture* WhiteTextureBuilder::build(Effect* effect, const SGPropertyNode*, + const osgDB::ReaderWriter::Options* options) +{ + return StateAttributeFactory::instance()->getWhiteTexture(); +} + +namespace +{ +TextureBuilder::Registrar installWhite("white", new WhiteTextureBuilder); +} + +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::WARN) << "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::WARN) << "DONE" << std::endl; + return image; +} + +class NoiseBuilder : public TextureBuilder +{ +public: + Texture* build(Effect* effect, const SGPropertyNode*, + const osgDB::ReaderWriter::Options* options); +protected: + typedef map > NoiseMap; + NoiseMap _noises; +}; + +Texture* NoiseBuilder::build(Effect* effect, const SGPropertyNode* props, + const osgDB::ReaderWriter::Options* options) +{ + int texSize = 64; + const SGPropertyNode* sizeProp = getEffectPropertyChild(effect, props, + "size"); + if (sizeProp) + texSize = sizeProp->getValue(); + NoiseMap::iterator itr = _noises.find(texSize); + if (itr != _noises.end()) + return itr->second.get(); + 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) ); + _noises.insert(make_pair(texSize, noiseTexture)); + return noiseTexture; +} + +namespace +{ +TextureBuilder::Registrar installNoise("noise", new NoiseBuilder); +} + +} diff --git a/simgear/scene/material/TextureBuilder.hxx b/simgear/scene/material/TextureBuilder.hxx new file mode 100644 index 00000000..259ef614 --- /dev/null +++ b/simgear/scene/material/TextureBuilder.hxx @@ -0,0 +1,34 @@ +// Copyright (C) 2009 Tim Moore timoore@redhat.com +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library 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. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +#ifndef SIMGEAR_TEXTUREBUILDER_HXX +#define SIMGEAR_TEXTUREBUILDER_HXX 1 + +#include +#include "EffectBuilder.hxx" + +namespace simgear +{ +class TextureBuilder : public EffectBuilder +{ +public: + // Hack to force inclusion of TextureBuilder.cxx in library + static osg::Texture* buildFromType(Effect* effect, const std::string& type, + const SGPropertyNode*props, + const osgDB::ReaderWriter::Options* options); +}; +} +#endif diff --git a/simgear/scene/material/makeEffect.cxx b/simgear/scene/material/makeEffect.cxx index 913fcfbd..0cdad0d9 100644 --- a/simgear/scene/material/makeEffect.cxx +++ b/simgear/scene/material/makeEffect.cxx @@ -55,10 +55,7 @@ OpenThreads::ReentrantMutex effectMutex; * of the result. Otherwise the left children are placed after the * right children in the result. * - * Nodes are considered identical if: - * Their names are equal; - * Either they both have "name" children and their values are equal; - * or their indexes are equal. + * Nodes are considered equal if their names and indexes are equal. */ struct PropPredicate @@ -69,15 +66,7 @@ struct PropPredicate { if (strcmp(node->getName(), arg->getName())) return false; - const SGPropertyNode* nodeName = node->getChild("name"); - const SGPropertyNode* argName = arg->getChild("name"); - if (nodeName && argName) - return !strcmp(nodeName->getStringValue(), - argName->getStringValue()); - else if (!(nodeName || argName)) - return node->getIndex() == arg->getIndex(); - else - return false; + return node->getIndex() == arg->getIndex(); } const SGPropertyNode* node; }; @@ -93,8 +82,6 @@ void mergePropertyTrees(SGPropertyNode* resultNode, RawPropVector leftChildren; for (int i = 0; i < left->nChildren(); ++i) leftChildren.push_back(left->getChild(i)); - // Maximum index of nodes (with same names) we've created. - map nodeIndex; // Merge identical nodes for (int i = 0; i < right->nChildren(); ++i) { const SGPropertyNode* node = right->getChild(i); @@ -102,8 +89,7 @@ void mergePropertyTrees(SGPropertyNode* resultNode, = find_if(leftChildren.begin(), leftChildren.end(), PropPredicate(node)); SGPropertyNode* newChild - = resultNode->getChild(node->getName(), - nodeIndex[node->getName()]++, true); + = resultNode->getChild(node->getName(), node->getIndex(), true); if (litr != leftChildren.end()) { mergePropertyTrees(newChild, *litr, node); leftChildren.erase(litr); @@ -111,13 +97,13 @@ void mergePropertyTrees(SGPropertyNode* resultNode, copyProperties(node, newChild); } } + // Now copy nodes remaining in the left tree for (RawPropVector::iterator itr = leftChildren.begin(), e = leftChildren.end(); itr != e; ++itr) { SGPropertyNode* newChild - = resultNode->getChild((*itr)->getName(), - nodeIndex[(*itr)->getName()]++, true); + = resultNode->getChild((*itr)->getName(), (*itr)->getIndex(), true); copyProperties(*itr, newChild); } } @@ -134,8 +120,10 @@ Effect* makeEffect(const string& name, effectFileName += ".eff"; string absFileName = osgDB::findDataFile(effectFileName, options); - if (absFileName.empty()) + if (absFileName.empty()) { + SG_LOG(SG_INPUT, SG_WARN, "can't find \"" << effectFileName << "\""); return 0; + } SGPropertyNode_ptr effectProps = new SGPropertyNode(); readProperties(absFileName, effectProps.ptr(), 0, true); Effect* result = makeEffect(effectProps.ptr(), realizeTechniques, options); @@ -179,9 +167,15 @@ Effect* makeEffect(SGPropertyNode* prop, if (inheritProp) { parent = makeEffect(inheritProp->getStringValue(), realizeTechniques, options); - effect->root = new SGPropertyNode; - mergePropertyTrees(effect->root, prop, parent->root); - effect->root->removeChild("inherits-from"); + if(parent) + { + effect->root = new SGPropertyNode; + mergePropertyTrees(effect->root, prop, parent->root); + effect->root->removeChild("inherits-from"); + } else { + effect->root = prop; + effect->root->removeChild("inherits-from"); + } } else { effect->root = prop; } diff --git a/simgear/scene/material/mat.cxx b/simgear/scene/material/mat.cxx index 5cb949a9..dc79d094 100644 --- a/simgear/scene/material/mat.cxx +++ b/simgear/scene/material/mat.cxx @@ -269,13 +269,12 @@ void SGMaterial::buildEffectProperties(const osgDB::ReaderWriter::Options* copyProperties(propRoot, effectProp); SGPropertyNode* effectParamProp = effectProp->getChild("parameters", 0); SGPropertyNode* texProp = makeChild(effectParamProp, "texture"); - SGPropertyNode* tex2dProp = makeChild(texProp, "texture2d"); - makeChild(tex2dProp, "image")->setStringValue(matState.texture_path); - makeChild(tex2dProp, "filter") + makeChild(texProp, "image")->setStringValue(matState.texture_path); + makeChild(texProp, "filter") ->setStringValue(mipmap ? "linear-mipmap-linear" : "nearest"); - makeChild(tex2dProp, "wrap-s") + makeChild(texProp, "wrap-s") ->setStringValue(wrapu ? "repeat" : "clamp"); - makeChild(tex2dProp, "wrap-t") + makeChild(texProp, "wrap-t") ->setStringValue(wrapv ? "repeat" : "clamp"); matState.effect = makeEffect(effectProp, false, options); matState.effect->setUserData(user.get()); diff --git a/simgear/scene/material/mat.hxx b/simgear/scene/material/mat.hxx index 5b74412c..c510575e 100644 --- a/simgear/scene/material/mat.hxx +++ b/simgear/scene/material/mat.hxx @@ -55,6 +55,7 @@ class StateSet; namespace simgear { class Effect; +void reload_shaders(); } class SGMaterialGlyph; -- 2.39.5