1 /* This file is part of the Spring engine (GPL v2 or later), see LICENSE.html */
2 
3 #ifndef SPRING_SHADER_STATES_HDR
4 #define SPRING_SHADER_STATES_HDR
5 
6 #include "Rendering/GL/myGL.h"
7 
8 #include <boost/cstdint.hpp>
9 #include <string.h>
10 #include <string>
11 #include <map>
12 #include <sstream>
13 
14 // NOTE:
15 //   the hash used here collides too much on certain inputs (eg. team-color
16 //   uniforms) and is not any faster to calculate than 4 direct comparisons
17 //   for floating-point inputs the v* are their bitwise representations (so
18 //   equality testing still works as expected)
19 //#define USE_HASH_COMPARISON
20 
21 namespace Shader {
22 	struct UniformState {
23 	private:
24 		union {
25 			boost::int32_t i[17];
26 			float          f[17];
27 		};
28 
29 		/// current glGetUniformLocation
30 		int location;
31 
32 		/// uniform name in the shader
33 		std::string name;
34 
35 	#ifdef DEBUG
36 		/// uniform type
37 		int type;
38 	#endif
39 
40 	public:
UniformStateUniformState41 		UniformState(const std::string& _name): location(-1), name(_name) {
42 			i[0] = -0xFFFFFF;
43 			i[1] = -0xFFFFFF;
44 			i[2] = -0xFFFFFF;
45 			i[3] = -0xFFFFFF;
46 		#ifdef DEBUG
47 			type = -1;
48 		#endif
49 		}
50 
GetIntValuesUniformState51 		const int* GetIntValues() const { return &i[0]; }
GetFltValuesUniformState52 		const float* GetFltValues() const { return &f[0]; }
53 
GetLocationUniformState54 		int GetLocation() const { return location; }
GetNameUniformState55 		const std::string& GetName() const { return name; }
56 
SetLocationUniformState57 		void SetLocation(int loc) { location = loc; }
58 
59 		bool IsLocationValid() const;
IsUninitUniformState60 		bool IsUninit() const {
61 			return (i[0] == -0xFFFFFF) && (i[1] == -0xFFFFFF) && (i[2] == -0xFFFFFF) && (i[3] == -0xFFFFFF);
62 		}
63 
64 	public:
GetTypeUniformState65 		int GetType() const {
66 		#ifdef DEBUG
67 			return type;
68 		#else
69 			return -1;
70 		#endif
71 		}
SetTypeUniformState72 		void SetType(int type) {
73 		#ifdef DEBUG
74 			this->type = type;
75 		#endif
76 		}
77 	#ifdef DEBUG
78 		void AssertType(int type) const;
79 	#else
AssertTypeUniformState80 		void AssertType(int type) const {}
81 	#endif
82 
83 	public:
84 		int Hash(const int v0, const int v1, const int v2, const int v3) const;
85 		int Hash(const int* v, int count) const;
86 
87 		bool CheckHash(const int v0, const int v1 = 0, const int v2 = 0, const int v3 = 0) const {
88 		#ifdef USE_HASH_COMPARISON
89 			return (Hash(i[0], i[1], i[2], i[3]) == Hash(v0, v1, v2, v3));
90 		#else
91 			return (i[0] == v0 && i[1] == v1 && i[2] == v2 && i[3] == v3);
92 		#endif
93 		}
CheckHashUniformState94 		bool CheckHash(const int* v, int count) const {
95 		#ifdef USE_HASH_COMPARISON
96 			return (Hash(i, count) == Hash(v, count));
97 		#else
98 			bool equal = true;
99 			for (int n = 0; (n < count) && equal; n++) {
100 				equal &= (v[n] == i[n]);
101 			}
102 			return equal;
103 		#endif
104 		}
105 
106 	private:
Set_UniformState107 		bool Set_(const int v0, const int v1, const int v2, const int v3) {
108 			if (CheckHash(v0, v1, v2, v3))
109 				return false;
110 			i[0] = v0; i[1] = v1; i[2] = v2; i[3] = v3;
111 			return IsLocationValid();
112 		}
113 
114 
Set_UniformState115 		bool Set_(const float v0, const float v1, const float v2, const float v3) {
116 			const int i0 = *reinterpret_cast<const int*>(&v0);
117 			const int i1 = *reinterpret_cast<const int*>(&v1);
118 			const int i2 = *reinterpret_cast<const int*>(&v2);
119 			const int i3 = *reinterpret_cast<const int*>(&v3);
120 			if (CheckHash(i0, i1, i2, i3))
121 				return false;
122 			f[0] = v0; f[1] = v1; f[2] = v2; f[3] = v3;
123 			return IsLocationValid();
124 		}
125 
126 	public:
SetUniformState127 		bool Set(const int v0, const int v1, const int v2, const int v3)
128 			{ AssertType(GL_INT_VEC4); return Set_(v0, v1, v2, v3); }
SetUniformState129 		bool Set(const int v0, const int v1, const int v2)
130 			{ AssertType(GL_INT_VEC3); return Set_(v0, v1, v2,  0); }
SetUniformState131 		bool Set(const int v0, const int v1)
132 			{ AssertType(GL_INT_VEC2); return Set_(v0, v1,  0,  0); }
SetUniformState133 		bool Set(const int v0)
134 			{ AssertType(GL_INT     ); return Set_(v0,  0,  0,  0); }
135 
SetUniformState136 		bool Set(const float v0, const float v1, const float v2, const float v3)
137 			{ AssertType(GL_FLOAT_VEC4); return Set_(v0, v1, v2, v3); }
SetUniformState138 		bool Set(const float v0, const float v1, const float v2)
139 			{ AssertType(GL_FLOAT_VEC3); return Set_(v0, v1, v2, 0.f); }
SetUniformState140 		bool Set(const float v0, const float v1)
141 			{ AssertType(GL_FLOAT_VEC2); return Set_(v0, v1, 0.f, 0.f); }
SetUniformState142 		bool Set(const float v0)
143 			{ AssertType(GL_FLOAT     ); return Set_(v0, 0.f, 0.f, 0.f); }
144 
Set2vUniformState145 		bool Set2v(const int* v) {
146 			AssertType(GL_INT_VEC2);
147 			if (CheckHash(v[0], v[1]))
148 				return false;
149 			i[0] = v[0]; i[1] = v[1];
150 			return IsLocationValid();
151 		}
Set3vUniformState152 		bool Set3v(const int* v) {
153 			AssertType(GL_INT_VEC3);
154 			if (CheckHash(v[0], v[1], v[2]))
155 				return false;
156 			i[0] = v[0]; i[1] = v[1]; i[2] = v[2];
157 			return IsLocationValid();
158 		}
Set4vUniformState159 		bool Set4v(const int* v) {
160 			AssertType(GL_INT_VEC4);
161 			if (CheckHash(v[0], v[1], v[2], v[3]))
162 				return false;
163 			i[0] = v[0]; i[1] = v[1]; i[2] = v[2]; i[3] = v[3];
164 			return IsLocationValid();
165 		}
166 
167 
Set2vUniformState168 		bool Set2v(const float* v) {
169 			AssertType(GL_FLOAT_VEC2);
170 			const int* vi = reinterpret_cast<const int*>(v);
171 			if (CheckHash(vi[0], vi[1]))
172 				return false;
173 			f[0] = v[0]; f[1] = v[1];
174 			return IsLocationValid();
175 		}
Set3vUniformState176 		bool Set3v(const float* v) {
177 			AssertType(GL_FLOAT_VEC3);
178 			const int* vi = reinterpret_cast<const int*>(v);
179 			if (CheckHash(vi[0], vi[1], vi[2]))
180 				return false;
181 			f[0] = v[0]; f[1] = v[1]; f[2] = v[2];
182 			return IsLocationValid();
183 		}
Set4vUniformState184 		bool Set4v(const float* v) {
185 			AssertType(GL_FLOAT_VEC4);
186 			const int* vi = reinterpret_cast<const int*>(v);
187 			if (CheckHash(vi[0], vi[1], vi[2], vi[3]))
188 				return false;
189 			f[0] = v[0]; f[1] = v[1]; f[2] = v[2]; f[3] = v[3];
190 			return IsLocationValid();
191 		}
192 
193 
Set2x2UniformState194 		bool Set2x2(const float* v, bool transp) {
195 			AssertType(GL_FLOAT_MAT2);
196 			const int* vi = reinterpret_cast<const int*>(v);
197 			if (CheckHash(vi, 4) && (bool)i[16] == transp)
198 				return false;
199 			memcpy(f, v, 4 * sizeof(float));
200 			i[16] = transp;
201 			return IsLocationValid();
202 		}
Set3x3UniformState203 		bool Set3x3(const float* v, bool transp) {
204 			AssertType(GL_FLOAT_MAT3);
205 			const int* vi = reinterpret_cast<const int*>(v);
206 			if (CheckHash(vi, 9) && (bool)i[16] == transp)
207 				return false;
208 			memcpy(f, v, 9 * sizeof(float));
209 			i[16] = transp;
210 			return IsLocationValid();
211 		}
Set4x4UniformState212 		bool Set4x4(const float* v, bool transp) {
213 			AssertType(GL_FLOAT_MAT4);
214 			const int* vi = reinterpret_cast<const int*>(v);
215 			if (CheckHash(vi, 16) && (bool)i[16] == transp)
216 				return false;
217 			memcpy(f, v, 16 * sizeof(float));
218 			i[16] = transp;
219 			return IsLocationValid();
220 		}
221 	};
222 
223 
224 	struct SShaderFlagState {
225 	public:
SShaderFlagStateSShaderFlagState226 		SShaderFlagState() : updates(0), lastUpdates(0), lastHash(0) {}
~SShaderFlagStateSShaderFlagState227 		virtual ~SShaderFlagState() {}
228 
229 		unsigned int GetHash();
230 
GetStringSShaderFlagState231 		std::string GetString() const
232 		{
233 			std::ostringstream strbuf;
234 			for (std::map<std::string, std::string>::const_iterator it = flags.begin(); it != flags.end(); ++it) {
235 				strbuf << "#define " << it->first << " " << it->second << std::endl;
236 			}
237 			return strbuf.str();
238 		}
239 
240 
ClearFlagSShaderFlagState241 		void ClearFlag(const std::string& flag)
242 		{
243 			++updates;
244 			flags.erase(flag);
245 		}
246 
SetFlagSShaderFlagState247 		void SetFlag(const std::string& flag, const bool enable)
248 		{
249 			if (enable) {
250 				++updates;
251 				flags[flag] = "";
252 			} else {
253 				ClearFlag(flag);
254 			}
255 		}
256 
257 		//FIXME gives compiletime error
258 		/*bool GetFlag(const std::string& flag) const
259 		{
260 			std::map<std::string, std::string>::const_iterator it = flags.find(flag);
261 			if (it != flags.end()) {
262 				return true;
263 			} else {
264 				return false;
265 			}
266 		}*/
267 
SetFlagSShaderFlagState268 		void SetFlag(const std::string& flag, const std::string& newvalue)
269 		{
270 			++updates;
271 			flags[flag] = newvalue;
272 		}
273 
GetFlagSShaderFlagState274 		const std::string& GetFlag(const std::string& flag) const
275 		{
276 			std::map<std::string, std::string>::const_iterator it = flags.find(flag);
277 			if (it != flags.end()) {
278 				return it->second;
279 			} else {
280 				static std::string nulstr;
281 				return nulstr;
282 			}
283 		}
284 
285 		template <typename T>
SetFlagSShaderFlagState286 		void SetFlag(const std::string& flag, const T newvalue)
287 		{
288 			++updates;
289 			std::ostringstream buffer;
290 			buffer << newvalue;
291 			flags[flag] = buffer.str();
292 		}
293 
294 		template <typename T>
GetFlagSShaderFlagState295 		T GetFlag(const std::string& flag) const
296 		{
297 			std::map<std::string, std::string>::const_iterator it = flags.find(flag);
298 			if (it != flags.end()) {
299 				std::istringstream buf(it->second);
300 				T temp;
301 				buf >> temp;
302 				return temp;
303 			} else {
304 				return T();
305 			}
306 
307 		}
308 
309 	private:
310 		int updates;
311 		int lastUpdates;
312 		int lastHash;
313 		std::map<std::string, std::string> flags;
314 		//std::set<std::string> skipAutoUpdate;
315 	};
316 }
317 
318 #endif
319