1 #ifndef SH_FACTORY_H
2 #define SH_FACTORY_H
3 
4 #include <map>
5 #include <string>
6 #include <sstream>
7 
8 #include "MaterialInstance.hpp"
9 #include "ShaderSet.hpp"
10 #include "Language.hpp"
11 
12 namespace sh
13 {
14 	class Platform;
15 
16 	class Configuration : public PropertySetGet
17 	{
18 	public:
setSourceFile(const std::string & file)19 		void setSourceFile (const std::string& file) { mSourceFile = file ; }
getSourceFile()20 		std::string getSourceFile () { return mSourceFile; }
21 
22 		void save(const std::string& name, std::ofstream &stream);
23 
24 	private:
25 		std::string mSourceFile;
26 	};
27 
28 	typedef std::map<std::string, MaterialInstance> MaterialMap;
29 	typedef std::map<std::string, ShaderSet> ShaderSetMap;
30 	typedef std::map<std::string, Configuration> ConfigurationMap;
31 	typedef std::map<int, PropertySetGet> LodConfigurationMap;
32 	typedef std::map<std::string, int> LastModifiedMap;
33 
34 	typedef std::map<std::string, std::string> TextureAliasMap;
35 
36 	/**
37 	 * @brief
38 	 * Allows you to be notified when a certain material was just created. Useful for changing material properties that you can't
39 	 * do in a .mat script (for example a series of animated textures) \n
40 	 * When receiving the event, you can get the platform material by calling m->getMaterial()
41 	 * and casting that to the platform specific material (e.g. for Ogre, sh::OgreMaterial)
42 	 */
43 	class MaterialListener
44 	{
45 	public:
46 		virtual void materialCreated (MaterialInstance* m, const std::string& configuration, unsigned short lodIndex) = 0;
47 	};
48 
49 	/**
50 	 * @brief
51 	 * The main interface class
52 	 */
53 	class Factory
54 	{
55 	public:
56 		Factory(Platform* platform);
57 		///< @note Ownership of \a platform is transferred to this class, so you don't have to delete it.
58 
59 		~Factory();
60 
61 		/**
62 		 * Create a MaterialInstance, optionally copying all properties from \a parentInstance
63 		 * @param name name of the new instance
64 		 * @param name of the parent (optional)
65 		 * @return newly created instance
66 		 */
67 		MaterialInstance* createMaterialInstance (const std::string& name, const std::string& parentInstance = "");
68 
69 		/// @note It is safe to call this if the instance does not exist
70 		void destroyMaterialInstance (const std::string& name);
71 
72 		/// Use this to enable or disable shaders on-the-fly
73 		void setShadersEnabled (bool enabled);
74 
75 		/// write generated shaders to current directory, useful for debugging
76 		void setShaderDebugOutputEnabled (bool enabled);
77 
78 		/// Use this to manage user settings. \n
79 		/// Global settings can be retrieved in shaders through a macro. \n
80 		/// When a global setting is changed, the shaders that depend on them are recompiled automatically.
81 		void setGlobalSetting (const std::string& name, const std::string& value);
82 
83 		/// Adjusts the given shared parameter. \n
84 		/// Internally, this will change all uniform parameters of this name marked with the macro \@shSharedParameter \n
85 		/// @param name of the shared parameter
86 		/// @param value of the parameter, use sh::makeProperty to construct this value
87 		void setSharedParameter (const std::string& name, PropertyValuePtr value);
88 
89 		Language getCurrentLanguage ();
90 
91 		/// Switch between different shader languages (cg, glsl, hlsl)
92 		void setCurrentLanguage (Language lang);
93 
94 		/// Get a MaterialInstance by name
95 		MaterialInstance* getMaterialInstance (const std::string& name);
96 
97 		/// Create a configuration, which can then be altered by using Factory::getConfiguration
98 		void createConfiguration (const std::string& name);
99 
100 		/// Register a lod configuration, which can then be used by setting up lod distance values for the material \n
101 		/// 0 refers to highest lod, so use 1 or higher as index parameter
102 		void registerLodConfiguration (int index, PropertySetGet configuration);
103 
104 		/// Set an alias name for a texture, the real name can then be retrieved with the "texture_alias"
105 		/// property in a texture unit - this is useful if you don't know the name of your texture beforehand. \n
106 		/// Example: \n
107 		///  - In the material definition: texture_alias ReflectionMap \n
108 		///  - At runtime: factory->setTextureAlias("ReflectionMap", "rtt_654654"); \n
109 		/// You can call factory->setTextureAlias as many times as you want, and if the material was already created, its texture will be updated!
110 		void setTextureAlias (const std::string& alias, const std::string& realName);
111 
112 		/// Retrieve the real texture name for a texture alias (the real name is set by the user)
113 		std::string retrieveTextureAlias (const std::string& name);
114 
115 		/// Attach a listener for material created events
116 		void setMaterialListener (MaterialListener* listener);
117 
118 		/// Call this after you have set up basic stuff, like the shader language.
119 		void loadAllFiles ();
120 
121 		/// Controls writing of generated shader source code to the cache folder, so that the
122 		/// (rather expensive) preprocessing step can be skipped on the next run. See Factory::setReadSourceCache \n
123 		/// \note The default is off (no cache writing)
setWriteSourceCache(bool write)124 		void setWriteSourceCache(bool write) { mWriteSourceCache = write; }
125 
126 		/// Controls reading of generated shader sources from the cache folder
127 		/// \note The default is off (no cache reading)
128 		/// \note Even if microcode caching is enabled, generating (or caching) the source is still required due to the macros.
setReadSourceCache(bool read)129 		void setReadSourceCache(bool read) { mReadSourceCache = read; }
130 
131 		/// Controls writing the microcode of the generated shaders to the cache folder. Microcode is machine independent
132 		/// and loads very fast compared to regular compilation. Note that the availability of this feature depends on the \a Platform.
133 		/// \note The default is off (no cache writing)
setWriteMicrocodeCache(bool write)134 		void setWriteMicrocodeCache(bool write) { mWriteMicrocodeCache = write; }
135 
136 		/// Controls reading of shader microcode from the cache folder. Microcode is machine independent
137 		/// and loads very fast compared to regular compilation. Note that the availability of this feature depends on the \a Platform.
138 		/// \note The default is off (no cache reading)
setReadMicrocodeCache(bool read)139 		void setReadMicrocodeCache(bool read) { mReadMicrocodeCache = read; }
140 
141 		/// Lists all materials currently registered with the factory. Whether they are
142 		/// loaded or not does not matter.
143 		void listMaterials (std::vector<std::string>& out);
144 
145 		/// Lists current name & value of all global settings.
146 		void listGlobalSettings (std::map<std::string, std::string>& out);
147 
148 		/// Lists configuration names.
149 		void listConfigurationNames (std::vector<std::string>& out);
150 
151 		/// Lists current name & value of settings for a given configuration.
152 		void listConfigurationSettings (const std::string& name, std::map<std::string, std::string>& out);
153 
154 		/// Lists shader sets.
155 		void listShaderSets (std::vector<std::string>& out);
156 
157 		/// \note This only works if microcode caching is disabled, as there is currently no way to remove the cache
158 		/// through the Ogre API. Luckily, this is already fixed in Ogre 1.9.
159 		bool reloadShaders();
160 
161 		/// Calls reloadShaders() if shader files have been modified since the last reload.
162 		/// \note This only works if microcode caching is disabled, as there is currently no way to remove the cache
163 		/// through the Ogre API. Luckily, this is already fixed in Ogre 1.9.
164 		void doMonitorShaderFiles();
165 
166 		/// Unloads all materials that are currently not referenced. This will not unload the textures themselves,
167 		/// but it will let go of the SharedPtr's to the textures, so that you may unload them if you so desire. \n
168 		/// A good time to call this would be after a new level has been loaded, but just calling it occasionally after a period
169 		/// of time should work just fine too.
170 		void unloadUnreferencedMaterials();
171 
172 		void destroyConfiguration (const std::string& name);
173 
174 		void notifyConfigurationChanged();
175 
176 		/// Saves all materials and configurations, by default to the file they were loaded from.
177 		/// If you wish to save them elsewhere, use setSourceFile first.
178 		void saveAll ();
179 
180 		/// Returns the error log as a string, then clears it.
181 		/// Note: Errors are also written to the standard error output, or thrown if they are fatal.
182 		std::string getErrorLog ();
183 
184 		static Factory& getInstance();
185 		///< Return instance of this class.
186 
187 		static Factory* getInstancePtr();
188 
189 		/// Make sure a material technique is loaded.\n
190 		/// You will probably never have to use this.
191 		void _ensureMaterial(const std::string& name, const std::string& configuration);
192 
193 
194 		Configuration* getConfiguration (const std::string& name);
195 
196 	private:
197 
198 		MaterialInstance* requestMaterial (const std::string& name, const std::string& configuration, unsigned short lodIndex);
199 		ShaderSet* getShaderSet (const std::string& name);
200 		Platform* getPlatform ();
201 
202 		PropertySetGet* getCurrentGlobalSettings();
203 
204 		void addTextureAliasInstance (const std::string& name, TextureUnitState* t);
205 		void removeTextureAliasInstances (TextureUnitState* t);
206 
getCacheFolder()207 		std::string getCacheFolder () { return mPlatform->getCacheFolder (); }
getReadSourceCache()208 		bool getReadSourceCache() { return mReadSourceCache; }
getWriteSourceCache()209 		bool getWriteSourceCache() { return mWriteSourceCache; }
210 	public:
getWriteMicrocodeCache()211 		bool getWriteMicrocodeCache() { return mWriteMicrocodeCache; } // Fixme
212 
213 	private:
214 		void setActiveConfiguration (const std::string& configuration);
215 		void setActiveLodLevel (int level);
216 
getShaderDebugOutputEnabled()217 		bool getShaderDebugOutputEnabled() { return mShaderDebugOutputEnabled; }
218 
219 		std::map<TextureUnitState*, std::string> mTextureAliasInstances;
220 
221 		void logError (const std::string& msg);
222 
223 		friend class Platform;
224 		friend class MaterialInstance;
225 		friend class ShaderInstance;
226 		friend class ShaderSet;
227 		friend class TextureUnitState;
228 
229 	private:
230 		static Factory* sThis;
231 
232 		bool mShadersEnabled;
233 		bool mShaderDebugOutputEnabled;
234 
235 		bool mReadMicrocodeCache;
236 		bool mWriteMicrocodeCache;
237 		bool mReadSourceCache;
238 		bool mWriteSourceCache;
239 		std::stringstream mErrorLog;
240 
241 		MaterialMap mMaterials;
242 		ShaderSetMap mShaderSets;
243 		ConfigurationMap mConfigurations;
244 		LodConfigurationMap mLodConfigurations;
245 		LastModifiedMap mShadersLastModified;
246 		LastModifiedMap mShadersLastModifiedNew;
247 
248 		PropertySetGet mGlobalSettings;
249 
250 		PropertySetGet* mCurrentConfiguration;
251 		PropertySetGet* mCurrentLodConfiguration;
252 
253 		TextureAliasMap mTextureAliases;
254 
255 		Language mCurrentLanguage;
256 
257 		MaterialListener* mListener;
258 
259 		Platform* mPlatform;
260 
261 		MaterialInstance* findInstance (const std::string& name);
262 		MaterialInstance* searchInstance (const std::string& name);
263 
264 		/// @return was anything removed?
265 		bool removeCache (const std::string& pattern);
266 
267 		static const std::string mBinaryCacheName;
268 	};
269 }
270 
271 #endif
272