X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=simgear%2Fscene%2Ftgdb%2FTreeBin.cxx;h=a530ba32d3216489a8d703f055fcdcb069c5a1e7;hb=7e7ce2f38e87d6244e05730fa4382da088bb25f1;hp=a97774443545abec937f7b0e69c519c1ec332617;hpb=be616894586358a2804207bc984c5429dafdcc39;p=simgear.git diff --git a/simgear/scene/tgdb/TreeBin.cxx b/simgear/scene/tgdb/TreeBin.cxx index a9777444..a530ba32 100644 --- a/simgear/scene/tgdb/TreeBin.cxx +++ b/simgear/scene/tgdb/TreeBin.cxx @@ -20,9 +20,12 @@ */ #include +#include #include #include +#include + #include #include #include @@ -64,8 +67,17 @@ using namespace osg; namespace simgear { -osg::Geometry* createOrthQuads(float w, float h, const osg::Matrix& rotate) +// memoize geometry +typedef boost::tuple ForestTuple; +typedef std::map > OrthQuadMap; + +osg::Geometry* createOrthQuads(float w, float h, int varieties, const osg::Matrix& rotate) { + static OrthQuadMap orthQuadMap; + OrthQuadMap::iterator giter + = orthQuadMap.find(ForestTuple(w, h, varieties)); + if (giter != orthQuadMap.end()) + return giter->second.get(); //const osg::Vec3& pos = osg::Vec3(0.0f,0.0f,0.0f), // set up the coords @@ -87,14 +99,19 @@ osg::Geometry* createOrthQuads(float w, float h, const osg::Matrix& rotate) v[6].set( cw,0.0f,h); v[7].set(-cw,0.0f,h); + // The texture coordinate range is not the + // entire coordinate space - as the texture + // has a number of different trees on it. + float tx = 1.0f/varieties; + t[0].set(0.0f,0.0f); - t[1].set(1.0f,0.0f); - t[2].set(1.0f,1.0f); + t[1].set( tx,0.0f); + t[2].set( tx,1.0f); t[3].set(0.0f,1.0f); t[4].set(0.0f,0.0f); - t[5].set(1.0f,0.0f); - t[6].set(1.0f,1.0f); + t[5].set( tx,0.0f); + t[6].set( tx,1.0f); t[7].set(0.0f,1.0f); // For now the normal is normal to the quad. If we want to get @@ -118,39 +135,37 @@ osg::Geometry* createOrthQuads(float w, float h, const osg::Matrix& rotate) // No color for now; that's used to pass the position. geom->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::QUADS,0,8)); + orthQuadMap.insert(std::make_pair(ForestTuple(w, h, varieties), geom)); return geom; } static char vertexShaderSource[] = "varying float fogFactor;\n" + "attribute float textureIndex;\n" "\n" "void main(void)\n" "{\n" + " gl_TexCoord[0] = gl_MultiTexCoord0 + vec4(textureIndex, 0.0, 0.0, 0.0);\n" " vec3 position = gl_Vertex.xyz * gl_Color.w + gl_Color.xyz;\n" " gl_Position = gl_ModelViewProjectionMatrix * vec4(position,1.0);\n" " vec3 ecPosition = vec3(gl_ModelViewMatrix * vec4(position, 1.0));\n" - " vec3 N = normalize(gl_NormalMatrix * gl_Normal);\n" - " vec3 diffuse = gl_FrontMaterial.diffuse.rgb * max(0.0, dot(N, gl_LightSource[0].position.xyz));\n" - " vec3 backDiffuse = gl_FrontMaterial.diffuse.rgb * max(0.0, dot(-N, gl_LightSource[0].position.xyz));\n" - " vec4 ambientColor = gl_FrontLightModelProduct.sceneColor + gl_LightSource[0].ambient * gl_FrontMaterial.ambient;\n" - " gl_FrontColor = ambientColor + gl_LightSource[0].diffuse * vec4(diffuse, 1.0);\n" - " gl_BackColor = ambientColor + gl_LightSource[0].diffuse * vec4(backDiffuse, 1.0)\n;" - " gl_TexCoord[0] = gl_MultiTexCoord0;\n" - " float fogCoord = abs(ecPosition.z);\n" + " float n = dot(normalize(gl_LightSource[0].position.xyz), normalize(-ecPosition));\n" + " vec3 diffuse = gl_FrontMaterial.diffuse.rgb * max(0.1, n);\n" + " vec4 ambientColor = gl_FrontLightModelProduct.sceneColor + gl_LightSource[0].ambient * gl_FrontMaterial.ambient;\n" + " gl_FrontColor = ambientColor + gl_LightSource[0].diffuse * vec4(diffuse, 1.0);\n" + " gl_BackColor = gl_FrontColor;\n" + " float fogCoord = abs(ecPosition.z);\n" " fogFactor = exp( -gl_Fog.density * gl_Fog.density * fogCoord * fogCoord);\n" " fogFactor = clamp(fogFactor, 0.0, 1.0);\n" "}\n"; static char fragmentShaderSource[] = "uniform sampler2D baseTexture; \n" -// "varying vec3 N;\n" -// "varying vec3 v;\n" "varying float fogFactor;\n" "\n" "void main(void) \n" "{ \n" " vec4 base = texture2D( baseTexture, gl_TexCoord[0].st);\n" - " vec4 finalColor = base * gl_Color;\n" " gl_FragColor = mix(gl_Fog.color, finalColor, fogFactor );\n" "}\n"; @@ -164,22 +179,23 @@ namespace { struct MakeTreesLeaf { - MakeTreesLeaf(float range, Geometry* geometry) : - _range(range), _geometry(geometry) + MakeTreesLeaf(float range, Geometry* geometry, int varieties) : + _range(range), _geometry(geometry), _varieties(varieties) {} MakeTreesLeaf(const MakeTreesLeaf& rhs) : - _range(rhs._range), _geometry(rhs._geometry) {} + _range(rhs._range), _geometry(rhs._geometry), _varieties(rhs._varieties) {} LOD* operator() () const { LOD* result = new LOD; Geode* geode = new Geode; - ShaderGeometry* sg = new ShaderGeometry; + ShaderGeometry* sg = new ShaderGeometry(_varieties); sg->setGeometry(_geometry); geode->addDrawable(sg); result->addChild(geode, 0, _range); return result; } float _range; + int _varieties; Geometry* _geometry; }; @@ -190,44 +206,57 @@ struct AddTreesLeafObject Geode* geode = static_cast(lod->getChild(0)); ShaderGeometry* sg = static_cast(geode->getDrawable(0)); - sg->addTree(tree.position.osg(), tree.height); + sg->addTree(tree); } }; struct GetTreeCoord { - GetTreeCoord(const Matrix& transform) : _transform(transform) {} - GetTreeCoord(const GetTreeCoord& rhs) : _transform(rhs._transform) {} Vec3 operator() (const TreeBin::Tree& tree) const { - return tree.position.osg() * _transform; + return tree.position.osg(); } - Matrix _transform; }; typedef QuadTreeBuilder ShaderGeometryQuadtree; } +struct TreeTransformer +{ + TreeTransformer(Matrix& mat_) : mat(mat_) {} + TreeBin::Tree operator()(const TreeBin::Tree& tree) const + { + const Vec3& pos = tree.position.osg(); + return TreeBin::Tree(SGVec3f(pos * mat), tree.texture_index, + tree.scale); + } + Matrix mat; +}; + +// This actually returns a MatrixTransform node. If we rotate the whole +// forest into the local Z-up coordinate system we can reuse the +// primitive tree geometry for all the forests of the same type. + osg::Group* createForest(TreeBin& forest, const osg::Matrix& transform) { + Matrix transInv = Matrix::inverse(transform); + static Matrix ident; // Set up some shared structures. - // FIXME: Currently we only take the texture, height and width of the first tree in the forest. In the future - // we should be able to handle multiple textures etc. - TreeBin::Tree firstTree = forest.getTree(0); - - osg::Geometry* shared_geometry = createOrthQuads(firstTree.width, - firstTree.height, - transform); + osg::Geometry* shared_geometry = createOrthQuads(forest.width, + forest.height, + forest.texture_varieties, + ident); + ref_ptr group; osg::StateSet* stateset = 0; - StateSetMap::iterator iter = treeTextureMap.find(firstTree.texture); + StateSetMap::iterator iter = treeTextureMap.find(forest.texture); if (iter == treeTextureMap.end()) { osg::Texture2D *tex = new osg::Texture2D; tex->setWrap( osg::Texture2D::WRAP_S, osg::Texture2D::CLAMP ); tex->setWrap( osg::Texture2D::WRAP_T, osg::Texture2D::CLAMP ); - tex->setImage(osgDB::readImageFile(firstTree.texture)); + tex->setImage(osgDB::readImageFile(forest.texture)); static ref_ptr alphaFunc; static ref_ptr program; @@ -244,6 +273,8 @@ osg::Group* createForest(TreeBin& forest, const osg::Matrix& transform) baseTextureSampler = new osg::Uniform("baseTexture", 0); Shader* vertex_shader = new Shader(Shader::VERTEX, vertexShaderSource); program->addShader(vertex_shader); + program->addBindAttribLocation("textureIndex", 1); + Shader* fragment_shader = new Shader(Shader::FRAGMENT, fragmentShaderSource); program->addShader(fragment_shader); @@ -251,34 +282,45 @@ osg::Group* createForest(TreeBin& forest, const osg::Matrix& transform) // Don´t track vertex color material->setColorMode(Material::OFF); material->setAmbient(Material::FRONT_AND_BACK, - Vec4(.6f, .6f, .6f, 1.0f)); + Vec4(1.0f, 1.0f, 1.0f, 1.0f)); material->setDiffuse(Material::FRONT_AND_BACK, - Vec4(.4f, .4f, .4f, 1.0f)); + Vec4(1.0f, 1.0f, 1.0f, 1.0f)); } stateset->setAttributeAndModes(alphaFunc.get()); stateset->setAttribute(program.get()); stateset->addUniform(baseTextureSampler.get()); stateset->setMode(GL_VERTEX_PROGRAM_TWO_SIDE, StateAttribute::ON); stateset->setAttribute(material.get()); - // XXX This should really come from a material definition - // instead of being hard-coded. - treeTextureMap.insert(StateSetMap::value_type(firstTree.texture, + + treeTextureMap.insert(StateSetMap::value_type(forest.texture, stateset)); } else { stateset = iter->second.get(); } // Now, create a quadtree for the forest. { - ShaderGeometryQuadtree quadtree(GetTreeCoord(Matrix::inverse(transform)), + ShaderGeometryQuadtree quadtree(GetTreeCoord(), AddTreesLeafObject(), SG_TREE_QUAD_TREE_DEPTH, - MakeTreesLeaf(firstTree.range, - shared_geometry)); - quadtree.buildQuadTree(forest._trees.begin(), forest._trees.end()); + MakeTreesLeaf(forest.range, + shared_geometry, + forest.texture_varieties)); + // Transform tree positions from the "geocentric" positions we + // get from the scenery polys into the local Z-up coordinate + // system. + std::vector rotatedTrees; + rotatedTrees.reserve(forest._trees.size()); + std::transform(forest._trees.begin(), forest._trees.end(), + std::back_inserter(rotatedTrees), + TreeTransformer(transInv)); + quadtree.buildQuadTree(rotatedTrees.begin(), rotatedTrees.end()); group = quadtree.getRoot(); } - group->setStateSet(stateset); - return group.release(); + MatrixTransform* mt = new MatrixTransform(transform); + for (int i = 0; i < group->getNumChildren(); ++i) + mt->addChild(group->getChild(i)); + mt->setStateSet(stateset); + return mt; } }