Index: build/premake/premake5.lua =================================================================== --- build/premake/premake5.lua +++ build/premake/premake5.lua @@ -730,7 +730,8 @@ "graphics/scripting", "renderer", "renderer/scripting", - "third_party/mikktspace" + "third_party/mikktspace", + "third_party/ogre3d_preprocessor" } extern_libs = { "opengl", Index: source/graphics/MaterialManager.cpp =================================================================== --- source/graphics/MaterialManager.cpp +++ source/graphics/MaterialManager.cpp @@ -19,13 +19,13 @@ #include "MaterialManager.h" +#include "graphics/PreprocessorWrapper.h" #include "lib/ogl.h" #include "maths/MathUtil.h" #include "maths/Vector4D.h" #include "ps/CLogger.h" #include "ps/ConfigDB.h" #include "ps/Filesystem.h" -#include "ps/PreprocessorWrapper.h" #include "ps/XML/Xeromyces.h" #include "renderer/RenderingOptions.h" Index: source/graphics/PreprocessorWrapper.h =================================================================== --- source/graphics/PreprocessorWrapper.h +++ source/graphics/PreprocessorWrapper.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2012 Wildfire Games. +/* Copyright (C) 2019 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -18,8 +18,8 @@ #ifndef INCLUDED_PREPROCESSORWRAPPER #define INCLUDED_PREPROCESSORWRAPPER -#include "ps/Preprocessor.h" #include "ps/CStr.h" +#include "third_party/ogre3d_preprocessor/OgreGLSLPreprocessor.h" class CShaderDefines; @@ -29,6 +29,8 @@ class CPreprocessorWrapper { public: + CPreprocessorWrapper(); + void AddDefine(const char* name, const char* value); void AddDefines(const CShaderDefines& defines); @@ -37,6 +39,8 @@ CStr Preprocess(const CStr& input); + static void PyrogenesisShaderError(void* UNUSED(iData), int iLine, const char* iError, const char* iToken, size_t iTokenLen); + private: CPreprocessor m_Preprocessor; }; Index: source/graphics/PreprocessorWrapper.cpp =================================================================== --- source/graphics/PreprocessorWrapper.cpp +++ source/graphics/PreprocessorWrapper.cpp @@ -1,4 +1,4 @@ -/* Copyright (C) 2012 Wildfire Games. +/* Copyright (C) 2019 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -22,6 +22,19 @@ #include "graphics/ShaderDefines.h" #include "ps/CLogger.h" +void CPreprocessorWrapper::PyrogenesisShaderError(void* UNUSED(iData), int iLine, const char* iError, const char* iToken, size_t iTokenLen) +{ + if (iToken) + LOGERROR("Preprocessor error: line %d: %s: '%s'\n", iLine, iError, std::string(iToken, iTokenLen).c_str()); + else + LOGERROR("Preprocessor error: line %d: %s\n", iLine, iError); +} + +CPreprocessorWrapper::CPreprocessorWrapper() +{ + CPreprocessor::ErrorHandler = CPreprocessorWrapper::PyrogenesisShaderError; +} + void CPreprocessorWrapper::AddDefine(const char* name, const char* value) { m_Preprocessor.Define(name, value); Index: source/graphics/ShaderManager.cpp =================================================================== --- source/graphics/ShaderManager.cpp +++ source/graphics/ShaderManager.cpp @@ -19,6 +19,7 @@ #include "ShaderManager.h" +#include "graphics/PreprocessorWrapper.h" #include "graphics/ShaderTechnique.h" #include "lib/config2.h" #include "lib/timer.h" @@ -26,7 +27,6 @@ #include "ps/CLogger.h" #include "ps/CStrIntern.h" #include "ps/Filesystem.h" -#include "ps/PreprocessorWrapper.h" #include "ps/Profile.h" #if USE_SHADER_XML_VALIDATION # include "ps/XML/RelaxNG.h" Index: source/graphics/ShaderProgram.cpp =================================================================== --- source/graphics/ShaderProgram.cpp +++ source/graphics/ShaderProgram.cpp @@ -20,6 +20,7 @@ #include "ShaderProgram.h" #include "graphics/Color.h" +#include "graphics/PreprocessorWrapper.h" #include "graphics/ShaderManager.h" #include "graphics/TextureManager.h" #include "lib/res/graphics/ogl_tex.h" @@ -27,7 +28,6 @@ #include "maths/Vector3D.h" #include "ps/CLogger.h" #include "ps/Filesystem.h" -#include "ps/PreprocessorWrapper.h" #if !CONFIG2_GLES Index: source/ps/Preprocessor.h =================================================================== --- /dev/null +++ source/ps/Preprocessor.h @@ -1,541 +0,0 @@ -/* - * This source file originally came from OGRE v1.7.2 - http://www.ogre3d.org/ - * with some tweaks as part of 0 A.D. - * All changes are released under the original license, as follows: - */ - -/* ------------------------------------------------------------------------------ -This source file is part of OGRE - (Object-oriented Graphics Rendering Engine) -For the latest info, see http://www.ogre3d.org/ - -Copyright (c) 2000-2009 Torus Knot Software Ltd - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. ------------------------------------------------------------------------------ -*/ - -#ifndef INCLUDED_CPREPROCESSOR -#define INCLUDED_CPREPROCESSOR - -/** - * This is a simplistic C/C++-like preprocessor. - * It takes an non-zero-terminated string on input and outputs a - * non-zero-terminated string buffer. - * - * This preprocessor was designed specifically for GLSL shaders, so - * if you want to use it for other purposes you might want to check - * if the feature set it provides is enough for you. - * - * Here's a list of supported features: - * - */ -class CPreprocessor -{ - /** - * A input token. - * - * For performance reasons most tokens will point to portions of the - * input stream, so no unneeded memory allocation is done. However, - * in some cases we must allocate different memory for token storage, - * in this case this is signalled by setting the Allocated member - * to non-zero in which case the destructor will know that it must - * free memory on object destruction. - * - * Again for performance reasons we use malloc/realloc/free here because - * C++-style new[] lacks the realloc() counterpart. - */ - class Token - { - public: - enum Kind - { - TK_EOS, // End of input stream - TK_ERROR, // An error has been encountered - TK_WHITESPACE, // A whitespace span (but not newline) - TK_NEWLINE, // A single newline (CR & LF) - TK_LINECONT, // Line continuation ('\' followed by LF) - TK_NUMBER, // A number - TK_KEYWORD, // A keyword - TK_PUNCTUATION, // A punctuation character - TK_DIRECTIVE, // A preprocessor directive - TK_STRING, // A string - TK_COMMENT, // A block comment - TK_LINECOMMENT, // A line comment - TK_TEXT, // An unparsed text (cannot be returned from GetToken()) - }; - - /// Token type - Kind Type; - /// True if string was allocated (and must be freed) - mutable size_t Allocated; - union - { - /// A pointer somewhere into the input buffer - const char *String; - /// A memory-allocated string - char *Buffer; - }; - /// Token length in bytes - size_t Length; - - Token () : Type (TK_ERROR), Allocated (0), String (NULL), Length (0) - { } - - Token (Kind iType) : Type (iType), Allocated (0), String (NULL), Length (0) - { } - - Token (Kind iType, const char *iString, size_t iLength) : - Type (iType), Allocated (0), String (iString), Length (iLength) - { } - - Token (const Token &iOther) - { - Type = iOther.Type; - Allocated = iOther.Allocated; - iOther.Allocated = 0; // !!! not quite correct but effective - String = iOther.String; - Length = iOther.Length; - } - - ~Token () - { if (Allocated) free (Buffer); } - - /// Assignment operator - Token &operator = (const Token &iOther) - { - if (Allocated) free (Buffer); - Type = iOther.Type; - Allocated = iOther.Allocated; - iOther.Allocated = 0; // !!! not quite correct but effective - String = iOther.String; - Length = iOther.Length; - return *this; - } - - /// Append a string to this token - void Append (const char *iString, size_t iLength); - - /// Append a token to this token - void Append (const Token &iOther); - - /// Append given number of newlines to this token - void AppendNL (int iCount); - - /// Count number of newlines in this token - int CountNL (); - - /// Get the numeric value of the token - bool GetValue (long &oValue) const; - - /// Set the numeric value of the token - void SetValue (long iValue); - - /// Test two tokens for equality - bool operator == (const Token &iOther) - { - if (iOther.Length != Length) - return false; - return (memcmp (String, iOther.String, Length) == 0); - } - }; - - /// A macro definition - class Macro - { - public: - /// Macro name - Token Name; - /// Number of arguments - int NumArgs; - /// The names of the arguments - Token *Args; - /// The macro value - Token Value; - /// Unparsed macro body (keeps the whole raw unparsed macro body) - Token Body; - /// Next macro in chained list - Macro *Next; - /// A pointer to function implementation (if macro is really a func) - Token (*ExpandFunc) (CPreprocessor *iParent, int iNumArgs, Token *iArgs); - /// true if macro expansion is in progress - bool Expanding; - - Macro (const Token &iName) : - Name (iName), NumArgs (0), Args (NULL), Next (NULL), - ExpandFunc (NULL), Expanding (false) - { } - - ~Macro () - { delete [] Args; delete Next; } - - /// Expand the macro value (will not work for functions) - Token Expand (int iNumArgs, Token *iArgs, Macro *iMacros); - }; - - friend class CPreprocessor::Macro; - - /// The current source text input - const char *Source; - /// The end of the source text - const char *SourceEnd; - /// Current line number - int Line; - /// True if we are at beginning of line - bool BOL; - /// A stack of 32 booleans packed into one value :) - unsigned EnableOutput; - /// The list of macros defined so far - Macro *MacroList; - - /** - * Private constructor to re-parse a single token. - */ - CPreprocessor (const Token &iToken, int iLine); - - /** - * Stateless tokenizer: Parse the input text and return the next token. - * @param iExpand - * If true, macros will be expanded to their values - * @return - * The next token from the input stream - */ - Token GetToken (bool iExpand); - - /** - * Handle a preprocessor directive. - * @param iToken - * The whole preprocessor directive line (until EOL) - * @param iLine - * The line where the directive begins (for error reports) - * @return - * The last input token that was not proceeded. - */ - Token HandleDirective (Token &iToken, int iLine); - - /** - * Handle a \#define directive. - * @param iBody - * The body of the directive (everything after the directive - * until end of line). - * @param iLine - * The line where the directive begins (for error reports) - * @return - * true if everything went ok, false if not - */ - bool HandleDefine (Token &iBody, int iLine); - - /** - * Undefine a previously defined macro - * @param iBody - * The body of the directive (everything after the directive - * until end of line). - * @param iLine - * The line where the directive begins (for error reports) - * @return - * true if everything went ok, false if not - */ - bool HandleUnDef (Token &iBody, int iLine); - - /** - * Handle an \#ifdef directive. - * @param iBody - * The body of the directive (everything after the directive - * until end of line). - * @param iLine - * The line where the directive begins (for error reports) - * @return - * true if everything went ok, false if not - */ - bool HandleIfDef (Token &iBody, int iLine); - - /** - * Handle an \#if directive. - * @param iBody - * The body of the directive (everything after the directive - * until end of line). - * @param iLine - * The line where the directive begins (for error reports) - * @return - * true if everything went ok, false if not - */ - bool HandleIf (Token &iBody, int iLine); - - /** - * Handle an \#else directive. - * @param iBody - * The body of the directive (everything after the directive - * until end of line). - * @param iLine - * The line where the directive begins (for error reports) - * @return - * true if everything went ok, false if not - */ - bool HandleElse (Token &iBody, int iLine); - - /** - * Handle an \#endif directive. - * @param iBody - * The body of the directive (everything after the directive - * until end of line). - * @param iLine - * The line where the directive begins (for error reports) - * @return - * true if everything went ok, false if not - */ - bool HandleEndIf (Token &iBody, int iLine); - - /** - * Get a single function argument until next ',' or ')'. - * @param oArg - * The argument is returned in this variable. - * @param iExpand - * If false, parameters are not expanded and no expressions are - * allowed; only a single keyword is expected per argument. - * @return - * The first unhandled token after argument. - */ - Token GetArgument (Token &oArg, bool iExpand); - - /** - * Get all the arguments of a macro: '(' arg1 { ',' arg2 { ',' ... }} ')' - * @param oNumArgs - * Number of parsed arguments is stored into this variable. - * @param oArgs - * This is set to a pointer to an array of parsed arguments. - * @param iExpand - * If false, parameters are not expanded and no expressions are - * allowed; only a single keyword is expected per argument. - */ - Token GetArguments (int &oNumArgs, Token *&oArgs, bool iExpand); - - /** - * Parse an expression, compute it and return the result. - * @param oResult - * A token containing the result of expression - * @param iLine - * The line at which the expression starts (for error reports) - * @param iOpPriority - * Operator priority (at which operator we will stop if - * proceeding recursively -- used internally. Parser stops - * when it encounters an operator with higher or equal priority). - * @return - * The last unhandled token after the expression - */ - Token GetExpression (Token &oResult, int iLine, int iOpPriority = 0); - - /** - * Get the numeric value of a token. - * If the token was produced by expanding a macro, we will get - * an TEXT token which can contain a whole expression; in this - * case we will call GetExpression to parse it. Otherwise we - * just call the token's GetValue() method. - * @param iToken - * The token to get the numeric value of - * @param oValue - * The variable to put the value into - * @param iLine - * The line where the directive begins (for error reports) - * @return - * true if ok, false if not - */ - bool GetValue (const Token &iToken, long &oValue, int iLine); - - /** - * Expand the given macro, if it exists. - * If macro has arguments, they are collected from source stream. - * @param iToken - * A KEYWORD token containing the (possible) macro name. - * @return - * The expanded token or iToken if it is not a macro - */ - Token ExpandMacro (const Token &iToken); - - /** - * Check if a macro is defined, and if so, return it - * @param iToken - * Macro name - * @return - * The macro object or NULL if a macro with this name does not exist - */ - Macro *IsDefined (const Token &iToken); - - /** - * The implementation of the defined() preprocessor function - * @param iParent - * The parent preprocessor object - * @param iNumArgs - * Number of arguments - * @param iArgs - * The arguments themselves - * @return - * The return value encapsulated in a token - */ - static Token ExpandDefined (CPreprocessor *iParent, int iNumArgs, Token *iArgs); - - /** - * Parse the input string and return a token containing the whole output. - * @param iSource - * The source text enclosed in a token - * @return - * The output text enclosed in a token - */ - Token Parse (const Token &iSource); - - /** - * Call the error handler - * @param iLine - * The line at which the error happened. - * @param iError - * The error string. - * @param iToken - * If not NULL contains the erroneous token - */ - void Error (int iLine, const char *iError, const Token *iToken = NULL); - -public: - /// Create an empty preprocessor object - CPreprocessor () : MacroList (NULL) - { } - - /// Destroy the preprocessor object - virtual ~CPreprocessor (); - - /** - * Define a macro without parameters. - * @param iMacroName - * The name of the defined macro - * @param iMacroNameLen - * The length of the name of the defined macro - * @param iMacroValue - * The value of the defined macro - * @param iMacroValueLen - * The length of the value of the defined macro - */ - void Define (const char *iMacroName, size_t iMacroNameLen, - const char *iMacroValue, size_t iMacroValueLen); - - /** - * Define a numerical macro. - * @param iMacroName - * The name of the defined macro - * @param iMacroNameLen - * The length of the name of the defined macro - * @param iMacroValue - * The value of the defined macro - */ - void Define (const char *iMacroName, size_t iMacroNameLen, long iMacroValue); - - /** - * Define a macro without parameters. - * @param iMacroName - * The name of the defined macro - * @param iMacroValue - * The value of the defined macro - */ - void Define (const char *iMacroName, const char *iMacroValue); - - /** - * Define a numerical macro. - * @param iMacroName - * The name of the defined macro - * @param iMacroValue - * The value of the defined macro - */ - void Define (const char *iMacroName, long iMacroValue); - - /** - * Undefine a macro. - * @param iMacroName - * The name of the macro to undefine - * @param iMacroNameLen - * The length of the name of the macro to undefine - * @return - * true if the macro has been undefined, false if macro doesn't exist - */ - bool Undef (const char *iMacroName, size_t iMacroNameLen); - - /** - * Parse the input string and return a newly-allocated output string. - * @note - * The returned preprocessed string is NOT zero-terminated - * (just like the input string). - * @param iSource - * The source text - * @param iLength - * The length of the source text in characters - * @param oLength - * The length of the output string. - * @return - * The output from preprocessor, allocated with malloc(). - * The parser can actually allocate more than needed for performance - * reasons, but this should not be a problem unless you will want - * to store the returned pointer for long time in which case you - * might want to realloc() it. - * If an error has been encountered, the function returns NULL. - * In some cases the function may return an unallocated address - * that's *inside* the source buffer. You must free() the result - * string only if the returned address is not inside the source text. - */ - char *Parse (const char *iSource, size_t iLength, size_t &oLength); - - /** - * An error handler function type. - * The default implementation just drops a note to stderr and - * then the parser ends, returning NULL. - * @param iData - * User-specific pointer from the corresponding CPreprocessor object. - * @param iLine - * The line at which the error happened. - * @param iError - * The error string. - * @param iToken - * If not NULL contains the erroneous token - * @param iTokenLen - * The length of iToken. iToken is never zero-terminated! - */ - typedef void (*ErrorHandlerFunc) ( - void *iData, int iLine, const char *iError, - const char *iToken, size_t iTokenLen); - - /** - * A pointer to the preprocessor's error handler. - * You can assign the address of your own function to this variable - * and implement your own error handling (e.g. throwing an exception etc). - */ - static ErrorHandlerFunc ErrorHandler; - - /// User-specific storage, passed to Error() - void *ErrorData; -}; - -#endif // INCLUDED_CPREPROCESSOR Index: source/third_party/ogre3d_preprocessor/OgreGLSLPreprocessor.cpp =================================================================== --- source/third_party/ogre3d_preprocessor/OgreGLSLPreprocessor.cpp +++ source/third_party/ogre3d_preprocessor/OgreGLSLPreprocessor.cpp @@ -34,9 +34,7 @@ #include "precompiled.h" -#include "Preprocessor.h" - -#include "ps/CLogger.h" +#include "OgreGLSLPreprocessor.h" // Limit max number of macro arguments to this #define MAX_MACRO_ARGS 16 @@ -230,11 +228,12 @@ const char *iToken, size_t iTokenLen) { (void)iData; + char line [1000]; if (iToken) - LOGERROR("Preprocessor error: line %d: %s: '%s'\n", - iLine, iError, std::string (iToken, iTokenLen)); + snprintf (line, sizeof (line), "line %d: %s: `%.*s'\n", + iLine, iError, int (iTokenLen), iToken); else - LOGERROR("Preprocessor error: line %d: %s\n", iLine, iError); + snprintf (line, sizeof (line), "line %d: %s\n", iLine, iError); } //---------------------------------------------------------------------------// Index: source/third_party/ogre3d_preprocessor/tests/test_Preprocessor.h =================================================================== --- source/third_party/ogre3d_preprocessor/tests/test_Preprocessor.h +++ source/third_party/ogre3d_preprocessor/tests/test_Preprocessor.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2016 Wildfire Games. +/* Copyright (C) 2019 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify @@ -17,11 +17,17 @@ #include "lib/self_test.h" -#include "ps/Preprocessor.h" +#include "graphics/PreprocessorWrapper.h" +#include "third_party/ogre3d_preprocessor/OgreGLSLPreprocessor.h" class TestPreprocessor : public CxxTest::TestSuite { public: + void setUp() + { + CPreprocessor::ErrorHandler = CPreprocessorWrapper::PyrogenesisShaderError; + } + void test_basic() { CPreprocessor preproc;