1 #include "pch.h" 2 #include "ShaderSet.hpp" 3 4 #include <fstream> 5 #include <sstream> 6 7 #include <boost/algorithm/string/predicate.hpp> 8 #include <boost/functional/hash.hpp> 9 #include <boost/lexical_cast.hpp> 10 #include <boost/filesystem.hpp> 11 12 #include "Factory.hpp" 13 14 namespace sh 15 { ShaderSet(const std::string & type,const std::string & cgProfile,const std::string & hlslProfile,const std::string & sourceFile,const std::string & basePath,const std::string & name,PropertySetGet * globalSettingsPtr)16 ShaderSet::ShaderSet (const std::string& type, const std::string& cgProfile, const std::string& hlslProfile, const std::string& sourceFile, const std::string& basePath, 17 const std::string& name, PropertySetGet* globalSettingsPtr) 18 : mBasePath(basePath) 19 , mName(name) 20 , mCgProfile(cgProfile) 21 , mHlslProfile(hlslProfile) 22 { 23 if (type == "vertex") 24 mType = GPT_Vertex; 25 else // if (type == "fragment") 26 mType = GPT_Fragment; 27 28 std::ifstream stream(sourceFile.c_str(), std::ifstream::in); 29 std::stringstream buffer; 30 31 boost::filesystem::path p (sourceFile); 32 p = p.branch_path(); 33 mBasePath = p.string(); 34 35 buffer << stream.rdbuf(); 36 stream.close(); 37 mSource = buffer.str(); 38 parse(); 39 } 40 ~ShaderSet()41 ShaderSet::~ShaderSet() 42 { 43 for (ShaderInstanceMap::iterator it = mInstances.begin(); it != mInstances.end(); ++it) 44 { 45 sh::Factory::getInstance().getPlatform()->destroyGpuProgram(it->second.getName()); 46 } 47 } 48 parse()49 void ShaderSet::parse() 50 { 51 std::string currentToken; 52 bool tokenIsRecognized = false; 53 bool isInBraces = false; 54 for (std::string::const_iterator it = mSource.begin(); it != mSource.end(); ++it) 55 { 56 char c = *it; 57 if (((c == ' ') && !isInBraces) || (c == '\n') || 58 ( ((c == '(') || (c == ')')) 59 && !tokenIsRecognized)) 60 { 61 if (tokenIsRecognized) 62 { 63 if (boost::starts_with(currentToken, "@shGlobalSetting")) 64 { 65 assert ((currentToken.find('(') != std::string::npos) && (currentToken.find(')') != std::string::npos)); 66 size_t start = currentToken.find('(')+1; 67 mGlobalSettings.push_back(currentToken.substr(start, currentToken.find(')')-start)); 68 } 69 else if (boost::starts_with(currentToken, "@shPropertyHasValue")) 70 { 71 assert ((currentToken.find('(') != std::string::npos) && (currentToken.find(')') != std::string::npos)); 72 size_t start = currentToken.find('(')+1; 73 mPropertiesToExist.push_back(currentToken.substr(start, currentToken.find(')')-start)); 74 } 75 else if (boost::starts_with(currentToken, "@shPropertyEqual")) 76 { 77 assert ((currentToken.find('(') != std::string::npos) && (currentToken.find(')') != std::string::npos) 78 && (currentToken.find(',') != std::string::npos)); 79 size_t start = currentToken.find('(')+1; 80 size_t end = currentToken.find(','); 81 mProperties.push_back(currentToken.substr(start, end-start)); 82 } 83 else if (boost::starts_with(currentToken, "@shProperty")) 84 { 85 assert ((currentToken.find('(') != std::string::npos) && (currentToken.find(')') != std::string::npos)); 86 size_t start = currentToken.find('(')+1; 87 std::string propertyName = currentToken.substr(start, currentToken.find(')')-start); 88 // if the property name is constructed dynamically (e.g. through an iterator) then there is nothing we can do 89 if (propertyName.find("@") == std::string::npos) 90 mProperties.push_back(propertyName); 91 } 92 } 93 94 currentToken = ""; 95 } 96 else 97 { 98 if (currentToken == "") 99 { 100 if (c == '@') 101 tokenIsRecognized = true; 102 else 103 tokenIsRecognized = false; 104 } 105 else 106 { 107 if (c == '@') 108 { 109 // ouch, there are nested macros 110 // ( for example @shForeach(@shPropertyString(foobar)) ) 111 currentToken = ""; 112 } 113 } 114 115 if (c == '(' && tokenIsRecognized) 116 isInBraces = true; 117 else if (c == ')' && tokenIsRecognized) 118 isInBraces = false; 119 120 currentToken += c; 121 122 } 123 } 124 } 125 getInstance(PropertySetGet * properties)126 ShaderInstance* ShaderSet::getInstance (PropertySetGet* properties) 127 { 128 size_t h = buildHash (properties); 129 if (std::find(mFailedToCompile.begin(), mFailedToCompile.end(), h) != mFailedToCompile.end()) 130 return NULL; 131 if (mInstances.find(h) == mInstances.end()) 132 { 133 ShaderInstance newInstance(this, mName + "_" + boost::lexical_cast<std::string>(h), properties); 134 if (!newInstance.getSupported()) 135 { 136 mFailedToCompile.push_back(h); 137 return NULL; 138 } 139 mInstances.insert(std::make_pair(h, newInstance)); 140 } 141 return &mInstances.find(h)->second; 142 } 143 buildHash(PropertySetGet * properties)144 size_t ShaderSet::buildHash (PropertySetGet* properties) 145 { 146 size_t seed = 0; 147 PropertySetGet* currentGlobalSettings = getCurrentGlobalSettings (); 148 149 for (std::vector<std::string>::iterator it = mProperties.begin(); it != mProperties.end(); ++it) 150 { 151 std::string v = retrieveValue<StringValue>(properties->getProperty(*it), properties->getContext()).get(); 152 boost::hash_combine(seed, v); 153 } 154 for (std::vector <std::string>::iterator it = mGlobalSettings.begin(); it != mGlobalSettings.end(); ++it) 155 { 156 boost::hash_combine(seed, retrieveValue<StringValue>(currentGlobalSettings->getProperty(*it), NULL).get()); 157 } 158 for (std::vector<std::string>::iterator it = mPropertiesToExist.begin(); it != mPropertiesToExist.end(); ++it) 159 { 160 std::string v = retrieveValue<StringValue>(properties->getProperty(*it), properties->getContext()).get(); 161 boost::hash_combine(seed, static_cast<bool>(v != "")); 162 } 163 boost::hash_combine(seed, static_cast<int>(Factory::getInstance().getCurrentLanguage())); 164 return seed; 165 } 166 getCurrentGlobalSettings() const167 PropertySetGet* ShaderSet::getCurrentGlobalSettings() const 168 { 169 return Factory::getInstance ().getCurrentGlobalSettings (); 170 } 171 getBasePath() const172 std::string ShaderSet::getBasePath() const 173 { 174 return mBasePath; 175 } 176 getSource() const177 std::string ShaderSet::getSource() const 178 { 179 return mSource; 180 } 181 getCgProfile() const182 std::string ShaderSet::getCgProfile() const 183 { 184 return mCgProfile; 185 } 186 getHlslProfile() const187 std::string ShaderSet::getHlslProfile() const 188 { 189 return mHlslProfile; 190 } 191 getType() const192 int ShaderSet::getType() const 193 { 194 return mType; 195 } 196 } 197