1 #include "pch.h" 2 #include "MaterialInstance.hpp" 3 4 #include <stdexcept> 5 #include <iostream> 6 7 #include "Factory.hpp" 8 #include "ShaderSet.hpp" 9 10 namespace sh 11 { MaterialInstance(const std::string & name,Factory * f)12 MaterialInstance::MaterialInstance (const std::string& name, Factory* f) 13 : mName(name) 14 , mShadersEnabled(true) 15 , mFactory(f) 16 , mListener(NULL) 17 , mFailedToCreate(false) 18 { 19 } 20 ~MaterialInstance()21 MaterialInstance::~MaterialInstance () 22 { 23 } 24 setParentInstance(const std::string & name)25 void MaterialInstance::setParentInstance (const std::string& name) 26 { 27 mParentInstance = name; 28 } 29 getParentInstance()30 std::string MaterialInstance::getParentInstance () 31 { 32 return mParentInstance; 33 } 34 create(Platform * platform)35 void MaterialInstance::create (Platform* platform) 36 { 37 mMaterial = platform->createMaterial(mName); 38 39 if (hasProperty ("shadow_caster_material")) 40 mMaterial->setShadowCasterMaterial (retrieveValue<StringValue>(getProperty("shadow_caster_material"), NULL).get()); 41 42 if (hasProperty ("lod_values")) 43 mMaterial->setLodLevels (retrieveValue<StringValue>(getProperty("lod_values"), NULL).get()); 44 } 45 destroyAll()46 void MaterialInstance::destroyAll () 47 { 48 if (hasProperty("create_configuration")) 49 return; 50 mMaterial->removeAll(); 51 mTexUnits.clear(); 52 mFailedToCreate = false; 53 } 54 setProperty(const std::string & name,PropertyValuePtr value)55 void MaterialInstance::setProperty (const std::string& name, PropertyValuePtr value) 56 { 57 PropertySetGet::setProperty (name, value); 58 destroyAll(); // trigger updates 59 } 60 createForConfiguration(const std::string & configuration,unsigned short lodIndex)61 bool MaterialInstance::createForConfiguration (const std::string& configuration, unsigned short lodIndex) 62 { 63 if (mFailedToCreate) 64 return false; 65 try{ 66 mMaterial->ensureLoaded(); 67 bool res = mMaterial->createConfiguration(configuration, lodIndex); 68 if (!res) 69 return false; // listener was false positive 70 71 if (mListener) 72 mListener->requestedConfiguration (this, configuration); 73 74 mFactory->setActiveConfiguration (configuration); 75 mFactory->setActiveLodLevel (lodIndex); 76 77 bool allowFixedFunction = true; 78 if (!mShadersEnabled && hasProperty("allow_fixed_function")) 79 { 80 allowFixedFunction = retrieveValue<BooleanValue>(getProperty("allow_fixed_function"), NULL).get(); 81 } 82 83 bool useShaders = mShadersEnabled || !allowFixedFunction; 84 85 // get passes of the top-most parent 86 PassVector* passes = getParentPasses(); 87 if (passes->empty()) 88 throw std::runtime_error ("material \"" + mName + "\" does not have any passes"); 89 90 for (PassVector::iterator it = passes->begin(); it != passes->end(); ++it) 91 { 92 boost::shared_ptr<Pass> pass = mMaterial->createPass (configuration, lodIndex); 93 it->copyAll (pass.get(), this); 94 95 // texture samplers used in the shaders 96 std::vector<std::string> usedTextureSamplersVertex; 97 std::vector<std::string> usedTextureSamplersFragment; 98 99 PropertySetGet* context = this; 100 101 // create or retrieve shaders 102 bool hasVertex = it->hasProperty("vertex_program") 103 && !retrieveValue<StringValue>(it->getProperty("vertex_program"), context).get().empty(); 104 bool hasFragment = it->hasProperty("fragment_program") 105 && !retrieveValue<StringValue>(it->getProperty("fragment_program"), context).get().empty(); 106 if (useShaders) 107 { 108 it->setContext(context); 109 it->mShaderProperties.setContext(context); 110 if (hasVertex) 111 { 112 ShaderSet* vertex = mFactory->getShaderSet(retrieveValue<StringValue>(it->getProperty("vertex_program"), context).get()); 113 ShaderInstance* v = vertex->getInstance(&it->mShaderProperties); 114 if (v) 115 { 116 pass->assignProgram (GPT_Vertex, v->getName()); 117 v->setUniformParameters (pass, &it->mShaderProperties); 118 119 std::vector<std::string> sharedParams = v->getSharedParameters (); 120 for (std::vector<std::string>::iterator it2 = sharedParams.begin(); it2 != sharedParams.end(); ++it2) 121 { 122 pass->addSharedParameter (GPT_Vertex, *it2); 123 } 124 125 std::vector<std::string> vector = v->getUsedSamplers (); 126 usedTextureSamplersVertex.insert(usedTextureSamplersVertex.end(), vector.begin(), vector.end()); 127 } 128 } 129 if (hasFragment) 130 { 131 ShaderSet* fragment = mFactory->getShaderSet(retrieveValue<StringValue>(it->getProperty("fragment_program"), context).get()); 132 ShaderInstance* f = fragment->getInstance(&it->mShaderProperties); 133 if (f) 134 { 135 pass->assignProgram (GPT_Fragment, f->getName()); 136 f->setUniformParameters (pass, &it->mShaderProperties); 137 138 std::vector<std::string> sharedParams = f->getSharedParameters (); 139 for (std::vector<std::string>::iterator it2 = sharedParams.begin(); it2 != sharedParams.end(); ++it2) 140 { 141 pass->addSharedParameter (GPT_Fragment, *it2); 142 } 143 144 std::vector<std::string> vector = f->getUsedSamplers (); 145 usedTextureSamplersFragment.insert(usedTextureSamplersFragment.end(), vector.begin(), vector.end()); 146 } 147 } 148 } 149 150 // create texture units 151 std::vector<MaterialInstanceTextureUnit>* texUnits = &it->mTexUnits; 152 int i=0; 153 for (std::vector<MaterialInstanceTextureUnit>::iterator texIt = texUnits->begin(); texIt != texUnits->end(); ++texIt ) 154 { 155 // only create those that are needed by the shader, OR those marked to be created in fixed function pipeline if shaders are disabled 156 bool foundVertex = std::find(usedTextureSamplersVertex.begin(), usedTextureSamplersVertex.end(), texIt->getName()) != usedTextureSamplersVertex.end(); 157 bool foundFragment = std::find(usedTextureSamplersFragment.begin(), usedTextureSamplersFragment.end(), texIt->getName()) != usedTextureSamplersFragment.end(); 158 if ( (foundVertex || foundFragment) 159 || (((!useShaders || (!hasVertex || !hasFragment)) && allowFixedFunction) && texIt->hasProperty("create_in_ffp") && retrieveValue<BooleanValue>(texIt->getProperty("create_in_ffp"), this).get())) 160 { 161 boost::shared_ptr<TextureUnitState> texUnit = pass->createTextureUnitState (texIt->getName()); 162 texIt->copyAll (texUnit.get(), context); 163 164 mTexUnits.push_back(texUnit); 165 166 // set texture unit indices (required by GLSL) 167 if (useShaders && ((hasVertex && foundVertex) || (hasFragment && foundFragment)) && (mFactory->getCurrentLanguage () == Language_GLSL 168 || mFactory->getCurrentLanguage() == Language_GLSLES)) 169 { 170 pass->setTextureUnitIndex (foundVertex ? GPT_Vertex : GPT_Fragment, texIt->getName(), i); 171 172 ++i; 173 } 174 } 175 } 176 } 177 178 if (mListener) 179 mListener->createdConfiguration (this, configuration); 180 return true; 181 182 } catch (std::runtime_error& e) 183 { 184 destroyAll(); 185 mFailedToCreate = true; 186 std::stringstream msg; 187 msg << "Error while creating material " << mName << ": " << e.what(); 188 std::cerr << msg.str() << std::endl; 189 mFactory->logError(msg.str()); 190 return false; 191 } 192 } 193 getMaterial()194 Material* MaterialInstance::getMaterial () 195 { 196 return mMaterial.get(); 197 } 198 createPass()199 MaterialInstancePass* MaterialInstance::createPass () 200 { 201 mPasses.push_back (MaterialInstancePass()); 202 mPasses.back().setContext(this); 203 return &mPasses.back(); 204 } 205 deletePass(unsigned int index)206 void MaterialInstance::deletePass(unsigned int index) 207 { 208 assert(mPasses.size() > index); 209 mPasses.erase(mPasses.begin()+index); 210 } 211 getParentPasses()212 PassVector* MaterialInstance::getParentPasses() 213 { 214 if (mParent) 215 return static_cast<MaterialInstance*>(mParent)->getParentPasses(); 216 else 217 return &mPasses; 218 } 219 getPasses()220 PassVector* MaterialInstance::getPasses() 221 { 222 return &mPasses; 223 } 224 setShadersEnabled(bool enabled)225 void MaterialInstance::setShadersEnabled (bool enabled) 226 { 227 if (enabled == mShadersEnabled) 228 return; 229 mShadersEnabled = enabled; 230 231 // trigger updates 232 if (mMaterial.get()) 233 destroyAll(); 234 } 235 save(std::ofstream & stream)236 void MaterialInstance::save (std::ofstream& stream) 237 { 238 stream << "material " << mName << "\n" 239 << "{\n"; 240 241 if (mParent) 242 { 243 stream << "\t" << "parent " << static_cast<MaterialInstance*>(mParent)->getName() << "\n"; 244 } 245 246 const PropertyMap& properties = listProperties (); 247 for (PropertyMap::const_iterator it = properties.begin(); it != properties.end(); ++it) 248 { 249 stream << "\t" << it->first << " " << retrieveValue<StringValue>(getProperty(it->first), NULL).get() << "\n"; 250 } 251 252 for (PassVector::iterator it = mPasses.begin(); it != mPasses.end(); ++it) 253 { 254 stream << "\tpass" << '\n'; 255 stream << "\t{" << '\n'; 256 it->save(stream); 257 stream << "\t}" << '\n'; 258 } 259 260 stream << "}\n"; 261 } 262 } 263