/** * reads a list of ShaderNode{} blocks * * @param statements the list of statements to parse * @throws IOException */ protected void readShaderNode(List<Statement> statements) throws IOException { for (Statement statement : statements) { String line = statement.getLine(); String[] split = statement.getLine().split("[ \\{]"); if (line.startsWith("Definition")) { ShaderNodeDefinition def = findDefinition(statement); shaderNode.setDefinition(def); if (def.isNoOutput()) { techniqueDef.getShaderGenerationInfo().getUnusedNodes().remove(shaderNode.getName()); } } else if (line.startsWith("Condition")) { String condition = line.substring(line.lastIndexOf(":") + 1).trim(); extractCondition(condition, statement); shaderNode.setCondition(conditionParser.getFormattedExpression()); } else if (line.startsWith("InputMapping")) { for (Statement statement1 : statement.getContents()) { VariableMapping mapping = readInputMapping(statement1); techniqueDef .getShaderGenerationInfo() .getUnusedNodes() .remove(mapping.getRightVariable().getNameSpace()); shaderNode.getInputMapping().add(mapping); } } else if (line.startsWith("OutputMapping")) { for (Statement statement1 : statement.getContents()) { VariableMapping mapping = readOutputMapping(statement1); techniqueDef.getShaderGenerationInfo().getUnusedNodes().remove(shaderNode.getName()); shaderNode.getOutputMapping().add(mapping); } } else { throw new MatParseException("ShaderNodeDefinition", split[0], statement); } } }
/** * reads an output mapping * * @param statement1 the staement being read * @return the mapping * @throws IOException */ public VariableMapping readOutputMapping(Statement statement1) throws IOException { VariableMapping mapping = null; try { mapping = parseMapping(statement1, new boolean[] {true, false}); } catch (Exception e) { throw new MatParseException("Unexpected mapping format", statement1, e); } ShaderNodeVariable left = mapping.getLeftVariable(); ShaderNodeVariable right = mapping.getRightVariable(); if (left.getType().startsWith("sampler") || right.getType().startsWith("sampler")) { throw new MatParseException("Samplers can only be inputs", statement1); } if (left.getNameSpace().equals("Global")) { left.setType("vec4"); // Globals are all vec4 for now (maybe forever...) storeGlobal(left, statement1); } else { throw new MatParseException( "Only Global nameSpace is allowed for outputMapping, got" + left.getNameSpace(), statement1); } if (!updateVariableFromList(right, shaderNode.getDefinition().getOutputs())) { throw new MatParseException( right.getName() + " is not an output variable of " + shaderNode.getDefinition().getName(), statement1); } checkTypes(mapping, statement1); return mapping; }
/** * check the types of a mapping, left type must match right type tkae the swizzle into account * * @param mapping the mapping * @param statement1 the statement being read * @throws MatParseException */ protected void checkTypes(VariableMapping mapping, Statement statement1) throws MatParseException { if (!ShaderUtils.typesMatch(mapping)) { String ls = mapping.getLeftSwizzling().length() == 0 ? "" : "." + mapping.getLeftSwizzling(); String rs = mapping.getRightSwizzling().length() == 0 ? "" : "." + mapping.getRightSwizzling(); throw new MatParseException( "Type mismatch, cannot convert " + mapping.getRightVariable().getType() + rs + " to " + mapping.getLeftVariable().getType() + ls, statement1); } if (!ShaderUtils.multiplicityMatch(mapping)) { String type1 = mapping.getLeftVariable().getType() + "[" + mapping.getLeftVariable().getMultiplicity() + "]"; String type2 = mapping.getRightVariable().getType() + "[" + mapping.getRightVariable().getMultiplicity() + "]"; throw new MatParseException( "Type mismatch, cannot convert " + type1 + " to " + type2, statement1); } }
/** * updates the type of the right variable of a mapping from the type of the left variable * * @param mapping the mapping to consider */ protected void updateRightTypeFromLeftType(VariableMapping mapping) { String type = mapping.getLeftVariable().getType(); int card = ShaderUtils.getCardinality(type, mapping.getRightSwizzling()); if (card > 0) { if (card == 1) { type = "float"; } else { type = "vec" + card; } } mapping.getRightVariable().setType(type); }
/** * updates the right variable of the given mapping from a UniformBinding (a WorldParam) it checks * if the unifrom hasn't already been loaded, add it to the maps if not. * * @param param the WorldParam UniformBinding * @param mapping the mapping * @param map the map of uniforms to search into * @return true if the param was added to the map */ protected boolean updateRightFromUniforms( UniformBinding param, VariableMapping mapping, Map<String, DeclaredVariable> map) { ShaderNodeVariable right = mapping.getRightVariable(); String name = "g_" + param.toString(); DeclaredVariable dv = map.get(name); if (dv == null) { right.setType(param.getGlslType()); right.setName(name); dv = new DeclaredVariable(right); map.put(right.getName(), dv); dv.addNode(shaderNode); mapping.setRightVariable(right); return true; } dv.addNode(shaderNode); mapping.setRightVariable(dv.var); return false; }
/** * updates a variable from the Attribute list * * @param right the variable * @param mapping the mapping */ public void updateVarFromAttributes(ShaderNodeVariable right, VariableMapping mapping) { DeclaredVariable dv = attributes.get(right.getName()); if (dv == null) { dv = new DeclaredVariable(right); attributes.put(right.getName(), dv); updateRightTypeFromLeftType(mapping); } else { mapping.setRightVariable(dv.var); } dv.addNode(shaderNode); }
/** * store a varying * * @param node the shaderNode * @param variable the variable to store */ public void storeVaryings(ShaderNode node, ShaderNodeVariable variable) { variable.setShaderOutput(true); if (node.getDefinition().getType() == Shader.ShaderType.Vertex && shaderNode.getDefinition().getType() == Shader.ShaderType.Fragment) { DeclaredVariable dv = varyings.get(variable.getName()); if (dv == null) { techniqueDef.getShaderGenerationInfo().getVaryings().add(variable); dv = new DeclaredVariable(variable); varyings.put(variable.getName(), dv); } dv.addNode(shaderNode); // if a variable is declared with the same name as an input and an output and is a varying, // set it as a shader output so it's declared as a varying only once. for (VariableMapping variableMapping : node.getInputMapping()) { if (variableMapping.getLeftVariable().getName().equals(variable.getName())) { variableMapping.getLeftVariable().setShaderOutput(true); } } } }
protected void computeConditions() { updateConditions(vertexDeclaredUniforms); updateConditions(fragmentDeclaredUniforms); updateConditions(varyings); for (DeclaredVariable v : varyings.values()) { for (ShaderNode sn : techniqueDef.getShaderNodes()) { if (sn.getDefinition().getType() == Shader.ShaderType.Vertex) { for (VariableMapping mapping : sn.getInputMapping()) { if (mapping.getLeftVariable().equals(v.var)) { if (mapping.getCondition() == null || v.var.getCondition() == null) { mapping.setCondition(v.var.getCondition()); } else { mapping.setCondition( "(" + mapping.getCondition() + ") || (" + v.var.getCondition() + ")"); } } } } } } updateConditions(attributes); // updateConditions(fragmentGlobals); // vertexGlobal.makeCondition(); }
/** * updates the right variable of the given mapping from a MatParam (a WorldParam) it checks if the * unifrom hasn't already been loaded, add it to the maps if not. * * @param param the MatParam * @param mapping the mapping * @param map the map of uniforms to search into * @return true if the param was added to the map */ public boolean updateRightFromUniforms( MatParam param, VariableMapping mapping, Map<String, DeclaredVariable> map, Statement statement) throws MatParseException { ShaderNodeVariable right = mapping.getRightVariable(); DeclaredVariable dv = map.get(param.getPrefixedName()); if (dv == null) { right.setType(param.getVarType().getGlslType()); right.setName(param.getPrefixedName()); if (mapping.getLeftVariable().getMultiplicity() != null) { if (!param.getVarType().name().endsWith("Array")) { throw new MatParseException(param.getName() + " is not of Array type", statement); } String multiplicity = mapping.getLeftVariable().getMultiplicity(); try { Integer.parseInt(multiplicity); } catch (NumberFormatException nfe) { // multiplicity is not an int attempting to find for a material parameter. MatParam mp = findMatParam(multiplicity); if (mp != null) { addDefine(multiplicity, VarType.Int); multiplicity = multiplicity.toUpperCase(); } else { throw new MatParseException( "Wrong multiplicity for variable" + mapping.getLeftVariable().getName() + ". " + multiplicity + " should be an int or a declared material parameter.", statement); } } right.setMultiplicity(multiplicity); } dv = new DeclaredVariable(right); map.put(right.getName(), dv); dv.addNode(shaderNode); mapping.setRightVariable(right); return true; } dv.addNode(shaderNode); mapping.setRightVariable(dv.var); return false; }
public void makeCondition() { var.setCondition(null); for (ShaderNode node : nodes) { String condition = null; for (VariableMapping mapping : node.getInputMapping()) { if (mapping.getRightVariable().equals(var)) { if (mapping.getCondition() == null) { condition = null; break; } if (condition == null) { condition = "(" + mapping.getCondition() + ")"; } else { if (!condition.contains(mapping.getCondition())) { condition = condition + " || (" + mapping.getCondition() + ")"; } } } } if (node.getCondition() == null && condition == null) { var.setCondition(null); return; } if (node.getCondition() != null) { if (condition == null) { condition = node.getCondition(); } else { if (!condition.contains(node.getCondition())) { condition = "(" + node.getCondition() + ") && (" + condition + ")"; } } } if (var.getCondition() == null) { var.setCondition(condition); } else { if (!var.getCondition().contains(condition)) { var.setCondition("(" + var.getCondition() + ") || (" + condition + ")"); } } } }
/** * reads a mapping statement. Sets the nameSpace, name and swizzling of the left variable. Sets * the name, nameSpace and swizzling of the right variable types will be determined later. <code> * Format : <nameSpace>.<varName>[.<swizzling>] = * <nameSpace>.<varName>[.<swizzling>][:Condition] * </code> * * @param statement the statement to read * @return the read mapping */ protected VariableMapping parseMapping(Statement statement, boolean[] hasNameSpace) throws IOException { VariableMapping mapping = new VariableMapping(); String[] cond = statement.getLine().split(":"); String[] vars = cond[0].split("="); checkMappingFormat(vars, statement); ShaderNodeVariable[] variables = new ShaderNodeVariable[2]; String[] swizzle = new String[2]; for (int i = 0; i < vars.length; i++) { String[] expression = vars[i].trim().split("\\."); if (hasNameSpace[i]) { if (expression.length <= 3) { variables[i] = new ShaderNodeVariable("", expression[0].trim(), expression[1].trim()); } if (expression.length == 3) { swizzle[i] = expression[2].trim(); } } else { if (expression.length <= 2) { variables[i] = new ShaderNodeVariable("", expression[0].trim()); } if (expression.length == 2) { swizzle[i] = expression[1].trim(); } } } mapping.setLeftVariable(variables[0]); mapping.setLeftSwizzling(swizzle[0] != null ? swizzle[0] : ""); mapping.setRightVariable(variables[1]); mapping.setRightSwizzling(swizzle[1] != null ? swizzle[1] : ""); if (cond.length > 1) { extractCondition(cond[1], statement); mapping.setCondition(conditionParser.getFormattedExpression()); } return mapping; }
/** * reads an input mapping * * @param statement1 the statement being read * @return the mapping * @throws IOException */ public VariableMapping readInputMapping(Statement statement1) throws IOException { VariableMapping mapping = null; try { mapping = parseMapping(statement1, new boolean[] {false, true}); } catch (Exception e) { throw new MatParseException("Unexpected mapping format", statement1, e); } ShaderNodeVariable left = mapping.getLeftVariable(); ShaderNodeVariable right = mapping.getRightVariable(); if (!updateVariableFromList(left, shaderNode.getDefinition().getInputs())) { throw new MatParseException( left.getName() + " is not an input variable of " + shaderNode.getDefinition().getName(), statement1); } if (left.getType().startsWith("sampler") && !right.getNameSpace().equals("MatParam")) { throw new MatParseException("Samplers can only be assigned to MatParams", statement1); } if (right.getNameSpace().equals("Global")) { right.setType("vec4"); // Globals are all vec4 for now (maybe forever...) // updateCondition(right, mapping); storeGlobal(right, statement1); } else if (right.getNameSpace().equals("Attr")) { if (shaderNode.getDefinition().getType() == Shader.ShaderType.Fragment) { throw new MatParseException( "Cannot have an attribute as input in a fragment shader" + right.getName(), statement1); } updateVarFromAttributes(mapping.getRightVariable(), mapping); // updateCondition(mapping.getRightVariable(), mapping); storeAttribute(mapping.getRightVariable()); } else if (right.getNameSpace().equals("MatParam")) { MatParam param = findMatParam(right.getName()); if (param == null) { throw new MatParseException( "Could not find a Material Parameter named " + right.getName(), statement1); } if (shaderNode.getDefinition().getType() == Shader.ShaderType.Vertex) { if (updateRightFromUniforms(param, mapping, vertexDeclaredUniforms, statement1)) { storeVertexUniform(mapping.getRightVariable()); } } else { if (updateRightFromUniforms(param, mapping, fragmentDeclaredUniforms, statement1)) { if (mapping.getRightVariable().getType().contains("|")) { String type = fixSamplerType(left.getType(), mapping.getRightVariable().getType()); if (type != null) { mapping.getRightVariable().setType(type); } else { throw new MatParseException( param.getVarType().toString() + " can only be matched to one of " + param.getVarType().getGlslType().replaceAll("\\|", ",") + " found " + left.getType(), statement1); } } storeFragmentUniform(mapping.getRightVariable()); } } } else if (right.getNameSpace().equals("WorldParam")) { UniformBinding worldParam = findWorldParam(right.getName()); if (worldParam == null) { throw new MatParseException( "Could not find a World Parameter named " + right.getName(), statement1); } if (shaderNode.getDefinition().getType() == Shader.ShaderType.Vertex) { if (updateRightFromUniforms(worldParam, mapping, vertexDeclaredUniforms)) { storeVertexUniform(mapping.getRightVariable()); } } else { if (updateRightFromUniforms(worldParam, mapping, fragmentDeclaredUniforms)) { storeFragmentUniform(mapping.getRightVariable()); } } } else { ShaderNode node = nodes.get(right.getNameSpace()); if (node == null) { throw new MatParseException( "Undeclared node" + right.getNameSpace() + ". Make sure this node is declared before the current node", statement1); } ShaderNodeVariable var = findNodeOutput(node.getDefinition().getOutputs(), right.getName()); if (var == null) { throw new MatParseException( "Cannot find output variable" + right.getName() + " form ShaderNode " + node.getName(), statement1); } right.setNameSpace(node.getName()); right.setType(var.getType()); right.setMultiplicity(var.getMultiplicity()); mapping.setRightVariable(right); storeVaryings(node, mapping.getRightVariable()); } checkTypes(mapping, statement1); return mapping; }