/******************************************************************************** CGoGN: Combinatorial and Geometric modeling with Generic N-dimensional Maps ** version 0.1 ** Copyright (C) 2009-2011, IGG Team, LSIIT, University of Strasbourg ** ** This library is free software; you can redistribute it and/or modify it ** under the terms of the GNU Lesser General Public License as published by the ** Free Software Foundation; either version 2.1 of the License, or (at your ** option) any later version. ** ** This library is distributed in the hope that it will be useful, but WITHOUT ** ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ** FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License ** for more details. ** ** You should have received a copy of the GNU Lesser General Public License ** along with this library; if not, write to the Free Software Foundation, ** Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. ** ** Web site: http://cgogn.u-strasbg.fr/ ** Contact information: cgogn@unistra.fr ** ********************************************************************************/#include "Utils/shaderMutator.h"namespaceCGoGN{namespaceUtils{ShaderMutator::ShaderMutator(conststd::string&shaderName,conststd::string&vertShaderSrc,conststd::string&fragShaderSrc,conststd::string&geomShaderSrc){// Store the shader namem_shaderName=shaderName;// Store the shader source codesm_vShaderMutation=vertShaderSrc;m_fShaderMutation=fragShaderSrc;m_gShaderMutation=geomShaderSrc;}boolShaderMutator::VS_containsVariableDeclaration(conststd::string&variableName){returncontainsVariableDeclaration(variableName,m_vShaderMutation);}boolShaderMutator::FS_containsVariableDeclaration(conststd::string&variableName){returncontainsVariableDeclaration(variableName,m_fShaderMutation);}boolShaderMutator::GS_containsVariableDeclaration(conststd::string&variableName){returncontainsVariableDeclaration(variableName,m_gShaderMutation);}voidShaderMutator::VS_insertCodeBeforeMainFunction(conststd::string&insertedCode){if(!insertCodeBeforeMainFunction(insertedCode,m_vShaderMutation)){CGoGNerr<<"ERROR - "<<"ShaderMutator::VS_insertCodeBeforeMainFunction : "<<"Unable to insert source code in vertex shader of "<<m_shaderName<<". You should check if the shader has a main function declaration"<<CGoGNendl;}}voidShaderMutator::FS_insertCodeBeforeMainFunction(conststd::string&insertedCode){if(!insertCodeBeforeMainFunction(insertedCode,m_fShaderMutation)){CGoGNerr<<"ERROR - "<<"ShaderMutator::FS_insertCodeBeforeMainFunction : "<<"Unable to insert source code in fragment shader of "<<m_shaderName<<". You should check if the shader has a main function declaration"<<CGoGNendl;}}voidShaderMutator::GS_insertCodeBeforeMainFunction(conststd::string&insertedCode){if(!insertCodeBeforeMainFunction(insertedCode,m_gShaderMutation)){CGoGNerr<<"ERROR - "<<"ShaderMutator::GS_insertCodeBeforeMainFunction : "<<"Unable to insert source code in geometry shader of "<<m_shaderName<<". You should check if the shader has a main function declaration"<<CGoGNendl;}}voidShaderMutator::VS_insertCodeAtMainFunctionBeginning(conststd::string&insertedCode){if(!insertCodeAtMainFunctionBeginning(insertedCode,m_vShaderMutation)){CGoGNerr<<"ERROR - "<<"ShaderMutator::VS_insertCodeAtMainFunctionBeginnning : "<<"Unable to insert source code vertex shader of "<<m_shaderName<<". You should check if the shader has a main function declaration"<<CGoGNendl;}}voidShaderMutator::FS_insertCodeAtMainFunctionBeginning(conststd::string&insertedCode){if(!insertCodeAtMainFunctionBeginning(insertedCode,m_fShaderMutation)){CGoGNerr<<"ERROR - "<<"ShaderMutator::FS_insertCodeAtMainFunctionBeginnning : "<<"Unable to insert source code in fragment shader of "<<m_shaderName<<". You should check if the shader has a main function declaration"<<CGoGNendl;}}voidShaderMutator::GS_insertCodeAtMainFunctionBeginning(conststd::string&insertedCode){if(!insertCodeAtMainFunctionBeginning(insertedCode,m_gShaderMutation)){CGoGNerr<<"ERROR - "<<"ShaderMutator::GS_insertCodeAtMainFunctionBeginnning : "<<"Unable to insert source code in geometry shader of "<<m_shaderName<<". You should check if the shader has a main function declaration"<<CGoGNendl;}}voidShaderMutator::VS_insertCodeAtMainFunctionEnd(conststd::string&insertedCode){if(!insertCodeAtMainFunctionEnd(insertedCode,m_vShaderMutation)){CGoGNerr<<"ERROR - "<<"ShaderMutator::VS_insertCodeAtMainFunctionEnd : "<<"Unable to insert source code in vertex shader of "<<m_shaderName<<". You should check if the shader has a main function declaration "

