1import sys
2import random
3import operator
4import itertools
5
6from genutil import *
7
8random.seed(1234567)
9indices = xrange(sys.maxint)
10
11# Constructors:
12#
13# - scalars types
14#   * int <-> float <-> bool (also float(float) etc.)
15#   * to bool: zero means false, others true
16#   * from bool: false==0, true==1
17#   * \todo [petri] float<->int rounding rules?
18# - scalar type from vector
19#   * choose the first component
20# - vectors & matrices
21#   * vector from scalar: broadcast to all components
22#   * matrix from scalar: broadcast scalar to diagonal, other components zero
23#   * vector from vector: copy existing components
24#     + illegal: vector from smaller vector
25#   * mat from mat: copy existing components, other components from identity matrix
26#   * from components: consumed by-component in column-major order, must have same
27#     number of components,
28#     + note: vec4(mat2) valid
29#     \todo [petri] Implement!
30# - notes:
31#   * type conversions are always allowed: mat3(ivec3, bvec3, bool, int, float) is valid!
32#
33# Accessors:
34#
35# - vector components
36#   * .xyzw, .rgba, .stpq
37#   * illegal to mix
38#   * now allowed for scalar types
39#   * legal to chain: vec4.rgba.xyzw.stpq
40#   * illegal to select more than 4 components
41#   * array indexing with [] operator
42#   * can also write!
43# - matrix columns
44#   * [] accessor
45#   * note: mat4[0].x = 1.0; vs mat4[0][0] = 1.0; ??
46#   * out-of-bounds accesses
47#
48# \todo [petri] Accessors!
49#
50# Spec issues:
51#
52# - constructing larger vector from smaller: vec3(vec2) ?
53# - base type and size conversion at same time: vec4(bool), int(vec3) allowed?
54
55def combineVec(comps):
56	res = []
57	for ndx in range(len(comps[0])):
58#		for x in comps:
59#			print x[ndx].toFloat().getScalars() ,
60		scalars = reduce(operator.add, [x[ndx].toFloat().getScalars() for x in comps])
61#		print "->", scalars
62		res.append(Vec.fromScalarList(scalars))
63	return res
64
65def combineIVec(comps):
66	res = []
67	for ndx in range(len(comps[0])):
68		res.append(Vec.fromScalarList(reduce(operator.add, [x[ndx].toInt().getScalars() for x in comps])))
69	return res
70
71def combineBVec(comps):
72	res = []
73	for ndx in range(len(comps[0])):
74		res.append(Vec.fromScalarList(reduce(operator.add, [x[ndx].toBool().getScalars() for x in comps])))
75	return res
76
77def combineMat(numCols, numRows, comps):
78	res = []
79	for ndx in range(len(comps[0])):
80		scalars = reduce(operator.add, [x[ndx].toFloat().getScalars() for x in comps])
81		res.append(Mat(numCols, numRows, scalars))
82	return res
83
84def combineMat2(comps):		return combineMat(2, 2, comps)
85def combineMat3(comps):		return combineMat(3, 3, comps)
86def combineMat4(comps):		return combineMat(4, 4, comps)
87
88# 0 \+ [f*f for f in lst]
89# r = 0 \+ [f in lst -> f*f]
90# r = 0 \+ lst
91
92# Templates.
93
94s_simpleCaseTemplate = """
95case ${{NAME}}
96	values
97	{
98		${{VALUES}}
99	}
100
101	both ""
102		precision mediump float;
103		precision mediump int;
104
105		${DECLARATIONS}
106
107		void main()
108		{
109			${SETUP}
110			${{OP}}
111			${OUTPUT}
112		}
113	""
114end
115"""[1:]
116
117s_simpleIllegalCaseTemplate = """
118case ${{NAME}}
119	expect compile_fail
120	values {}
121
122	both ""
123		precision mediump float;
124		precision mediump int;
125
126		${DECLARATIONS}
127
128		void main()
129		{
130			${SETUP}
131			${{OP}}
132			${OUTPUT}
133		}
134	""
135end
136"""[1:]
137
138class SimpleCase(ShaderCase):
139	def __init__(self, name, inputs, outputs, op):
140		self.name		= name
141		self.inputs		= inputs
142		self.outputs	= outputs
143		self.op			= op
144
145	def __str__(self):
146		params = {
147			"NAME":		self.name,
148			"VALUES":	genValues(self.inputs, self.outputs),
149			"OP":		self.op
150		}
151		return fillTemplate(s_simpleCaseTemplate, params)
152
153class ConversionCase(ShaderCase):
154	def __init__(self, inValues, convFunc):
155		outValues = convFunc(inValues)
156		inType	= inValues[0].typeString()
157		outType	= outValues[0].typeString()
158		self.name		= "%s_to_%s" % (inType, outType)
159		self.op			= "out0 = %s(in0);" % outType
160		self.inputs		= [("%s in0" % inType, inValues)]
161		self.outputs	= [("%s out0" % outType, outValues)]
162
163	def __str__(self):
164		params = {
165			"NAME":		self.name,
166			"VALUES":	genValues(self.inputs, self.outputs),
167			"OP":		self.op
168		}
169		return fillTemplate(s_simpleCaseTemplate, params)
170
171class IllegalConversionCase(ShaderCase):
172	def __init__(self, inValue, outValue):
173		inType	= inValue.typeString()
174		outType	= outValue.typeString()
175		self.name		= "%s_to_%s" % (inType, outType)
176		self.op			= "%s in0 = %s;\n%s out0 = %s(in0);" % (inType, str(inValue), outType, outType)
177		self.inType		= inType
178		self.outType	= outType
179
180	def __str__(self):
181		params = {
182			"NAME":		self.name,
183			"OP":		self.op
184		}
185		return fillTemplate(s_simpleIllegalCaseTemplate, params)
186
187class CombineCase(ShaderCase):
188	def __init__(self, inComps, combFunc):
189		self.inComps	= inComps
190		self.outValues	= combFunc(inComps)
191		self.outType	= self.outValues[0].typeString()
192		inTypes = [values[0].typeString() for values in inComps]
193		self.name		= "%s_to_%s" % ("_".join(inTypes), self.outType)
194		self.inputs		= [("%s in%s" % (comp[0].typeString(), ndx), comp) for (comp, ndx) in zip(inComps, indices)]
195		self.outputs	= [("%s out0" % self.outType, self.outValues)]
196		self.op			= "out0 = %s(%s);" % (self.outType, ", ".join(["in%d" % x for x in range(len(inComps))]))
197
198	def __str__(self):
199		params = {
200			"NAME":		self.name,
201			"VALUES":	genValues(self.inputs, self.outputs),
202			"OP":		self.op
203		}
204		return fillTemplate(s_simpleCaseTemplate, params)
205
206# CASE DECLARATIONS
207
208inFloat	= [Scalar(x) for x in [0.0, 1.0, 2.0, 3.5, -0.5, -8.25, -20.125, 36.8125]]
209inInt	= [Scalar(x) for x in [0, 1, 2, 5, 8, 11, -12, -66, -192, 255]]
210inBool	= [Scalar(x) for x in [True, False]]
211
212inVec4	= [Vec4(0.0, 0.5, 0.75, 0.825), Vec4(1.0, 1.25, 1.125, 1.75),
213		   Vec4(-0.5, -2.25, -4.875, 9.0), Vec4(-32.0, 64.0, -51.0, 24.0),
214		   Vec4(-0.75, -1.0/31.0, 1.0/19.0, 1.0/4.0)]
215inVec3	= toVec3(inVec4)
216inVec2	= toVec2(inVec4)
217inIVec4	= toIVec4(inVec4)
218inIVec3	= toIVec3(inVec4)
219inIVec2	= toIVec2(inVec4)
220inBVec4	= [Vec4(True, False, False, True), Vec4(False, False, False, True), Vec4(False, True, False, False), Vec4(True, True, True, True), Vec4(False, False, False, False)]
221inBVec3	= toBVec3(inBVec4)
222inBVec2	= toBVec2(inBVec4)
223
224# \todo [petri] Enable large values when epsilon adapts to the values.
225inMat4	= [Mat4(1.0, 0.0, 0.0, 0.0,  0.0, 1.0, 0.0, 0.0,  0.0, 0.0, 1.0, 0.0,  0.0, 0.0, 0.0, 1.0),
226		   Mat4(6.5, 12.5, -0.75, 9.975,  32.0, 1.0/48.0, -8.425, -6.542,  1.0/8.0, 1.0/16.0, 1.0/32.0, 1.0/64.0,  -6.725, -0.5, -0.0125, 9.975),
227		   #Mat4(128.0, 256.0, -512.0, -1024.0,  2048.0, -4096.0, 8192.0, -8192.0,  192.0, -384.0, 768.0, -1536.0,  8192.0, -8192.0, 6144.0, -6144.0)
228		   ]
229inMat3	= [Mat3(1.0, 0.0, 0.0,  0.0, 1.0, 0.0,  0.0, 0.0, 1.0),
230		   Mat3(6.5, 12.5, -0.75,  32.0, 1.0/32.0, 1.0/64.0,  1.0/8.0, 1.0/16.0, 1.0/32.0),
231		   #Mat3(-18.725, -0.5, -0.0125,  19.975, -0.25, -17.75,  9.25, 65.125, -21.425),
232		   #Mat3(128.0, -4096.0, -8192.0,  192.0, 768.0, -1536.0,  8192.0, 6144.0, -6144.0)
233		   ]
234inMat2	= [Mat2(1.0, 0.0,  0.0, 1.0),
235		   Mat2(6.5, 12.5,  -0.75, 9.975),
236		   Mat2(6.5, 12.5,  -0.75, 9.975),
237		   Mat2(8.0, 16.0,  -24.0, -16.0),
238		   Mat2(1.0/8.0, 1.0/16.0,  1.0/32.0, 1.0/64.0),
239		   Mat2(-18.725, -0.5,  -0.0125, 19.975),
240		   #Mat2(128.0, -4096.0,  192.0, -1536.0),
241		   #Mat2(-1536.0, 8192.0,  6144.0, -6144.0)
242		   ]
243
244def genConversionCases(inValueList, convFuncList):
245	combinations = list(itertools.product(inValueList, convFuncList))
246	return [ConversionCase(inValues, convFunc) for (inValues, convFunc) in combinations]
247
248def genIllegalConversionCases(inValueList, outValueList):
249	inValues	= [x[0] for x in inValueList]
250	outValues	= [x[0] for x in outValueList]
251	combinations = list(itertools.product(inValues, outValues))
252	return [IllegalConversionCase(inVal, outVal) for (inVal, outVal) in combinations]
253
254def shuffleSubLists(outer):
255	return [shuffled(inner) for inner in outer]
256
257# Generate all combinations of CombineCases.
258# inTupleList	a list of tuples of value-lists
259# combFuncList	a list of comb* functions to combine
260def genComponentCases(inCompLists, combFuncList):
261	res = []
262	for comps in inCompLists:
263		maxLen = reduce(max, [len(values) for values in comps])
264		comps = [repeatToLength(values, maxLen) for values in comps]
265		comps = [shuffled(values) for values in comps]
266		for combFunc in combFuncList:
267			res += [CombineCase(comps, combFunc)]
268	return res
269
270allConversionCases = []
271
272# Scalar-to-scalar conversions.
273allConversionCases.append(CaseGroup("scalar_to_scalar", "Scalar to Scalar Conversions",
274	genConversionCases([inFloat, inInt, inBool], [toFloat, toInt, toBool])))
275
276# Scalar-to-vector conversions.
277allConversionCases.append(CaseGroup("scalar_to_vector", "Scalar to Vector Conversions",
278	genConversionCases([inFloat, inInt, inBool], [toVec2, toVec3, toVec4, toIVec2, toIVec3, toIVec4, toBVec2, toBVec3, toBVec4])))
279
280# Vector-to-scalar conversions.
281allConversionCases.append(CaseGroup("vector_to_scalar", "Vector to Scalar Conversions",
282	genConversionCases([inVec2, inVec3, inVec4, inIVec2, inIVec3, inIVec4, inBVec2, inBVec3, inBVec4], [toFloat, toInt, toBool])))
283
284# Illegal vector-to-vector conversions (to longer vec).
285allConversionCases.append(CaseGroup("vector_illegal", "Illegal Vector Conversions",
286	genIllegalConversionCases([inVec2, inIVec2, inBVec2], [inVec3, inIVec3, inBVec3, inVec4, inIVec4, inBVec4]) +\
287	genIllegalConversionCases([inVec3, inIVec3, inBVec3], [inVec4, inIVec4, inBVec4])))
288
289# Vector-to-vector conversions (type conversions, downcasts).
290allConversionCases.append(CaseGroup("vector_to_vector", "Vector to Vector Conversions",
291	genConversionCases([inVec4, inIVec4, inBVec4], [toVec4, toVec3, toVec2, toIVec4, toIVec3, toIVec2, toBVec4, toBVec3, toBVec2]) +\
292	genConversionCases([inVec3, inIVec3, inBVec3], [toVec3, toVec2, toIVec3, toIVec2, toBVec3, toBVec2]) +\
293	genConversionCases([inVec2, inIVec2, inBVec2], [toVec2, toIVec2, toBVec2])))
294
295# Scalar-to-matrix.
296allConversionCases.append(CaseGroup("scalar_to_matrix", "Scalar to Matrix Conversions",
297	genConversionCases([inFloat, inInt, inBool], [toMat4, toMat3, toMat2])))
298
299# Vector-to-matrix.
300#allConversionCases += genConversionCases([inVec4, inIVec4, inBVec4], [toMat4])
301#allConversionCases += genConversionCases([inVec3, inIVec3, inBVec3], [toMat3])
302#allConversionCases += genConversionCases([inVec2, inIVec2, inBVec2], [toMat2])
303
304# Matrix-to-matrix.
305allConversionCases.append(CaseGroup("matrix_to_matrix", "Matrix to Matrix Conversions",
306	genConversionCases([inMat4, inMat3, inMat2], [toMat4, toMat3, toMat2])))
307
308# Vector-from-components, matrix-from-components.
309in2Comp 	= [[inFloat, inFloat], [inInt, inInt], [inBool, inBool], [inFloat, inInt], [inFloat, inBool], [inInt, inBool]]
310in3Comp 	= [[inFloat, inFloat, inFloat], [inInt, inInt, inInt], [inBool, inBool, inBool], [inBool, inFloat, inInt], [inVec2, inBool], [inBVec2, inFloat], [inBVec2, inInt], [inBool, inIVec2]]
311in4Comp 	= [[inVec2, inVec2], [inBVec2, inBVec2], [inFloat, inFloat, inFloat, inFloat], [inInt, inInt, inInt, inInt], [inBool, inBool, inBool, inBool], [inBool, inFloat, inInt, inBool], [inVec2, inIVec2], [inVec2, inBVec2], [inBVec3, inFloat], [inVec3, inFloat], [inInt, inIVec2, inInt], [inBool, inFloat, inIVec2]]
312in9Comp 	= [[inVec3, inVec3, inVec3], [inIVec3, inIVec3, inIVec3], [inVec2, inIVec2, inFloat, inFloat, inInt, inBool, inBool], [inBool, inFloat, inInt, inVec2, inBool, inBVec2, inFloat], [inBool, inBVec2, inInt, inVec4, inBool], [inFloat, inBVec4, inIVec2, inBool, inBool]]
313in16Comp	= [[inVec4, inVec4, inVec4, inVec4], [inIVec4, inIVec4, inIVec4, inIVec4], [inBVec4, inBVec4, inBVec4, inBVec4], [inFloat, inIVec3, inBVec3, inVec4, inIVec2, inFloat, inVec2]]
314
315allConversionCases.append(CaseGroup("vector_combine", "Vector Combine Constructors",
316	genComponentCases(in4Comp, [combineVec, combineIVec, combineBVec]) +\
317	genComponentCases(in3Comp, [combineVec, combineIVec, combineBVec]) +\
318	genComponentCases(in2Comp, [combineVec, combineIVec, combineBVec])))
319
320allConversionCases.append(CaseGroup("matrix_combine", "Matrix Combine Constructors",
321	genComponentCases(in4Comp, [combineMat2]) +\
322	genComponentCases(in9Comp, [combineMat3]) +\
323	genComponentCases(in16Comp, [combineMat4])
324	))
325
326# Main program.
327
328if __name__ == "__main__":
329	print "Generating shader case files."
330	writeAllCases("conversions.test", allConversionCases)
331