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