<<CGoGNendl;}}voidShaderMutator::FS_insertCodeAtMainFunctionEnd(conststd::string&insertedCode){if(!insertCodeAtMainFunctionEnd(insertedCode,m_fShaderMutation)){CGoGNerr<<"ERROR - "<<"ShaderMutator::FS_insertCodeAtMainFunctionEnd : "<<"Unable to insert source code in fragment shader of "<<m_shaderName<<". You should check if the shader has a main function declaration "

<<CGoGNendl;}}voidShaderMutator::GS_insertCodeAtMainFunctionEnd(conststd::string&insertedCode){if(!insertCodeAtMainFunctionEnd(insertedCode,m_gShaderMutation)){CGoGNerr<<"ERROR - "<<"ShaderMutator::GS_insertCodeAtMainFunctionEnd : "<<"Unable to insert source code in geometry shader of "<<m_shaderName<<". You should check if the shader has a main function declaration "

<<CGoGNendl;}}boolShaderMutator::isCommented(size_tpos,conststd::string&str){// Verify that the given position is not out of the stringif(pos>=str.length()){CGoGNerr<<"ERROR - "<<"ShaderMutator::isCommented : "<<"Given position is out of range"<<CGoGNendl;returnfalse;}// Look backward in the string to see if there is any comment symbol (// or /* */)// First look for one-line commentsif(isOneLineCommented(pos,str))returntrue;// Now look for multi-line comments size_ti;for(i=pos;i>0;i--){if(str[i]=='/'){// End of multi-line commentif(str[i-1]=='*'){// Verify that the end of multi-line comment is not one-line commented !if(!isOneLineCommented(i,str))returnfalse;}}elseif(str[i]=='*'){// Beginning of multi-line commentif(str[i-1]=='/'){// Verify that the beginning of multi-line comment is not one-line commented !if(!isOneLineCommented(i,str))returntrue;}}}// No one-line or multi-line comments were foundreturnfalse;}boolShaderMutator::isOneLineCommented(size_tpos,conststd::string&str){// Verify that the given position is not out of the stringif(pos>=str.length()){CGoGNerr<<"ERROR - "<<"ShaderMutator::isOneLineCommented : "<<"Given position is out of range"<<CGoGNendl;returnfalse;}// Look backward in the string to see if there is any "//"size_ti;for(i=pos;i>0;i--){// As soon as a '\n' is found, any other "//" will not affect this line anymoreif(str[i]=='\n')returnfalse;elseif(str[i]=='/')if(str[i-1]=='/')returntrue;}// No one-line comments were foundreturnfalse;}boolShaderMutator::containsVariableDeclaration(conststd::string&variableName,std::string&src){// Regular expression for variable declaration// <',' OR white-space[1 or more times]> <variableName> <',' OR ';' OR white-space>boost::regexvar_re("(,|\\s+)"+variableName+"(,|;|\\s)");// Matches resultsboost::match_results<std::string::iterator>matches;// Search for the first expression that matches and isn't commentedstd::string::iteratorstart=src.begin();std::string::iteratorend=src.end();while(regex_search(start,end,matches,var_re,boost::format_first_only)){// Start position of the matchsize_tstartPosition=std::distance(src.begin(),matches[0].first);// Finish if the matched variable is the good one (i.e. not commented)if(!isCommented(startPosition,src))returntrue;// Else continue to search for it after last matchelsestart=matches[0].second;}// At this point no correct match was foundreturnfalse;}boolShaderMutator::insertCodeBeforeMainFunction(conststd::string&insertedCode,std::string&modifiedSrc){// Regular expression for main function// <void> <white-space>[1 or more times] <main> <white-space>[0 or more times] <'('>boost::regexmain_re("(void)\\s+(main)\\s*\\(");// Matches resultsboost::match_results<std::string::iterator>matches;// Search for the first expression that matches and isn't commentedstd::string::iteratorstart=modifiedSrc.begin();std::string::iteratorend=modifiedSrc.end();while(regex_search(start,end,matches,main_re,boost::format_first_only)){// Start position of the matchsize_tstartPosition=std::distance(modifiedSrc.begin(),matches[0].first);// Insert and finish if the matched "main" is the good one (i.e. not commented)if(!isCommented(startPosition,modifiedSrc)){modifiedSrc.insert(startPosition,insertedCode);returntrue;}// Else continue to search for it after last matchelse{start=matches[0].second;}}// At this point no correct match was foundreturnfalse;}boolShaderMutator::insertCodeAtMainFunctionBeginning(conststd::string&insertedCode,std::string&modifiedSrc){// Regular expression for main function// <void> <white-space>[1 or more times] <main> <white-space>[0 or more times]// <'('> <white-space>[0 or more times] <')'>// <white-space>[0 or more times] <'{'>boost::regexmain_re("(void)\\s+(main)\\s*\\(\\s*\\)\\s*\\{");// Matches resultsboost::match_results<std::string::iterator>matches;// Search for the first expression that matches and isn't commentedstd::string::iteratorstart=modifiedSrc.begin();std::string::iteratorend=modifiedSrc.end();while(regex_search(start,end,matches,main_re,boost::format_first_only)){// Start position of the matchsize_tstartPosition=std::distance(modifiedSrc.begin(),matches[0].first);// End position of the matchsize_tendPosition=std::distance(modifiedSrc.begin(),matches[0].second);// Insert and finish if the matched "main" is the good one (i.e. not commented)if(!isCommented(startPosition,modifiedSrc)){modifiedSrc.insert(endPosition,insertedCode);returntrue;}// Else continue to search for it after last matchelse{start=matches[0].second;}}// At this point no correct match was foundreturnfalse;}boolShaderMutator::insertCodeAtMainFunctionEnd(conststd::string&insertedCode,std::string&modifiedSrc){// Regular expression for main function// <void> <white-space>[1 or more times] <main> <white-space>[0 or more times]// <'('> <white-space>[0 or more times] <')'>// <white-space>[0 or more times] <'{'>boost::regexmain_re("(void)\\s+(main)\\s*\\(\\s*\\)\\s*\\{");// Matches resultsboost::match_results<std::string::iterator>matches;// Search for the first expression that matches and isn't commentedstd::string::iteratorstart=modifiedSrc.begin();std::string::iteratorend=modifiedSrc.end();size_tmainFirstBracePos=0;// The aim is to find this positionwhile(regex_search(start,end,matches,main_re,boost::format_first_only)&&(mainFirstBracePos==0)){// Start position of the matchsize_tstartPosition=std::distance(modifiedSrc.begin(),matches[0].first);// End position of the matchsize_tendPosition=std::distance(modifiedSrc.begin(),matches[0].second);// Get the main first brace position if the matched "main" is the good one (i.e. not commented)if(!isCommented(startPosition,modifiedSrc))mainFirstBracePos=endPosition;// Else continue to search for it after last matchelsestart=matches[0].second;}// If mainFirstBracePos is still zero, no correct match was foundif(mainFirstBracePos==0)returnfalse;// Else, it is now possible to count the opening and closing braces till the final closing brace of the main function is reachedintbracesCounter=1;// =1 since the first opening brace is counted in, it will be =0 when the final closing brace is reachedsize_tclosestBracePos=mainFirstBracePos;size_tclosestOpeningBracePos;size_tclosestClosingBracePos;while(bracesCounter!=0){closestOpeningBracePos=modifiedSrc.find_first_of('{',closestBracePos+1);// If this brace appears to be commented, try to get the next onewhile((closestOpeningBracePos!=std::string::npos)&&isCommented(closestOpeningBracePos,modifiedSrc))closestOpeningBracePos=modifiedSrc.find_first_of('{',closestOpeningBracePos+1);closestClosingBracePos=modifiedSrc.find_first_of('}',closestBracePos+1);// If this brace appears to be commented, try to get the next onewhile((closestClosingBracePos!=std::string::npos)&&isCommented(closestClosingBracePos,modifiedSrc))closestClosingBracePos=modifiedSrc.find_first_of('}',closestClosingBracePos+1);// Happens if there is not enough "}" for the corresponding "{"if(closestClosingBracePos==std::string::npos)returnfalse;// Refresh the closest brace position, and increment or decrement the counterif(closestClosingBracePos<closestOpeningBracePos){closestBracePos=closestClosingBracePos;bracesCounter-=1;}else{closestBracePos=closestOpeningBracePos;bracesCounter+=1;}}// We should now have the final '}' of the main functionsize_tmainLastBracePos=closestBracePos;// Insert the source theremodifiedSrc.insert(mainLastBracePos,insertedCode);returntrue;}}// namespace Utils}// namespace CGoGN