diff --git a/simgear/scene/material/mat.hxx b/simgear/scene/material/mat.hxx index b245850d..abeb96b0 100644 --- a/simgear/scene/material/mat.hxx +++ b/simgear/scene/material/mat.hxx @@ -45,6 +45,7 @@ class StateSet; } #include +#include #include // for SGMutex #include #include @@ -326,6 +327,15 @@ public: */ inline double get_cos_tree_zero_density_slope_angle () const { return cos_tree_zero_density_slope_angle; } + /** + * Get the various colour attributes + */ + inline osg::Vec4 get_ambient() const { return toOsg(ambient); } + inline osg::Vec4 get_diffuse() const { return toOsg(diffuse); } + inline osg::Vec4 get_specular() const { return toOsg(specular); } + inline osg::Vec4 get_emission() const { return toOsg(emission); } + inline double get_shininess() const { return shininess; } + /** * Get the list of names for this material */ diff --git a/simgear/scene/material/matlib.cxx b/simgear/scene/material/matlib.cxx index f4008a0c..68168113 100644 --- a/simgear/scene/material/matlib.cxx +++ b/simgear/scene/material/matlib.cxx @@ -306,8 +306,7 @@ SGMaterialCache::Atlas SGMaterialLib::getMaterialTextureAtlas(SGVec2f center, co { SG_LOG(SG_TERRAIN, SG_DEBUG, "Getting Texture Atlas for " << center); - SGMaterialCache::AtlasIndex atlasIndex; - SGMaterialCache::AtlasImage atlasImage; + SGMaterialCache::Atlas atlas; std::string id; const_landclass_map_iterator lc_iter = landclasslib.begin(); for (; lc_iter != landclasslib.end(); ++lc_iter) { @@ -323,19 +322,44 @@ SGMaterialCache::Atlas SGMaterialLib::getMaterialTextureAtlas(SGVec2f center, co // Cache lookup failure - generate a new atlas, but only if we have a change of reading any textures if (options == 0) { - return SGMaterialCache::Atlas(atlasIndex, atlasImage); + return atlas; } - atlasImage = new osg::Texture2DArray(); + atlas.image = new osg::Texture2DArray(); - atlasImage->setMaxAnisotropy(16.0f); - atlasImage->setResizeNonPowerOfTwoHint(false); + osg::ref_ptr dimensionImage = new osg::Image(); + dimensionImage->allocateImage(512, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE); + atlas.dimensions = new osg::Texture1D(dimensionImage.get()); + atlas.dimensions->setFilter(osg::Texture::MIN_FILTER, osg::Texture::NEAREST); + atlas.dimensions->setFilter(osg::Texture::MAG_FILTER, osg::Texture::NEAREST); + atlas.dimensions->setWrap(osg::Texture::WRAP_S,osg::Texture::CLAMP); + atlas.dimensions->setWrap(osg::Texture::WRAP_T,osg::Texture::CLAMP); - atlasImage->setFilter(osg::Texture::MIN_FILTER, osg::Texture::NEAREST_MIPMAP_NEAREST); - atlasImage->setFilter(osg::Texture::MAG_FILTER, osg::Texture::NEAREST_MIPMAP_NEAREST); - atlasImage->setWrap(osg::Texture::WRAP_S,osg::Texture::REPEAT); - atlasImage->setWrap(osg::Texture::WRAP_T,osg::Texture::REPEAT); + osg::ref_ptr diffuseImage = new osg::Image(); + diffuseImage->allocateImage(512, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE); + atlas.diffuse = new osg::Texture1D(diffuseImage.get()); + atlas.diffuse->setFilter(osg::Texture::MIN_FILTER, osg::Texture::NEAREST); + atlas.diffuse->setFilter(osg::Texture::MAG_FILTER, osg::Texture::NEAREST); + atlas.diffuse->setWrap(osg::Texture::WRAP_S,osg::Texture::CLAMP); + atlas.diffuse->setWrap(osg::Texture::WRAP_T,osg::Texture::CLAMP); + + osg::ref_ptr specularImage = new osg::Image(); + specularImage->allocateImage(512, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE); + atlas.specular = new osg::Texture1D(specularImage.get()); + atlas.specular->setFilter(osg::Texture::MIN_FILTER, osg::Texture::NEAREST); + atlas.specular->setFilter(osg::Texture::MAG_FILTER, osg::Texture::NEAREST); + atlas.specular->setWrap(osg::Texture::WRAP_S,osg::Texture::CLAMP); + atlas.specular->setWrap(osg::Texture::WRAP_T,osg::Texture::CLAMP); + + atlas.image->setMaxAnisotropy(16.0f); + atlas.image->setResizeNonPowerOfTwoHint(false); + + atlas.image->setFilter(osg::Texture::MIN_FILTER, osg::Texture::NEAREST_MIPMAP_NEAREST); + atlas.image->setFilter(osg::Texture::MAG_FILTER, osg::Texture::NEAREST_MIPMAP_NEAREST); + + atlas.image->setWrap(osg::Texture::WRAP_S,osg::Texture::REPEAT); + atlas.image->setWrap(osg::Texture::WRAP_T,osg::Texture::REPEAT); int index = -1; lc_iter = landclasslib.begin(); @@ -345,19 +369,13 @@ SGMaterialCache::Atlas SGMaterialLib::getMaterialTextureAtlas(SGVec2f center, co ++index; int i = lc_iter->first; SGMaterial* mat = find(lc_iter->second, center); - atlasIndex[i] = index; - - SG_LOG(SG_TERRAIN, SG_DEBUG, " Lookup " << i << " " << lc_iter->second); - + atlas.index[i] = index; if (mat == NULL) continue; - SG_LOG(SG_TERRAIN, SG_DEBUG, " Found it!"); - // Just get the first texture in the first texture-set for the moment. // Should add some variability in texture-set in the future. const std::string texture = mat->get_one_texture(0,0); - if (texture.empty()) continue; SGPath texturePath = SGPath("Textures"); @@ -375,14 +393,24 @@ SGMaterialCache::Atlas SGMaterialLib::getMaterialTextureAtlas(SGVec2f center, co if (subtexture && subtexture->valid()) { subtexture->scaleImage(2048,2048,1); - SG_LOG(SG_TERRAIN, SG_ALERT, "Adding image " << fullPath << " to texture atlas " << subtexture->getInternalTextureFormat()); - atlasImage->setImage(index,subtexture); + + // Add other useful information, such as the texture size in m. + // As we pack the texture size into a texture, we need to scale to [0..1.0] + float x_size = (0 < mat->get_xsize()) ? mat->get_xsize()/10000.0 : 0.1f; + float y_size = (0 < mat->get_ysize()) ? mat->get_ysize()/10000.0 : 0.1f; + + SG_LOG(SG_TERRAIN, SG_DEBUG, "Adding image " << fullPath << " to texture atlas " << x_size << " " << y_size); + atlas.image->setImage(index,subtexture); + + atlas.dimensions->getImage()->setColor(osg::Vec4(x_size, y_size, mat->get_shininess(), 1.0f), index); + atlas.diffuse->getImage()->setColor(mat->get_diffuse(), index); + atlas.specular->getImage()->setColor(mat->get_specular(), index); } + } } // Cache for future lookups - SGMaterialCache::Atlas atlas = SGMaterialCache::Atlas(atlasIndex, atlasImage); _atlasCache[id] = atlas; return atlas; } diff --git a/simgear/scene/material/matlib.hxx b/simgear/scene/material/matlib.hxx index 439e0b6e..d7fdb0e9 100644 --- a/simgear/scene/material/matlib.hxx +++ b/simgear/scene/material/matlib.hxx @@ -31,6 +31,7 @@ #include #include #include +#include #include #include // Standard C++ string library @@ -49,11 +50,18 @@ class SGMaterialCache : public osg::Referenced { public: - // An atlas, consisting of a landclass index and an atlas image + // An atlas, consisting of a landclass index, an atlas image and set + // of texture1D containing further data typedef std::map AtlasIndex; typedef osg::ref_ptr AtlasImage; - typedef std::pair Atlas; + typedef struct { + AtlasIndex index; + AtlasImage image; + osg::ref_ptr dimensions; + osg::ref_ptr diffuse; + osg::ref_ptr specular; + } Atlas; // Constructor SGMaterialCache (Atlas atlas); @@ -66,8 +74,7 @@ public: SGMaterial *find( const std::string& material ) const; SGMaterial *find( int material ) const; - AtlasIndex getAtlasIndex() { return _atlas.first; }; - AtlasImage getAtlasImage() { return _atlas.second; }; + Atlas getAtlas() { return _atlas; }; // Destructor ~SGMaterialCache ( void ); @@ -137,8 +144,8 @@ public: * cache of the valid materials based on the current state and a given position. */ - SGMaterialCache *generateMatCache( SGVec2f center, const simgear::SGReaderWriterOptions* options=0); - SGMaterialCache *generateMatCache( SGGeod center, const simgear::SGReaderWriterOptions* options=0); + SGMaterialCache *generateMatCache( SGVec2f center, const simgear::SGReaderWriterOptions* options); + SGMaterialCache *generateMatCache( SGGeod center, const simgear::SGReaderWriterOptions* options); material_map_iterator begin() { return matlib.begin(); } const_material_map_iterator begin() const { return matlib.begin(); } diff --git a/simgear/scene/model/model.cxx b/simgear/scene/model/model.cxx index 228c2187..79a97ac5 100644 --- a/simgear/scene/model/model.cxx +++ b/simgear/scene/model/model.cxx @@ -354,7 +354,7 @@ ref_ptr instantiateMaterialEffects(osg::Node* modelGroup, if (options->getMaterialLib()) { const SGGeod loc = SGGeod(options->getLocation()); - SGMaterialCache* matcache = options->getMaterialLib()->generateMatCache(loc); + SGMaterialCache* matcache = options->getMaterialLib()->generateMatCache(loc, options); SGMaterial* mat = matcache->find(options->getMaterialName()); delete matcache; diff --git a/simgear/scene/tgdb/SGOceanTile.cxx b/simgear/scene/tgdb/SGOceanTile.cxx index 29839b29..9a41fe50 100644 --- a/simgear/scene/tgdb/SGOceanTile.cxx +++ b/simgear/scene/tgdb/SGOceanTile.cxx @@ -279,7 +279,7 @@ osg::Node* SGOceanTile(const SGBucket& b, SGMaterialLib *matlib, int latPoints, double tex_width = 1000.0; // find Ocean material in the properties list - SGMaterialCache* matcache = matlib->generateMatCache(b.get_center()); + SGMaterialCache* matcache = matlib->generateMatCache(b.get_center(), 0); SGMaterial* mat = matcache->find( "Ocean" ); delete matcache; diff --git a/simgear/scene/tgdb/SGTileDetailsCallback.hxx b/simgear/scene/tgdb/SGTileDetailsCallback.hxx index 9a52b208..13b88beb 100644 --- a/simgear/scene/tgdb/SGTileDetailsCallback.hxx +++ b/simgear/scene/tgdb/SGTileDetailsCallback.hxx @@ -114,7 +114,7 @@ public: matlib = _options->getMaterialLib(); if (matlib) { SGGeod geodPos = SGGeod::fromCart(_gbs_center); - matcache = matlib->generateMatCache(geodPos); + matcache = matlib->generateMatCache(geodPos, _options); } #if 0 @@ -281,7 +281,7 @@ public: // Generate a materials cache if (matlib) { - matcache = matlib->generateMatCache(geodPos); + matcache = matlib->generateMatCache(geodPos, _options); } // rotate the tiles so that the bounding boxes get nearly axis aligned. diff --git a/simgear/scene/tgdb/VPBTechnique.cxx b/simgear/scene/tgdb/VPBTechnique.cxx index 33622869..669b757b 100644 --- a/simgear/scene/tgdb/VPBTechnique.cxx +++ b/simgear/scene/tgdb/VPBTechnique.cxx @@ -799,7 +799,7 @@ void VPBTechnique::generateGeometry(BufferData& buffer, Locator* masterLocator, const SGVec3d world2 = SGVec3d(world.x(), world.y(), world.z()); const SGGeod loc = SGGeod::fromCart(world2); SG_LOG(SG_TERRAIN, SG_DEBUG, "Applying VPB material " << loc); - SGMaterialCache* matcache = _options->getMaterialLib()->generateMatCache(loc); + SGMaterialCache* matcache = _options->getMaterialLib()->generateMatCache(loc, _options); SGMaterial* mat = matcache->find("ws30"); delete matcache; @@ -1337,17 +1337,19 @@ void VPBTechnique::generateGeometry(BufferData& buffer, Locator* masterLocator, // Tile-specific information for the shaders osg::StateSet *ss = buffer._geode->getOrCreateStateSet(); osg::ref_ptr level = new osg::Uniform("tile_level", _terrainTile->getTileID().level); - level->setDataVariance(osg::Object::STATIC); ss->addUniform(level); // Determine the x and y texture scaling. Has to be performed after we've generated all the vertices. // Because the earth is round, each tile is not a rectangle. Apart from edge cases like the poles, the // difference in axis length is < 1%, so we will just take the average. + // Note that we can ignore the actual texture coordinates as we know from above that they are always + // [0..1.0] [0..1.0] across the entire tile. osg::Vec3f bottom_left, bottom_right, top_left, top_right; bool got_bl = VNG.vertex(0, 0, bottom_left); bool got_br = VNG.vertex(0, VNG._numColumns - 1, bottom_right); bool got_tl = VNG.vertex(VNG._numColumns - 1, 0, top_left); bool got_tr = VNG.vertex(VNG._numColumns - 1, VNG._numRows -1, top_right); + float tile_width = 1.0; float tile_height = 1.0; if (got_bl && got_br && got_tl && got_tr) { @@ -1359,14 +1361,11 @@ void VPBTechnique::generateGeometry(BufferData& buffer, Locator* masterLocator, tile_height = 0.5 * (t.length() + v.length()); } - //SG_LOG(SG_TERRAIN, SG_ALERT, "Tile Level " << _terrainTile->getTileID().level << " width " << tile_width << " height " << tile_height); + SG_LOG(SG_TERRAIN, SG_DEBUG, "Tile Level " << _terrainTile->getTileID().level << " width " << tile_width << " height " << tile_height); osg::ref_ptr twu = new osg::Uniform("tile_width", tile_width); - twu->setDataVariance(osg::Object::STATIC); ss->addUniform(twu); - osg::ref_ptr thu = new osg::Uniform("tile_height", tile_height); - thu->setDataVariance(osg::Object::STATIC); ss->addUniform(thu); // Force build of KD trees? @@ -1385,10 +1384,12 @@ void VPBTechnique::generateGeometry(BufferData& buffer, Locator* masterLocator, void VPBTechnique::applyColorLayers(BufferData& buffer, Locator* masterLocator) { - typedef std::map LayerToTextureMap; - typedef std::map LayerToAtlasMap; - LayerToTextureMap layerToTextureMap; + typedef std::map LayerToAtlasMap; + typedef std::map> LayerToTexture2DMap; + typedef std::map> LayerToTexture1DMap; LayerToAtlasMap layerToAtlasMap; + LayerToTexture2DMap layerToTextureMap; + LayerToTexture1DMap layerToContourMap; for(unsigned int layerNum=0; layerNum<_terrainTile->getNumColorLayers(); ++layerNum) { @@ -1413,15 +1414,17 @@ void VPBTechnique::applyColorLayers(BufferData& buffer, Locator* masterLocator) osgTerrain::ImageLayer* imageLayer = dynamic_cast(colorLayer); osgTerrain::ContourLayer* contourLayer = dynamic_cast(colorLayer); + SGMaterialCache::Atlas atlas = layerToAtlasMap[colorLayer]; if (imageLayer) { osg::StateSet* stateset = buffer._geode->getOrCreateStateSet(); - osg::Texture2D* texture2D = dynamic_cast(layerToTextureMap[colorLayer]); - osg::Texture2DArray* atlasTexture = dynamic_cast(layerToAtlasMap[colorLayer]); + osg::ref_ptr texture2D = layerToTextureMap[colorLayer]; + SGMaterialCache::Atlas atlas = layerToAtlasMap[colorLayer]; + if (!texture2D) { - texture2D = new osg::Texture2D; + texture2D = new osg::Texture2D; // First time generating this texture, so process to change landclass IDs to texure indexes. SGPropertyNode_ptr effectProp; @@ -1441,9 +1444,8 @@ void VPBTechnique::applyColorLayers(BufferData& buffer, Locator* masterLocator) if (_matcache ==0) _matcache = _options->getMaterialLib()->generateMatCache(loc, _options); - atlasTexture = _matcache->getAtlasImage(); - layerToAtlasMap[colorLayer] = atlasTexture; - SGMaterialCache::AtlasIndex atlasIndex = _matcache->getAtlasIndex(); + atlas = _matcache->getAtlas(); + SGMaterialCache::AtlasIndex atlasIndex = atlas.index; for (int s = 0; s < image->s(); s++) { for (int t = 0; t < image->t(); t++) { @@ -1476,20 +1478,21 @@ void VPBTechnique::applyColorLayers(BufferData& buffer, Locator* masterLocator) texture2D->setFilter(osg::Texture::MIN_FILTER, osg::Texture::LINEAR); } - layerToTextureMap[colorLayer] = texture2D; - + layerToAtlasMap[colorLayer] = atlas; } - stateset->setTextureAttributeAndModes(2*layerNum, texture2D, osg::StateAttribute::ON); - stateset->setTextureAttributeAndModes(2*layerNum +1, atlasTexture, osg::StateAttribute::ON); - + stateset->setTextureAttributeAndModes(5*layerNum, texture2D, osg::StateAttribute::ON); + stateset->setTextureAttributeAndModes(5*layerNum + 1, atlas.image, osg::StateAttribute::ON); + stateset->setTextureAttributeAndModes(5*layerNum + 2, atlas.dimensions, osg::StateAttribute::ON); + stateset->setTextureAttributeAndModes(5*layerNum + 3, atlas.diffuse, osg::StateAttribute::ON); + stateset->setTextureAttributeAndModes(5*layerNum + 4, atlas.specular, osg::StateAttribute::ON); } else if (contourLayer) { osg::StateSet* stateset = buffer._geode->getOrCreateStateSet(); - osg::Texture1D* texture1D = dynamic_cast(layerToTextureMap[colorLayer]); + osg::ref_ptr< osg::Texture1D> texture1D = layerToContourMap[colorLayer]; if (!texture1D) { texture1D = new osg::Texture1D; @@ -1498,11 +1501,10 @@ void VPBTechnique::applyColorLayers(BufferData& buffer, Locator* masterLocator) texture1D->setFilter(osg::Texture::MIN_FILTER, osg::Texture::NEAREST); texture1D->setFilter(osg::Texture::MAG_FILTER, colorLayer->getMagFilter()); - layerToTextureMap[colorLayer] = texture1D; + layerToContourMap[colorLayer] = texture1D; } stateset->setTextureAttributeAndModes(layerNum, texture1D, osg::StateAttribute::ON); - } } } diff --git a/simgear/scene/tgdb/obj.cxx b/simgear/scene/tgdb/obj.cxx index c39d2db5..6305b23b 100644 --- a/simgear/scene/tgdb/obj.cxx +++ b/simgear/scene/tgdb/obj.cxx @@ -85,7 +85,7 @@ SGLoadBTG(const std::string& path, const simgear::SGReaderWriterOptions* options SGGeod geodPos = SGGeod::fromCart(center); SGQuatd hlOr = SGQuatd::fromLonLat(geodPos)*SGQuatd::fromEulerDeg(0, 0, 180); if (matlib) - matcache = matlib->generateMatCache(geodPos); + matcache = matlib->generateMatCache(geodPos, options); std::vector nodes = tile.get_wgs84_nodes();