2 ** Copyright (c) 2014 The Khronos Group Inc.
4 ** Permission is hereby granted, free of charge, to any person obtaining a
5 ** copy of this software and/or associated documentation files (the
6 ** "Materials"), to deal in the Materials without restriction, including
7 ** without limitation the rights to use, copy, modify, merge, publish,
8 ** distribute, sublicense, and/or sell copies of the Materials, and to
9 ** permit persons to whom the Materials are furnished to do so, subject to
10 ** the following conditions:
12 ** The above copyright notice and this permission notice shall be included
13 ** in all copies or substantial portions of the Materials.
15 ** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 ** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 ** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18 ** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
19 ** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
20 ** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
21 ** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
25 var GLSLConstructorTestsGenerator = (function() {
27 var wtu = WebGLTestUtils;
29 // Shader code templates
30 var constructorVertexTemplate = [
31 "attribute vec4 vPosition;",
33 "precision mediump int;",
34 "precision mediump float;",
36 // Colors used to signal correctness of component values comparison
37 "const vec4 green = vec4(0.0, 1.0, 0.0, 1.0);",
38 "const vec4 red = vec4(1.0, 0.0, 0.0, 1.0);",
40 // Error bound used in comparison of floating point values
43 "varying vec4 vColor;",
48 " $(type) v = $(type)($(argsConstr));",
50 " if ($(checkCompVals))",
55 " gl_Position = vPosition;",
60 var passThroughColorFragmentShader = [
61 "precision mediump float;",
63 "varying vec4 vColor;",
66 " gl_FragColor = vColor;",
71 var constructorFragmentTemplate = [
72 "precision mediump int;",
73 "precision mediump float;",
75 // Colors used to signal correctness of component values comparison
76 "const vec4 green = vec4(0.0, 1.0, 0.0, 1.0); ",
77 "const vec4 red = vec4(1.0, 0.0, 0.0, 1.0); ",
79 // Error bound used in comparison of floating point values
85 " $(type) v = $(type)($(argsConstr));",
87 " if ($(checkCompVals))",
88 " gl_FragColor = green;",
90 " gl_FragColor = red;",
95 // Coding of the different argument types
104 // Returns the dimensions of the type
105 // Count of columns, count of rows
106 function getTypeCodeDimensions(typeCode) {
108 case "s": return [1, 1];
109 case "v2": return [1, 2];
110 case "v3": return [1, 3];
111 case "v4": return [1, 4];
112 case "m2": return [2, 2];
113 case "m3": return [3, 3];
114 case "m4": return [4, 4];
117 wtu.error("GLSLConstructorTestsGenerator.getTypeCodeDimensions(), unknown type code");
123 // Returns the component count for the type code
124 function getTypeCodeComponentCount(typeCode) {
125 var dim = getTypeCodeDimensions(typeCode);
127 return dim[0] * dim[1];
131 // Returns glsl name of type code
132 function getGLSLBaseTypeName(typeCode) {
135 case "v2": return "vec2";
136 case "v3": return "vec3";
137 case "v4": return "vec4";
138 case "m2": return "mat2";
139 case "m3": return "mat3";
140 case "m4": return "mat4";
143 wtu.error("GLSLConstructorTestsGenerator.getGLSLBaseTypeName(), unknown type code");
149 // Returns the scalar glsl type name related to the structured type
150 function getGLSLScalarType(targetType) {
151 switch(targetType[0]) {
152 case 'i': return "int";
153 case 'b': return "bool";
160 wtu.error("GLSLConstructorTestsGenerator.getGLSLScalarType(), unknown target type");
166 // Returns the scalar prefix for the associated scalar type
167 function getGLSLScalarPrefix(targetType) {
168 switch(targetType[0]) {
171 return targetType[0];
178 wtu.error("GLSLConstructorTestsGenerator.getGLSLScalarPrefix(), unknown target type");
184 // Returns the type for a specified target type and argument type code
185 function getGLSLArgumentType(typeCode, targetType) {
186 var baseType = getGLSLBaseTypeName(typeCode);
187 if (baseType !== "") {
188 if (typeCode[0] === "v") {
189 // Vectors come in different flavours
190 return getGLSLScalarPrefix(targetType) + baseType;
196 return getGLSLScalarType(targetType);
200 // Returns the glsl type of the argument components
201 function getGLSLArgumentComponentType(argTypeCode, targetType) {
204 if (argTypeCode[0] === "m") {
205 // Matrices are always floats
206 scalarType = "float";
209 scalarType = getGLSLScalarType(targetType);
215 function getGLSLColumnSize(targetType) {
216 colSize = parseInt(targetType.slice(-1));
221 wtu.error("GLSLConstructorTestsGenerator.getGLSLColumnSize(), invalid target type");
226 // Returns correct string representation of scalar value
227 function getScalarTypeValStr(val, scalarType) {
231 switch (scalarType) {
232 case "float": return val.toFixed(1);
233 case "int": return val;
234 case "bool": return (val === 0) ? "false" : "true";
237 wtu.error("GLSLConstructorTestsGenerator.getScalarTypeValStr(), unknown scalar type");
243 // Returns true if the glsl type name is a matrix
244 function isGLSLTypeMatrix(type) {
245 return (type.indexOf("mat") !== -1);
249 // Returns true if the glsl type name is a vector
250 function isGLSLTypeVector(type) {
251 return (type.indexOf("vec") !== -1);
255 // Returns the count of components
256 function getGLSLTypeComponentCount(type) {
257 var colSize = getGLSLColumnSize(type);
259 if (isGLSLTypeMatrix(type))
260 return colSize * colSize;
266 // Returns the constructor expression with the components set to a sequence of scalar values
267 // Like vec3(1.0, 2.0, 3.0)
268 function getComponentSequenceConstructorExpression(typeCode, firstCompValue, targetType) {
269 var scalarType = getGLSLArgumentComponentType(typeCode, targetType);
271 if (typeCode === "s") {
273 return getScalarTypeValStr(firstCompValue, scalarType) + ";";
276 // Structured typeargTypeCode[0] === "m"
277 compCount = getTypeCodeComponentCount(typeCode);
278 var constrExpParts = new Array(compCount);
279 for (var aa = 0; aa < compCount; ++aa)
280 constrExpParts[aa] = getScalarTypeValStr(firstCompValue + aa, scalarType);
282 return getGLSLArgumentType(typeCode, targetType) + "(" + constrExpParts.join(", ") + ");";
287 // Returns the expression to select a component of the structured type
288 function getComponentSelectorExpStr(targetType, compIx) {
289 if (isGLSLTypeMatrix(targetType)) {
290 var colRowIx = getColRowIndexFromLinearIndex(compIx, getGLSLColumnSize(targetType));
291 return "v[" + colRowIx.colIx + "][" + colRowIx.rowIx + "]";
294 return "v[" + compIx + "]";
298 // Returns expression which validates the components set by the constructor expression
299 function getComponentValidationExpression(refCompVals, targetType) {
300 // Early out for invalid arguments
301 if (refCompVals.length === 0)
304 var scalarType = getGLSLScalarType(targetType);
305 var checkComponentValueParts = new Array(refCompVals.length);
306 for (var cc = 0; cc < refCompVals.length; ++cc) {
307 var val_str = getScalarTypeValStr(refCompVals[cc], scalarType);
308 var comp_sel_exp = getComponentSelectorExpStr(targetType, cc);
309 if (scalarType === "float") {
310 // Comparison of floating point values with error bound
311 checkComponentValueParts[cc] = "abs(" + comp_sel_exp + " - " + val_str + ") <= errorBound";
314 // Simple comparison to expected value
315 checkComponentValueParts[cc] = comp_sel_exp + " == " + val_str;
319 return checkComponentValueParts.join(" && ");
323 // Returns substitution parts to turn the shader template into testable shader code
324 function getTestShaderParts(targetType, argExp, firstCompValue) {
325 // glsl code of declarations of arguments
326 var argsListParts = new Array(argExp.length);
328 // glsl code of constructor expression
329 var argsConstrParts = new Array(argExp.length);
331 // glsl type expression
332 var typeExpParts = new Array(argExp.length);
333 for (var aa = 0; aa < argExp.length; ++aa) {
334 var typeCode = argExp[aa];
335 var argCompCount = getTypeCodeComponentCount(typeCode);
336 var argName = "a" + aa;
337 var argType = getGLSLArgumentType(typeCode, targetType);
338 var argConstrExp = argType + " " + argName + " = " + getComponentSequenceConstructorExpression(typeCode, firstCompValue, targetType);
340 // Add construction of one argument
341 // Indent if not first argument
342 argsListParts[aa] = ((aa > 0) ? " " : "") + argConstrExp;
344 // Add argument name to target type argument list
345 argsConstrParts[aa] = argName;
347 // Add type name to type expression
348 typeExpParts[aa] = argType;
350 // Increment argument component value so all argument component arguments have a unique value
351 firstCompValue += argCompCount;
355 argsList: argsListParts.join("\n") + "\n",
356 argsConstr: argsConstrParts.join(", "),
357 typeExp: targetType + "(" + typeExpParts.join(", ") + ")"
362 // Utility functions to manipulate the array of reference values
364 // Returns array filled with identical values
365 function getArrayWithIdenticalValues(size, val) {
366 var matArray = new Array(size);
367 for (var aa = 0; aa < size; ++aa)
374 // Returns array filled with increasing values from a specified start value
375 function getArrayWithIncreasingValues(size, start) {
376 var matArray = new Array(size);
377 for (var aa = 0; aa < size; ++aa)
378 matArray[aa] = start + aa;
384 // Utility functions to manipulate the array of reference values if the target type is a matrix
386 // Returns an array which is the column order layout of a square matrix where the diagonal is set to a specified value
387 function matCompArraySetDiagonal(matArray, diagVal) {
388 // The entries for the diagonal start at array index 0 and increase
389 // by column size + 1
390 var colSize = Math.round(Math.sqrt(matArray.length));
393 matArray[dIx] = diagVal;
394 dIx += (colSize + 1);
396 while (dIx < colSize * colSize);
402 // Returns an array which contains the values of an identity matrix read out in column order
403 function matCompArrayCreateDiagonalMatrix(colSize, diagVal) {
404 var size = colSize * colSize;
405 var matArray = new Array(size);
406 for (var aa = 0; aa < size; ++aa)
409 return matCompArraySetDiagonal(matArray, diagVal);
413 // Returns the column and row index from the linear index if the components of the matrix are stored in column order in an array
414 // in a one dimensional array in column order
415 function getColRowIndexFromLinearIndex(linIx, colSize) {
417 colIx: Math.floor(linIx / colSize),
418 rowIx: linIx % colSize
423 // Returns the linear index for matrix column and row index for a specified matrix size
424 function getLinearIndexFromColRowIndex(rowColIx, colSize) {
425 return rowColIx.colIx * colSize + rowColIx.rowIx;
429 // Returns a matrix set from another matrix
430 function matCompArraySetMatrixFromMatrix(dstColSize, srcMatArray) {
431 // Overwrite components from destination with the source component values at the same col, row coordinates
432 var dstMatArray = matCompArrayCreateDiagonalMatrix(dstColSize, 1);
434 var srcColSize = Math.round(Math.sqrt(srcMatArray.length));
436 for (var c_ix = 0; c_ix < srcMatArray.length; ++c_ix) {
437 var srcMatIx = getColRowIndexFromLinearIndex(c_ix, srcColSize);
438 if (srcMatIx.colIx < dstColSize && srcMatIx.rowIx < dstColSize) {
439 // Source matrix coordinates are valid destination matrix coordinates
440 dstMatArray[getLinearIndexFromColRowIndex(srcMatIx, dstColSize)] = srcMatArray[c_ix];
448 // Returns the glsl code to verify if the components are set correctly
449 // and the message to display for the test
450 function getConstructorExpressionInfo(targetType, argExp, firstCompValue) {
451 var argCompCountsSum = 0;
452 var argCompCounts = new Array(argExp.length);
453 for (var aa = 0; aa < argExp.length; ++aa) {
454 argCompCounts[aa] = getTypeCodeComponentCount(argExp[aa]);
455 argCompCountsSum += argCompCounts[aa];
458 var targetCompCount = getGLSLTypeComponentCount(targetType);
464 if (argCompCountsSum === 0) {
465 // A constructor needs at least one argument
467 testMsg = "invalid (no arguments)";
471 if (isGLSLTypeVector(targetType)) {
472 if (argCompCountsSum === 1) {
473 // One scalar argument
474 // Vector constructor with one scalar argument set all components to the same value
475 refCompVals = getArrayWithIdenticalValues(targetCompCount, firstCompValue);
476 testMsg = "valid (all components set to the same value)";
480 // Not one scalar argument
481 if (argCompCountsSum < targetCompCount) {
482 // Not all components set
484 testMsg = "invalid (not enough arguments)";
488 // argCompCountsSum >= targetCompCount
489 // All components set
490 var lastArgFirstCompIx = argCompCountsSum - argCompCounts[argCompCounts.length - 1];
492 if (lastArgFirstCompIx < targetCompCount) {
493 // First component of last argument is used
494 refCompVals = getArrayWithIncreasingValues(targetCompCount, firstCompValue);
499 // First component of last argument is not used
501 testMsg = "invalid (unused argument)";
508 // Matrix target type
509 if (argCompCountsSum === 1) {
510 // One scalar argument
511 // Matrix constructors with one scalar set all components on the diagonal to the same value
512 // All other components are set to zero
513 refCompVals = matCompArrayCreateDiagonalMatrix(Math.round(Math.sqrt(targetCompCount)), firstCompValue);
514 testMsg = "valid (diagonal components set to the same value, off-diagonal components set to zero)";
518 // Not one scalar argument
519 if (argExp.length === 1 && argExp[0][0] === "m") {
520 // One single matrix argument
521 var dstColSize = getGLSLColumnSize(targetType);
522 refCompVals = matCompArraySetMatrixFromMatrix(dstColSize, getArrayWithIncreasingValues(getTypeCodeComponentCount(argExp[0]), firstCompValue));
523 testMsg = "valid, components at corresponding col, row indices are set from argument, other components are set from identity matrix";
527 // More than one argument or one argument not of type matrix
528 // Can be treated in the same manner
529 // Arguments can not be of type matrix
530 var matFound = false;
531 for (var aa = 0; aa < argExp.length; ++aa)
532 if (argExp[aa][0] === "m")
537 testMsg = "invalid, argument list greater than one contains matrix type";
541 if (argCompCountsSum < targetCompCount) {
543 testMsg = "invalid (not enough arguments)";
547 // argCompCountsSum >= targetCompCount
548 // All components set
549 var lastArgFirstCompIx = argCompCountsSum - argCompCounts[argCompCounts.length - 1];
551 if (lastArgFirstCompIx < targetCompCount) {
552 // First component of last argument is used
553 refCompVals = getArrayWithIncreasingValues(targetCompCount, firstCompValue);
558 // First component of last argument is not used
560 testMsg = "invalid (unused argument)";
570 // Check if no case is missed
571 if (testMsg == null || valid == null) {
572 wtu.error("GLSLConstructorTestsGenerator.getConstructorExpressionInfo(), info not set");
577 refCompVals: refCompVals,
584 // Returns a vertex shader testcase and a fragment shader testcase
585 function getVertexAndFragmentShaderTestCase(targetType, argExp) {
586 var firstCompValue = 0;
587 if (isGLSLTypeMatrix(targetType)) {
588 // Use value different from 0 and 1
589 // 0 and 1 are values used by matrix constructed from a matrix or a single scalar
593 var argCode = getTestShaderParts (targetType, argExp, firstCompValue);
594 var expInfo = getConstructorExpressionInfo(targetType, argExp, firstCompValue);
596 var substitutions = {
598 errorBound: (getGLSLScalarType(targetType) === "float") ? "const float errorBound = 1.0E-5;" : "",
599 argsList: argCode.argsList,
600 argsConstr: argCode.argsConstr,
601 checkCompVals: getComponentValidationExpression(expInfo.refCompVals, targetType)
605 // Test constructor argument list in vertex shader
606 vShaderSource: wtu.replaceParams(constructorVertexTemplate, substitutions),
607 vShaderSuccess: expInfo.valid,
608 fShaderSource: passThroughColorFragmentShader,
609 fShaderSuccess: true,
610 linkSuccess: expInfo.valid,
611 passMsg: "Vertex shader : " + argCode.typeExp + ", " + expInfo.testMsg,
612 render: expInfo.valid
614 // Test constructor argument list in fragment shader
615 vShaderSource: GLSLConformanceTester.defaultVertexShader,
616 vShaderSuccess: true,
617 fShaderSource: wtu.replaceParams(constructorFragmentTemplate, substitutions),
618 fShaderSuccess: expInfo.valid,
619 linkSuccess: expInfo.valid,
620 passMsg: "Fragment shader : " + argCode.typeExp + ", " + expInfo.testMsg,
621 render: expInfo.valid
627 // Incrementing the argument expressions
628 // Utility object which defines the order of incrementing the argument types
629 var typeCodeIncrementer = {
630 s: { typeCode: "v2", order: 0 },
631 v2: { typeCode: "v3", order: 1 },
632 v3: { typeCode: "v4", order: 2 },
633 v4: { typeCode: "m2", order: 3 },
634 m2: { typeCode: "m3", order: 4 },
635 m3: { typeCode: "m4", order: 5 },
636 m4: { typeCode: "s", order: 6 },
641 // Returns the next argument sequence
642 function getNextArgumentSequence(inSeq) {
644 if (inSeq.length === 0) {
645 // Current argument sequence is empty, add first argument
646 nextSeq = [typeCodeIncrementer.first];
649 nextSeq = new Array(inSeq.length);
651 for (var aa = 0; aa < inSeq.length; ++aa) {
652 var currArg = inSeq[aa];
654 // Increment the current argument type
655 var nextArg = typeCodeIncrementer[currArg].typeCode;
656 nextSeq[aa] = nextArg;
657 overflow = (nextArg === typeCodeIncrementer.first);
660 // Copy remainder of sequence
661 nextSeq[aa] = currArg;
666 nextSeq.push(typeCodeIncrementer.first);
674 // Returns true if two argument expressions are equal
675 function areArgExpEqual(expA, expB) {
676 if (expA.length !== expB.length)
679 for (var aa = 0; aa < expA.length; ++aa)
680 if (expA[aa] !== expB[aa])
687 // Returns true if first argument expression is smaller
688 // (comes before the second one in iterating order)
689 // compared to the second argument expression
690 function isArgExpSmallerOrEqual(argExpA, argExpB) {
691 var aLen = argExpA.length;
692 var bLen = argExpB.length;
694 return (aLen < bLen);
696 // Argument type expression lengths are equal
697 for (var aa = aLen - 1; aa >= 0; --aa) {
698 var argA = argExpA[aa];
699 var argB = argExpB[aa];
702 var aOrder = typeCodeIncrementer[argA].order;
703 var bOrder = typeCodeIncrementer[argB].order;
704 if (aOrder !== bOrder)
705 return (aOrder < bOrder);
709 // Argument type expressions are equal
714 // Returns the next argument expression from sequence set
715 // Returns null if end is reached
716 function getNextArgumentExpression(testExp, testSet) {
717 var testInterval = testSet[testExp.ix];
719 if (areArgExpEqual(testExp.argExp, testInterval[1])) {
720 // End of current interval reached
721 if (testExp.ix === testSet.length - 1) {
722 // End of set reached
726 // Return first argument expression of next interval
727 var nextIx = testExp.ix + 1;
728 return { ix: nextIx, argExp: testSet[nextIx][0] };
732 // Return next expression in current interval
733 return { ix: testExp.ix, argExp: getNextArgumentSequence(testExp.argExp) };
738 // Returns an array of the parts in the string separated by commas and with the white space trimmed
739 function convertCsvToArray(str) {
740 // Checks type codes in input
741 function checkInput(el, ix, arr) {
742 var typeCode = el.trim();
743 if (!(typeCode in typeCodeIncrementer) && typeCode !== "first") {
744 wtu.error("GLSLConstructorTestsGenerator.convertCsvToArray(), unknown type code" + typeCode);
751 var spArr = str.split(",");
753 // Convert empty string to empty array
754 if (spArr.length === 1 && spArr[0].trim() === "")
757 spArr.forEach(checkInput);
763 // Processes the set of specified test sequences
764 function processInputs(testSequences) {
765 var testSet = new Array(testSequences.length);
766 for (var tt = 0; tt < testSequences.length; ++tt) {
767 var interval = testSequences[tt];
768 var bounds = interval.split("-");
769 var begin = convertCsvToArray(bounds[0]);
770 var end = convertCsvToArray(bounds[bounds.length - 1]);
772 // Check if interval is valid
773 if (!isArgExpSmallerOrEqual(begin, end)) {
774 wtu.error("GLSLConstructorTestsGenerator.processInputs(), interval not valid");
778 testSet[tt] = [ begin, end ];
786 * Returns list of test cases for vector types
787 * All combinations of arguments up to one unused argument of one component are tested
788 * @param {targetType} Name of target type to test the constructor expressions on
789 * @param {testSet} Set of intervals of argument sequences to test
791 function getConstructorTests(targetType, testSequences) {
792 // List of tests to return
795 // List of argument types
796 var testSet = processInputs(testSequences);
797 var testExp = { ix: 0, argExp: testSet[0][0] };
800 // Add one vertex shader test case and one fragment shader test case
801 testInfos = testInfos.concat(getVertexAndFragmentShaderTestCase(targetType, testExp.argExp));
803 // Generate next argument expression
804 testExp = getNextArgumentExpression(testExp, testSet);
806 while (testExp != null);
812 // Returns default test argument expression set
813 // For details on input format : see bottom of file
814 function getDefaultTestSet(targetType) {
820 // No arguments and all single argument expressions
823 // All two argument expressions with a scalar as second argument
826 // All two arguments expressions with a scalar as first argument
827 "s, v2", "s, v3", "s, v4", "s, m2", "s, m3", "s, m4",
829 // Three argument expression
837 // No arguments and all single argument expressions
840 // All two argument expressions with a scalar as second argument
843 // All two argument expressions with a scalar as first argument
844 "s, v2", "s, v3", "s, v4", "s, m2", "s, m3", "s, m4",
846 // All three argument expressions with two scalars as second and third argument
847 "s, s, s - m4, s, s",
849 // All three argument expressions with two scalars as first and second argument
850 "s, s, v2", "s, s, v3", "s, s, v4", "s, s, m2", "s, s, m3", "s, s, m4",
852 // Four argument expression
861 // No arguments and all single argument expressions
864 // All two argument expressions with a scalar as second argument
867 // All two argument expressions with a scalar as first argument
868 "s, v2", "s, v3", "s, v4", "s, m2", "s, m3", "s, m4",
870 // All three argument expressions with two scalars as second and third argument
871 "s, s, s - m4, s, s",
873 // All three argument expressions with two scalars as first and second argument
874 "s, s, v2", "s, s, v3", "s, s, v4", "s, s, m2", "s, s, m3", "s, s, m4",
876 // All four argument expressions with three scalars as second, third and fourth argument
877 "s, s, s, s - m4, s, s, s",
879 // All four argument expressions with three scalars as first, second and third argument
880 "s, s, s, v2", "s, s, s, v3", "s, s, s, v4", "s, s, s, m2", "s, s, s, m3", "s, s, s, m4",
882 // Five argument expression
889 // No arguments and all single argument expressions
892 // All two argument expressions with a scalar as second argument
895 // All two argument expressions with a scalar as first argument
896 "s, v2", "s, v3", "s, v4", "s, m2", "s, m3", "s, m4",
898 // Several argument sequences
899 "v4, s, v4", "v4, s, v3, v2", "v4, v4, v3, v2", "v4, v4, v4, v4", "v2, v2, v2, v2, v2", "v2, v2, v2, v2, v2, v2, v2, v2",
900 "v3, v3, v3", "v3, v3, v3, s", "v3, v3, v3, v3, v3, s", "v3, v3, v3, v3, v3, s, s",
908 getConstructorTests: getConstructorTests,
909 getDefaultTestSet: getDefaultTestSet
915 // Input is an array of intervals of argument types
916 // The generated test argument sequences are from (including) the lower interval boundary
917 // until (including) the upper boundary
918 // Coding and order of the different argument types :
927 // One interval is put in one string
928 // Low and high bound are separated by a dash.
929 // If there is no dash it is regarded as an interval of one expression
930 // The individual argument codes are separated by commas
931 // The individual arguments are incremented from left to right
932 // The left most argument is the one which is incremented first
933 // Once the left most arguments wraps the second argument is increased
935 // "s - m4" : All single arguments from scalar up to (including) mat4
936 // "m2, s - m4, s" : All two argument expressions with a matrix argument as first argument and a scalar as second argument
937 // " - m4, m4" : The empty argument, all one arguments and all two argument expressions
938 // "m2, s, v3, m4" : One 4 argument expression : mat2, scalar, vec3, mat4