| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536 |
- #include "MaterialShaderProgramCreator.h"
- #include "Util/Scanner/Scanner.h"
- #include "Misc/Parser.h"
- #include "BuildinMaterialVariable.h"
- #include <boost/assign/list_of.hpp>
- #include <boost/foreach.hpp>
- #include <boost/property_tree/ptree.hpp>
- //==============================================================================
- // Statics =
- //==============================================================================
- boost::unordered_map<GLenum, const char*>
- MaterialShaderProgramCreator::glTypeToTxt = boost::assign::map_list_of
- (GL_FLOAT, "float")
- (GL_FLOAT_VEC2, "vec2")
- (GL_FLOAT_VEC3, "vec3")
- (GL_FLOAT_VEC4, "vec4")
- (GL_SAMPLER_2D, "sampler2D")
- (GL_FLOAT_MAT3, "mat3")
- (GL_FLOAT_MAT4, "mat4")
- (GL_NONE, "void");
- ConstCharPtrHashMap<GLenum>::Type MaterialShaderProgramCreator::txtToGlType =
- boost::assign::map_list_of
- ("float", GL_FLOAT)
- ("vec2", GL_FLOAT_VEC2)
- ("vec3", GL_FLOAT_VEC3)
- ("vec4", GL_FLOAT_VEC4)
- ("sampler2D", GL_SAMPLER_2D)
- ("mat3", GL_FLOAT_MAT3)
- ("mat4", GL_FLOAT_MAT4)
- ("void", GL_NONE);
- boost::unordered_map<MaterialShaderProgramCreator::ArgQualifier, const char*>
- MaterialShaderProgramCreator::argQualifierToTxt = boost::assign::map_list_of
- (AQ_IN, "in")
- (AQ_OUT, "out")
- (AQ_INOUT, "inout");
- ConstCharPtrHashMap<MaterialShaderProgramCreator::ArgQualifier>::Type
- MaterialShaderProgramCreator::txtToArgQualifier = boost::assign::map_list_of
- ("in", AQ_IN)
- ("out", AQ_OUT)
- ("inout", AQ_INOUT);
- const char* MaterialShaderProgramCreator::depthPassDefine = "DEPTH_PASS";
- //==============================================================================
- // Constructor =
- //==============================================================================
- MaterialShaderProgramCreator::MaterialShaderProgramCreator(
- const boost::property_tree::ptree& pt)
- {
- parseShaderProgramTag(pt);
- }
- //==============================================================================
- // Destructor =
- //==============================================================================
- MaterialShaderProgramCreator::~MaterialShaderProgramCreator()
- {}
- //==============================================================================
- // parseShaderFileForFunctionDefinitions =
- //==============================================================================
- void MaterialShaderProgramCreator::parseShaderFileForFunctionDefinitions(
- const char* filename)
- {
- Scanner::Scanner scanner(filename, false);
- const Scanner::Token* token = &scanner.getCrntToken();
- // Forever
- while(true)
- {
- getNextTokenAndSkipNewlines(scanner);
- FuncDefinition* funcDef = NULL;
- // EOF
- if(token->getCode() == Scanner::TC_EOF)
- {
- break;
- }
- // #
- else if(token->getCode() == Scanner::TC_SHARP)
- {
- parseUntilNewline(scanner);
- continue;
- }
- // Return type
- else if(token->getCode() == Scanner::TC_IDENTIFIER)
- {
- funcDef = new FuncDefinition;
- funcDefs.push_back(funcDef);
- try
- {
- funcDef->returnDataType =
- txtToGlType.at(token->getValue().getString());
- }
- catch(std::exception& e)
- {
- throw PARSER_EXCEPTION("Unsupported type: " +
- token->getValue().getString());
- }
- funcDef->returnDataTypeTxt = token->getValue().getString();
- }
- else
- {
- throw PARSER_EXCEPTION_EXPECTED("identifier");
- }
- // Function name
- getNextTokenAndSkipNewlines(scanner);
- if(token->getCode() != Scanner::TC_IDENTIFIER)
- {
- throw PARSER_EXCEPTION_EXPECTED("identifier");
- }
- funcDef->name = token->getValue().getString();
- funcNameToDef[funcDef->name.c_str()] = funcDef;
- // (
- getNextTokenAndSkipNewlines(scanner);
- if(token->getCode() != Scanner::TC_LPAREN)
- {
- throw PARSER_EXCEPTION_EXPECTED("(");
- }
- // Arguments
- while(true)
- {
- ArgDefinition* argDef = new ArgDefinition;
- funcDef->argDefinitions.push_back(argDef);
- // Argument qualifier
- getNextTokenAndSkipNewlines(scanner);
- if(token->getCode() != Scanner::TC_IDENTIFIER)
- {
- throw PARSER_EXCEPTION_EXPECTED("identifier");
- }
- // For now accept only "in"
- if(strcmp(token->getValue().getString(), "in"))
- {
- throw PARSER_EXCEPTION("Incorrect qualifier: " +
- token->getValue().getString());
- }
- try
- {
- argDef->argQualifier = txtToArgQualifier.at(
- token->getValue().getString());
- }
- catch(std::exception& e)
- {
- throw PARSER_EXCEPTION("Unsupported qualifier: " +
- token->getValue().getString());
- }
- argDef->argQualifierTxt = token->getValue().getString();
- // Type
- getNextTokenAndSkipNewlines(scanner);
- if(token->getCode() != Scanner::TC_IDENTIFIER)
- {
- throw PARSER_EXCEPTION_EXPECTED("identifier");
- }
- try
- {
- argDef->dataType = txtToGlType.at(
- token->getValue().getString());
- }
- catch(std::exception& e)
- {
- throw PARSER_EXCEPTION("Unsupported type: " +
- token->getValue().getString());
- }
- argDef->dataTypeTxt = token->getValue().getString();
- // Name
- getNextTokenAndSkipNewlines(scanner);
- if(token->getCode() != Scanner::TC_IDENTIFIER)
- {
- throw PARSER_EXCEPTION_EXPECTED("identifier");
- }
- argDef->name = token->getValue().getString();
- // ,
- getNextTokenAndSkipNewlines(scanner);
- if(token->getCode() == Scanner::TC_COMMA)
- {
- continue;
- }
- // )
- else if(token->getCode() == Scanner::TC_RPAREN)
- {
- break;
- }
- else
- {
- throw PARSER_EXCEPTION_UNEXPECTED();
- }
- } // End arguments
- // {
- getNextTokenAndSkipNewlines(scanner);
- if(token->getCode() != Scanner::TC_LBRACKET)
- {
- throw PARSER_EXCEPTION_EXPECTED("{");
- }
- // Skip until closing bracket
- int bracketsNum = 0;
- while(true)
- {
- getNextTokenAndSkipNewlines(scanner);
- if(token->getCode() == Scanner::TC_RBRACKET)
- {
- if(bracketsNum == 0)
- {
- break;
- }
- --bracketsNum;
- }
- else if(token->getCode() == Scanner::TC_LBRACKET)
- {
- ++bracketsNum;
- }
- else if(token->getCode() == Scanner::TC_EOF)
- {
- throw PARSER_EXCEPTION_UNEXPECTED();
- }
- else
- {
- continue;
- }
- } // End until closing bracket
- /*std::stringstream ss;
- ss << "Func def: " << funcDef->returnArg << " " << funcDef->name << " ";
- BOOST_FOREACH(const ArgDefinition& adef, funcDef->argDefinitions)
- {
- ss << adef.callType << " " << adef.dataType << " " <<
- adef.name << ", ";
- }
- std::cout << ss.str() << std::endl;*/
- } // End for all functions
- }
- //==============================================================================
- // parseUntilNewline =
- //==============================================================================
- void MaterialShaderProgramCreator::parseUntilNewline(Scanner::Scanner& scanner)
- {
- const Scanner::Token* token = &scanner.getCrntToken();
- Scanner::TokenCode prevTc;
- while(true)
- {
- prevTc = token->getCode();
- scanner.getNextToken();
- if(token->getCode() == Scanner::TC_EOF)
- {
- break;
- }
- else if(token->getCode() == Scanner::TC_NEWLINE &&
- prevTc != Scanner::TC_BACK_SLASH)
- {
- break;
- }
- }
- }
- //==============================================================================
- // getNextTokenAndSkipNewlines =
- //==============================================================================
- void MaterialShaderProgramCreator::getNextTokenAndSkipNewlines(
- Scanner::Scanner& scanner)
- {
- const Scanner::Token* token;
- while(true)
- {
- token = &scanner.getNextToken();
- if(token->getCode() != Scanner::TC_NEWLINE)
- {
- break;
- }
- }
- }
- //==============================================================================
- // parseShaderProgramTag =
- //==============================================================================
- void MaterialShaderProgramCreator::parseShaderProgramTag(
- const boost::property_tree::ptree& pt)
- {
- using namespace boost::property_tree;
- srcLines.push_back("#pragma anki start vertexShader");
- srcLines.push_back("#pragma anki include \"shaders/MaterialVert.glsl\"");
- srcLines.push_back("#pragma anki start fragmentShader");
- //
- // <includes></includes>
- //
- boost::ptr_vector<FuncDefinition> funcDefs;
- Vec<std::string> includeLines;
- const ptree& includesPt = pt.get_child("includes");
- BOOST_FOREACH(const ptree::value_type& v, includesPt)
- {
- if(v.first != "include")
- {
- throw EXCEPTION("Expected include and not: " + v.first);
- }
- const std::string& fname = v.second.data();
- parseShaderFileForFunctionDefinitions(fname.c_str());
- includeLines.push_back("#pragma anki include \"" + fname + "\"");
- }
- std::sort(includeLines.begin(), includeLines.end(), compareStrings);
- srcLines.insert(srcLines.end(), includeLines.begin(), includeLines.end());
- //
- // <ins></ins>
- //
- Vec<std::string> uniformsLines; // Store the source of the uniform vars
- boost::optional<const ptree&> insPt = pt.get_child_optional("ins");
- if(insPt)
- {
- BOOST_FOREACH(const ptree::value_type& v, insPt.get())
- {
- if(v.first != "in")
- {
- throw EXCEPTION("Expected in and not: " + v.first);
- }
- const ptree& inPt = v.second;
- std::string line;
- parseInTag(inPt, line);
- uniformsLines.push_back(line);
- } // end for all ins
- srcLines.push_back("");
- std::sort(uniformsLines.begin(), uniformsLines.end(), compareStrings);
- srcLines.insert(srcLines.end(), uniformsLines.begin(),
- uniformsLines.end());
- }
- //
- // <operators></operators>
- //
- srcLines.push_back("\n#pragma anki include "
- "\"shaders/MaterialFragmentVariables.glsl\"\n"
- "\nvoid main()\n{");
- const ptree& opsPt = pt.get_child("operators");
- BOOST_FOREACH(const ptree::value_type& v, opsPt)
- {
- if(v.first != "operator")
- {
- throw EXCEPTION("Expected operator and not: " + v.first);
- }
- const ptree& opPt = v.second;
- parseOperatorTag(opPt);
- } // end for all operators
- srcLines.push_back("}\n");
- //
- // Create the output
- //
- BOOST_FOREACH(const std::string& line, srcLines)
- {
- source += line + "\n";
- }
- //std::cout << source << std::endl;
- }
- //==============================================================================
- // parseInTag =
- //==============================================================================
- void MaterialShaderProgramCreator::parseInTag(
- const boost::property_tree::ptree& pt, std::string& line)
- {
- using namespace boost::property_tree;
- const std::string& name = pt.get<std::string>("name");
- boost::optional<const ptree&> valuePt = pt.get_child_optional("value");
- line = "uniform ";
- // Buildin
- if(!valuePt)
- {
- BuildinMaterialVariable::BuildinVariable tmp;
- GLenum dataType;
- if(!BuildinMaterialVariable::isBuildin(name.c_str(), &tmp, &dataType))
- {
- throw EXCEPTION("The variable is not build in: " + name);
- }
- boost::unordered_map<GLenum, const char*>::const_iterator it =
- glTypeToTxt.find(dataType);
- ASSERT(it != glTypeToTxt.end() &&
- "Buildin's type is not registered");
- line += it->second;
- }
- else
- {
- if(valuePt.get().size() != 1)
- {
- throw EXCEPTION("Bad value for in: " + name);
- }
- const ptree::value_type& v = valuePt.get().front();
- // Wrong tag
- if(txtToGlType.find(v.first.c_str()) == txtToGlType.end())
- {
- throw EXCEPTION("Wrong type \"" + v.first + "\" for in: " +
- name);
- }
- line += v.first;
- }
- line += " " + name + ";";
- }
- //==============================================================================
- // parseOperatorTag =
- //==============================================================================
- void MaterialShaderProgramCreator::parseOperatorTag(
- const boost::property_tree::ptree& pt)
- {
- using namespace boost::property_tree;
- int id = pt.get<int>("id");
- const std::string& funcName = pt.get<std::string>("function");
- const ptree& argsPt = pt.get_child("arguments");
- std::stringstream line;
- // Find func def
- ConstCharPtrHashMap<FuncDefinition*>::Type::const_iterator it =
- funcNameToDef.find(funcName.c_str());
- if(it == funcNameToDef.end())
- {
- throw EXCEPTION("Function is not defined in any include file: " +
- funcName);
- }
- const FuncDefinition* def = it->second;
- // Check args size
- if(argsPt.size() != def->argDefinitions.size())
- {
- throw EXCEPTION("Incorrect number of arguments for: " + funcName);
- }
- // Write return value
- if(def->returnDataType != GL_NONE)
- {
- line << def->returnDataTypeTxt << " operatorOut" << id << " = ";
- }
- // Func name
- line << funcName + "(";
- // Write all arguments
- size_t i = 0;
- BOOST_FOREACH(const ptree::value_type& v, argsPt)
- {
- if(v.first != "argument")
- {
- throw EXCEPTION("Unexpected tag \"" + v.first +
- "\" for operator: " + boost::lexical_cast<std::string>(id));
- }
- line << v.second.data();
- // Add a comma
- ++i;
- if(i != argsPt.size())
- {
- line << ", ";
- }
- }
- line << ");";
- srcLines.push_back("\t" + line.str());
- }
- //==============================================================================
- // compareStrings =
- //==============================================================================
- bool MaterialShaderProgramCreator::compareStrings(
- const std::string& a, const std::string& b)
- {
- return a < b;
- }
|