1 /*
2 -----------------------------------------------------------------------------
3 This source file is part of OGRE
4 (Object-oriented Graphics Rendering Engine)
5 For the latest info, see http://www.ogre3d.org/
6
7 Copyright (c) 2000-2013 Torus Knot Software Ltd
8 Permission is hereby granted, free of charge, to any person obtaining a copy
9 of this software and associated documentation files (the "Software"), to deal
10 in the Software without restriction, including without limitation the rights
11 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 copies of the Software, and to permit persons to whom the Software is
13 furnished to do so, subject to the following conditions:
14
15 The above copyright notice and this permission notice shall be included in
16 all copies or substantial portions of the Software.
17
18 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24 THE SOFTWARE.
25 -----------------------------------------------------------------------------
26 */
27
28 #include "OgreShaderFunctionAtom.h"
29 #include "OgreRoot.h"
30
31 namespace Ogre {
32 namespace RTShader {
33 //-----------------------------------------------------------------------------
Operand(ParameterPtr parameter,Operand::OpSemantic opSemantic,int opMask,ushort indirectionLevel)34 Operand::Operand(ParameterPtr parameter, Operand::OpSemantic opSemantic, int opMask, ushort indirectionLevel) : mParameter(parameter), mSemantic(opSemantic), mMask(opMask), mIndirectionLevel(indirectionLevel)
35 {
36 }
37 //-----------------------------------------------------------------------------
Operand(const Operand & other)38 Operand::Operand(const Operand& other)
39 {
40 *this = other;
41 }
42 //-----------------------------------------------------------------------------
operator =(const Operand & other)43 Operand& Operand::operator= (const Operand & other)
44 {
45 if (this != &other)
46 {
47 mParameter = other.mParameter;
48 mSemantic = other.mSemantic;
49 mMask = other.mMask;
50 mIndirectionLevel = other.mIndirectionLevel;
51 }
52 return *this;
53 }
54 //-----------------------------------------------------------------------------
~Operand()55 Operand::~Operand()
56 {
57 // nothing todo
58 }
59 //-----------------------------------------------------------------------------
getMaskAsString(int mask)60 String Operand::getMaskAsString(int mask)
61 {
62 String retVal = "";
63
64 if (mask & ~OPM_ALL)
65 {
66 if (mask & OPM_X)
67 {
68 retVal += "x";
69 }
70
71 if (mask & OPM_Y)
72 {
73 retVal += "y";
74 }
75
76 if (mask & OPM_Z)
77 {
78 retVal += "z";
79 }
80
81 if (mask & OPM_W)
82 {
83 retVal += "w";
84 }
85 }
86
87 return retVal;
88 }
89
90 //-----------------------------------------------------------------------------
getFloatCount(int mask)91 int Operand::getFloatCount(int mask)
92 {
93 int floatCount = 0;
94
95 while (mask != 0)
96 {
97 if ((mask & Operand::OPM_X) != 0)
98 {
99 floatCount++;
100
101 }
102 mask = mask >> 1;
103 }
104
105 return floatCount;
106 }
107
108 //-----------------------------------------------------------------------------
getGpuConstantType(int mask)109 GpuConstantType Operand::getGpuConstantType(int mask)
110 {
111 int floatCount = getFloatCount(mask);
112 GpuConstantType type;
113
114 switch (floatCount)
115 {
116
117 case 1:
118 type = GCT_FLOAT1;
119 break;
120
121 case 2:
122 type = GCT_FLOAT2;
123 break;
124
125 case 3:
126 type = GCT_FLOAT3;
127 break;
128
129 case 4:
130 type = GCT_FLOAT4;
131 break;
132
133 default:
134 type = GCT_UNKNOWN;
135 break;
136 }
137
138 return type;
139 }
140
141 //-----------------------------------------------------------------------------
toString() const142 String Operand::toString() const
143 {
144 String retVal = mParameter->toString();
145 if ((mMask & OPM_ALL) || ((mMask & OPM_X) && (mMask & OPM_Y) && (mMask & OPM_Z) && (mMask & OPM_W)))
146 {
147 return retVal;
148 }
149
150 retVal += "." + getMaskAsString(mMask);
151
152 return retVal;
153 }
154
155 //-----------------------------------------------------------------------------
FunctionAtom()156 FunctionAtom::FunctionAtom()
157 {
158 mGroupExecutionOrder = -1;
159 mInternalExecutionOrder = -1;
160 }
161
162 //-----------------------------------------------------------------------------
getGroupExecutionOrder() const163 int FunctionAtom::getGroupExecutionOrder() const
164 {
165 return mGroupExecutionOrder;
166 }
167
168 //-----------------------------------------------------------------------------
getInternalExecutionOrder() const169 int FunctionAtom::getInternalExecutionOrder() const
170 {
171 return mInternalExecutionOrder;
172 }
173
174
175 String FunctionInvocation::Type = "FunctionInvocation";
176
177 //-----------------------------------------------------------------------
FunctionInvocation(const String & functionName,int groupOrder,int internalOrder,String returnType)178 FunctionInvocation::FunctionInvocation(const String& functionName,
179 int groupOrder, int internalOrder, String returnType) :
180 mFunctionName(functionName), mReturnType(returnType)
181 {
182 mGroupExecutionOrder = groupOrder;
183 mInternalExecutionOrder = internalOrder;
184 }
185
186 //-----------------------------------------------------------------------------
FunctionInvocation(const FunctionInvocation & other)187 FunctionInvocation::FunctionInvocation(const FunctionInvocation& other) :
188 mFunctionName(other.mFunctionName), mReturnType(other.mReturnType)
189 {
190 mGroupExecutionOrder = other.mGroupExecutionOrder;
191 mInternalExecutionOrder = other.mInternalExecutionOrder;
192
193 for ( OperandVector::const_iterator it = other.mOperands.begin(); it != other.mOperands.end(); ++it)
194 mOperands.push_back(Operand(*it));
195 }
196
197 //-----------------------------------------------------------------------
writeSourceCode(std::ostream & os,const String & targetLanguage) const198 void FunctionInvocation::writeSourceCode(std::ostream& os, const String& targetLanguage) const
199 {
200 // Write function name.
201 os << mFunctionName << "(";
202
203 // Write parameters.
204 ushort curIndLevel = 0;
205 for (OperandVector::const_iterator it = mOperands.begin(); it != mOperands.end(); )
206 {
207 os << (*it).toString();
208 ++it;
209
210 ushort opIndLevel = 0;
211 if (it != mOperands.end())
212 {
213 opIndLevel = (*it).getIndirectionLevel();
214 }
215
216 if (curIndLevel < opIndLevel)
217 {
218 while (curIndLevel < opIndLevel)
219 {
220 ++curIndLevel;
221 os << "[";
222 }
223 }
224 else //if (curIndLevel >= opIndLevel)
225 {
226 while (curIndLevel > opIndLevel)
227 {
228 --curIndLevel;
229 os << "]";
230 }
231 if (opIndLevel != 0)
232 {
233 os << "][";
234 }
235 else if (it != mOperands.end())
236 {
237 os << ", ";
238 }
239 }
240 }
241
242 // Write function call closer.
243 os << ");";
244 }
245
246 //-----------------------------------------------------------------------
pushOperand(ParameterPtr parameter,Operand::OpSemantic opSemantic,int opMask,int indirectionLevel)247 void FunctionInvocation::pushOperand(ParameterPtr parameter, Operand::OpSemantic opSemantic, int opMask, int indirectionLevel)
248 {
249 mOperands.push_back(Operand(parameter, opSemantic, opMask, indirectionLevel));
250 }
251
252 //-----------------------------------------------------------------------
operator ==(const FunctionInvocation & rhs) const253 bool FunctionInvocation::operator == ( const FunctionInvocation& rhs ) const
254 {
255 return FunctionInvocationCompare()(*this, rhs);
256 }
257
258 //-----------------------------------------------------------------------
operator !=(const FunctionInvocation & rhs) const259 bool FunctionInvocation::operator != ( const FunctionInvocation& rhs ) const
260 {
261 return !(*this == rhs);
262 }
263
264 //-----------------------------------------------------------------------
operator <(const FunctionInvocation & rhs) const265 bool FunctionInvocation::operator < ( const FunctionInvocation& rhs ) const
266 {
267 return FunctionInvocationLessThan()(*this, rhs);
268 }
269
operator ()(FunctionInvocation const & lhs,FunctionInvocation const & rhs) const270 bool FunctionInvocation::FunctionInvocationLessThan::operator ()(FunctionInvocation const& lhs, FunctionInvocation const& rhs) const
271 {
272 // Check the function names first
273 // Adding an exception to std::string sorting. I feel that functions beginning with an underscore should be placed before
274 // functions beginning with an alphanumeric character. By default strings are sorted based on the ASCII value of each character.
275 // Underscores have an ASCII value in between capital and lowercase characters. This is why the exception is needed.
276 if (lhs.getFunctionName() < rhs.getFunctionName())
277 {
278 if(rhs.getFunctionName().at(0) == '_')
279 return false;
280 else
281 return true;
282 }
283 if (lhs.getFunctionName() > rhs.getFunctionName())
284 {
285 if(lhs.getFunctionName().at(0) == '_')
286 return true;
287 else
288 return false;
289 }
290
291 // Next check the return type
292 if (lhs.getReturnType() < rhs.getReturnType())
293 return true;
294 if (lhs.getReturnType() > rhs.getReturnType())
295 return false;
296
297 // Check the number of operands
298 if (lhs.mOperands.size() < rhs.mOperands.size())
299 return true;
300 if (lhs.mOperands.size() > rhs.mOperands.size())
301 return false;
302
303 // Now that we've gotten past the two quick tests, iterate over operands
304 // Check the semantic and type. The operands must be in the same order as well.
305 OperandVector::const_iterator itLHSOps = lhs.mOperands.begin();
306 OperandVector::const_iterator itRHSOps = rhs.mOperands.begin();
307
308 for ( ; ((itLHSOps != lhs.mOperands.end()) && (itRHSOps != rhs.mOperands.end())); ++itLHSOps, ++itRHSOps)
309 {
310 if (itLHSOps->getSemantic() < itRHSOps->getSemantic())
311 return true;
312 if (itLHSOps->getSemantic() > itRHSOps->getSemantic())
313 return false;
314
315 GpuConstantType leftType = itLHSOps->getParameter()->getType();
316 GpuConstantType rightType = itRHSOps->getParameter()->getType();
317
318 if (Ogre::Root::getSingletonPtr()->getRenderSystem()->getName().find("OpenGL ES 2") != String::npos)
319 {
320 if (leftType == GCT_SAMPLER1D)
321 leftType = GCT_SAMPLER2D;
322
323 if (rightType == GCT_SAMPLER1D)
324 rightType = GCT_SAMPLER2D;
325 }
326
327 // If a swizzle mask is being applied to the parameter, generate the GpuConstantType to
328 // perform the parameter type comparison the way that the compiler will see it.
329 if ((itLHSOps->getFloatCount(itLHSOps->getMask()) > 0) ||
330 (itRHSOps->getFloatCount(itRHSOps->getMask()) > 0))
331 {
332 if (itLHSOps->getFloatCount(itLHSOps->getMask()) > 0)
333 {
334 leftType = (GpuConstantType)((itLHSOps->getParameter()->getType() - itLHSOps->getParameter()->getType()) +
335 itLHSOps->getFloatCount(itLHSOps->getMask()));
336 }
337 if (itRHSOps->getFloatCount(itRHSOps->getMask()) > 0)
338 {
339 rightType = (GpuConstantType)((itRHSOps->getParameter()->getType() - itRHSOps->getParameter()->getType()) +
340 itRHSOps->getFloatCount(itRHSOps->getMask()));
341 }
342 }
343
344 if (leftType < rightType)
345 return true;
346 if (leftType > rightType)
347 return false;
348 }
349
350 return false;
351 }
352
operator ()(FunctionInvocation const & lhs,FunctionInvocation const & rhs) const353 bool FunctionInvocation::FunctionInvocationCompare::operator ()(FunctionInvocation const& lhs, FunctionInvocation const& rhs) const
354 {
355 // Check the function names first
356 if (lhs.getFunctionName() != rhs.getFunctionName())
357 return false;
358
359 // Next check the return type
360 if (lhs.getReturnType() != rhs.getReturnType())
361 return false;
362
363 // Check the number of operands
364 if (lhs.mOperands.size() != rhs.mOperands.size())
365 return false;
366
367 // Now that we've gotten past the two quick tests, iterate over operands
368 // Check the semantic and type. The operands must be in the same order as well.
369 OperandVector::const_iterator itLHSOps = lhs.mOperands.begin();
370 OperandVector::const_iterator itRHSOps = rhs.mOperands.begin();
371 for ( ; ((itLHSOps != lhs.mOperands.end()) && (itRHSOps != rhs.mOperands.end())); ++itLHSOps, ++itRHSOps)
372 {
373 if (itLHSOps->getSemantic() != itRHSOps->getSemantic())
374 return false;
375
376 GpuConstantType leftType = itLHSOps->getParameter()->getType();
377 GpuConstantType rightType = itRHSOps->getParameter()->getType();
378
379 if (Ogre::Root::getSingletonPtr()->getRenderSystem()->getName().find("OpenGL ES 2") != String::npos)
380 {
381 if (leftType == GCT_SAMPLER1D)
382 leftType = GCT_SAMPLER2D;
383
384 if (rightType == GCT_SAMPLER1D)
385 rightType = GCT_SAMPLER2D;
386 }
387
388 // If a swizzle mask is being applied to the parameter, generate the GpuConstantType to
389 // perform the parameter type comparison the way that the compiler will see it.
390 if ((itLHSOps->getFloatCount(itLHSOps->getMask()) > 0) ||
391 (itRHSOps->getFloatCount(itRHSOps->getMask()) > 0))
392 {
393 if (itLHSOps->getFloatCount(itLHSOps->getMask()) > 0)
394 {
395 leftType = (GpuConstantType)((itLHSOps->getParameter()->getType() - itLHSOps->getParameter()->getType()) +
396 itLHSOps->getFloatCount(itLHSOps->getMask()));
397 }
398 if (itRHSOps->getFloatCount(itRHSOps->getMask()) > 0)
399 {
400 rightType = (GpuConstantType)((itRHSOps->getParameter()->getType() - itRHSOps->getParameter()->getType()) +
401 itRHSOps->getFloatCount(itRHSOps->getMask()));
402 }
403 }
404
405 if (leftType != rightType)
406 return false;
407 }
408
409 // Passed all tests, they are the same
410 return true;
411 }
412
413 }
414 }
415