1 #include "material.hpp" 2 3 #include <osg/Fog> 4 #include <osg/Depth> 5 #include <osg/TexEnvCombine> 6 #include <osg/Texture2D> 7 #include <osg/TexMat> 8 #include <osg/BlendFunc> 9 10 #include <components/shader/shadermanager.hpp> 11 12 #include <mutex> 13 14 namespace 15 { 16 class BlendmapTexMat 17 { 18 public: value(const int blendmapScale)19 static const osg::ref_ptr<osg::TexMat>& value(const int blendmapScale) 20 { 21 static BlendmapTexMat instance; 22 return instance.get(blendmapScale); 23 } 24 get(const int blendmapScale)25 const osg::ref_ptr<osg::TexMat>& get(const int blendmapScale) 26 { 27 const std::lock_guard<std::mutex> lock(mMutex); 28 auto texMat = mTexMatMap.find(blendmapScale); 29 if (texMat == mTexMatMap.end()) 30 { 31 osg::Matrixf matrix; 32 float scale = (blendmapScale/(static_cast<float>(blendmapScale)+1.f)); 33 matrix.preMultTranslate(osg::Vec3f(0.5f, 0.5f, 0.f)); 34 matrix.preMultScale(osg::Vec3f(scale, scale, 1.f)); 35 matrix.preMultTranslate(osg::Vec3f(-0.5f, -0.5f, 0.f)); 36 // We need to nudge the blendmap to look like vanilla. 37 // This causes visible seams unless the blendmap's resolution is doubled, but Vanilla also doubles the blendmap, apparently. 38 matrix.preMultTranslate(osg::Vec3f(1.0f/blendmapScale/4.0f, 1.0f/blendmapScale/4.0f, 0.f)); 39 40 texMat = mTexMatMap.insert(std::make_pair(blendmapScale, new osg::TexMat(matrix))).first; 41 } 42 return texMat->second; 43 } 44 45 private: 46 std::mutex mMutex; 47 std::map<float, osg::ref_ptr<osg::TexMat>> mTexMatMap; 48 }; 49 50 class LayerTexMat 51 { 52 public: value(const float layerTileSize)53 static const osg::ref_ptr<osg::TexMat>& value(const float layerTileSize) 54 { 55 static LayerTexMat instance; 56 return instance.get(layerTileSize); 57 } 58 get(const float layerTileSize)59 const osg::ref_ptr<osg::TexMat>& get(const float layerTileSize) 60 { 61 const std::lock_guard<std::mutex> lock(mMutex); 62 auto texMat = mTexMatMap.find(layerTileSize); 63 if (texMat == mTexMatMap.end()) 64 { 65 texMat = mTexMatMap.insert(std::make_pair(layerTileSize, 66 new osg::TexMat(osg::Matrix::scale(osg::Vec3f(layerTileSize, layerTileSize, 1.f))))).first; 67 } 68 return texMat->second; 69 } 70 71 private: 72 std::mutex mMutex; 73 std::map<float, osg::ref_ptr<osg::TexMat>> mTexMatMap; 74 }; 75 76 class EqualDepth 77 { 78 public: value()79 static const osg::ref_ptr<osg::Depth>& value() 80 { 81 static EqualDepth instance; 82 return instance.mValue; 83 } 84 85 private: 86 osg::ref_ptr<osg::Depth> mValue; 87 EqualDepth()88 EqualDepth() 89 : mValue(new osg::Depth) 90 { 91 mValue->setFunction(osg::Depth::EQUAL); 92 } 93 }; 94 95 class LequalDepth 96 { 97 public: value()98 static const osg::ref_ptr<osg::Depth>& value() 99 { 100 static LequalDepth instance; 101 return instance.mValue; 102 } 103 104 private: 105 osg::ref_ptr<osg::Depth> mValue; 106 LequalDepth()107 LequalDepth() 108 : mValue(new osg::Depth) 109 { 110 mValue->setFunction(osg::Depth::LEQUAL); 111 } 112 }; 113 114 class BlendFuncFirst 115 { 116 public: value()117 static const osg::ref_ptr<osg::BlendFunc>& value() 118 { 119 static BlendFuncFirst instance; 120 return instance.mValue; 121 } 122 123 private: 124 osg::ref_ptr<osg::BlendFunc> mValue; 125 BlendFuncFirst()126 BlendFuncFirst() 127 : mValue(new osg::BlendFunc(osg::BlendFunc::SRC_ALPHA, osg::BlendFunc::ZERO)) 128 { 129 } 130 }; 131 132 class BlendFunc 133 { 134 public: value()135 static const osg::ref_ptr<osg::BlendFunc>& value() 136 { 137 static BlendFunc instance; 138 return instance.mValue; 139 } 140 141 private: 142 osg::ref_ptr<osg::BlendFunc> mValue; 143 BlendFunc()144 BlendFunc() 145 : mValue(new osg::BlendFunc(osg::BlendFunc::SRC_ALPHA, osg::BlendFunc::ONE)) 146 { 147 } 148 }; 149 150 class TexEnvCombine 151 { 152 public: value()153 static const osg::ref_ptr<osg::TexEnvCombine>& value() 154 { 155 static TexEnvCombine instance; 156 return instance.mValue; 157 } 158 159 private: 160 osg::ref_ptr<osg::TexEnvCombine> mValue; 161 TexEnvCombine()162 TexEnvCombine() 163 : mValue(new osg::TexEnvCombine) 164 { 165 mValue->setCombine_RGB(osg::TexEnvCombine::REPLACE); 166 mValue->setSource0_RGB(osg::TexEnvCombine::PREVIOUS); 167 } 168 }; 169 } 170 171 namespace Terrain 172 { createPasses(bool useShaders,Shader::ShaderManager * shaderManager,const std::vector<TextureLayer> & layers,const std::vector<osg::ref_ptr<osg::Texture2D>> & blendmaps,int blendmapScale,float layerTileSize)173 std::vector<osg::ref_ptr<osg::StateSet> > createPasses(bool useShaders, Shader::ShaderManager* shaderManager, const std::vector<TextureLayer> &layers, 174 const std::vector<osg::ref_ptr<osg::Texture2D> > &blendmaps, int blendmapScale, float layerTileSize) 175 { 176 std::vector<osg::ref_ptr<osg::StateSet> > passes; 177 178 unsigned int blendmapIndex = 0; 179 unsigned int passIndex = 0; 180 for (std::vector<TextureLayer>::const_iterator it = layers.begin(); it != layers.end(); ++it) 181 { 182 bool firstLayer = (it == layers.begin()); 183 184 osg::ref_ptr<osg::StateSet> stateset (new osg::StateSet); 185 186 if (!blendmaps.empty()) 187 { 188 stateset->setMode(GL_BLEND, osg::StateAttribute::ON); 189 stateset->setRenderBinDetails(passIndex++, "RenderBin"); 190 if (!firstLayer) 191 { 192 stateset->setAttributeAndModes(BlendFunc::value(), osg::StateAttribute::ON); 193 stateset->setAttributeAndModes(EqualDepth::value(), osg::StateAttribute::ON); 194 } 195 else 196 { 197 stateset->setAttributeAndModes(BlendFuncFirst::value(), osg::StateAttribute::ON); 198 stateset->setAttributeAndModes(LequalDepth::value(), osg::StateAttribute::ON); 199 } 200 } 201 202 int texunit = 0; 203 204 if (useShaders) 205 { 206 stateset->setTextureAttributeAndModes(texunit, it->mDiffuseMap); 207 208 if (layerTileSize != 1.f) 209 stateset->setTextureAttributeAndModes(texunit, LayerTexMat::value(layerTileSize), osg::StateAttribute::ON); 210 211 stateset->addUniform(new osg::Uniform("diffuseMap", texunit)); 212 213 if (!blendmaps.empty()) 214 { 215 ++texunit; 216 osg::ref_ptr<osg::Texture2D> blendmap = blendmaps.at(blendmapIndex++); 217 218 stateset->setTextureAttributeAndModes(texunit, blendmap.get()); 219 stateset->setTextureAttributeAndModes(texunit, BlendmapTexMat::value(blendmapScale)); 220 stateset->addUniform(new osg::Uniform("blendMap", texunit)); 221 } 222 223 if (it->mNormalMap) 224 { 225 ++texunit; 226 stateset->setTextureAttributeAndModes(texunit, it->mNormalMap); 227 stateset->addUniform(new osg::Uniform("normalMap", texunit)); 228 } 229 230 Shader::ShaderManager::DefineMap defineMap; 231 defineMap["normalMap"] = (it->mNormalMap) ? "1" : "0"; 232 defineMap["blendMap"] = (!blendmaps.empty()) ? "1" : "0"; 233 defineMap["specularMap"] = it->mSpecular ? "1" : "0"; 234 defineMap["parallax"] = (it->mNormalMap && it->mParallax) ? "1" : "0"; 235 236 osg::ref_ptr<osg::Shader> vertexShader = shaderManager->getShader("terrain_vertex.glsl", defineMap, osg::Shader::VERTEX); 237 osg::ref_ptr<osg::Shader> fragmentShader = shaderManager->getShader("terrain_fragment.glsl", defineMap, osg::Shader::FRAGMENT); 238 if (!vertexShader || !fragmentShader) 239 { 240 // Try again without shader. Error already logged by above 241 return createPasses(false, shaderManager, layers, blendmaps, blendmapScale, layerTileSize); 242 } 243 244 stateset->setAttributeAndModes(shaderManager->getProgram(vertexShader, fragmentShader)); 245 stateset->addUniform(new osg::Uniform("colorMode", 2)); 246 } 247 else 248 { 249 // Add the actual layer texture 250 osg::ref_ptr<osg::Texture2D> tex = it->mDiffuseMap; 251 stateset->setTextureAttributeAndModes(texunit, tex.get()); 252 253 if (layerTileSize != 1.f) 254 stateset->setTextureAttributeAndModes(texunit, LayerTexMat::value(layerTileSize), osg::StateAttribute::ON); 255 256 ++texunit; 257 258 // Multiply by the alpha map 259 if (!blendmaps.empty()) 260 { 261 osg::ref_ptr<osg::Texture2D> blendmap = blendmaps.at(blendmapIndex++); 262 263 stateset->setTextureAttributeAndModes(texunit, blendmap.get()); 264 265 // This is to map corner vertices directly to the center of a blendmap texel. 266 stateset->setTextureAttributeAndModes(texunit, BlendmapTexMat::value(blendmapScale)); 267 stateset->setTextureAttributeAndModes(texunit, TexEnvCombine::value(), osg::StateAttribute::ON); 268 269 ++texunit; 270 } 271 272 } 273 274 passes.push_back(stateset); 275 } 276 return passes; 277 } 278 279 } 280