From c190e95c5c44a4228a7eda8c5a360b112a5a12e9 Mon Sep 17 00:00:00 2001 From: Bergmann89 Date: Sun, 9 Aug 2015 13:21:53 +0200 Subject: [PATCH] * initial commit --- uengShaderCodeGenerator.pas | 21 + uengShaderFile.inc | 3 + uengShaderFile.old.pas | 5641 ++++++++++++++++++++++++++++++++ uengShaderFile.pas | 96 + uengShaderFileConstants.pas | 93 + uengShaderFileExpression.pas | 630 ++++ uengShaderFileHelper.pas | 56 + uengShaderFileParser.pas | 333 ++ uengShaderFileScope.pas | 23 + uengShaderFileTypes.pas | 148 + uengShaderPart.pas | 233 ++ uengShaderPartCall.pas | 158 + uengShaderPartClass.pas | 117 + uengShaderPartCntr.pas | 159 + uengShaderPartComment.pas | 55 + uengShaderPartEcho.pas | 62 + uengShaderPartIf.pas | 183 ++ uengShaderPartInclude.pas | 100 + uengShaderPartKeyValuePair.pas | 106 + uengShaderPartMessage.pas | 31 + uengShaderPartMeta.pas | 175 + uengShaderPartParameter.pas | 143 + uengShaderPartProc.pas | 251 ++ uengShaderPartScope.pas | 20 + uengShaderPartText.pas | 143 + 25 files changed, 8980 insertions(+) create mode 100644 uengShaderCodeGenerator.pas create mode 100644 uengShaderFile.inc create mode 100644 uengShaderFile.old.pas create mode 100644 uengShaderFile.pas create mode 100644 uengShaderFileConstants.pas create mode 100644 uengShaderFileExpression.pas create mode 100644 uengShaderFileHelper.pas create mode 100644 uengShaderFileParser.pas create mode 100644 uengShaderFileScope.pas create mode 100644 uengShaderFileTypes.pas create mode 100644 uengShaderPart.pas create mode 100644 uengShaderPartCall.pas create mode 100644 uengShaderPartClass.pas create mode 100644 uengShaderPartCntr.pas create mode 100644 uengShaderPartComment.pas create mode 100644 uengShaderPartEcho.pas create mode 100644 uengShaderPartIf.pas create mode 100644 uengShaderPartInclude.pas create mode 100644 uengShaderPartKeyValuePair.pas create mode 100644 uengShaderPartMessage.pas create mode 100644 uengShaderPartMeta.pas create mode 100644 uengShaderPartParameter.pas create mode 100644 uengShaderPartProc.pas create mode 100644 uengShaderPartScope.pas create mode 100644 uengShaderPartText.pas diff --git a/uengShaderCodeGenerator.pas b/uengShaderCodeGenerator.pas new file mode 100644 index 0000000..fc7dde6 --- /dev/null +++ b/uengShaderCodeGenerator.pas @@ -0,0 +1,21 @@ +unit uengShaderCodeGenerator; + +{$mode objfpc}{$H+} +{$I uengShaderFile.inc} + +interface + +uses + Classes, SysUtils, + uengShaderPartCntr; + +type +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + TengShaderCodeGenerator = class(TengShaderPartCntr) + + end; + +implementation + +end. + diff --git a/uengShaderFile.inc b/uengShaderFile.inc new file mode 100644 index 0000000..0a29871 --- /dev/null +++ b/uengShaderFile.inc @@ -0,0 +1,3 @@ +{$DEFINE EXPRESSION_ADD_BRACKET} // add brackets to expressions +{$DEFINE USE_BITSPACE_UTILS} // use bitSpace Utils +{$DEFINE DEBUG} // enable debug output diff --git a/uengShaderFile.old.pas b/uengShaderFile.old.pas new file mode 100644 index 0000000..23a533c --- /dev/null +++ b/uengShaderFile.old.pas @@ -0,0 +1,5641 @@ +unit uengShaderFile; + +{ Package: SpaceEngine + Prefix: eng - ENGine + Beschreibung: stellt Klassen zum laden von Shader-Datein zur Verfügung + beim laden des Codes wird gleichzeitig die Präprozessor-Sprache ausgewertet + Hint: 'USE_VFS' in Projekt-Einstellungen definieren um VFS Support zu aktivieren + 'SHADER_FILE_NO_VFS' in Projekt-Einstellungen um VFS Support für diese Unit zu deaktivieren} + +{$mode objfpc}{$H+} +{.$DEFINE EXPRESSION_ADD_BRACKET} +{.$DEFINE DEBUG} + +interface + +{$IFDEF SHADER_FILE_NO_VFS} + {$UNDEF USE_VFS} +{$ENDIF} + +uses + //System + Classes, SysUtils, variants, + + //bitSpaceEngine + uutlGenerics, uutlCommon; + +type +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//EXPRESSIONS/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + TengShaderPartScope = class; + TengGenCodeArgs = class; + + TengExpressionItem = class + protected + fLine: Integer; + fCol: Integer; + fFilename: String; + public + function GetText: String; virtual; + function GetValue(const aScope: TengShaderPartScope; const aGenCodeArgs: TengGenCodeArgs): Variant; virtual; + constructor Create(const aLine, aCol: Integer; const aFilename: String); + end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + TengExpressionValue = class(TengExpressionItem) + private + fValue: Variant; + public + function GetText: String; override; + function GetValue(const aScope: TengShaderPartScope; const aGenCodeArgs: TengGenCodeArgs): Variant; override; + constructor Create(const aValue: Variant; const aLine, aCol: Integer; const aFilename: String); + end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + TengExpressionVariable = class(TengExpressionItem) + private + fVariableName: String; + public + function GetText: String; override; + function GetValue(const aScope: TengShaderPartScope; const aGenCodeArgs: TengGenCodeArgs): Variant; override; + constructor Create(const aVariableName: String; const aLine, aCol: Integer; const aFilename: String); + end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + TengExpressionGroup = class(TengExpressionItem) + private + fChild: TengExpressionItem; + public + property Child: TengExpressionItem read fChild write fChild; + function GetText: String; override; + function GetValue(const aScope: TengShaderPartScope; const aGenCodeArgs: TengGenCodeArgs): Variant; override; + constructor Create(const aChild: TengExpressionItem; const aLine, aCol: Integer; const aFilename: String); + destructor Destroy; override; + end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + TengExpressionUnaryOperator = ( + opBinaryNot, opLogicalNot, opDefined, opSet + ); + TengExpressionUnaryOperation = class(TengExpressionItem) + private + fChild: TengExpressionItem; + fUnaryOp: TengExpressionUnaryOperator; + public + property Child: TengExpressionItem read fChild write fChild; + property UnaryOp: TengExpressionUnaryOperator read fUnaryOp; + + function GetText: String; override; + function GetValue(const aScope: TengShaderPartScope; const aGenCodeArgs: TengGenCodeArgs): Variant; override; + + constructor Create(const aUnaryOp: TengExpressionUnaryOperator; const aLine, aCol: Integer; const aFilename: String); + destructor Destroy; override; + end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + TengExpressionBinaryOperator = ( //order of elements in this enum is also the weight of the operators + opBinaryOr, opBinaryAnd, opBinaryXor, // binary + opMultiply, opDivide, opAdd, opSubtract, // arithmetic + opLogicalOr, opLogicalAnd, opLogicalXor, // logical + opEquals, opLesser, opGreater, opLEquals, opGEquals, opUnequals // comparison + ); + TengExpressionBinaryOperation = class(TengExpressionItem) + private + fFirst: TengExpressionItem; + fSecond: TengExpressionItem; + fBinaryOp: TengExpressionBinaryOperator; + public + property First: TengExpressionItem read fFirst write fFirst; + property Second: TengExpressionItem read fSecond write fSecond; + property BinaryOp: TengExpressionBinaryOperator read fBinaryOp; + + function GetText: String; override; + function GetValue(const aScope: TengShaderPartScope; const aGenCodeArgs: TengGenCodeArgs): Variant; override; + + constructor Create(const aOperator: TengExpressionBinaryOperator; const aLine, aCol: Integer; const aFilename: String); + destructor Destroy; override; + end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//EXCEPTIONS//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + TengShaderPart = class; + CengShaderPart = class of TengShaderPart; + + EengShaderPart = class(Exception) + public + Line, Col: Integer; + Filename: String; + constructor Create(const aMsg: String; const aLine, aCol: Integer; const aFilename: String); overload; + end; + + EengInvalidParamter = class(EengShaderPart) + constructor Create(const aMsg: String; const aLine, aCol: Integer; const aFilename: String); overload; + end; + + EengInvalidIdentifier = class(EengShaderPart) + constructor Create(const aIdentifier: String; const aLine, aCol: Integer; const aFilename: String); overload; + end; + + EengEmptyToken = class(EengShaderPart) + constructor Create(const aLine, aCol: Integer; const aFilename: String); overload; + end; + + EengInvalidToken = class(EengShaderPart) + constructor Create(const aClassName: String; const aToken: String; const aLine, aCol: Integer; const aFilename: String); overload; + end; + + EengInvalidParamterCount = class(EengShaderPart) + constructor Create(const aToken: String; const aLine, aCol: Integer; const aFilename: String); overload; + end; + + EengDuplicateIdentifier = class(EengShaderPart) + constructor Create(const aName: String; const aNew, aOld: TengShaderPart); overload; + end; + + EengInternal = class(EengShaderPart) + constructor Create(const aMsg: String); overload; + constructor Create(const aMsg: String; const aLine, aCol: Integer; const aFilename: String); overload; + end; + + EengUnknownIdentifier = class(EengShaderPart) + constructor Create(const aIdent: String; const aLine, aCol: Integer; const aFilename: String); overload; + end; + + EengExpression = class(EengShaderPart); + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//SHADER PARTS////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + TengShaderFile = class; + TengParseArgs = class; + + TengTokenParameter = packed record + Name: String; + Quoted: Boolean; + Line: Integer; + Col: Integer; + end; + TengTokenParameterList = specialize TutlSimpleList; + + TengMapDataFlag = ( + mdfIfEvaluate, //evaluate if parts and add suitable subtree + mdfIfAll, //do not evaluate if parts and add all subtrees + mdfAddInherited, //add inherited scopes to parent + mdfMapInherited, //map parts of inherited scopes + mdfCurrentScope, //do not map child scopes + mdfChild //is set if current node is not that node the recursion started + ); + TengMapDataFlags = set of TengMapDataFlag; + + TengShaderPartFlag = ( + spfCodeGenVisited //this item was visited by code gen routine + ); + TengShaderPartFlags = set of TengShaderPartFlag; + TengShaderPart = class(TutlInterfaceNoRefCount) + { Load & Store Code } + protected type + TengShaderPartEnumerator = class(TObject) + private + fOwner: TengShaderPart; + fPosition: Integer; + function GetCurrent: TengShaderPart; + public + property Current: TengShaderPart read GetCurrent; + function MoveNext: Boolean; + constructor Create(const aOwner: TengShaderPart); + end; + + private + fRoot: TengShaderFile; + fParent: TengShaderPart; + fLine: Integer; + fCol: Integer; + protected + function GetCount: Integer; virtual; + function GetChild(const aIndex: Integer): TengShaderPart; virtual; + function GetFilename: String; virtual; + function GetShaderClass: String; virtual; + function GetText: String; virtual; + + function ParseTextIntern(const aParseArgs: TengParseArgs; const aParameters: TengTokenParameterList): String; virtual; + function ParseText(const aParseArgs: TengParseArgs): String; + + { Generate Shader Code } + private + fFlags: TengShaderPartFlags; + protected + procedure MapData(const aFlags: TengMapDataFlags; const aTypes: array of CengShaderPart); virtual; + procedure GenCodeIntern(const aGenCodeArgs: TengGenCodeArgs); virtual; + procedure ClearGenCode; virtual; + public + property Flags: TengShaderPartFlags read fFlags; + + { General } + public + property Root: TengShaderFile read fRoot; + property Line: Integer read fLine; + property Col: Integer read fCol; + property Filename: String read GetFilename; + property ShaderClass: String read GetShaderClass; + property Parent: TengShaderPart read fParent; + property Count: Integer read GetCount; + property Children[const aIndex: Integer]: TengShaderPart read GetChild; default; + property Text: String read GetText; + + function HasParentType(const aParentType: CengShaderPart; const aIncludeSelf: Boolean = false): Boolean; + procedure GetParentByType(const aParentType: CengShaderPart; out aPart); + function GetEnumerator: TengShaderPartEnumerator; + + constructor Create(const aParent: TengShaderPart); virtual; + public + class function GetTokenName: String; virtual; + class function CheckToken(const aToken: String): Boolean; virtual; + class procedure CheckToken(const aParseArgs: TengParseArgs; const aParent: TengShaderPart); virtual; + end; + TengShaderPartList = specialize TutlList; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + TengShaderPartContainer = class(TengShaderPart) + { Load & Store Code } + private + fChildren: TengShaderPartList; + function HandleToken(var aToken: String; const aParseArgs: TengParseArgs): String; + protected + function GetCount: Integer; override; + function GetChild(const aIndex: Integer): TengShaderPart; override; + function GetText: String; override; + function ParseTextIntern(const aParseArgs: TengParseArgs; const aParameters: TengTokenParameterList): String; override; + + { Generate Shader Code } + protected + procedure MapData(const aFlags: TengMapDataFlags; const aTypes: array of CengShaderPart); override; + procedure GenCodeIntern(const aGenCodeArgs: TengGenCodeArgs); override; + procedure ClearGenCode; override; + + { General } + public + procedure AddChild(const aChild: TengShaderPart; const aPrepend: Boolean = false); + constructor Create(const aParent: TengShaderPart); override; + destructor Destroy; override; + end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + TengFindMappedPartFlag = ( + // general + ffGlobal, // set current node to root before searching + ffDescending, // depth search starting at current node + ffAscending, // search in parents and grand parents starting at current node + ffLocal, // search in mapped parts of current item (will be reseted when entering next or previous recursion level) + ffFindFirst, // return after finding at least one result + ffVisited, // only search in scopes that are already visited by GenCode + + // class data + ffInherited, // search in inherited classes (this is not a new recursion level!) + ffFile, // search in file that belongs to this class (this is not a new recursion level!) + + // file + ffIgnoreClasses // ignore class parts + ); + TengFindMappedPartFlags = set of TengFindMappedPartFlag; + + TengShaderPartScope = class(TengShaderPartContainer) + { Generate Shader Code } + private type + TengShaderPartScopeHashSet = specialize TutlHashSet; + TengShaderPartMap = specialize TutlMap; + private + fInherited: TengShaderPartScopeHashSet; + fChildScopes: TengShaderPartScopeHashSet; + fMappedParts: TengShaderPartMap; + + function CheckName(const aName: String; const aShaderPart: TengShaderPart): Boolean; + protected + procedure MapChildScope(const aScope: TengShaderPartScope); + procedure MapInheritedScope(const aScope: TengShaderPartScope); + function MapShaderPart(const aName: String; const aShaderPart: TengShaderPart): Boolean; + + procedure FindMappedPart(out aShaderPart; const aName: String; const aFlags: TengFindMappedPartFlags; const aType: CengShaderPart = nil); + procedure FindMappedParts(const aParts: TengShaderPartList; const aName: String; const aFlags: TengFindMappedPartFlags; const aType: CengShaderPart = nil); virtual; + + function GetFindPropertyFlags: TengFindMappedPartFlags; virtual; + procedure CheckDuplicate(const aName: String; const aOld, aNew: TengShaderPart); virtual; + procedure MapData(const aFlags: TengMapDataFlags; const aTypes: array of CengShaderPart); override; + procedure GenCodeIntern(const aGenCodeArgs: TengGenCodeArgs); override; + procedure ClearGenCode; override; + procedure ClearMappedData(const aExcludedTypes: array of CengShaderPart); overload; + procedure ClearMappedData; overload; + public + constructor Create(const aParent: TengShaderPart); override; + destructor Destroy; override; + end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + TengShaderCode = class; + TengShaderPartProperty = class; + TengShaderPartDefine = class; + TengCodeGenerator = class(TengShaderPartScope) + private + function GetProperty(const aName: String): TengShaderPartProperty; + protected + procedure GenerateCode(const aGenCodeArgs: TengGenCodeArgs); virtual; + public + property Properties[const aName: String]: TengShaderPartProperty read GetProperty; default; + + function GenerateCode: TengShaderCode; + procedure ListProperties(const aList: TStrings); virtual; + end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + TengShaderPartClass = class(TengCodeGenerator) + { Load & Store Code } + private + fName: String; + fExtends: TStringList; + function GetExtendCount: Integer; + function GetExtends(const aIndex: Integer): String; + protected + function GetText: String; override; + function GetShaderClass: String; override; + + function ParseTextIntern(const aParseArgs: TengParseArgs; const aParameters: TengTokenParameterList): String; override; + public + property Name: String read fName; + property ExtendCount: Integer read GetExtendCount; + property Extends[const aIndex: Integer]: String read GetExtends; + + { Generate Shader Code } + protected + procedure CheckDuplicate(const aName: String; const aOld, aNew: TengShaderPart); override; + function GetFindPropertyFlags: TengFindMappedPartFlags; override; + procedure GenCodeIntern(const aGenCodeArgs: TengGenCodeArgs); override; + procedure GenerateCode(const aGenCodeArgs: TengGenCodeArgs); override; + public + procedure FindMappedParts(const aParts: TengShaderPartList; const aName: String; const aFlags: TengFindMappedPartFlags; const aType: CengShaderPart = nil); override; + procedure MapData(const aFlags: TengMapDataFlags; const aTypes: array of CengShaderPart); override; + + { General } + public + constructor Create(const aParent: TengShaderPart); override; + destructor Destroy; override; + public + class function GetTokenName: String; override; + class procedure CheckToken(const aParseArgs: TengParseArgs; const aParent: TengShaderPart); override; + end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + TengShaderFile = class(TengCodeGenerator) + { Load & Store Code } + private + fFilename: String; + protected + function GetFilename: String; override; + public + property Filename: String read fFilename; + procedure LoadFromFile(const aFilename: String); + procedure SaveToFile(const aFilename: String); + procedure LoadFromStream(const aStream: TStream; const aFilename: String); + procedure SaveToStream(const aStream: TStream); + + { Generate Shader Code } + private type + TengShaderPartClassMap = specialize TutlMap; + private + fClasses: TengShaderPartClassMap; + function GetGenerator(const aName: String): TengCodeGenerator; + protected + function GetFindPropertyFlags: TengFindMappedPartFlags; override; + procedure MapData(const aFlags: TengMapDataFlags; const aTypes: array of CengShaderPart); override; + function GetClass(const aName: String): TengShaderPartClass; + procedure AddClass(const aClass: TengShaderPartClass); + procedure GenerateCode(const aGenCodeArgs: TengGenCodeArgs); override; + public + { be carefull with the returned object, it will be destroyed + when the shaderfile is cleared, reloaded or destroyed } + property Generator[const aName: String]: TengCodeGenerator read GetGenerator; + procedure ListGenerators(const aList: TStrings); + + { General } + public + procedure Clear; + constructor Create(const aParent: TengShaderPart); override; overload; + constructor Create; overload; + destructor Destroy; override; + end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + TengShaderPartInclude = class(TengShaderPart) + { Load & Store Code } + private + fShaderFile: TengShaderFile; + fIncludeFile: String; + fAbsoluteFile: String; + protected + function GetCount: Integer; override; + function GetChild(const aIndex: Integer): TengShaderPart; override; + function GetText: String; override; + function ParseTextIntern(const aParseArgs: TengParseArgs; const aParameters: TengTokenParameterList): String; override; + + { Generate Code } + private + procedure CheckShaderFile; + protected + procedure MapData(const aFlags: TengMapDataFlags; const aTypes: array of CengShaderPart); override; + procedure GenCodeIntern(const aGenCodeArgs: TengGenCodeArgs); override; + + { General } + public + property IncludeFile: String read fIncludeFile; + constructor Create(const aParent: TengShaderPart); override; + destructor Destroy; override; + public + class function GetTokenName: String; override; + end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + TengShaderPartComment = class(TengShaderPart) + private + fText: String; + protected + function GetText: String; override; + function ParseTextIntern(const aParseArgs: TengParseArgs; const aParameters: TengTokenParameterList): String; override; + public + class function GetTokenName: String; override; + end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + TengShaderPartInherited = class(TengShaderPart) + { Load & Store Code } + private + fInheritedName: String; + fParameters: TStringList; + protected + function GetText: String; override; + function ParseTextIntern(const aParseArgs: TengParseArgs; const aParameters: TengTokenParameterList): String; override; + + { Generate Shader Code } + protected + procedure GenCodeIntern(const aGenCodeArgs: TengGenCodeArgs); override; + + { General } + public + constructor Create(const aParent: TengShaderPart); override; + destructor Destroy; override; + public + class function GetTokenName: String; override; + class procedure CheckToken(const aParseArgs: TengParseArgs; const aParent: TengShaderPart); override; + end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + TengMetaType = (metaNormal, metaVersion, metaExtension, metaLayout); + IengMetaData = interface(IUnknown) + ['{8064AB43-4A82-4E77-BE46-E222827522FF}'] + function GetValues(const aIndex: Integer): String; + function GetCount: Integer; + function GetMetaType: TengMetaType; + function GetName: String; + + property MetaType: TengMetaType read GetMetaType; + property Name: String read GetName; + property Count: Integer read GetCount; + property Values[const aIndex: Integer]: String read GetValues; default; + end; + TengMetaData = class(TInterfacedObject, IengMetaData) + private + fMetaType: TengMetaType; + fName: String; + fValues: TStringList; + function GetValues(const aIndex: Integer): String; + function GetCount: Integer; + function GetMetaType: TengMetaType; + function GetName: String; + public + property MetaType: TengMetaType read GetMetaType; + property Name: String read GetName; + property Count: Integer read GetCount; + property Values[const aIndex: Integer]: String read GetValues; default; + + procedure AddValue(const aValue: String); + + constructor Create(const aName: String; const aType: TengMetaType); + destructor Destroy; override; + end; + TengShaderPartMeta = class(TengShaderPart) + private + fMetaData: IengMetaData; + protected + function GetText: String; override; + function ParseTextIntern(const aParseArgs: TengParseArgs; const aParameters: TengTokenParameterList): String; override; + procedure GenCodeIntern(const aGenCodeArgs: TengGenCodeArgs); override; + public + property Data: IengMetaData read fMetaData; + public + destructor Destroy; override; + public + class function GetTokenName: String; override; + end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + TengShaderPartKeyValuePair = class(TengShaderPart) + { Load & Store Code } + protected + fName: String; + fValue: Variant; + fValueName: String; + + function GetText: String; override; + function ParseTextIntern(const aParseArgs: TengParseArgs; const aParameters: TengTokenParameterList): String; override; + public + property Name: String read fName; + property Value: Variant read fValue; + + constructor CreateValue(const aParent: TengShaderPart; const aName: String; const aValue: Variant); + constructor CreateName(const aParent: TengShaderPart; const aName, aValueName: String); + { Generate Code } + protected + procedure GenCodeIntern(const aGenCodeArgs: TengGenCodeArgs); override; + end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + TengShaderPartProperty = class(TengShaderPartKeyValuePair) + public + property Value: Variant read fValue write fValue; + procedure MapData(const aFlags: TengMapDataFlags; const aTypes: array of CengShaderPart); override; + public + class function GetTokenName: String; override; + end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + TengShaderPartDefine = class(TengShaderPartKeyValuePair) + protected + function ParseTextIntern(const aParseArgs: TengParseArgs; const aParameters: TengTokenParameterList): String; override; + procedure MapData(const aFlags: TengMapDataFlags; const aTypes: array of CengShaderPart); override; + public + class function GetTokenName: String; override; + end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + TengShaderPartCodeProperty = class(TengShaderPart) + { Load & Store Code } + protected + fName: String; + fType: String; + function GetText: String; override; + function ParseTextIntern(const aParseArgs: TengParseArgs; const aParameters: TengTokenParameterList): String; override; + + { Generate Code } + protected + property Name: String read fName; + property PropType: String read fType; + function IsEquals(const aCodeProp: TengShaderPartCodeProperty): Boolean; virtual; + procedure MapData(const aFlags: TengMapDataFlags; const aTypes: array of CengShaderPart); override; + procedure GenCodeIntern(const aGenCodeArgs: TengGenCodeArgs); override; + end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + TengShaderPartVar = class(TengShaderPartCodeProperty) + { Load & Store Cde } + private + fDefault: String; + protected + function GetText: String; override; + function ParseTextIntern(const aParseArgs: TengParseArgs; const aParameters: TengTokenParameterList): String; override; + + { Generate Shader Code } + protected + function IsEquals(const aCodeProp: TengShaderPartCodeProperty): Boolean; override; + procedure GenCodeIntern(const aGenCodeArgs: TengGenCodeArgs); override; + + { General } + public + class function GetTokenName: String; override; + end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + TengShaderPartVarying = class(TengShaderPartCodeProperty) + { Generate Shader Code } + protected + procedure GenCodeIntern(const aGenCodeArgs: TengGenCodeArgs); override; + + { General } + public + class function GetTokenName: String; override; + end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + TengShaderPartUniform = class(TengShaderPartCodeProperty) + { Generate Shader Code } + protected + procedure GenCodeIntern(const aGenCodeArgs: TengGenCodeArgs); override; + + { General } + public + class function GetTokenName: String; override; + end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + TengShaderPartCall = class(TengShaderPart) + { Load & Store Code } + private + fName: String; + fParameters: TStringList; + protected + function GetText: String; override; + function ParseTextIntern(const aParseArgs: TengParseArgs; const aParameters: TengTokenParameterList): String; override; + + { Generate Shader Code } + protected + procedure GenCodeIntern(const aGenCodeArgs: TengGenCodeArgs); override; + + { General } + public + constructor Create(const aParent: TengShaderPart); override; + destructor Destroy; override; + public + class function GetTokenName: String; override; + end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + TengShaderPartProcParam = packed record + Typ: String; + Name: String; + end; + TengShaderPartProcParamList = specialize TutlSimpleList; + TengShaderPartProc = class(TengShaderPartScope) + { Load & Store Code } + private + fName: String; + fIsInline: Boolean; + fParameters: TengShaderPartProcParamList; + protected + function GetHeaderText: String; virtual; + function GetText: String; override; + function ParseTextIntern(const aParseArgs: TengParseArgs; const aParameters: TengTokenParameterList): String; override; + + { Generate Shader Code } + protected + function GenHeaderCode: String; virtual; + procedure GenInlineCode(const aGenCodeArgs: TengGenCodeArgs; const aAddToken: Boolean = true); virtual; + procedure GenCodeIntern(const aGenCodeArgs: TengGenCodeArgs); override; + procedure MapData(const aFlags: TengMapDataFlags; const aTypes: array of CengShaderPart); override; + + { General } + public + property Name: String read fName; + property IsInline: Boolean read fIsInline; + constructor Create(const aParent: TengShaderPart); override; + destructor Destroy; override; + public + class function GetTokenName: String; override; + class procedure CheckToken(const aParseArgs: TengParseArgs; const aParent: TengShaderPart); override; + end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + TengShaderPartMain = class(TengShaderPartProc) + { Save & Store Code } + protected + function GetHeaderText: String; override; + function ParseTextIntern(const aParseArgs: TengParseArgs; const aParameters: TengTokenParameterList): String; override; + + { Generate Code } + protected + function GenHeaderCode: String; override; + + { General } + public + class function GetTokenName: String; override; + end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + TengShaderPartFunc = class(TengShaderPartProc) + { Save & Store Code } + private + fReturnType: String; + protected + function GetHeaderText: String; override; + function ParseTextIntern(const aParseArgs: TengParseArgs; const aParameters: TengTokenParameterList): String; override; + public + property ReturnType: String read fReturnType; + + { Generate Code } + protected + procedure GenInlineCode(const aGenCodeArgs: TengGenCodeArgs; const aAddToken: Boolean = true); override; + function GenHeaderCode: String; override; + + { General } + public + class function GetTokenName: String; override; + class procedure CheckToken(const aParseArgs: TengParseArgs; const aParent: TengShaderPart); override; + end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + TengShaderPartIf = class(TengShaderPart) + { Load & Store Code } + private + fExpression: TengExpressionItem; + fIfPart: TengShaderPart; + fElsePart: TengShaderPart; + + function ParseExpression(const aParameters: TengTokenParameterList; aIndex: Integer): TengExpressionItem; + protected + function GetCount: Integer; override; + function GetChild(const aIndex: Integer): TengShaderPart; override; + function GetText: String; override; + function ParseTextIntern(const aParseArgs: TengParseArgs; const aParameters: TengTokenParameterList): String; override; + + function HandleToken(const aToken: String; const aParseArgs: TengParseArgs): String; + function HandleEndToken(const aToken: String; const aParseArgs: TengParseArgs): String; virtual; + + { Generate Shader Code } + protected + procedure MapData(const aFlags: TengMapDataFlags; const aTypes: array of CengShaderPart); override; + procedure GenCodeIntern(const aGenCodeArgs: TengGenCodeArgs); override; + + { General } + public + destructor Destroy; override; + public + class function GetTokenName: String; override; + end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + TengShaderPartElIf = class(TengShaderPartIf) + protected + function GetText: String; override; + function HandleEndToken(const aToken: String; const aParseArgs: TengParseArgs): String; override; + public + class function GetTokenName: String; override; + end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + TengShaderPartElse = class(TengShaderPartContainer) + protected + function GetText: String; override; + public + class function GetTokenName: String; override; + end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + TengShaderPartEcho = class(TengShaderPart) + { Load & Store Code } + private + fName: String; + protected + function GetText: String; override; + function ParseTextIntern(const aParseArgs: TengParseArgs; const aParameters: TengTokenParameterList): String; override; + + { Generate Shader Code } + protected + procedure GenCodeIntern(const aGenCodeArgs: TengGenCodeArgs); override; + + { General } + public + class function GetTokenName: String; override; + end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + TengShaderPartMessage = class(TengShaderPart) + private + fMessage: String; + protected + function GetText: String; override; + function ParseTextIntern(const aParseArgs: TengParseArgs; const aParameters: TengTokenParameterList): String; override; + public + class function GetTokenName: String; override; + end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + TengShaderPartWarning = class(TengShaderPartMessage) + public + class function GetTokenName: String; override; + end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + TengShaderPartError = class(TengShaderPartMessage) + protected + procedure GenCodeIntern(const aGenCodeArgs: TengGenCodeArgs); override; + public + class function GetTokenName: String; override; + end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + TengShaderPartCode = class(TengShaderPart) + { Load & Store Code } + private + fCode: String; + protected + function GetText: String; override; + function ParseTextIntern(const aParseArgs: TengParseArgs; const aParameters: TengTokenParameterList): String; override; + public + property Code: String read fCode; + + { Generate Shader Code } + protected + procedure GenCodeIntern(const aGenCodeArgs: TengGenCodeArgs); override; + end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + TengShaderPartLineBreak = class(TengShaderPart) + { Load & Store Code } + protected + function GetText: String; override; + function ParseTextIntern(const aParseArgs: TengParseArgs; const aParameters: TengTokenParameterList): String; override; + + { Generate Shader Code } + protected + procedure GenCodeIntern(const aGenCodeArgs: TengGenCodeArgs); override; + + { General } + public + class function GetTokenName: String; override; + end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + TengShaderPartCommandEnd = class(TengShaderPart) + { Load & Store Code } + private + fToken: String; + protected + function GetText: String; override; + function ParseTextIntern(const aParseArgs: TengParseArgs; const aParameters: TengTokenParameterList): String; override; + + { Generate Shader Code } + protected + procedure GenCodeIntern(const aGenCodeArgs: TengGenCodeArgs); override; + + { General } + public + class function CheckToken(const aToken: String): Boolean; override; + end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//HELPER//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + TengShaderCode = class(TStringList) + private type + TMetaList = specialize TutlList; + private + function GetMeta(const aIndex: Integer): IengMetaData; + function GetMetaCount: Integer; + protected + fMetaList: TMetaList; + public + property Meta[const aIndex: Integer]: IengMetaData read GetMeta; + property MetaCount: Integer read GetMetaCount; + + constructor Create; + destructor Destroy; override; + end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + TengShaderCodeIntern = class(TengShaderCode) + public + property MetaList: TMetaList read fMetaList; + procedure AddMeta(const aMeta: IengMetaData); + end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + TengParseArgs = class + private + fCode: TStringList; + fLineLength: Integer; + fLineCount: Integer; + fCurrentLine: String; + fCurrentChar: Char; + fCol: Integer; + fLine: Integer; + fOwner: TengShaderFile; + + procedure SetCol(const aValue: Integer); + procedure SetLine(const aValue: Integer); + function GetEndOfLine: Boolean; + function GetEndOfFile: Boolean; + function GetCode: TStrings; + public + property Code: TStrings read GetCode; + property LineLength: Integer read fLineLength; + property LineCount: Integer read fLineCount; + property CurrentLine: String read fCurrentLine; + property CurrentChar: Char read fCurrentChar; + property EndOfLine: Boolean read GetEndOfLine; + property EndOfFile: Boolean read GetEndOfFile; + property Col: Integer read fCol write SetCol; + property Line: Integer read fLine write SetLine; + + procedure IncCol; + procedure IncLine; + function ParseParameters(const aParameters: TengTokenParameterList): Boolean; + procedure LoadCode(const aStream: TStream); + + constructor Create(const aOwner: TengShaderFile); + destructor Destroy; override; + end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + TengGenCodeFlag = ( + gcfGenProcedure, // generate shader code for procedure or function + gcfGenProcInline, // generate inline shader code for procedure or function + gcfGenProcCall, // generate procedure call + gcfGenCodeProp // generate shader code for code properties (e.g. Var, Varying, Uniform) + ); + TengGenCodeFlags = set of TengGenCodeFlag; + TengGenCodeArgs = class(TObject) + private type + TCodeItem = class + public + function GetText: String; virtual; + function IsEmpty: Boolean; + end; + + TCodeItemStart = class(TCodeItem) + function GetText: String; override; + end; + + TCodeItemText = class(TCodeItem) + public + Text: String; + function GetText: String; override; + constructor Create(const aText: String); + end; + + TCodeItemLineBreak = class(TCodeItem) + public + function GetText: String; override; + end; + + TCodeItemCommandEnd = class(TCodeItem) + public + Token: String; + function GetText: String; override; + constructor Create(const aToken: String); + end; + + TTokenType = (ttBegin, ttEnd, ttSingle); + TCodeItemToken = class(TCodeItem) + public + TokenType: TTokenType; + Level: Integer; + constructor Create(const aTokenType: TTokenType; const aLevel: Integer = -1); + end; + + TCodeItemList = specialize TutlList; + TCodeStackItem = class + private type + TFlag = (cfIgnoreNextSemicolon); + TFlags = set of TFlag; + private + fFlags: TFlags; + fItems: TCodeItemList; + function GetEmpty: Boolean; + public + property Items: TCodeItemList read fItems; + property Empty: Boolean read GetEmpty; + + {$IFDEF DEBUG} + function GetDebugText: String; + {$ENDIF} + function GetText: String; + procedure SplitCurrentCommand(const aItem: TCodeStackItem); + function Merge(const aItem: TCodeStackItem; aIndex: Integer): Integer; + + procedure AddText(const aText: String); + procedure AddCommandEnd(const aToken: String = ''); + procedure AddToken(const aTokenType: TTokenType; const aLevel: Integer = -1); + procedure AddLineEnd; + + function GetMinLineOffset: Integer; + procedure IgnoreNextSemicolon; + + procedure ReplaceIdents(const aOld, aNew: TStrings); + procedure ReplaceReturns(const aItem: TCodeStackItem; const aRetType, aFuncName: String; const aCntr: Integer); + + constructor Create; + destructor Destroy; override; + end; + + TProcWrapper = class + public + Proc: TengShaderPartProc; + Code: TCodeStackItem; + constructor Create; + destructor Destroy; override; + end; + + TCodeStack = specialize TutlList; + TProcParamStack = specialize TutlList; + TGenCodeFlagsStack = specialize TutlList; + TProcedureList = specialize TutlList; + TCodePropertyMap = specialize TutlMap; + public type + TPopCodeFlag = ( + pcfAppend, + pcfPrepend, + pcfAddEmptyLine + ); + TPopCodeFlags = set of TPopCodeFlag; + private + fMaxPropNameLen: Integer; + fRoot: TengShaderPartScope; + fFlags: TGenCodeFlagsStack; + fProcParams: TProcParamStack; + fProcedures: TProcedureList; + fProperties: TCodePropertyMap; + fCode: TCodeStack; + fCommands: TCodeStack; + fShaderCode: TengShaderCodeIntern; + fInlineRetCounter: Integer; + + function GetFlags: TengGenCodeFlags; + function GetText: String; + function GetCode: TCodeStackItem; + function GetProcParams: TStrings; + public + property Root: TengShaderPartScope read fRoot; + property Flags: TengGenCodeFlags read GetFlags; + property Code: TCodeStackItem read GetCode; + property ProcParams: TStrings read GetProcParams; + property MaxPropNameLen: Integer read fMaxPropNameLen; + + procedure PushCode; + procedure InsertCode(const aCodeStackItem: TCodeStackItem); + function PushCurrentCommand: TCodeStackItem; + procedure PushFlags(const aFlags: TengGenCodeFlags); + procedure PushProcParams(const aParams: TStrings); + + procedure PopCode(const aFlags: TPopCodeFlags = [pcfAppend]); + function ExtractCode: TCodeStackItem; + procedure PopCurrentCommand(const aRetType, aFuncName: String); + procedure PopFlags; + procedure PopProcParams; + + procedure AddProcedure(const aProc: TengShaderPartProc); + procedure AddCodeProperty(const aProp: TengShaderPartCodeProperty); + procedure AddMeta(const aMeta: IengMetaData); + + function HasCodeProperty(const aName: String): Boolean; + + procedure GenProcedureCode(const aAppend: Boolean = false); + procedure GenCodePropertyCode(const aTypes: array of CengShaderPart); + procedure GenMetaCode; + + constructor Create(const aShaderCode: TengShaderCodeIntern; const aRoot: TengShaderPartScope); + destructor Destroy; override; + end; + +function TrySetProperty(const aGenerator: TengCodeGenerator; const aName: String; const aValue: Variant): Boolean; + +{$IFDEF DEBUG} +procedure SaveAsXMindXml(const aShaderPart: TengShaderPart; const aDirectory: String); +{$ENDIF} + +implementation + +uses + uutlExceptions, FileUtil, RegExpr, Math{$IFDEF USE_VFS}, uvfsManager{$ENDIF}; + +const + PRECOMPILER_STATEMENT_BEGIN = '{'; + PRECOMPILER_STATEMENT_END = '}'; + PRECOMPILER_QUOTE_CHAR = ''''; + TOKEN_IDENTIFIER = '$'; + TOKEN_COMMAND_END = ';'; + TOKEN_SCOPE_BEGIN = '{'; + TOKEN_SCOPE_END = '}'; + TOKEN_LINE_BREAK = sLineBreak; + COMMENT_IDENTIFIER = '.'; + + TOKEN_CLASS = TOKEN_IDENTIFIER + 'CLASS'; //{$CLASS PhongLight $EXTENDS Normal Glow} + TOKEN_EXTENDS = TOKEN_IDENTIFIER + 'EXTENDS'; + TOKEN_INHERITED = TOKEN_IDENTIFIER + 'INHERITED'; //{$INHERITED} {$INHERITED BaseClass} + + TOKEN_INCLUDE = TOKEN_IDENTIFIER + 'INCLUDE'; //{$INCLUDE 'Normal.frag'} + + TOKEN_META = TOKEN_IDENTIFIER + 'META'; //{$META 'Fuu' 'Bar'} + TOKEN_VERSION = TOKEN_IDENTIFIER + 'VERSION'; //{$META $VERSION 'version'} + TOKEN_EXTENSION = TOKEN_IDENTIFIER + 'EXTENSION'; //{$META $EXTENSION 'GL_ARB_geometry_shader4' 'enable'} + TOKEN_LAYOUT = TOKEN_IDENTIFIER + 'LAYOUT'; //{$META $LAYOUT '(line_strip, max_vertices = 6) out'} + + TOKEN_PROPERTY = TOKEN_IDENTIFIER + 'PROPERTY'; //{$PROPERTY InvertRoughmap 'false'} + TOKEN_DEFINE = TOKEN_IDENTIFIER + 'DEFINE'; //{$DEFINE RENDER_FACE_FRONT '0'} + TOKEN_ECHO = TOKEN_IDENTIFIER + 'ECHO'; //{$ECHO InvertRoughmap} + + TOKEN_VAR = TOKEN_IDENTIFIER + 'VAR'; //{$VAR 'float' 'refractivity' '0.0'} + TOKEN_VARYING = TOKEN_IDENTIFIER + 'VARYING'; //{$VARYING 'vec3' 'vVertex'} + TOKEN_UNIFORM = TOKEN_IDENTIFIER + 'UNIFORM'; //{$UNIFORM 'sampler2D' 'uShadowMap'} + + TOKEN_CALL = TOKEN_IDENTIFIER + 'CALL'; //{$CALL CalcLight} + TOKEN_PROC = TOKEN_IDENTIFIER + 'PROC'; //{$PROC CalcLight} Code... {$END} + TOKEN_FUNC = TOKEN_IDENTIFIER + 'FUNC'; //{$FUND 'float' 'ShadowPoisson' 'vec2' 'shadowMapST' 'float' 'receiver'} Code... {$END} + TOKEN_MAIN = TOKEN_IDENTIFIER + 'MAIN'; + TOKEN_INLINE = TOKEN_IDENTIFIER + 'INLINE'; //{$PROC CalcLight $INLINE} Code... {$END} + + TOKEN_IF = TOKEN_IDENTIFIER + 'IF'; //{$IF PhongLight = '0'} Code ... {$END} + TOKEN_ELIF = TOKEN_IDENTIFIER + 'ELIF'; + TOKEN_ELSE = TOKEN_IDENTIFIER + 'ELSE'; + TOKEN_END = TOKEN_IDENTIFIER + 'END'; + + TOKEN_MESSAGE = TOKEN_IDENTIFIER + 'MESSAGE'; //{$MESSAGE 'message'} + TOKEN_WARNING = TOKEN_IDENTIFIER + 'WARNING'; //{$WARNING 'message'} + TOKEN_ERROR = TOKEN_IDENTIFIER + 'ERROR'; //{$ERROR 'message'} + + TOKEN_OP_LOGICAL_NOT = TOKEN_IDENTIFIER + 'NOT'; //{$IF $NOT test} + TOKEN_OP_LOGICAL_OR = TOKEN_IDENTIFIER + 'OR'; //{$IF test1 $OR test2} + TOKEN_OP_LOGICAL_AND = TOKEN_IDENTIFIER + 'AND'; //{$IF test1 $AND test2} + TOKEN_OP_LOGICAL_XOR = TOKEN_IDENTIFIER + 'XOR'; //{$IF test1 $XOR test2} + TOKEN_OP_DEFINED = TOKEN_IDENTIFIER + 'DEFINED'; //{$IF $DEFINED test2} + TOKEN_OP_SET = TOKEN_IDENTIFIER + 'SET'; //{$IF $SET vVertex} + TOKEN_OP_ADD = '+'; //{$IF test1 + test2} + TOKEN_OP_SUBTRACT = '-'; //{$IF test1 - test2} + TOKEN_OP_MULTIPLY = '*'; //{$IF test1 * test2} + TOKEN_OP_DIVIDE = '/'; //{$IF test1 / test2} + TOKEN_OP_EQUALS = '='; //{$IF test1 = test2} + TOKEN_OP_LESSER = '<'; //{$IF test1 < test2} + TOKEN_OP_GREATER = '>'; //{$IF test1 > test2} + TOKEN_OP_LEQUALS = '<='; //{$IF test1 <= test2} + TOKEN_OP_GEQUALS = '>='; //{$IF test1 >= test2} + TOKEN_OP_UNEQUALS = '<>'; //{$IF test1 <> test2} + TOKEN_OP_BINARY_OR = '|'; //{$IF test1 | test2} + TOKEN_OP_BINARY_AND = '&'; //{$IF test1 & test2} + TOKEN_OP_BINARY_XOR = '^'; //{$IF test1 ^ test2} + TOKEN_OP_BINARY_NOT = '!'; //{$IF !test1} + TOKEN_OP_GROUP_BEGIN = '('; //{$IF (test1 $OR test2) >= '0'} + TOKEN_OP_GROUP_END = ')'; + + WHITESPACES = [' ', #9]; + VALID_IDENT_CHARS = ['A'..'Z', 'a'..'z', '0'..'9', '_']; + VALID_TOKEN_CHARS = ['$'] + VALID_IDENT_CHARS; + TOKEN_SPLIT_CHARS = [' ', #9, TOKEN_OP_GROUP_BEGIN, TOKEN_OP_GROUP_END]; + + LAYOUT_MIN_VERSION = 150; + VERSION_EXTRA_COMPAT = 'compatibility'; //{$META $VERSION 'compatibility'} + + EXPRESSION_UNARY_OPERATIONS: array[TengExpressionUnaryOperator] of String = ( + TOKEN_OP_BINARY_NOT, //opBinaryNot + TOKEN_OP_LOGICAL_NOT, //opLogicalNot + TOKEN_OP_DEFINED, //opDefined + TOKEN_OP_SET //opSet + ); + + EXPRESSION_BINARY_OPERATIONS: array[TengExpressionBinaryOperator] of String = ( + TOKEN_OP_BINARY_OR, //opBinaryOr + TOKEN_OP_BINARY_AND, //opBinaryAnd + TOKEN_OP_BINARY_XOR, //opBinaryXor + + TOKEN_OP_MULTIPLY, //opMultiply + TOKEN_OP_DIVIDE, //opDivide + TOKEN_OP_ADD, //opAdd + TOKEN_OP_SUBTRACT, //opSubtract + + TOKEN_OP_LOGICAL_OR, //opLogicalOr + TOKEN_OP_LOGICAL_AND, //opLogicalAnd + TOKEN_OP_LOGICAL_XOR, //opLogicalXor + + TOKEN_OP_EQUALS, //opEquals + TOKEN_OP_LESSER, //opLesser + TOKEN_OP_GREATER, //opGreater + TOKEN_OP_LEQUALS, //opLEquals + TOKEN_OP_GEQUALS, //opGEquals + TOKEN_OP_UNEQUALS //opUnequals, + ); + + TOKEN_CLASSES: array[0..20] of CengShaderPart = ( + TengShaderPartProperty, + TengShaderPartClass, + TengShaderPartDefine, + TengShaderPartError, + TengShaderPartIf, + TengShaderPartInclude, + TengShaderPartMessage, + TengShaderPartMeta, + TengShaderPartCall, + TengShaderPartProc, + TengShaderPartFunc, + TengShaderPartMain, + TengShaderPartInherited, + TengShaderPartUniform, + TengShaderPartVar, + TengShaderPartVarying, + TengShaderPartWarning, + TengShaderPartLineBreak, + TengShaderPartCommandEnd, + TengShaderPartComment, + TengShaderPartEcho); + + COMMAND_END_TOKENS = [TOKEN_COMMAND_END, TOKEN_SCOPE_BEGIN, TOKEN_SCOPE_END]; + + FIND_OVERWRITTEN_FLAGS: TengFindMappedPartFlags = [ffLocal, ffInherited]; // search all ShaderParts in current and inherited scopes + FIND_INHERITED_FLAGS: TengFindMappedPartFlags = [ffInherited]; // search in inherited scropes only + FIND_IN_SCOPE_FLAGS: TengFindMappedPartFlags = [ffLocal, ffAscending, ffInherited, ffFile]; // search in current, all parent, all interhited scopes and in file the scope + FIND_GLOBAL: TengFindMappedPartFlags = [ffGlobal, ffLocal]; // search in root file only (for defines that are set from the program) + GEN_CODE_FIND_FLAGS: TengFindMappedPartFlags = [ffLocal, ffAscending, ffInherited, ffFile, ffVisited]; // search in current, all parent, all inherited scopes and in file scope, but search only in already visited scopes + FIND_PROPERTY_FLAGS: TengFindMappedPartFlags = [ffLocal, ffDescending, ffInherited]; // search in current, all inherited and all child scopes + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +{$IFDEF DEBUG} +function MakeDebugStr(const aItems: TengGenCodeArgs.TCodeItemList; const aFilename: String): String; +var + i: TengGenCodeArgs.TCodeItem; + fs: TFileStream; +begin + fs := TFileStream.Create(aFilename, fmCreate); + try + result := ''; + for i in aItems do begin + result := result + i.ClassName; + result := result + '('; + if (i is TengGenCodeArgs.TCodeItemLineBreak) then + result := result + 'LB)' + sLineBreak + sLineBreak + else + result := result + i.GetText + ')' + sLineBreak; + end; + fs.Write(result[1], Length(result)); + finally + FreeAndNil(fs); + end; +end; +{$ENDIF} + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TrySetProperty(const aGenerator: TengCodeGenerator; const aName: String; const aValue: Variant): Boolean; +var + prop: TengShaderPartProperty; +begin + prop := aGenerator.Properties[aName]; + result := Assigned(prop); + if result then + prop.Value := aValue; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function IsValidIdentifier(const aIdent: String): Boolean; +var + i, len: Integer; +begin + len := Length(aIdent); + result := false; + for i := 1 to len do + if not (aIdent[i] in VALID_IDENT_CHARS) then + exit; + result := true; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function CheckEndToken(const aParseArgs: TengParseArgs; const aShaderPart: TengShaderPart): String; +var + oldLine, oldCol: Integer; + param: TengTokenParameterList; +begin + param := TengTokenParameterList.Create; + try + oldLine := aParseArgs.Line; + oldCol := aParseArgs.Col; + if not aParseArgs.ParseParameters(param) then + raise EengInvalidToken.Create('expected ' + TOKEN_END, oldLine, oldCol, aShaderPart.Filename); + if (param[0].Name <> TOKEN_END) then + raise EengInvalidToken.Create(aShaderPart.ClassName, param[0].Name, oldLine, oldCol, aShaderPart.Filename); + if (param.Count <> 1) then + raise EengInvalidParamterCount.Create(TOKEN_END, oldLine, oldCol, aShaderPart.Filename); + result := ''; + finally + FreeAndNil(param); + end; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function CheckType(const aShaderPart: TengShaderPart; const aTypes: array of CengShaderPart): Boolean; +var + t: CengShaderPart; +begin + result := true; + for t in aTypes do + if (aShaderPart is t) then + exit; + result := (Length(aTypes) = 0); +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function CheckParentScope(const aShaderPart: TengShaderPart): TengShaderPartScope; +begin + aShaderPart.GetParentType(TengShaderPartScope, result); + if not Assigned(result) then + raise EengInternal.Create('this part has no container parent'); +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//TengExpressionItem//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengExpressionItem.GetText: String; +begin + result := ''; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengExpressionItem.GetValue(const aScope: TengShaderPartScope; const aGenCodeArgs: TengGenCodeArgs): Variant; +begin + result := Unassigned; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +constructor TengExpressionItem.Create(const aLine, aCol: Integer; const aFilename: String); +begin + inherited Create; + fLine := aLine; + fCol := aCol; + fFilename := aFilename; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//TengExpressionItemSingle////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengExpressionValue.GetText: String; +begin + result := '''' + fValue + ''''; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengExpressionValue.GetValue(const aScope: TengShaderPartScope; const aGenCodeArgs: TengGenCodeArgs): Variant; +begin + result := fValue; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +constructor TengExpressionValue.Create(const aValue: Variant; const aLine, aCol: Integer; const aFilename: String); +begin + inherited Create(aLine, aCol, aFilename); + fValue := aValue; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//TengExpressionVariable//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengExpressionVariable.GetText: String; +begin + result := fVariableName; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengExpressionVariable.GetValue(const aScope: TengShaderPartScope; const aGenCodeArgs: TengGenCodeArgs): Variant; +var + p: TengShaderPart; +begin + aScope.FindMappedPart(p, fVariableName, FIND_IN_SCOPE_FLAGS); + if not Assigned(p) then begin + aScope.FindMappedPart(p, fVariableName, FIND_GLOBAL); + if not Assigned(p) then + raise EengUnknownIdentifier.Create(fVariableName, fLine, fCol, fFilename) + end + else if not (p is TengShaderPartProperty) and not (p is TengShaderPartDefine) then + raise EengInvalidParamter.Create('unexpected type, expected ' + + TengShaderPartProperty.GetTokenName + ' or ' + + TengShaderPartDefine.GetTokenName, + fLine, fCol, fFilename) + else + result := (p as TengShaderPartKeyValuePair).Value; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +constructor TengExpressionVariable.Create(const aVariableName: String; const aLine, aCol: Integer; const aFilename: String); +begin + inherited Create(aLine, aCol, aFilename); + fVariableName := aVariableName; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//TengExpressionGroup/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengExpressionGroup.GetText: String; +begin + if Assigned(fChild) then + result := TOKEN_OP_GROUP_BEGIN + fChild.GetText + TOKEN_OP_GROUP_END + else + result := ''; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengExpressionGroup.GetValue(const aScope: TengShaderPartScope; const aGenCodeArgs: TengGenCodeArgs): Variant; +begin + result := fChild.GetValue(aScope, aGenCodeArgs); +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +constructor TengExpressionGroup.Create(const aChild: TengExpressionItem; const aLine, aCol: Integer; const aFilename: String); +begin + inherited Create(aLine, aCol, aFilename); + fChild := aChild; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +destructor TengExpressionGroup.Destroy; +begin + FreeAndNil(fChild); + inherited Destroy; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengExpressionUnaryOperation.GetText: String; +begin + if not Assigned(fChild) then + EengExpression.Create('no child assigned'); + result := + {$IFDEF EXPRESSION_ADD_BRACKET}TOKEN_OP_GROUP_BEGIN +{$ENDIF} + EXPRESSION_UNARY_OPERATIONS[fUnaryOp] + ' ' + fChild.GetText + {$IFDEF EXPRESSION_ADD_BRACKET} + TOKEN_OP_GROUP_END{$ENDIF}; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengExpressionUnaryOperation.GetValue(const aScope: TengShaderPartScope; const aGenCodeArgs: TengGenCodeArgs): Variant; +var + p: TengShaderPart; + v: Variant; +begin + try + case fUnaryOp of + + opBinaryNot: begin + v := fChild.GetValue(aScope, aGenCodeArgs); + result := not Integer(v); + end; + + opLogicalNot: begin + v := fChild.GetValue(aScope, aGenCodeArgs); + result := not Boolean(v); + end; + + opDefined: begin + v := (fChild as TengExpressionVariable).fVariableName; + if not (fChild is TengExpressionVariable) then + raise EengInternal.Create('child is not a variable', fLine, fCol, fFilename); + aScope.FindMappedPart(p, (fChild as TengExpressionVariable).fVariableName, FIND_IN_SCOPE_FLAGS); + result := Assigned(p); + if result and (not (p is TengShaderPartProperty) or not (p is TengShaderPartDefine)) then with fChild do + raise EengInvalidParamter.Create('unexpected type, expected ' + + TengShaderPartProperty.GetTokenName + ' or ' + + TengShaderPartDefine.GetTokenName, + fLine, fCol, fFilename); + end; + + opSet: begin + if Assigned(aGenCodeArgs) then begin + if not (fChild is TengExpressionVariable) then + raise EengInternal.Create('child is not a variable', fLine, fCol, fFilename); + result := aGenCodeArgs.HasCodeProperty((fChild as TengExpressionVariable).fVariableName); + end else + result := false; + end + + else + result := inherited GetValue(aScope, aGenCodeArgs); + end; + except + on ex: Exception do + raise EengInvalidParamter.Create(ex.Message + ' ("' + GetText + '" ==> "' + EXPRESSION_UNARY_OPERATIONS[fUnaryOp] + ' ' + v + '")', fLine, fCol, fFilename); + end; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +constructor TengExpressionUnaryOperation.Create(const aUnaryOp: TengExpressionUnaryOperator; const aLine, aCol: Integer; const aFilename: String); +begin + inherited Create(aLine, aCol, aFilename); + fUnaryOp := aUnaryOp; + fChild := nil; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +destructor TengExpressionUnaryOperation.Destroy; +begin + FreeAndNil(fChild); + inherited Destroy; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//TengExpressionBinaryOperation/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengExpressionBinaryOperation.GetText: String; +begin + if not Assigned(fFirst) or not Assigned(fSecond) then + raise EengExpression.Create('first or second item not assigned'); + result := + {$IFDEF EXPRESSION_ADD_BRACKET}TOKEN_OP_GROUP_BEGIN +{$ENDIF} + fFirst.GetText + ' ' + EXPRESSION_BINARY_OPERATIONS[fBinaryOp] + ' ' + fSecond.GetText + {$IFDEF EXPRESSION_ADD_BRACKET} + TOKEN_OP_GROUP_END{$ENDIF}; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengExpressionBinaryOperation.GetValue(const aScope: TengShaderPartScope; const aGenCodeArgs: TengGenCodeArgs): Variant; +var + v1, v2: Variant; +begin + v1 := fFirst.GetValue(aScope, aGenCodeArgs); + v2 := fSecond.GetValue(aScope, aGenCodeArgs); + try + case fBinaryOp of + opBinaryOr: result := (Integer(v1) or Integer(v2)); + opBinaryAnd: result := (Integer(v1) and Integer(v2)); + opBinaryXor: result := (Integer(v1) xor Integer(v2)); + + opMultiply: result := (v1 * v2); + opDivide: result := (v1 / v2); + opAdd: result := (v1 + v2); + opSubtract: result := (v1 - v2); + + opLogicalOr: result := (Boolean(v1) or Boolean(v2)); + opLogicalAnd: result := (Boolean(v1) and Boolean(v2)); + opLogicalXor: result := (Boolean(v1) xor Boolean(v2)); + + opEquals: result := (v1 = v2); + opLesser: result := (v1 < v2); + opGreater: result := (v1 > v2); + opLEquals: result := (v1 <= v2); + opGEquals: result := (v1 >= v2); + opUnequals: result := (v1 <> v2); + end; + except + on ex: Exception do + raise EengInvalidParamter.Create(ex.Message + ' ("' + GetText + '" ==> "' + v1 + ' ' + EXPRESSION_BINARY_OPERATIONS[fBinaryOp] + ' ' + v2 + '")', fLine, fCol, fFilename); + end; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +constructor TengExpressionBinaryOperation.Create(const aOperator: TengExpressionBinaryOperator; const aLine, aCol: Integer; const aFilename: String); +begin + inherited Create(aLine, aCol, aFilename); + fBinaryOp := aOperator; + fFirst := nil; + fSecond := nil; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +destructor TengExpressionBinaryOperation.Destroy; +begin + FreeAndNil(fFirst); + FreeAndNil(fSecond); + inherited Destroy; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//EengShaderPart//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +constructor EengShaderPart.Create(const aMsg: String; const aLine, aCol: Integer; const aFilename: String); +begin + inherited Create(aMsg + format(' (file: %s; line: %d; col: %d)', [ExtractFileName(aFilename), aLine+1, aCol])); + Line := aLine; + Col := aCol; + Filename := aFilename; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//EengInvalidParamter/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +constructor EengInvalidParamter.Create(const aMsg: String; const aLine, aCol: Integer; const aFilename: String); +begin + inherited Create('invalid parameter: ' + aMsg, aLine, aCol, aFilename); +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//EengInvalidIdentifier///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +constructor EengInvalidIdentifier.Create(const aIdentifier: String; const aLine, aCol: Integer; const aFilename: String); +begin + inherited Create('invalid identifier: ' + aIdentifier, aLine, aCol, aFilename); +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//EengEmptyToken//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +constructor EengEmptyToken.Create(const aLine, aCol: Integer; const aFilename: String); +begin + inherited Create('empty token', aLine, aCol, aFilename); +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//EengInvalidToken////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +constructor EengInvalidToken.Create(const aClassName: String; const aToken: String; const aLine, aCol: Integer; const aFilename: String); +begin + inherited Create('invalid token: ' + aClassName + ' <> '+ aToken, aLine, aCol, aFilename); +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//EengInvalidParamterCount////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +constructor EengInvalidParamterCount.Create(const aToken: String; const aLine, aCol: Integer; const aFilename: String); +begin + inherited Create('invalid parameter count in ' + aToken, aLine, aCol, aFilename); +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +constructor EengDuplicateIdentifier.Create(const aName: String; const aNew, aOld: TengShaderPart); +begin + inherited Create(format('duplicate identifier: %s (previously declared here: %s %d:%d)', + [aName, aOld.Filename, aOld.Line, aOld.Col]), aNew.Line, aNew.Col, aNew.Filename); +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//EengInternal////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +constructor EengInternal.Create(const aMsg: String); +begin + inherited Create(aMsg); +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +constructor EengInternal.Create(const aMsg: String; const aLine, aCol: Integer; const aFilename: String); +begin + inherited Create(aMsg, aLine, aCol, aFilename); +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//EengUnknownIdentifier///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +constructor EengUnknownIdentifier.Create(const aIdent: String; const aLine, aCol: Integer; const aFilename: String); +begin + inherited Create('unknown identifier: ' + aIdent, aLine, aCol, aFilename); +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//TengShaderPart.TengShaderPartEnumerator/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengShaderPart.TengShaderPartEnumerator.GetCurrent: TengShaderPart; +begin + result := fOwner[fPosition]; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengShaderPart.TengShaderPartEnumerator.MoveNext: Boolean; +begin + inc(fPosition); + result := (fPosition < fOwner.Count); +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +constructor TengShaderPart.TengShaderPartEnumerator.Create(const aOwner: TengShaderPart); +begin + inherited Create; + fOwner := aOwner; + fPosition := -1; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//TengShaderPart//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengShaderPart.GetCount: Integer; +begin + result := 0; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengShaderPart.{%H-}GetChild(const aIndex: Integer): TengShaderPart; +begin + raise EengShaderPart.Create('this part does not have any children'); +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengShaderPart.GetFilename: String; +begin + if Assigned(fParent) then + result := fParent.Filename + else + result := ''; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengShaderPart.GetShaderClass: String; +begin + if Assigned(fParent) then + result := fParent.ShaderClass + else + result := ''; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengShaderPart.GetText: String; +begin + result := ''; //DUMMY +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengShaderPart.ParseTextIntern(const aParseArgs: TengParseArgs; const aParameters: TengTokenParameterList): String; +begin + result := ''; //DUMMY +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengShaderPart.ParseText(const aParseArgs: TengParseArgs): String; +var + param: TengTokenParameterList; +begin + param := TengTokenParameterList.Create; + try + fCol := aParseArgs.Col; + fLine := aParseArgs.Line; + if (GetTokenName <> '') then + aParseArgs.ParseParameters(param); + result := ParseTextIntern(aParseArgs, param); + finally + FreeAndNil(param); + end; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +procedure TengShaderPart.MapData(const aFlags: TengMapDataFlags; const aTypes: array of CengShaderPart); +begin + //DUMMY +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +procedure TengShaderPart.GenCodeIntern(const aGenCodeArgs: TengGenCodeArgs); +begin + fFlags := fFlags + [spfCodeGenVisited]; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +procedure TengShaderPart.ClearGenCode; +begin + fFlags := fFlags - [spfCodeGenVisited]; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengShaderPart.HasParentType(const aParentType: CengShaderPart; const aIncludeSelf: Boolean): Boolean; +var + p: TengShaderPart; +begin + result := aIncludeSelf and (self is aParentType); + if not result then begin + GetParentType(aParentType, p); + result := Assigned(p); + end; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengShaderPart.ParentOrSelfHasType(const aParentType: CengShaderPart): Boolean; +begin + result := (self is aParentType) or ParentHasType(aParentType); +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +procedure TengShaderPart.GetParentByType(const aParentType: CengShaderPart; out aPart); +begin + if (fParent is aParentType) then + TengShaderPart(aPart) := fParent + else if Assigned(fParent) then + fParent.GetParentType(aParentType, aPart) + else + TengShaderPart(aPart) := nil; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengShaderPart.GetEnumerator: TengShaderPartEnumerator; +begin + result := TengShaderPartEnumerator.Create(self); +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +constructor TengShaderPart.Create(const aParent: TengShaderPart); +begin + inherited Create; + fParent := aParent; + if Assigned(fParent) then + fRoot := aParent.Root + else + fRoot := nil; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +class function TengShaderPart.GetTokenName: String; +begin + result := ''; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +class function TengShaderPart.CheckToken(const aToken: String): Boolean; +begin + result := (aToken = GetTokenName); +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +class procedure TengShaderPart.CheckToken(const aParseArgs: TengParseArgs; const aParent: TengShaderPart); +begin + //DUMMY +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//TengShaderPartContainer/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengShaderPartContainer.HandleToken(var aToken: String; const aParseArgs: TengParseArgs): String; +var + obj: TengShaderPart; + c: CengShaderPart; +begin + obj := nil; + for c in TOKEN_CLASSES do + if c.CheckToken(aToken) then begin + c.CheckToken(aParseArgs, self); + obj := c.Create(self); + fChildren.Add(obj); + break; + end; + + if Assigned(obj) then + result := obj.ParseText(aParseArgs) + else + result := aToken; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengShaderPartContainer.GetCount: Integer; +begin + result := fChildren.Count; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengShaderPartContainer.GetChild(const aIndex: Integer): TengShaderPart; +begin + result := fChildren[aIndex]; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengShaderPartContainer.GetText: String; +var + p: TengShaderPart; +begin + result := ''; + for p in self do + result := result + p.Text; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengShaderPartContainer.ParseTextIntern(const aParseArgs: TengParseArgs; const aParameters: TengTokenParameterList): String; +var + codeObj: TengShaderPartCode; +begin + fChildren.Clear; + while not aParseArgs.EndOfFile do begin + codeObj := TengShaderPartCode.Create(self); + try + result := codeObj.ParseText(aParseArgs); + if (codeObj.Code <> '') then + AddChild(codeObj) + else + FreeAndNil(codeObj); + except + FreeAndNil(codeObj); + raise; + end; + if (result <> '') then begin + result := HandleToken(result, aParseArgs); + if (result <> '') then + break; + end; + end; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +procedure TengShaderPartContainer.MapData(const aFlags: TengMapDataFlags; const aTypes: array of CengShaderPart); +var + p: TengShaderPart; +begin + inherited MapData(aFlags, aTypes); + for p in fChildren do + p.MapData(aFlags, aTypes); +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +procedure TengShaderPartContainer.GenCodeIntern(const aGenCodeArgs: TengGenCodeArgs); +var + p: TengShaderPart; +begin + inherited GenCodeIntern(aGenCodeArgs); + for p in fChildren do + if not (p is TengShaderPartClass) then + p.GenCodeIntern(aGenCodeArgs); +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +procedure TengShaderPartContainer.ClearGenCode; +var + p: TengShaderPart; +begin + inherited ClearGenCode; + for p in fChildren do + p.ClearGenCode; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +procedure TengShaderPartContainer.AddChild(const aChild: TengShaderPart; const aPrepend: Boolean); +begin + if aPrepend then + fChildren.PushFirst(aChild) + else + fChildren.PushLast(aChild); +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +constructor TengShaderPartContainer.Create(const aParent: TengShaderPart); +begin + inherited Create(aParent); + fChildren := TengShaderPartList.Create(true); +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +destructor TengShaderPartContainer.Destroy; +begin + FreeAndNil(fChildren); + inherited Destroy; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//TengShaderPartScope/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengShaderPartScope.CheckName(const aName: String; const aShaderPart: TengShaderPart): Boolean; +var + old: TengShaderPart; +begin + result := false; + + // check properties (global) + FindMappedPart(old, aName, [ffGlobal, ffLocal, ffDescending], TengShaderPartProperty); + if Assigned(old) then begin + if (old <> aShaderPart) then + raise EengDuplicateIdentifier.Create(aName, aShaderPart, old) + else + exit; + end; + + // check all others + FindMappedPart(old, aName, FIND_IN_SCOPE_FLAGS); + if Assigned(old) then begin + if (old <> aShaderPart) then + CheckDuplicate(aName, old, aShaderPart) + else + exit; + end; + + result := true; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +procedure TengShaderPartScope.MapChildScope(const aScope: TengShaderPartScope); +begin + if (CheckParentScope(aScope) <> self) then + raise EengInternal.Create('container is not a direct child of this container'); + if not fChildScopes.Contains(aScope) then + fChildScopes.Add(aScope); +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +procedure TengShaderPartScope.MapInheritedScope(const aScope: TengShaderPartScope); +begin + if not fInherited.Contains(aScope) then + fInherited.Add(aScope); +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengShaderPartScope.MapShaderPart(const aName: String; const aShaderPart: TengShaderPart): Boolean; +begin + if (CheckParentScope(aShaderPart) <> self) then + raise EengInternal.Create('shader part does not belong to this container'); + + result := CheckName(aName, aShaderPart); + if result then + fMappedParts.Add(aName, aShaderPart); +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +procedure TengShaderPartScope.FindMappedPart(out aShaderPart; const aName: String; const aFlags: TengFindMappedPartFlags; const aType: CengShaderPart); +var + list: TengShaderPartList; +begin + TengShaderPart(aShaderPart) := nil; + list := TengShaderPartList.Create(false); + try + FindMappedParts(list, aName, aFlags + [ffFindFirst], aType); + if (list.Count > 0) then + TengShaderPart(aShaderPart) := list[0]; + finally + FreeAndNil(list); + end; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +procedure TengShaderPartScope.FindMappedParts(const aParts: TengShaderPartList; const aName: String; const aFlags: TengFindMappedPartFlags; const aType: CengShaderPart); + + procedure AddPart(const aShaderPart: TengShaderPart); + begin + if Assigned(aShaderPart) and + (not Assigned(aType) or (aShaderPart is aType)) and + (aParts.IndexOf(aShaderPart) < 0) then + aParts.Add(aShaderPart); + end; + +var + s: TengShaderPartScope; + p: TengShaderPart; +begin + if (ffFindFirst in aFlags) and (aParts.Count > 0) then + exit; + + if not (ffGlobal in aFlags) then begin + + // local + if (ffLocal in aFlags) then begin + if (aName <> '') then + AddPart(fMappedParts[aName]) + else + for p in fMappedParts do + AddPart(p); + end; + + // descending + if (ffDescending in aFlags) then + for s in fChildScopes do + s.FindMappedParts(aParts, aName, aFlags + [ffLocal], aType); + + // ascending + if (ffAscending in aFlags) then begin + GetParentType(TengShaderPartScope, s); + if Assigned(s) and s.fChildScopes.Contains(self) then + s.FindMappedParts(aParts, aName, aFlags + [ffLocal], aType); + end; + + // search in inherited scopes + if (ffInherited in aFlags) then + for s in fInherited do + s.FindMappedParts(aParts, aName, aFlags + [ffLocal], aType); + + end else + fRoot.FindMappedParts(aParts, aName, aFlags - [ffGlobal], aType); +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengShaderPartScope.GetFindPropertyFlags: TengFindMappedPartFlags; +begin + result := FIND_PROPERTY_FLAGS; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +procedure TengShaderPartScope.CheckDuplicate(const aName: String; const aOld, aNew: TengShaderPart); +begin + raise EengDuplicateIdentifier.Create(aName, aNew, aOld); +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +procedure TengShaderPartScope.MapData(const aFlags: TengMapDataFlags; const aTypes: array of CengShaderPart); +var + s: TengShaderPartScope; + p: TengShaderPart; +begin + if (mdfCurrentScope in aFlags) and (mdfChild in aFlags) then + exit; + + GetParentType(TengShaderPartScope, s); + if Assigned(s) then + s.MapChildScope(self); + + for p in fChildren do + p.MapData(aFlags + [mdfChild], aTypes); + + if (mdfMapInherited in aFlags) then + for s in fInherited do + s.MapData(aFlags, aTypes); +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +procedure TengShaderPartScope.GenCodeIntern(const aGenCodeArgs: TengGenCodeArgs); +begin + MapData([mdfMapInherited, mdfCurrentScope, mdfIfEvaluate], []); + inherited GenCodeIntern(aGenCodeArgs); +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +procedure TengShaderPartScope.ClearGenCode; +var + p: TengShaderPartScope; +begin + inherited ClearGenCode; + for p in fInherited do + p.ClearGenCode; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +procedure TengShaderPartScope.ClearMappedData(const aExcludedTypes: array of CengShaderPart); +var + s: TengShaderPartScope; + i: Integer; +begin + for s in fChildScopes do + s.ClearMappedData(aExcludedTypes); + for s in fInherited do + s.ClearMappedData(aExcludedTypes); + for i := fMappedParts.Count-1 downto 0 do + if not CheckType(fMappedParts.ValueAt[i], aExcludedTypes) then + fMappedParts.DeleteAt(i); +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +procedure TengShaderPartScope.ClearMappedData; +var + s: TengShaderPartScope; +begin + for s in fChildScopes do + s.ClearMappedData; + fChildScopes.Clear; + + for s in fInherited do + s.ClearMappedData; + fInherited.Clear; + + fMappedParts.Clear; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +constructor TengShaderPartScope.Create(const aParent: TengShaderPart); +begin + inherited Create(aParent); + fInherited := TengShaderPartScopeHashSet.Create(false); + fChildScopes := TengShaderPartScopeHashSet.Create(false); + fMappedParts := TengShaderPartMap.Create(false); +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +destructor TengShaderPartScope.Destroy; +begin + FreeAndNil(fMappedParts); + FreeAndNil(fChildScopes); + FreeAndNil(fInherited); + inherited Destroy; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//TengCodeGenerator///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengCodeGenerator.GetProperty(const aName: String): TengShaderPartProperty; +begin + FindMappedPart(result, aName, GetFindPropertyFlags, TengShaderPartProperty); +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +procedure TengCodeGenerator.GenerateCode(const aGenCodeArgs: TengGenCodeArgs); +begin + //DUMMY +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengCodeGenerator.GenerateCode: TengShaderCode; +var + args: TengGenCodeArgs; +begin + result := TengShaderCodeIntern.Create; + args := TengGenCodeArgs.Create((result as TengShaderCodeIntern), self); + try + ClearGenCode; + ClearMappedData([TengShaderPartProperty]); + + GenCodeIntern(args); + + args.PushCode; + try + GenerateCode(args); + args.GenProcedureCode; + finally + args.PopCode; + end; + + args.GenCodePropertyCode([TengShaderPartVar]); + args.GenCodePropertyCode([TengShaderPartVarying]); + args.GenCodePropertyCode([TengShaderPartUniform]); + args.GenMetaCode; + finally + FreeAndNil(args); + end; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +procedure TengCodeGenerator.ListProperties(const aList: TStrings); +var + list: TengShaderPartList; + p: TengShaderPart; +begin + list := TengShaderPartList.Create(false); + try + FindMappedParts(list, '', GetFindPropertyFlags, TengShaderPartProperty); + for p in list do + aList.Add((p as TengShaderPartProperty).Name); + finally + FreeAndNil(list); + end; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//TengShaderPartClass/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengShaderPartClass.GetExtendCount: Integer; +begin + result := fExtends.Count; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengShaderPartClass.GetExtends(const aIndex: Integer): String; +begin + if (aIndex >= 0) and (aIndex < fExtends.Count) then + result := fExtends[aIndex] + else + raise EOutOfRange.Create(aIndex, 0, fExtends.Count-1); +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengShaderPartClass.GetText: String; +var + s: String; +begin + result := PRECOMPILER_STATEMENT_BEGIN + GetTokenName + ' ' + fName; + if (fExtends.Count > 0) then begin + result := result + ' ' + TOKEN_EXTENDS; + for s in fExtends do + result := result + ' ' + s; + end; + result := result + PRECOMPILER_STATEMENT_END + + inherited GetText + + PRECOMPILER_STATEMENT_BEGIN + TOKEN_END + PRECOMPILER_STATEMENT_END; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengShaderPartClass.GetShaderClass: String; +begin + result := fName; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengShaderPartClass.ParseTextIntern(const aParseArgs: TengParseArgs; const aParameters: TengTokenParameterList): String; +var + i: Integer; +begin + if (aParameters[0].Name <> GetTokenName) then + raise EengInvalidToken.Create(ClassName, aParameters[0].Name, Line, Col, Filename); + if (aParameters.Count < 2) then + raise EengInvalidParamterCount.Create(GetTokenName, Line, Col, Filename); + fName := aParameters[1].Name; + if not IsValidIdentifier(fName) then + raise EengShaderPart.Create('invalid name: ' + fName, Line, Col, GetFilename); + if (aParameters.Count > 2) then begin + if (aParameters.Count < 4) then + raise EengInvalidParamterCount.Create(GetTokenName, Line, Col, Filename); + if (aParameters[2].Name <> TOKEN_EXTENDS) then + raise EengInvalidParamter.Create(aParameters[2].Name + ' (expected ' + TOKEN_EXTENDS + ')', Line, Col, Filename); + fExtends.Clear; + for i := 3 to aParameters.Count-1 do + fExtends.Add(aParameters[i].Name); + end; + + fRoot.AddClass(self); + + inherited ParseTextIntern(aParseArgs, aParameters); + result := CheckEndToken(aParseArgs, self); +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +procedure TengShaderPartClass.CheckDuplicate(const aName: String; const aOld, aNew: TengShaderPart); + + function IsInherited(const aRoot: TengShaderPartScope; const aClass: TengShaderPartClass): Boolean; + var + p: TengShaderPartScope; + begin + result := true; + for p in fInherited do + if (p is TengShaderPartClass) and ((p = aClass) or IsInherited(p, aClass)) then + exit; + result := false; + end; + + function CompareParam(const p1, p2: TengShaderPartProcParam): Boolean; + begin + result := (p1.Name = p2.Name) and (p1.Typ = p2.Typ); + end; + +var + i: Integer; + o, n: TengShaderPartProc; + c: TengShaderPartClass; +begin + if (aOld is TengShaderPartProc) and (aNew is TengShaderPartProc) then begin + o := (aOld as TengShaderPartProc); + n := (aNew as TengShaderPartProc); + o.GetParentType(TengShaderPartClass, c); + if (o.fParameters.Count <> n.fParameters.Count) then + raise EengInvalidParamterCount.Create('method must have the same parameters as the overwritten one', n.Line, n.Col, n.Filename); + for i := 0 to o.fParameters.Count-1 do + if not CompareParam(n.fParameters[i], o.fParameters[i]) then + raise EengInvalidParamter.Create('parameters must have the same name and type as the overwritten one', n.Line, n.Col, n.Filename); + if (o.ClassName <> n.ClassName) then + raise EengInvalidToken.Create('method must be the same type as the overwritten one', n.Line, n.Col, n.Filename); + if (o is TengShaderPartFunc) and ((o as TengShaderPartFunc).ReturnType <> (n as TengShaderPartFunc).ReturnType) then + raise EengInvalidParamter.Create('return type must be the same as the overwritten one', n.Line, n.Col, n.Filename); + end else + inherited CheckDuplicate(aName, aOld, aNew); +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengShaderPartClass.GetFindPropertyFlags: TengFindMappedPartFlags; +begin + result := inherited GetFindPropertyFlags + [ffFile]; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +procedure TengShaderPartClass.GenCodeIntern(const aGenCodeArgs: TengGenCodeArgs); +var + p: TengShaderPartScope; +begin + for p in fInherited do + p.GenCodeIntern(aGenCodeArgs); + aGenCodeArgs.Code.AddToken(ttBegin); + try + inherited GenCodeIntern(aGenCodeArgs); + finally + aGenCodeArgs.Code.AddToken(ttEnd); + end; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +procedure TengShaderPartClass.GenerateCode(const aGenCodeArgs: TengGenCodeArgs); +var + main: TengShaderPartMain; +begin + FindMappedPart(main, '', FIND_IN_SCOPE_FLAGS, TengShaderPartMain); + if not Assigned(main) then + raise EengInternal.Create('no main routine found'); + + aGenCodeArgs.PushFlags([gcfGenProcedure]); + try + main.GenCodeIntern(aGenCodeArgs); + finally + aGenCodeArgs.PopFlags; + end; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +procedure TengShaderPartClass.FindMappedParts(const aParts: TengShaderPartList; const aName: String; const aFlags: TengFindMappedPartFlags; const aType: CengShaderPart); +var + f: TengShaderFile; +begin + if (ffIgnoreClasses in aFlags) or + ((ffFindFirst in aFlags) and (aParts.Count > 0)) then + exit; + + // search in file + if not (ffGlobal in aFlags) and (ffFile in aFlags) then begin + GetParentType(TengShaderFile, f); + if not Assigned(f) then + EengInternal.Create('unable to find file object'); + f.FindMappedParts(aParts, aName, aFlags + [ffIgnoreClasses], aType); + end; + + inherited FindMappedParts(aParts, aName, aFlags, aType); +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +procedure TengShaderPartClass.MapData(const aFlags: TengMapDataFlags; const aTypes: array of CengShaderPart); +var + s: String; + sc: TengShaderPartScope; +begin + if (mdfAddInherited in aFlags) then begin + for s in fExtends do begin + sc := fRoot.GetClass(s); + if not Assigned(sc) then + raise EengUnknownIdentifier.Create(s, Line, Col, Filename); + MapInheritedScope(sc); + end; + end; + inherited MapData(aFlags, aTypes); +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +constructor TengShaderPartClass.Create(const aParent: TengShaderPart); +begin + inherited Create(aParent); + fExtends := TStringList.Create; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +destructor TengShaderPartClass.Destroy; +begin + FreeAndNil(fExtends); + inherited Destroy; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +class function TengShaderPartClass.GetTokenName: String; +begin + result := TOKEN_CLASS; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +class procedure TengShaderPartClass.CheckToken(const aParseArgs: TengParseArgs; const aParent: TengShaderPart); + + procedure RaiseEx(const aToken: String); + begin + with aParseArgs do + raise EengShaderPart.Create('token ' + GetTokenName + ' is not allowed in ' + aToken, Line, Col, aParent.Filename); + end; + +begin + if (aParent is TengShaderPartClass) or aParent.ParentHasType(TengShaderPartClass) then + RaiseEx(TengShaderPartClass.GetTokenName); + if (aParent is TengShaderPartIf) or aParent.ParentHasType(TengShaderPartIf) then + RaiseEx(TengShaderPartIf.GetTokenName); + if (aParent is TengShaderPartElse) or aParent.ParentHasType(TengShaderPartElse) then + RaiseEx(TengShaderPartElse.GetTokenName); + if (aParent is TengShaderPartElIf) or aParent.ParentHasType(TengShaderPartElIf) then + RaiseEx(TengShaderPartElIf.GetTokenName); +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//TengShaderFile//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengShaderFile.GetFilename: String; +begin + result := fFilename; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +procedure TengShaderFile.LoadFromFile(const aFilename: String); +var + s: TStream; + {$IFDEF USE_VFS}sHandle: IStreamHandle;{$ENDIF} + + function GetStream(out aStream: TStream): Boolean; + begin + {$IFDEF USE_VFS} + result := vfsManager.ReadFile(aFilename, sHandle); + if result then + aStream := sHandle.GetStream + else + aStream := nil;; + {$ELSE} + result := true; + aStream := TFileStream.Create(aFilename, fmOpenRead); + {$ENDIF} + end; + + procedure FreeStream(var aStream: TStream); + begin + {$IFDEF USE_VFS} + aStream := nil; + sHandle := nil; + {$ELSE} + FreeAndNil(aStream); + {$ENDIF} + end; + +begin + if not {$IFDEF USE_VFS}vfsManager.{$ENDIF}FileExists(aFilename) then + if Assigned(fParent) then with fParent do + raise EengShaderPart.Create('file does not exist: ' + aFilename, Line, Col, Filename) + else + raise EengShaderPart.Create('file does not exist: ' + aFilename); + + if GetStream(s) then begin + try + LoadFromStream(s, aFilename); + finally + FreeStream(s); + end; + end; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +procedure TengShaderFile.SaveToFile(const aFilename: String); +var + s: TStream; + {$IFDEF USE_VFS}sHandle: IStreamHandle;{$ENDIF} + + function GetStream(out aStream: TStream): Boolean; + begin + {$IFDEF USE_VFS} + result := vfsManager.CreateFile(aFilename, sHandle); + if result then + aStream := sHandle.GetStream + else + aStream := nil;; + {$ELSE} + result := true; + aStream := TFileStream.Create(aFilename, fmCreate); + {$ENDIF} + end; + + procedure FreeStream(var aStream: TStream); + begin + {$IFDEF USE_VFS} + aStream := nil; + sHandle := nil; + {$ELSE} + FreeAndNil(aStream); + {$ENDIF} + end; + +begin + fFilename := aFilename; + if GetStream(s) then begin + try + SaveToStream(s); + finally + FreeStream(s); + end; + end; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +procedure TengShaderFile.LoadFromStream(const aStream: TStream; const aFilename: String); +var + token: String; + args: TengParseArgs; +begin + fFilename := aFilename; + Clear; + args := TengParseArgs.Create(self); + try + args.LoadCode(aStream); + token := ParseText(args); + if (token <> '') then + raise EengShaderPart.Create('unknown token ''' + token + '''', args.Line, args.Col, Filename); + finally + FreeAndNil(args); + end; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +procedure TengShaderFile.SaveToStream(const aStream: TStream); +var + sl: TStringList; +begin + sl := TStringList.Create; + try + sl.Text := Text; + sl.SaveToStream(aStream); + finally + FreeAndNil(sl); + end; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengShaderFile.GetGenerator(const aName: String): TengCodeGenerator; +begin + ClearMappedData; + MapData([], [TengShaderPartDefine]); + MapData([mdfIfAll, mdfAddInherited], [TengShaderPartProperty]); + if (aName <> '') then + result := fClasses[aName] + else + result := self; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengShaderFile.GetFindPropertyFlags: TengFindMappedPartFlags; +begin + result := inherited GetFindPropertyFlags + [ffIgnoreClasses]; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +procedure TengShaderFile.MapData(const aFlags: TengMapDataFlags; const aTypes: array of CengShaderPart); +var + s: TengShaderPartScope; + p: TengShaderPart; +begin + // do not call inherited or included files will map themself as child to this file-scope, + // but files are all inherited to each other + if (mdfCurrentScope in aFlags) and (mdfChild in aFlags) then + exit; + + if (mdfAddInherited in aFlags) then begin + GetParentType(TengShaderPartScope, s); + if Assigned(s) then begin + if(s is TengShaderFile) then + s.MapInheritedScope(self) + else + s.MapChildScope(self); + end; + end; + + for p in fChildren do + p.MapData(aFlags + [mdfChild], aTypes); + + if (mdfMapInherited in aFlags) then + for s in fInherited do + s.MapData(aFlags, aTypes); +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengShaderFile.GetClass(const aName: String): TengShaderPartClass; +begin + result := fClasses[aName]; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +procedure TengShaderFile.AddClass(const aClass: TengShaderPartClass); +var + c: TengShaderPartClass; +begin + c := fClasses[aClass.Name]; + if not Assigned(c) then + fClasses.Add(aClass.Name, aClass) + else if (c <> aClass) then + raise EengInternal.Create('name is already registred for other class data object: ' + aClass.Name); +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +procedure TengShaderFile.GenerateCode(const aGenCodeArgs: TengGenCodeArgs); +var + main: TengShaderPartMain; +begin + FindMappedPart(main, '', FIND_IN_SCOPE_FLAGS, TengShaderPartMain); + if Assigned(main) then begin + aGenCodeArgs.PushFlags([gcfGenProcedure]); + try + main.GenCodeIntern(aGenCodeArgs); + finally + aGenCodeArgs.PopFlags; + end; + end; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +procedure TengShaderFile.ListGenerators(const aList: TStrings); +var + s: String; +begin + ClearMappedData; + MapData([], [TengShaderPartDefine]); + MapData([mdfIfAll, mdfAddInherited], [TengShaderPartProperty]); + for s in fClasses.Keys do + aList.Add(s); +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +procedure TengShaderFile.Clear; +begin + ClearMappedData; + ClearGenCode; + fClasses.Clear; + fChildren.Clear; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +constructor TengShaderFile.Create(const aParent: TengShaderPart); +begin + inherited Create(aParent); + fClasses := TengShaderPartClassMap.Create(false); + if not Assigned(fRoot) then + fRoot := self; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +constructor TengShaderFile.Create; +begin + Create(nil); +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +destructor TengShaderFile.Destroy; +begin + FreeAndNil(fClasses); + inherited Destroy; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//TengShaderPartInclude///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengShaderPartInclude.GetCount: Integer; +begin + if Assigned(fShaderFile) then + result := 1 + else + result := 0; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengShaderPartInclude.GetChild(const aIndex: Integer): TengShaderPart; +begin + if Assigned(fShaderFile) then + result := fShaderFile + else + raise EOutOfRange.Create(aIndex, 0, -1); +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengShaderPartInclude.GetText: String; +begin + result := PRECOMPILER_STATEMENT_BEGIN + GetTokenName + ' ''' + fIncludeFile + '''' + PRECOMPILER_STATEMENT_END; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengShaderPartInclude.ParseTextIntern(const aParseArgs: TengParseArgs; const aParameters: TengTokenParameterList): String; +begin + if (aParameters[0].Name <> GetTokenName) then + raise EengInvalidToken.Create(ClassName, aParameters[0].Name, Line, Col, Filename); + if (aParameters.Count <> 2) then + raise EengInvalidParamterCount.Create(GetTokenName, Line, Col, Filename); + fIncludeFile := aParameters[1].Name; + fAbsoluteFile := CreateAbsolutePath(fIncludeFile, ExtractFilePath(Filename)); + result := ''; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +procedure TengShaderPartInclude.CheckShaderFile; +begin + if not Assigned(fShaderFile) then + fShaderFile := TengShaderFile.Create(self); + if (fShaderFile.Filename <> fAbsoluteFile) then + fShaderFile.LoadFromFile(fAbsoluteFile); +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +procedure TengShaderPartInclude.MapData(const aFlags: TengMapDataFlags; const aTypes: array of CengShaderPart); +begin + inherited MapData(aFlags, aTypes); + CheckShaderFile; + fShaderFile.MapData(aFlags, aTypes); +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +procedure TengShaderPartInclude.GenCodeIntern(const aGenCodeArgs: TengGenCodeArgs); +begin + inherited GenCodeIntern(aGenCodeArgs); + CheckShaderFile; + aGenCodeArgs.Code.AddToken(ttBegin); + try + aGenCodeArgs.Code.AddToken(ttSingle); + aGenCodeArgs.Code.AddLineEnd; + fShaderFile.GenCodeIntern(aGenCodeArgs); + finally + aGenCodeArgs.Code.AddToken(ttEnd); + end; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +constructor TengShaderPartInclude.Create(const aParent: TengShaderPart); +begin + inherited Create(aParent); + fShaderFile := nil; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +destructor TengShaderPartInclude.Destroy; +begin + FreeAndNil(fShaderFile); + inherited Destroy; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +class function TengShaderPartInclude.GetTokenName: String; +begin + result := TOKEN_INCLUDE; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//TengShaderPartComment///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengShaderPartComment.GetText: String; +begin + result := PRECOMPILER_STATEMENT_BEGIN + GetTokenName + fText + PRECOMPILER_STATEMENT_END; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengShaderPartComment.ParseTextIntern(const aParseArgs: TengParseArgs; const aParameters: TengTokenParameterList): String; +begin + if (aParameters[0].Name <> GetTokenName) then + raise EengInvalidToken.Create(ClassName, aParameters[0].Name, Line, Col, Filename); + if (aParameters.Count <> 2) then + raise EengInvalidParamterCount.Create(GetTokenName, Line, Col, Filename); + fText := aParameters[1].Name; + result := ''; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +class function TengShaderPartComment.GetTokenName: String; +begin + result := COMMENT_IDENTIFIER; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//TengShaderPartInherited/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengShaderPartInherited.GetText: String; +begin + result := PRECOMPILER_STATEMENT_BEGIN + GetTokenName; + if (fInheritedName <> '') then + result := ' ' + fInheritedName; + result := result + PRECOMPILER_STATEMENT_END; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengShaderPartInherited.ParseTextIntern(const aParseArgs: TengParseArgs; const aParameters: TengTokenParameterList): String; +var + i: Integer; +begin + if (aParameters[0].Name <> GetTokenName) then + raise EengInvalidToken.Create(ClassName, aParameters[0].Name, Line, Col, Filename); + if (aParameters.Count < 1) then + raise EengInvalidParamterCount.Create(GetTokenName, Line, Col, Filename); + + fParameters.Clear; + if (aParameters.Count >= 2) then begin + if not IsValidIdentifier(aParameters[1].Name) and (aParameters[1].Name <> TOKEN_MAIN) then + raise EengInvalidIdentifier.Create(aParameters[1].Name, Line, Col, Filename); + fInheritedName := aParameters[1].Name; + for i := 2 to aParameters.Count-1 do + fParameters.Add(aParameters[i].Name); + end else + fInheritedName := ''; + result := ''; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +procedure TengShaderPartInherited.GenCodeIntern(const aGenCodeArgs: TengGenCodeArgs); + + function FindProc(const aParentProc: TengShaderPartProc): TengShaderPartProc; + var + c: TengShaderPartClass; + p: TengShaderPart; + s: TengShaderPartScope; + procs: TengShaderPartList; + begin + procs := TengShaderPartList.Create(false); + try + s := CheckParentScope(aParentProc); + if not (s is TengShaderPartClass) then + raise EengInternal.Create('parent scope of method with inherited token must be a class', Line, Col, Filename); + s.FindMappedParts(procs, aParentProc.Name, FIND_INHERITED_FLAGS, TengShaderPartProc); + if (fInheritedName <> '') then begin + for p in procs do begin + result := (p as TengShaderPartProc); + result.GetParentType(TengShaderPartClass, c); + if not Assigned(c) then + raise EengInternal.Create('inherited method without class', Line, Col, Filename); + if (c.Name = fInheritedName) then + exit; + end; + raise EengInvalidIdentifier.Create('could not find inherited method: ' + aParentProc.Name, Line, Col, Filename) + end else if (procs.Count > 1) then + raise EengInvalidParamterCount.Create(GetTokenName + ' is ambiguous: specify inherited class') + else if (procs.Count <= 0) then + raise EengInvalidIdentifier.Create('could not find inherited method: ' + aParentProc.Name, Line, Col, Filename) + else + result := (procs[0] as TengShaderPartProc); + finally + FreeAndNil(procs); + end; + end; + + procedure GenCode(const aProc: TengShaderPartProc; const aParams: TStrings); + begin + aGenCodeArgs.PushFlags(aGenCodeArgs.Flags + [gcfGenProcInline]); + aGenCodeArgs.PushProcParams(aParams); + try + aProc.GenCodeIntern(aGenCodeArgs); + finally + aGenCodeArgs.PopProcParams; + aGenCodeArgs.PopFlags; + end; + end; + +var + proc: TengShaderPartProc; + params: TStringList; + p: TengShaderPartProcParam; +begin + inherited GenCodeIntern(aGenCodeArgs); + + GetParentType(TengShaderPartProc, proc); + if not Assigned(proc) then + raise EengInternal.Create('inherited without parent procedure', Line, Col, Filename); + + proc := FindProc(proc); + if (fParameters.Count > 0) then begin + if (fParameters.Count <> proc.fParameters.Count) then + raise EengInvalidParamterCount.Create(proc.Name + ' expects ' + IntToStr(proc.fParameters.Count) + ' parameter', Line, Col, Filename); + GenCode(proc, fParameters); + end else begin + params := TStringList.Create; + try + for p in proc.fParameters do + params.Add(p.Name); + GenCode(proc, params); + finally + FreeAndNil(params); + end; + end; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +constructor TengShaderPartInherited.Create(const aParent: TengShaderPart); +begin + inherited Create(aParent); + fParameters := TStringList.Create; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +destructor TengShaderPartInherited.Destroy; +begin + FreeAndNil(fParameters); + inherited Destroy; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +class function TengShaderPartInherited.GetTokenName: String; +begin + result := TOKEN_INHERITED; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +class procedure TengShaderPartInherited.CheckToken(const aParseArgs: TengParseArgs; const aParent: TengShaderPart); +begin + inherited CheckToken(aParseArgs, aParent); + if not ((aParent is TengShaderPartProc) or aParent.ParentHasType(TengShaderPartProc)) or + not (aParent.ParentHasType(TengShaderPartClass)) then + with aParseArgs do + raise EengShaderPart.Create(GetTokenName + ' is not allowed outside of a function or procedure', Line, Col, aParent.GetFilename); +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//TengMetaData////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengMetaData.GetCount: Integer; +begin + result := fValues.Count; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengMetaData.GetMetaType: TengMetaType; +begin + result := fMetaType; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengMetaData.GetName: String; +begin + result := fName; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengMetaData.GetValues(const aIndex: Integer): String; +begin + result := fValues[aIndex]; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +procedure TengMetaData.AddValue(const aValue: String); +begin + fValues.Add(aValue); +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +constructor TengMetaData.Create(const aName: String; const aType: TengMetaType); +begin + inherited Create; + fName := aName; + fMetaType := aType; + fValues := TStringList.Create; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +destructor TengMetaData.Destroy; +begin + FreeAndNil(fValues); + inherited Destroy; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//TengShaderPartMeta//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengShaderPartMeta.GetText: String; +var + i: Integer; +begin + result := PRECOMPILER_STATEMENT_BEGIN + GetTokenName + ' ' + fMetaData.Name; + for i := 0 to fMetaData.Count-1 do + result := result + ' ' + fMetaData[i]; + result := result + PRECOMPILER_STATEMENT_END; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengShaderPartMeta.ParseTextIntern(const aParseArgs: TengParseArgs; const aParameters: TengTokenParameterList): String; +var + i: Integer; + t: TengMetaType; + d: TengMetaData; + n: String; +begin + if (aParameters[0].Name <> GetTokenName) then + raise EengInvalidToken.Create(ClassName, aParameters[0].Name, Line, Col, Filename); + if (aParameters.Count < 2) then + raise EengInvalidParamterCount.Create(GetTokenName, Line, Col, Filename); + + result := ''; + n := aParameters[1].Name; + + {.$VERSION} + if (n = TOKEN_VERSION) then begin + t := metaVersion; + if (aParameters.Count >= 3) and (aParameters.Count <= 4) then + + if (aParameters.Count = 3) then begin + if (aParameters[2].Name <> VERSION_EXTRA_COMPAT) and not TryStrToInt(aParameters[2].Name, i) then + raise EengInvalidParamter.Create('version must be an number or "' + VERSION_EXTRA_COMPAT + '"', Line, Col, Filename); + end else if (aParameters.Count = 4) then begin + if (aParameters[2].Name <> VERSION_EXTRA_COMPAT) and not TryStrToInt(aParameters[2].Name, i) then + raise EengInvalidParamter.Create('version must be an number or "' + VERSION_EXTRA_COMPAT + '"', Line, Col, Filename); + if (aParameters[3].Name <> VERSION_EXTRA_COMPAT) then + raise EengInvalidParamter.Create('only "' + VERSION_EXTRA_COMPAT + '" is alowed as second parameter', Line, Col, Filename); + end else + raise EengInvalidParamterCount.Create(GetTokenName, Line, Col, Filename); + + {.$EXTENSION} + end else if (n = TOKEN_EXTENSION) then begin + t := metaExtension; + if (aParameters.Count <> 4) then + raise EengInvalidParamterCount.Create(GetTokenName, Line, Col, Filename); + + {.$LAYOUT} + end else if (n = TOKEN_LAYOUT) then begin + t := metaLayout; + if (aParameters.Count <> 3) then + raise EengInvalidParamterCount.Create(GetTokenName, Line, Col, Filename); + + {.VALUES} + end else + t := metaNormal; + + d := TengMetaData.Create(n, t); + for i := 2 to aParameters.Count-1 do + d.AddValue(aParameters[i].Name); + fMetaData := d; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +procedure TengShaderPartMeta.GenCodeIntern(const aGenCodeArgs: TengGenCodeArgs); +begin + inherited GenCodeIntern(aGenCodeArgs); + aGenCodeArgs.AddMeta(fMetaData); +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +destructor TengShaderPartMeta.Destroy; +begin + fMetaData := nil; + inherited Destroy; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +class function TengShaderPartMeta.GetTokenName: String; +begin + result := TOKEN_META; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//TengShaderPartKeyValuePair//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengShaderPartKeyValuePair.GetText: String; +begin + result := PRECOMPILER_STATEMENT_BEGIN + GetTokenName + ' ' + fName; + if (fValueName <> '') then + result := result + ' ' + fValueName + else if (fValue <> Unassigned) then + result := result + ' ''' + String(fValue) + ''''; + result := result + PRECOMPILER_STATEMENT_END; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengShaderPartKeyValuePair.ParseTextIntern(const aParseArgs: TengParseArgs; const aParameters: TengTokenParameterList): String; +begin + if (aParameters[0].Name <> GetTokenName) then + raise EengInvalidToken.Create(ClassName, GetTokenName, Line, Col, Filename); + if (aParameters.Count < 2) or (aParameters.Count > 3) then + raise EengInvalidParamterCount.Create(GetTokenName, Line, Col, Filename); + + result := ''; + fName := aParameters[1].Name; + if not IsValidIdentifier(fName) then + raise EengInvalidIdentifier.Create(fName, Line, Col, Filename); + if (aParameters.Count >= 3) then + if aParameters[2].Quoted then begin + fValue := aParameters[2].Name; + fValueName := ''; + end else begin + fValue := Unassigned; + fValueName := aParameters[2].Name; + end + else begin + fValue := Unassigned; + fValueName := ''; + end; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +constructor TengShaderPartKeyValuePair.CreateValue(const aParent: TengShaderPart; const aName: String; const aValue: Variant); +begin + inherited Create(aParent); + fName := aName; + fValue := aValue; + fValueName := ''; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +constructor TengShaderPartKeyValuePair.CreateName(const aParent: TengShaderPart; const aName, aValueName: String); +begin + inherited Create(aParent); + fName := aName; + fValue := Unassigned; + fValueName := aValueName; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +procedure TengShaderPartKeyValuePair.GenCodeIntern(const aGenCodeArgs: TengGenCodeArgs); +begin + inherited GenCodeIntern(aGenCodeArgs); + aGenCodeArgs.Code.AddToken(ttSingle); +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//TengShaderPartProperty////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +procedure TengShaderPartProperty.MapData(const aFlags: TengMapDataFlags; const aTypes: array of CengShaderPart); +var + p: TengShaderPart; + s: TengShaderPartScope; +begin + inherited MapData(aFlags, aTypes); + if CheckType(self, aTypes) then begin + s := CheckParentScope(self); + if s.MapShaderPart(Name, self) and (fValueName <> '') then begin + s.FindMappedPart(p, fValueName, FIND_IN_SCOPE_FLAGS); + if not Assigned(p) then + raise EengUnknownIdentifier.Create(fValueName, Line, Col, Filename) + else if not (p is TengShaderPartDefine) then + raise EengInvalidParamter.Create('invalid type, expected ' + TengShaderPartDefine.GetTokenName, Line, Col, Filename) + else + fValue := (p as TengShaderPartDefine).Value; + end; + end; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +class function TengShaderPartProperty.GetTokenName: String; +begin + result := TOKEN_PROPERTY; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//TengShaderPartDefine////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengShaderPartDefine.ParseTextIntern(const aParseArgs: TengParseArgs; const aParameters: TengTokenParameterList): String; +begin + if (aParameters.Count <> 3) then + raise EengInvalidParamterCount.Create(GetTokenName, Line, Col, GetFilename); + result := inherited ParseTextIntern(aParseArgs, aParameters); + if (fValueName <> '') then + fValue := fValueName; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +procedure TengShaderPartDefine.MapData(const aFlags: TengMapDataFlags; const aTypes: array of CengShaderPart); +begin + if CheckType(self, aTypes) then + CheckParentScope(self).MapShaderPart(Name, self); +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +class function TengShaderPartDefine.GetTokenName: String; +begin + result := TOKEN_DEFINE; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//TengShaderPartCodeProperty//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengShaderPartCodeProperty.GetText: String; +begin + result := PRECOMPILER_STATEMENT_BEGIN + GetTokenName + ' ''' + fType + ''' ''' + fName + '''' + PRECOMPILER_STATEMENT_END; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengShaderPartCodeProperty.ParseTextIntern(const aParseArgs: TengParseArgs; const aParameters: TengTokenParameterList): String; +begin + if (aParameters[0].Name <> GetTokenName) then + raise EengInvalidToken.Create(ClassName, aParameters[0].Name, Line, Col, Filename); + if (aParameters.Count <> 3) then + raise EengInvalidParamterCount.Create(GetTokenName, Line, Col, Filename); + + result := ''; + fType := aParameters[1].Name; + fName := aParameters[2].Name; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengShaderPartCodeProperty.IsEquals(const aCodeProp: TengShaderPartCodeProperty): Boolean; +begin + result := + (ClassName = aCodeProp.ClassName) and + (fName = aCodeProp.fName) and + (fType = aCodeProp.fType); +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +procedure TengShaderPartCodeProperty.MapData(const aFlags: TengMapDataFlags; const aTypes: array of CengShaderPart); +begin + if CheckType(self, aTypes) then + CheckParentScope(self).MapShaderPart(fName, self); +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +procedure TengShaderPartCodeProperty.GenCodeIntern(const aGenCodeArgs: TengGenCodeArgs); +begin + inherited GenCodeIntern(aGenCodeArgs); + if not (gcfGenCodeProp in aGenCodeArgs.Flags) then begin + aGenCodeArgs.AddCodeProperty(self); + aGenCodeArgs.Code.AddToken(ttSingle); + end; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//TengShaderPartVar///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengShaderPartVar.GetText: String; +begin + result := PRECOMPILER_STATEMENT_BEGIN + GetTokenName + ' ''' + fType + ''' ''' + fName + ''''; + if (fDefault <> Unassigned) then + result := result + ' ''' + fDefault + ''''; + result := result + PRECOMPILER_STATEMENT_END; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengShaderPartVar.ParseTextIntern(const aParseArgs: TengParseArgs; const aParameters: TengTokenParameterList): String; +begin + if (aParameters[0].Name <> GetTokenName) then + raise EengInvalidToken.Create(ClassName, aParameters[0].Name, Line, Col, Filename); + if (aParameters.Count < 3) or (aParameters.Count > 4) then + raise EengInvalidParamterCount.Create(GetTokenName, Line, Col, Filename); + + result := ''; + fType := aParameters[1].Name; + fName := aParameters[2].Name; + if (aParameters.Count >= 4) then + fDefault := aParameters[3].Name + else + fDefault := Unassigned; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengShaderPartVar.IsEquals(const aCodeProp: TengShaderPartCodeProperty): Boolean; +begin + result := inherited IsEquals(aCodeProp); + if result and ((aCodeProp as TengShaderPartVar).fDefault <> '') and (fDefault <> '') then + result := ((aCodeProp as TengShaderPartVar).fDefault = fDefault); +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +procedure TengShaderPartVar.GenCodeIntern(const aGenCodeArgs: TengGenCodeArgs); +begin + inherited GenCodeIntern(aGenCodeArgs); + if (gcfGenCodeProp in aGenCodeArgs.Flags) then begin + aGenCodeArgs.Code.AddText(Format('%'+IntToStr(aGenCodeArgs.MaxPropNameLen)+'s %s', [fType, fName])); + if (fDefault <> '') then + aGenCodeArgs.Code.AddText(' = ' + fDefault); + aGenCodeArgs.Code.AddText(';'); + end; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +class function TengShaderPartVar.GetTokenName: String; +begin + result := TOKEN_VAR; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//TengShaderPartVarying///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +procedure TengShaderPartVarying.GenCodeIntern(const aGenCodeArgs: TengGenCodeArgs); +begin + inherited GenCodeIntern(aGenCodeArgs); + if (gcfGenCodeProp in aGenCodeArgs.Flags) then + aGenCodeArgs.Code.AddText(Format('varying %'+IntToStr(aGenCodeArgs.MaxPropNameLen)+'s %s;', [fType, fName])); +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +class function TengShaderPartVarying.GetTokenName: String; +begin + result := TOKEN_VARYING; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//TengShaderPartUniform///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +procedure TengShaderPartUniform.GenCodeIntern(const aGenCodeArgs: TengGenCodeArgs); +begin + inherited GenCodeIntern(aGenCodeArgs); + if (gcfGenCodeProp in aGenCodeArgs.Flags) then + aGenCodeArgs.Code.AddText(Format('uniform %'+IntToStr(aGenCodeArgs.MaxPropNameLen)+'s %s;', [fType, fName])); +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +class function TengShaderPartUniform.GetTokenName: String; +begin + result := TOKEN_UNIFORM; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//TengShaderPartCall//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengShaderPartCall.GetText: String; +var + i: Integer; +begin + result := PRECOMPILER_STATEMENT_BEGIN + GetTokenName + ' ' + fName; + for i := 0 to fParameters.Count-1 do + if (PtrInt(fParameters.Objects[i]) <> 0) then + result := result + ' ''' + fParameters[i] + '''' + else + result := result + ' ' + fParameters[i]; + result := result + PRECOMPILER_STATEMENT_END; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengShaderPartCall.ParseTextIntern(const aParseArgs: TengParseArgs; const aParameters: TengTokenParameterList): String; +var + i: Integer; +begin + if (aParameters[0].Name <> GetTokenName) then + raise EengInvalidToken.Create(ClassName, aParameters[0].Name, Line, Col, Filename); + if (aParameters.Count < 2) then + raise EengInvalidParamterCount.Create(GetTokenName, Line, Col, Filename); + + fParameters.Clear; + result := ''; + fName := aParameters[1].Name; + if not IsValidIdentifier(fName) then + raise EengShaderPart.Create('invalid name: ' + fName, Line, Col, GetFilename); + for i := 2 to aParameters.Count-1 do + fParameters.AddObject(aParameters[i].Name, TObject(PtrInt(aParameters[i].Quoted))); +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +procedure TengShaderPartCall.GenCodeIntern(const aGenCodeArgs: TengGenCodeArgs); +var + p: TengShaderPartProc; +begin + aGenCodeArgs.Root.FindMappedPart(p, fName, FIND_OVERWRITTEN_FLAGS, TengShaderPartProc); + if not Assigned(p) then + CheckParentScope(self).FindMappedPart(p, fName, GEN_CODE_FIND_FLAGS, TengShaderPartProc); + + if not Assigned(p) then + raise EengUnknownIdentifier.Create(fName, Line, Col, Filename); + if not (p is TengShaderPartProc) then + raise EengInvalidParamter.Create('Expected ' + TengShaderPartFunc.GetTokenName + ' or ' + TengShaderPartProc.GetTokenName, Line, Col, Filename); + if ((p as TengShaderPartProc).fParameters.Count <> fParameters.Count) then + raise EengInvalidParamterCount.Create(fName + ' expects ' + IntToStr((p as TengShaderPartProc).fParameters.Count) + ' parameter', Line, Col, Filename); + + aGenCodeArgs.PushProcParams(fParameters); + aGenCodeArgs.PushFlags(aGenCodeArgs.Flags - [gcfGenProcedure, gcfGenProcInline] + [gcfGenProcCall]); + try + p.GenCodeIntern(aGenCodeArgs); + finally + aGenCodeArgs.PopProcParams; + aGenCodeArgs.PopFlags; + end; + inherited GenCodeIntern(aGenCodeArgs); +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +constructor TengShaderPartCall.Create(const aParent: TengShaderPart); +begin + inherited Create(aParent); + fParameters := TStringList.Create; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +destructor TengShaderPartCall.Destroy; +begin + FreeAndNil(fParameters); + inherited Destroy; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +class function TengShaderPartCall.GetTokenName: String; +begin + result := TOKEN_CALL; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//TengShaderPartProc//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengShaderPartProc.GetHeaderText: String; +var + p: TengShaderPartProcParam; +begin + result := PRECOMPILER_STATEMENT_BEGIN + GetTokenName + ' ''' + fName + ''''; + for p in fParameters do + result := result + ' ''' + p.Typ + ''' ''' + p.Name + ''''; + result := result + PRECOMPILER_STATEMENT_END; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengShaderPartProc.GetText: String; +begin + result := GetHeaderText + + inherited GetText + + PRECOMPILER_STATEMENT_BEGIN + TOKEN_END + PRECOMPILER_STATEMENT_END; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengShaderPartProc.ParseTextIntern(const aParseArgs: TengParseArgs; const aParameters: TengTokenParameterList): String; +type + TParseArgsState = (pasType, pasName); +var + i: Integer; + state: TParseArgsState; + param: TengShaderPartProcParam; +begin + if (aParameters[0].Name <> GetTokenName) then + raise EengInvalidToken.Create(ClassName, aParameters[0].Name, Line, Col, Filename); + if (aParameters.Count < 2) then + raise EengInvalidParamterCount.Create(GetTokenName, Line, Col, Filename); + + result := ''; + fName := aParameters[1].Name; + state := pasType; + fParameters.Clear; + i := 2; + while (i < aParameters.Count) do begin + case state of + pasType: begin + if (aParameters[i].Name = TOKEN_INLINE) then begin + fIsInline := true; + end else begin + param.Typ := aParameters[i].Name; + state := pasName; + end; + end; + + pasName: begin + if (aParameters[i].Name = TOKEN_INLINE) then begin + raise EengInvalidParamter.Create('expected parameter name, found ' + TOKEN_INLINE, aParameters[i].Line, aParameters[i].Col, Filename); + end else begin + param.Name := aParameters[i].Name; + fParameters.Add(param); + state := pasType; + end; + end; + end; + inc(i); + end; + if (state <> pasType) then + raise EengInvalidParamterCount.Create(GetTokenName, Line, Col, Filename); + + inherited ParseTextIntern(aParseArgs, aParameters); + result := CheckEndToken(aParseArgs, self); +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengShaderPartProc.GenHeaderCode: String; +var + p: TengShaderPartProcParam; +begin + result := ''; + for p in fParameters do begin + if (result <> '') then + result := result + ', '; + result := result + p.Typ + ' ' + p.Name; + end; + if (result = '') then + result := 'void'; + result := 'void ' + fName + '(' + result + ')'; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +procedure TengShaderPartProc.GenInlineCode(const aGenCodeArgs: TengGenCodeArgs; const aAddToken: Boolean); +var + old, new: TStringList; + p: TengShaderPartProcParam; + rx: TRegExpr; + s: String; +begin + aGenCodeArgs.PushCode; + if aAddToken then + aGenCodeArgs.Code.AddToken(ttBegin); + try + inherited GenCodeIntern(aGenCodeArgs); + + old := TStringList.Create; + new := TStringList.Create; + rx := TRegExpr.Create; + try + //prepare old parameter + for p in fParameters do + old.Add(p.Name); + + //prepare new parameter + rx.Expression := '[^A-z0-9_]+'; + for s in aGenCodeArgs.ProcParams do + if (rx.Exec(s)) then + new.Add('(' + s + ')') + else + new.Add(s); + + //replace parameter + aGenCodeArgs.Code.ReplaceIdents(old, new); + finally + FreeAndNil(rx); + FreeAndNil(old); + FreeAndNil(new); + end; + finally + if aAddToken then + aGenCodeArgs.Code.AddToken(ttEnd); + aGenCodeArgs.PopCode; + end; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +procedure TengShaderPartProc.GenCodeIntern(const aGenCodeArgs: TengGenCodeArgs); +var + s, params: String; +begin + // generate inline code + if (aGenCodeArgs.Flags * [gcfGenProcCall, gcfGenProcedure] <> []) and + ((gcfGenProcInline in aGenCodeArgs.Flags) or fIsInline) then + begin + GenInlineCode(aGenCodeArgs); + if (ClassType = TengShaderPartProc) then + aGenCodeArgs.Code.IgnoreNextSemicolon; + + // generate code + end else if (gcfGenProcedure in aGenCodeArgs.Flags) then begin + aGenCodeArgs.Code.AddLineEnd; + aGenCodeArgs.Code.AddText(GenHeaderCode); + aGenCodeArgs.Code.AddLineEnd; + aGenCodeArgs.Code.AddText('{'); + aGenCodeArgs.Code.AddLineEnd; + aGenCodeArgs.Code.AddToken(ttBegin); + aGenCodeArgs.Code.AddCommandEnd(); + try + inherited GenCodeIntern(aGenCodeArgs); + finally + aGenCodeArgs.Code.AddText('}'); + aGenCodeArgs.Code.AddToken(ttEnd); + aGenCodeArgs.Code.AddCommandEnd(); + aGenCodeArgs.Code.AddLineEnd; + end; + + // generate call + end else if (gcfGenProcCall in aGenCodeArgs.Flags) then begin + params := ''; + for s in aGenCodeArgs.ProcParams do begin + if (params <> '') then + params := params + ', '; + params := params + s; + end; + aGenCodeArgs.Code.AddText(fName + '(' + params + ')'); + aGenCodeArgs.AddProcedure(self); + end; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +procedure TengShaderPartProc.MapData(const aFlags: TengMapDataFlags; const aTypes: array of CengShaderPart); +begin + if CheckType(self, aTypes) then begin + with CheckParentScope(self) do begin + MapShaderPart(fName, self); // Procs are named shader parts + MapChildScope(self); // and also Child Scopes + end; + end; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +constructor TengShaderPartProc.Create(const aParent: TengShaderPart); +begin + inherited Create(aParent); + fParameters := TengShaderPartProcParamList.Create(true); +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +destructor TengShaderPartProc.Destroy; +begin + FreeAndNil(fParameters); + inherited Destroy; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +class function TengShaderPartProc.GetTokenName: String; +begin + result := TOKEN_PROC; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +class procedure TengShaderPartProc.CheckToken(const aParseArgs: TengParseArgs; const aParent: TengShaderPart); +begin + if (aParent is TengShaderPartProc) or (aParent.ParentHasType(TengShaderPartProc)) then + with aParseArgs do + raise EengShaderPart.Create('token ' + GetTokenName + ' is not allowed in procedure or function', Line, Col, aParent.Filename); +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//TengShaderPartMain//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengShaderPartMain.GetHeaderText: String; +begin + result := PRECOMPILER_STATEMENT_BEGIN + GetTokenName + PRECOMPILER_STATEMENT_END; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengShaderPartMain.ParseTextIntern(const aParseArgs: TengParseArgs; const aParameters: TengTokenParameterList): String; +var + p: TengTokenParameter; +begin + if (aParameters[0].Name <> GetTokenName) then + raise EengInvalidToken.Create(ClassName, aParameters[0].Name, Line, Col, Filename); + if (aParameters.Count <> 1) then + raise EengInvalidParamterCount.Create(GetTokenName, Line, Col, Filename); + + result := ''; + p.Name := 'main'; + p.Quoted := false; + aParameters.Add(p); + inherited ParseTextIntern(aParseArgs, aParameters); +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengShaderPartMain.GenHeaderCode: String; +begin + result := 'void main(void)'; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +class function TengShaderPartMain.GetTokenName: String; +begin + result := TOKEN_MAIN; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//TengShaderPartFunc//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengShaderPartFunc.GetHeaderText: String; +var + p: TengShaderPartProcParam; +begin + result := PRECOMPILER_STATEMENT_BEGIN + GetTokenName + ' ''' + fReturnType + ''' ''' + fName + ''''; + for p in fParameters do + result := result + ' ''' + p.Typ + ''' ''' + p.Name + ''''; + result := result + PRECOMPILER_STATEMENT_END; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengShaderPartFunc.ParseTextIntern(const aParseArgs: TengParseArgs; const aParameters: TengTokenParameterList): String; +begin + if (aParameters[0].Name <> GetTokenName) then + raise EengInvalidToken.Create(ClassName, aParameters[0].Name, Line, Col, Filename); + if (aParameters.Count < 3) then + raise EengInvalidParamterCount.Create(GetTokenName, Line, Col, Filename); + + fReturnType := aParameters[1].Name; + aParameters.Delete(1); + result := inherited ParseTextIntern(aParseArgs, aParameters); +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +procedure TengShaderPartFunc.GenInlineCode(const aGenCodeArgs: TengGenCodeArgs; const aAddToken: Boolean); +var + o: Integer; +begin + o := aGenCodeArgs.PushCurrentCommand.GetMinLineOffset; + aGenCodeArgs.PushCode; + aGenCodeArgs.Code.AddLineEnd; + aGenCodeArgs.Code.AddToken(ttBegin, o); + try + inherited GenInlineCode(aGenCodeArgs, false); + finally + aGenCodeArgs.PopCurrentCommand(fReturnType, fName); + aGenCodeArgs.Code.AddToken(ttEnd); + aGenCodeArgs.PopCode; + end; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengShaderPartFunc.GenHeaderCode: String; +var + p: TengShaderPartProcParam; +begin + result := ''; + for p in fParameters do begin + if (result <> '') then + result := result + ', '; + result := result + p.Typ + ' ' + p.Name; + end; + if (result = '') then + result := 'void'; + result := fReturnType + ' ' + fName + '(' + result + ')'; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +class function TengShaderPartFunc.GetTokenName: String; +begin + result := TOKEN_FUNC; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +class procedure TengShaderPartFunc.CheckToken(const aParseArgs: TengParseArgs; const aParent: TengShaderPart); +begin + if (aParent is TengShaderPartFunc) or (aParent.ParentHasType(TengShaderPartFunc)) then + with aParseArgs do + raise EengShaderPart.Create('token ' + GetTokenName + ' is not allowed in function', Line, Col, aParent.Filename); +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//TengShaderPartIf////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengShaderPartIf.ParseExpression(const aParameters: TengTokenParameterList; aIndex: Integer): TengExpressionItem; +type + TExpectedParam = (exVariable, exValue, exGroupBegin, exGroupEnd, exUnaryOperation, exBinaryOperation); + TExpectedParams = set of TExpectedParam; + TExpressionItemStack = specialize TutlList; + +var + param: TengTokenParameter; + + function NextParam: Boolean; + begin + inc(aIndex); + result := (aIndex < aParameters.Count); + if result then + param := aParameters[aIndex]; + end; + + function IsUnaryOperation(const aParam: String; out aOperator: TengExpressionUnaryOperator): Boolean; + begin + result := true; + for aOperator in TengExpressionUnaryOperator do + if (aParam = EXPRESSION_UNARY_OPERATIONS[aOperator]) then + exit; + result := false; + end; + + function IsBinaryOperation(const aParam: String; out aOperator: TengExpressionBinaryOperator): Boolean; + begin + result := true; + for aOperator in TengExpressionBinaryOperator do + if (aParam = EXPRESSION_BINARY_OPERATIONS[aOperator]) then + exit; + result := false; + end; + + procedure MergeItems(const aStack: TExpressionItemStack; const aNew: TengExpressionItem); + var + itm: TengExpressionItem; + begin + if (aStack.Count > 0) then begin + itm := aStack.Last; + if (itm is TengExpressionBinaryOperation) then begin + if (aNew is TengExpressionBinaryOperation) then begin + + //both are binary operators, new is weaker then existing + if ((aNew as TengExpressionBinaryOperation).BinaryOp < (itm as TengExpressionBinaryOperation).BinaryOp) then begin + aStack.PopLast; + (aNew as TengExpressionBinaryOperation).First := itm; + aStack.PushLast(aNew); + + //both are binary operators, new is stronger than existing + end else begin + if not Assigned((itm as TengExpressionBinaryOperation).Second) then + raise EengExpression.Create('inconsistent state', param.Line, param.Col, Filename); + (aNew as TengExpressionBinaryOperation).First := (itm as TengExpressionBinaryOperation).Second; + (itm as TengExpressionBinaryOperation).Second := aNew; + aStack.PushLast(aNew); + end; + + //existing is binary operator, new is normal + end else begin + if Assigned((itm as TengExpressionBinaryOperation).Second) then + raise EengExpression.Create('inconsistent state', param.Line, param.Col, Filename); + (itm as TengExpressionBinaryOperation).Second := aNew; + while (aStack.Count > 1) do + aStack.PopLast; //remove all but first + end; + end else begin + + //existing is normal item, new is binary operation + if (aNew is TengExpressionBinaryOperation) then begin + aStack.PopLast; + (aNew as TengExpressionBinaryOperation).First := itm; + aStack.PushLast(aNew); + + //existing is unary operation, new is normal item or unary operation + end else if (itm is TengExpressionUnaryOperation) then begin + if Assigned((itm as TengExpressionUnaryOperation).Child) then + raise EengExpression.Create('inconsistent state', param.Line, param.Col, Filename); + (itm as TengExpressionUnaryOperation).Child := aNew; + if not (aNew is TengExpressionUnaryOperation) then begin + while (aStack.Count > 1) do + aStack.PopLast; //remove all but first + end else + aStack.PushLast(aNew); + + //existing and new are both normal items + end else begin + raise EengExpression.Create('inconsistent state', param.Line, param.Col, Filename); + end; + end; + end else + aStack.PushLast(aNew); + end; + + function BuildTree(const aDepth: Integer = 0): TengExpressionItem; + var + uOp: TengExpressionUnaryOperator; + bOp: TengExpressionBinaryOperator; + expected: TExpectedParams; + + stack: TExpressionItemStack; + begin + expected := [exVariable, exValue, exGroupBegin, exUnaryOperation]; + result := nil; + stack := TExpressionItemStack.Create(false); + try try + repeat + //GroupBegin + if (param.Name = TOKEN_OP_GROUP_BEGIN) then begin + if not (exGroupBegin in expected) then + raise EengExpression.Create('unexpected ''' + TOKEN_OP_GROUP_BEGIN + '''', param.Line, param.Col, Filename); + if not NextParam then + raise EengExpression.Create('unexpected end', Line, Col, Filename); + MergeItems(stack, TengExpressionGroup.Create(BuildTree(aDepth + 1), param.Line, param.Col, Filename)); + if (param.Name <> TOKEN_OP_GROUP_END) then + raise EengExpression.Create('missing ''' + TOKEN_OP_GROUP_END + '''', param.Line, param.Col, Filename); + expected := [exBinaryOperation, exGroupEnd]; + + //GroupEnd + end else if (param.Name = TOKEN_OP_GROUP_END) then begin + if not (exGroupEnd in expected) or (aDepth = 0) then + raise EengExpression.Create('unexpected ''' + TOKEN_OP_GROUP_END + '''', param.Line, param.Col, Filename); + exit; + + //UnaryOperation + end else if IsUnaryOperation(param.Name, uOp) then begin + if not (exUnaryOperation in expected) then + raise EengExpression.Create('unexpected operator: ' + param.Name, param.Line, param.Col, Filename); + MergeItems(stack, TengExpressionUnaryOperation.Create(uOp, param.Line, param.Col, Filename)); + expected := [exVariable]; + if (uOp <> opDefined) then + expected := expected + [exValue, exGroupBegin, exUnaryOperation] + + //BinaryOperation + end else if IsBinaryOperation(param.Name, bOp) then begin + if not (exBinaryOperation in expected) then + raise EengExpression.Create('unexpected operator: ' + param.Name, param.Line, param.Col, Filename); + MergeItems(stack, TengExpressionBinaryOperation.Create(bOp, param.Line, param.Col, Filename)); + expected := [exVariable, exValue, exGroupBegin, exUnaryOperation]; + + //Value + end else if param.Quoted and IsValidIdentifier(param.Name) then begin + if not (exValue in expected) then + raise EengExpression.Create('unexpected value: ' + param.Name, param.Line, param.Col, Filename); + MergeItems(stack, TengExpressionValue.Create(param.Name, param.Line, param.Col, Filename)); + expected := [exGroupEnd, exBinaryOperation]; + + //Variable + end else if IsValidIdentifier(param.Name) then begin + if not (exVariable in expected) then + raise EengExpression.Create('unexpected variable: ' + param.Name, param.Line, param.Col, Filename); + MergeItems(stack, TengExpressionVariable.Create(param.Name, param.Line, param.Col, Filename)); + expected := [exGroupEnd, exBinaryOperation]; + + //Unknown + end else + raise EengExpression.Create('invalid parameter: ' + param.Name, param.Line, param.Col, Filename); + until not NextParam; + + except + if (stack.Count > 0) then begin + stack[0].Free; + stack[0] := nil; + end; + raise; + end; + finally + if (stack.Count > 0) then + result := stack[0]; + FreeAndNil(stack); + end; + end; + +begin + if (aIndex >= aParameters.Count) then + raise EengExpression.Create('invalid parameter count in expression', Line, Col, Filename); + dec(aIndex); + NextParam; + result := BuildTree; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengShaderPartIf.GetCount: Integer; +begin + result := 1; + if Assigned(fElsePart) then + inc(result); +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengShaderPartIf.GetChild(const aIndex: Integer): TengShaderPart; +begin + if (aIndex >= 0) and (aIndex < Count) then begin + case aIndex of + 0: result := fIfPart; + 1: result := fElsePart; + end; + end else + raise EOutOfRange.Create(aIndex, 0, Count-1); +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengShaderPartIf.GetText: String; +begin + result := PRECOMPILER_STATEMENT_BEGIN + GetTokenName + ' ' + fExpression.GetText + PRECOMPILER_STATEMENT_END + fIfPart.Text; + if Assigned(fElsePart) then + result := result + fElsePart.Text; + result := result + PRECOMPILER_STATEMENT_BEGIN + TOKEN_END + PRECOMPILER_STATEMENT_END; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengShaderPartIf.ParseTextIntern(const aParseArgs: TengParseArgs; const aParameters: TengTokenParameterList): String; +begin + if (aParameters[0].Name <> GetTokenName) then + raise EengInvalidToken.Create(ClassName, aParameters[0].Name, Line, Col, Filename); + if (aParameters.Count < 2) then + raise EengInvalidParamterCount.Create(GetTokenName, Line, Col, Filename); + + fExpression := ParseExpression(aParameters, 1); + + fIfPart := TengShaderPartContainer.Create(self); + result := fIfPart.ParseText(aParseArgs); + result := HandleToken(result, aParseArgs); +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengShaderPartIf.HandleToken(const aToken: String; const aParseArgs: TengParseArgs): String; +begin + result := aToken; + if (result = TengShaderPartElse.GetTokenName) then begin + fElsePart := TengShaderPartElse.Create(self); + result := fElsePart.ParseText(aParseArgs); + end else if (result = TengShaderPartElIf.GetTokenName) then begin + fElsePart := TengShaderPartElIf.Create(self); + result := fElsePart.ParseText(aParseArgs); + end; + result := HandleEndToken(result, aParseArgs); +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengShaderPartIf.HandleEndToken(const aToken: String; const aParseArgs: TengParseArgs): String; +begin + result := CheckEndToken(aParseArgs, self); +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +procedure TengShaderPartIf.MapData(const aFlags: TengMapDataFlags; const aTypes: array of CengShaderPart); +begin + inherited MapData(aFlags, aTypes); + + //map all + if (mdfIfAll in aFlags) then begin + if Assigned(fIfPart) then + fIfPart.MapData(aFlags, aTypes); + if Assigned(fElsePart) then + fElsePart.MapData(aFlags, aTypes); + + // evaluete and map suitable + end else if (mdfIfEvaluate in aFlags) then begin + if fExpression.GetValue(CheckParentScope(self), nil) then begin + if Assigned(fIfPart) then + fIfPart.MapData(aFlags, aTypes); + end else begin + if Assigned(fElsePart) then + fElsePart.MapData(aFlags, aTypes); + end; + end; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +procedure TengShaderPartIf.GenCodeIntern(const aGenCodeArgs: TengGenCodeArgs); +var + p: TengShaderPart; + b: Boolean; +begin + inherited GenCodeIntern(aGenCodeArgs); + + b := fExpression.GetValue(CheckParentScope(self), aGenCodeArgs); + if b then + p := fIfPart + else + p := fElsePart; + + aGenCodeArgs.Code.AddToken(ttBegin); // IF ... + try + if Assigned(p) then + p.GenCodeIntern(aGenCodeArgs); + finally + aGenCodeArgs.Code.AddToken(ttEnd); // ... END + end; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +destructor TengShaderPartIf.Destroy; +begin + FreeAndNil(fExpression); + FreeAndNil(fIfPart); + FreeAndNil(fElsePart); + inherited Destroy; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +class function TengShaderPartIf.GetTokenName: String; +begin + result := TOKEN_IF; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//TengShaderPartElIf//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengShaderPartElIf.GetText: String; +begin + result := PRECOMPILER_STATEMENT_BEGIN + GetTokenName + PRECOMPILER_STATEMENT_END + fIfPart.Text; + if Assigned(fElsePart) then + result := result + fElsePart.Text; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengShaderPartElIf.HandleEndToken(const aToken: String; const aParseArgs: TengParseArgs): String; +begin + result := aToken; + if (result <> TOKEN_END) then + raise EengInvalidToken.Create(ClassName, result, aParseArgs.Line, aParseArgs.Col, Filename); +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +class function TengShaderPartElIf.GetTokenName: String; +begin + result := TOKEN_ELIF; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//TengShaderPartElse//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengShaderPartElse.GetText: String; +begin + result := PRECOMPILER_STATEMENT_BEGIN + GetTokenName + PRECOMPILER_STATEMENT_END + inherited GetText; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +class function TengShaderPartElse.GetTokenName: String; +begin + result := TOKEN_ELSE; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//TengShaderPartEcho//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengShaderPartEcho.GetText: String; +begin + result := PRECOMPILER_STATEMENT_BEGIN + GetTokenName + ' ' + fName + PRECOMPILER_STATEMENT_END; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengShaderPartEcho.ParseTextIntern(const aParseArgs: TengParseArgs; const aParameters: TengTokenParameterList): String; +begin + if (aParameters[0].Name <> GetTokenName) then + raise EengInvalidToken.Create(ClassName, aParameters[0].Name, Line, Col, Filename); + if (aParameters.Count <> 2) then + raise EengInvalidParamterCount.Create(GetTokenName, Line, Col, Filename); + result := ''; + fName := aParameters[1].Name; + if not IsValidIdentifier(fName) then + raise EengShaderPart.Create('invalid name: ' + fName, Line, Col, GetFilename); +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +procedure TengShaderPartEcho.GenCodeIntern(const aGenCodeArgs: TengGenCodeArgs); +var + p: TengShaderPart; +begin + CheckParentScope(self).FindMappedPart(p, fName, GEN_CODE_FIND_FLAGS); + + if not Assigned(p) then + raise EengUnknownIdentifier.Create(fName, Line, Col, Filename); + if not (p is TengShaderPartKeyValuePair) then + raise EengInvalidParamter.Create('Expected ' + TengShaderPartDefine.GetTokenName + ' or ' + TengShaderPartProperty.GetTokenName, Line, Col, Filename); + + aGenCodeArgs.Code.AddText((p as TengShaderPartKeyValuePair).Value); + inherited GenCodeIntern(aGenCodeArgs); +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +class function TengShaderPartEcho.GetTokenName: String; +begin + result := TOKEN_ECHO; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//TengShaderPartMessage///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengShaderPartMessage.GetText: String; +begin + result := PRECOMPILER_STATEMENT_BEGIN + GetTokenName + ' ''' + fMessage + '''' + PRECOMPILER_STATEMENT_END; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengShaderPartMessage.ParseTextIntern(const aParseArgs: TengParseArgs; const aParameters: TengTokenParameterList): String; +begin + if (aParameters[0].Name <> GetTokenName) then + raise EengInvalidToken.Create(ClassName, aParameters[0].Name, Line, Col, Filename); + if (aParameters.Count <> 2) then + raise EengInvalidParamterCount.Create(GetTokenName, Line, Col, Filename); + result := ''; + fMessage := aParameters[1].Name; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +class function TengShaderPartMessage.GetTokenName: String; +begin + result := TOKEN_MESSAGE; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//TengShaderPartWarning///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +class function TengShaderPartWarning.GetTokenName: String; +begin + result := TOKEN_WARNING; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//TengShaderPartError/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +procedure TengShaderPartError.GenCodeIntern(const aGenCodeArgs: TengGenCodeArgs); +begin + inherited GenCodeIntern(aGenCodeArgs); + raise EengShaderPart.Create(fMessage, Line, Col, Filename); +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +class function TengShaderPartError.GetTokenName: String; +begin + result := TOKEN_ERROR; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//TengShaderPartCode//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengShaderPartCode.GetText: String; +begin + result := fCode; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengShaderPartCode.ParseTextIntern(const aParseArgs: TengParseArgs; const aParameters: TengTokenParameterList): String; + + function CheckToken: Boolean; + begin + with aParseArgs do + result := + (CurrentChar = PRECOMPILER_STATEMENT_BEGIN) and + (Col < LineLength) and + (CurrentLine[Col + 1] in [TOKEN_IDENTIFIER, COMMENT_IDENTIFIER]); + end; + + function FindToken: String; + var + c: Integer; + begin + with aParseArgs do + if (CurrentChar = TOKEN_COMMAND_END) then + result := TOKEN_COMMAND_END + else if (Col < LineLength) then begin + c := Col + 1; + case CurrentLine[c] of + TOKEN_IDENTIFIER: begin + result := TOKEN_IDENTIFIER; + inc(c); + while (c <= LineLength) and (CurrentLine[c] in VALID_TOKEN_CHARS) do begin + result := result + CurrentLine[c]; + inc(c); + end; + result := Trim(result); + if (result = TOKEN_IDENTIFIER) then + raise EengShaderPart.Create('empty token', Line, Col, Filename); + end; + + //skip comment + COMMENT_IDENTIFIER: + result := COMMENT_IDENTIFIER; + end; + end else begin + result := ''; + aParseArgs.IncCol; + end; + end; + +begin + fCode := ''; + while not aParseArgs.EndOfLine do begin + if CheckToken then begin + result := FindToken; + if (result <> '') then + exit; + end else if (aParseArgs.CurrentChar in COMMAND_END_TOKENS) then begin + result := aParseArgs.CurrentChar; + exit; + end else begin + fCode := fCode + aParseArgs.CurrentChar; + aParseArgs.IncCol; + end; + end; + result := TOKEN_LINE_BREAK; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +procedure TengShaderPartCode.GenCodeIntern(const aGenCodeArgs: TengGenCodeArgs); +begin + inherited GenCodeIntern(aGenCodeArgs); + aGenCodeArgs.Code.AddText(fCode); +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//TengShaderPartLineBreak/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengShaderPartLineBreak.GetText: String; +begin + result := GetTokenName; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengShaderPartLineBreak.ParseTextIntern(const aParseArgs: TengParseArgs; const aParameters: TengTokenParameterList): String; +begin + if not aParseArgs.EndOfLine then + raise EengShaderPart.Create('TengShaderPartLineBreak but not end of line', aParseArgs.Line, aParseArgs.Col, Filename); + aParseArgs.IncLine; + result := ''; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +procedure TengShaderPartLineBreak.GenCodeIntern(const aGenCodeArgs: TengGenCodeArgs); +begin + inherited GenCodeIntern(aGenCodeArgs); + aGenCodeArgs.Code.AddLineEnd; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +class function TengShaderPartLineBreak.GetTokenName: String; +begin + result := TOKEN_LINE_BREAK; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//TengShaderPartCommandEnd////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengShaderPartCommandEnd.GetText: String; +begin + result := fToken; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengShaderPartCommandEnd.ParseTextIntern(const aParseArgs: TengParseArgs; const aParameters: TengTokenParameterList): String; +begin + result := ''; + fToken := aParseArgs.CurrentChar; + aParseArgs.IncCol; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +procedure TengShaderPartCommandEnd.GenCodeIntern(const aGenCodeArgs: TengGenCodeArgs); +begin + inherited GenCodeIntern(aGenCodeArgs); + aGenCodeArgs.Code.AddCommandEnd(fToken); +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +class function TengShaderPartCommandEnd.CheckToken(const aToken: String): Boolean; +var + s: String; +begin + result := true; + for s in COMMAND_END_TOKENS do + if (s = aToken) then + exit; + result := false; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//TengShaderCode//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengShaderCode.GetMeta(const aIndex: Integer): IengMetaData; +begin + result := fMetaList[aIndex]; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengShaderCode.GetMetaCount: Integer; +begin + result := fMetaList.Count; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +constructor TengShaderCode.Create; +begin + inherited Create; + fMetaList := TMetaList.Create; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +destructor TengShaderCode.Destroy; +begin + FreeAndNil(fMetaList); + inherited Destroy; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//TengShaderCodeIntern////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +procedure TengShaderCodeIntern.AddMeta(const aMeta: IengMetaData); +begin + fMetaList.Add(aMeta); +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//TengParseArgs///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +procedure TengParseArgs.SetCol(const aValue: Integer); +begin + fCol := aValue; + if not EndOfLine then + fCurrentChar := fCurrentLine[fCol] + else + fCurrentChar := #0; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +procedure TengParseArgs.SetLine(const aValue: Integer); +begin + fLine := aValue; + if not EndOfFile then begin + fCurrentLine := fCode[fLine]; + fLineLength := Length(fCurrentLine); + end else begin + fCurrentLine := ''; + fLineLength := -1; + end; + Col := 1; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengParseArgs.GetEndOfFile: Boolean; +begin + result := (fLine >= fLineCount); +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengParseArgs.GetEndOfLine: Boolean; +begin + result := (fCol > fLineLength); +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengParseArgs.GetCode: TStrings; +begin + result := fCode; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +procedure TengParseArgs.IncCol; +begin + Col := Col + 1; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +procedure TengParseArgs.IncLine; +begin + Line := Line + 1; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengParseArgs.ParseParameters(const aParameters: TengTokenParameterList): Boolean; +type + TCharType = (ctUnknown, ctValidTokenChar, ctInvalidTokenChar, ctWhiteSpace); +var + s: String; + charType: TCharType; + pLine, pCol: Integer; + isComment: Boolean; + + procedure AddPart(const aTrimAndCheck: Boolean = true); + var + len: Integer; + p: TengTokenParameter; + begin + if aTrimAndCheck then + s := Trim(s); + if not aTrimAndCheck or (s <> '')then begin + len := Length(s); + if aTrimAndCheck and ((s[1] = PRECOMPILER_QUOTE_CHAR) or (s[len] = PRECOMPILER_QUOTE_CHAR)) then begin + if not (s[1] = PRECOMPILER_QUOTE_CHAR) then + raise EengShaderPart.Create('missing leading quote char', Line, Col, fOwner.Filename); + if not (s[len] = PRECOMPILER_QUOTE_CHAR) then + raise EengShaderPart.Create('missing trailing quote char', Line, Col, fOwner.Filename); + delete(s, len, 1); + delete(s, 1, 1); + p.Quoted := true; + end else + p.Quoted := false; + p.Name := s; + p.Line := pLine; + p.Col := pCol; + aParameters.Add(p); + end; + s := ''; + pLine := Line; + pCol := Col; + charType := ctUnknown; + end; + +var + quote, inToken, commentTokenAdded: Boolean; + lOld, cOld: Integer; +begin + result := false; + aParameters.Clear; + if (CurrentChar <> PRECOMPILER_STATEMENT_BEGIN) or + (Col + 1 > LineLength) or + ( (CurrentLine[Col + 1] <> TOKEN_IDENTIFIER) and + (CurrentLine[Col + 1] <> COMMENT_IDENTIFIER)) then + exit; + + result := true; + quote := false; + inToken := false; + isComment := CurrentLine[Col + 1] = COMMENT_IDENTIFIER; + commentTokenAdded := false; + s := ''; + charType := ctUnknown; + lOld := Line; + cOld := Col; + AddPart; //initialize + + while not EndOfFile do begin + while not EndOfLine do begin + case CurrentChar of + PRECOMPILER_STATEMENT_BEGIN: begin + if quote then + s := s + PRECOMPILER_STATEMENT_BEGIN + else if not inToken then + inToken := true + else + EengShaderPart.Create('invalid char in token'); + end; + + PRECOMPILER_STATEMENT_END: begin + if not quote then begin + AddPart(not isComment); + IncCol; + if (aParameters.Count <= 0) or (aParameters[0].Name = TOKEN_IDENTIFIER) then + raise EengEmptyToken.Create(lOld, cOld, fOwner.Filename); + exit; + end else + s := s + CurrentChar; + end; + + PRECOMPILER_QUOTE_CHAR: begin + if not quote and not isComment then + AddPart; + s := s + PRECOMPILER_QUOTE_CHAR; + quote := not quote; + if not quote and not isComment then + AddPart; + end; + + COMMENT_IDENTIFIER: begin + s := s + COMMENT_IDENTIFIER; + if isComment and not commentTokenAdded then begin + commentTokenAdded := true; + AddPart(false); + end; + end; + else + if not quote and not isComment then begin + if (CurrentChar in TOKEN_SPLIT_CHARS) then begin + AddPart; + end else if (CurrentChar in VALID_TOKEN_CHARS) then begin + if (charType <> ctValidTokenChar) then + AddPart; + charType := ctValidTokenChar; + end else begin + if (charType <> ctInvalidTokenChar) then + AddPart; + charType := ctInvalidTokenChar; + end; + end; + s := s + CurrentChar; + end; + IncCol; + end; + s := s + sLineBreak; + IncLine; + end; + raise EengShaderPart.Create('incomplete token', lOld, cOld, fOwner.Filename); +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +procedure TengParseArgs.LoadCode(const aStream: TStream); +begin + fCode.LoadFromStream(aStream); + fLineCount := fCode.Count; + Line := 0; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +constructor TengParseArgs.Create(const aOwner: TengShaderFile); +begin + inherited Create; + fOwner := aOwner; + fCode := TStringList.Create; + fLineCount := fCode.Count; + Line := 0; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +destructor TengParseArgs.Destroy; +begin + FreeAndNil(fCode); + inherited Destroy; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//TengGenCodeArgs.TCodeItem///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengGenCodeArgs.TCodeItem.GetText: String; +begin + result := ''; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengGenCodeArgs.TCodeItem.IsEmpty: Boolean; +begin + result := (Trim(GetText) = ''); +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//TengGenCodeArgs.TCodeItemStart//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengGenCodeArgs.TCodeItemStart.GetText: String; +begin + result := ''; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//TengGenCodeArgs.TCodeItemText///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengGenCodeArgs.TCodeItemText.GetText: String; +begin + result := Text; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +constructor TengGenCodeArgs.TCodeItemText.Create(const aText: String); +begin + inherited Create; + Text := aText; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//TCodeItemLineBreak.TCodeItemLineBreak///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengGenCodeArgs.TCodeItemLineBreak.GetText: String; +begin + result := sLineBreak; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//TengGenCodeArgs.TCodeItemCommandEnd/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengGenCodeArgs.TCodeItemCommandEnd.GetText: String; +begin + result := Token; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +constructor TengGenCodeArgs.TCodeItemCommandEnd.Create(const aToken: String); +begin + inherited Create; + Token := aToken; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//TengGenCodeArgs.TCodeItemToken//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +constructor TengGenCodeArgs.TCodeItemToken.Create(const aTokenType: TTokenType; const aLevel: Integer); +begin + inherited Create; + TokenType := aTokenType; + Level := aLevel; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//TengGenCodeArgs.TCodeStackItem//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengGenCodeArgs.TCodeStackItem.GetEmpty: Boolean; +begin + result := (fItems.Count = 0) or + ((fItems.Count = 1) and (fItems[0] is TCodeItemStart)); +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +{$IFDEF DEBUG} +function TengGenCodeArgs.TCodeStackItem.GetDebugText: String; +var + ci: TCodeItem; +begin + result := ''; + for ci in fItems do + if (ci is TCodeItemToken) then with (ci as TCodeItemToken) do begin + case TokenType of + ttBegin: result := result + '$B'; + ttEnd: result := result + '$E'; + ttSingle: result := result + '$S'; + end; + if (Level >= 0) then + result := result + IntToStr(Level); + end else if (ci is TCodeItemCommandEnd) then with (ci as TCodeItemCommandEnd) do begin + result := result + '$C("' + ci.GetText + '")'; + end else + result := result + ci.GetText; +end; +{$ENDIF} + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengGenCodeArgs.TCodeStackItem.GetText: String; +type + TGenFlag = ( + gfToken, // current line has a token in it + gfTokenSingle, // current line has a single token in it + gfPrevEmpty, // previouse line was empty + gfAddToPrevLine, // trim left current line and add to prev line if not empty + gfAddNextLine // trim left next line and add to current line if not empty + ); + TGenFlags = set of TGenFlag; +var + i: Integer; + line: String; + sl: TStringList; + f: TGenFlags; + + function GetStrOffset(const aStr: String): Integer; + var + len: Integer; + begin + result := 0; + len := Length(aStr); + while (result < len) and (aStr[result+1] in WHITESPACES) do + inc(result); + end; + + function GetOffset(const aItem: TCodeItemToken): Integer; + begin + result := aItem.Level; + if (result < 0) then + result := GetStrOffset(line); + end; + + function GetMinOffset(aStartIndex: Integer): Integer; + begin + if (Trim(line) <> '') then + result := GetStrOffset(line) + else + result := High(Integer); + while (aStartIndex < sl.Count) do begin + if (Trim(sl[aStartIndex]) <> '') then + result := Min(result, GetStrOffset(sl[aStartIndex])); + inc(aStartIndex); + end; + if (result >= High(Integer)) then + result := -1; + end; + + function TrimLeftLen(const aStr: String; aLen: Integer): String; + var + i, len: Integer; + begin + i := 1; + len := Length(aStr); + while (i <= len) and (aStr[i] in WHITESPACES) and (aLen > 0) do begin + inc(i); + dec(aLen); + end; + result := Copy(aStr, i, len - i + 1); + end; + + function PrepareStr(const aStr: String; const aOffset: Integer): String; + begin + if (aOffset < 0) then + result := StringOfChar(' ', -aOffset) + aStr + else + result := TrimLeftLen(aStr, aOffset); + end; + + procedure IndentBlock(aStartIndex: Integer; const aOffset: Integer); + var + o: Integer; + begin + o := GetMinOffset(aStartIndex); + if (o < 0) then + exit; + o := o - aOffset; + if (o = 0) then + exit; + while (aStartIndex < sl.Count) do begin + sl[aStartIndex] := PrepareStr(sl[aStartIndex], o); + inc(aStartIndex); + end; + line := PrepareStr(line, o); + end; + + procedure ProgressBlock(const aOffset: Integer); + var + item: TCodeItem; + s: String; + lineIndex: Integer; + begin + lineIndex := sl.Count; //start at next line + while (i < fItems.Count) do begin + item := fItems[i]; + inc(i); + + // LineBreak + if (item is TCodeItemLineBreak) then begin + if (Trim(line) = '') then begin + if (f * [gfToken, gfPrevEmpty] = []) then begin + sl.Add(line); + Include(f, gfPrevEmpty); + end; + if not (gfTokenSingle in f) then + Exclude(f, gfAddToPrevLine); + end else begin + if not (gfAddToPrevLine in f) then begin + sl.Add(line); + Exclude(f, gfPrevEmpty); + end else if (sl.Count > 0) then + sl[sl.Count-1] := sl[sl.Count-1] + TrimLeft(line) + else + sl.Add(line); + Exclude(f, gfAddToPrevLine); + end; + Exclude(f, gfToken); + Exclude(f, gfTokenSingle); + if (gfAddNextLine in f) then + f := f + [gfAddToPrevLine] - [gfAddNextLine]; + line := ''; + + // Token + end else if (item is TCodeItemToken) then with (item as TCodeItemToken) do begin + Include(f, gfToken); + case TokenType of + ttBegin: begin + if (Trim(line) <> '') then + Include(f, gfAddNextLine); + Include(f, gfPrevEmpty); + ProgressBlock(GetOffset(item as TCodeItemToken)); + end; + + ttEnd: begin + if (Trim(line) = '') then + Include(f, gfAddToPrevLine); + IndentBlock(lineIndex, aOffset); + exit; + end; + + ttSingle: begin + Include(f, gfTokenSingle); + end; + end; + + // other + end else begin + s := item.GetText;; + if (gfAddNextLine in f) and (Trim(s) <> '') then + Exclude(f, gfAddNextLine); + line := line + s; + end; + end; + end; + + procedure TrimList; + begin + while (sl.Count > 0) and (Trim(sl[0]) = '') do + sl.Delete(0); + while (sl.Count > 0) and (Trim(sl[sl.Count-1]) = '') do + sl.Delete(sl.Count-1); + end; + +begin + sl := TStringList.Create; + try + {$IFDEF DEBUG} + sl.Text := GetDebugText; + sl.SaveToFile('dbg'); + sl.Clear; + {$ENDIF} + + i := 0; + line := ''; + f := [gfPrevEmpty]; + ProgressBlock(0); + TrimList; + result := sl.Text; + finally + FreeAndNil(sl); + end; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +procedure TengGenCodeArgs.TCodeStackItem.SplitCurrentCommand(const aItem: TCodeStackItem); +var + HasCode: Boolean; + ci: TCodeItem; + + function IsEndToken(const ci: TCodeItem): Boolean; + begin + result := (ci is TCodeItemToken) and ((ci as TCodeItemToken).TokenType = ttEnd) + end; + +begin + fItems.OwnsObjects := false; + aItem.fItems.OwnsObjects := false; + try + //move all items before TCodeItemCommandEnd to aItem + while (fItems.Count > 1) and not (fItems[fItems.Count-1] is TCodeItemCommandEnd) do begin + ci := fItems.PopLast; + if (trim(ci.GetText) <> '') then + HasCode := true; + if IsEndToken(ci) then + HasCode := false; + aItem.fItems.Insert(1, ci); + end; + + // if ther is no code between last CommandEnd and Last End-Token, move back to last end Token + if not HasCode then begin + while not IsEndToken(aItem.fItems[1]) do begin + fItems.PushLast(aItem.fItems[1]); + aItem.fItems.Delete(1); + end; + fItems.PushLast(aItem.fItems[1]); + aItem.fItems.Delete(1); + end; + finally + aItem.fItems.OwnsObjects := true; + fItems.OwnsObjects := true; + end; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengGenCodeArgs.TCodeStackItem.Merge(const aItem: TCodeStackItem; aIndex: Integer): Integer; +begin + if (aIndex <= 0) then + aIndex := 1; // do not go below start item + result := aIndex + aItem.fItems.Count - 1; + aItem.fItems.OwnsObjects := false; + try + while (aItem.fItems.Count > 1) do begin + fItems.Insert(aIndex, aItem.fItems[aItem.fItems.Count-1]); + aItem.fItems.Delete(aItem.fItems.Count-1); + end; + finally + aItem.fItems.OwnsObjects := true; + end; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +procedure TengGenCodeArgs.TCodeStackItem.AddText(const aText: String); +begin + fItems.Add(TCodeItemText.Create(aText)); + if (Trim(aText) <> '') then + Exclude(fFlags, cfIgnoreNextSemicolon); +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +procedure TengGenCodeArgs.TCodeStackItem.AddCommandEnd(const aToken: String); +begin + if (cfIgnoreNextSemicolon in fFlags) then begin + if (aToken <> '') then + Exclude(fFlags, cfIgnoreNextSemicolon); + if (aToken = ';') then + exit; + end; + fItems.Add(TCodeItemCommandEnd.Create(aToken)); +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +procedure TengGenCodeArgs.TCodeStackItem.AddToken(const aTokenType: TTokenType; const aLevel: Integer); +begin + fItems.Add(TCodeItemToken.Create(aTokenType, aLevel)); +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +procedure TengGenCodeArgs.TCodeStackItem.AddLineEnd; +begin + fItems.Add(TCodeItemLineBreak.Create); +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengGenCodeArgs.TCodeStackItem.GetMinLineOffset: Integer; + + procedure CalcOffset(const aLine: String); + var i, len: Integer; + begin + if (Trim(aLine) = '') then + exit; + len := Length(aLine); + i := 1; + while (i <= len) and (aLine[i] in WHITESPACES) do + inc(i); + if (i < result) then + result := i-1; + end; + +var + item: TCodeItem; + line: String; +begin + result := High(Integer); + line := ''; + for item in fItems do begin + if (item is TCodeItemLineBreak) then begin + CalcOffset(line); + line := ''; + end else + line := line + item.GetText; + end; + CalcOffset(line); + if (result = High(Integer)) then + result := -1; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +procedure TengGenCodeArgs.TCodeStackItem.IgnoreNextSemicolon; +begin + Include(fFlags, cfIgnoreNextSemicolon); +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +procedure TengGenCodeArgs.TCodeStackItem.ReplaceIdents(const aOld, aNew: TStrings); +var + rx: TRegExpr; + i: Integer; + itm: TCodeItem; +begin + if (aOld.Count <> aNew.Count) then + raise EengInternal.Create('old and new idents must have the same size'); + rx := TRegExpr.Create; + try + for i := 0 to aOld.Count-1 do begin + rx.Expression := '([^A-z0-9_]+|^)' + aOld[i] + '([^A-z0-9_]+|$)'; + for itm in fItems do + if (itm is TCodeItemText) then + with (itm as TCodeItemText) do + Text := rx.Replace(Text, '$1' + aNew[i] + '$2', true); + end; + finally + FreeAndNil(rx); + end; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +procedure TengGenCodeArgs.TCodeStackItem.ReplaceReturns(const aItem: TCodeStackItem; const aRetType, aFuncName: String; const aCntr: Integer); +var + s: String; + i, j, retCount, first, firstOffset: Integer; + item: TCodeItem; + rx: TRegExpr; +begin + rx := TRegExpr.Create; + try + rx.Expression := '([^A-z0-9_]+|^)return([^A-z0-9_]+|$)'; + + //find number of "return" in code and first item with not only whitespaces + retCount := 0; + first := 0; + for i := 0 to fItems.Count-1 do begin + item := fItems[i]; + s := item.GetText; + if (item is TCodeItemText) and (Trim(s) <> '') and (first = 0) then begin + first := i; + firstOffset := Length(s) - Length(TrimLeft(s)); + end; + if (rx.Exec(s)) then + inc(retCount); + end; + + //more than one return + if (retCount > 1) then begin + //TrimEnd; + s := aFuncName + Format('_ret%.3d', [aCntr]); + fItems.Insert(first, TCodeItemText.Create(StringOfChar(' ', firstOffset) + aRetType + ' ' + s)); + fItems.Insert(first + 1, TCodeItemCommandEnd.Create(';')); + fItems.Insert(first + 2, TCodeItemLineBreak.Create); + + for item in fItems do + if (item is TCodeItemText) then + with (item as TCodeItemText) do + Text := rx.Replace(Text, '$1' + s + ' =$2', true); + + Merge(aItem, fItems.Count); + AddText(s); + + // only one return + end else begin + i := fItems.Count-1; + while (i > 0) do begin + item := fItems[i]; + if (item is TCodeItemText) then + with (item as TCodeItemText) do begin + if (rx.Exec(Text)) then begin + // replace + fItems.Insert(i, TCodeItemText.Create(rx.Match[1])); + Text := rx.Replace(Text, '(', true); + + // replace last CommandEnd with ')' + j := fItems.Count-1; + while (j > i) and not (fItems[j] is TCodeItemCommandEnd) do + dec(j); + if (j > i) then begin + fItems.Delete(j); + fItems.Insert(j, TCodeItemText.Create(')')); + fItems.Insert(j+1, TCodeItemToken.Create(ttEnd)); + end; + + // merge + i := fItems.IndexOf(item); + fItems.Insert(i, TCodeItemToken.Create(ttBegin)); + inc(i); + i := Merge(aItem, i); + exit; + end; + end; + dec(i); + end; + + raise EengInternal.Create('no return found in current code'); + end; + finally + FreeAndNil(rx); + end; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +constructor TengGenCodeArgs.TCodeStackItem.Create; +begin + inherited Create; + fItems := TCodeItemList.Create(true); + fItems.Add(TCodeItemStart.Create); +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +destructor TengGenCodeArgs.TCodeStackItem.Destroy; +begin + FreeAndNil(fItems); + inherited Destroy; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//TengGenCodeArgs.TProcWrapper////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +constructor TengGenCodeArgs.TProcWrapper.Create; +begin + Proc := nil; + Code := nil; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +destructor TengGenCodeArgs.TProcWrapper.Destroy; +begin + FreeAndNil(Code); + Proc := nil; + inherited Destroy; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//TengGenCodeArgs/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengGenCodeArgs.GetFlags: TengGenCodeFlags; +begin + if (fFlags.Count > 0) then + result := fFlags.Last + else + result := []; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengGenCodeArgs.GetText: String; +begin + result := fCode.Last.GetText; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengGenCodeArgs.GetCode: TCodeStackItem; +begin + result := fCode.Last; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengGenCodeArgs.GetProcParams: TStrings; +begin + result := fProcParams.Last; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +procedure TengGenCodeArgs.PushCode; +begin + fCode.PushLast(TCodeStackItem.Create); +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +procedure TengGenCodeArgs.InsertCode(const aCodeStackItem: TCodeStackItem); +begin + fCode.PushLast(aCodeStackItem); +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengGenCodeArgs.PushCurrentCommand: TCodeStackItem; +begin + result := TCodeStackItem.Create; + fCommands.PushLast(result); + Code.SplitCurrentCommand(result); +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +procedure TengGenCodeArgs.PushFlags(const aFlags: TengGenCodeFlags); +begin + fFlags.PushLast(aFlags); +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +procedure TengGenCodeArgs.PushProcParams(const aParams: TStrings); +begin + fProcParams.PushLast(aParams); +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +procedure TengGenCodeArgs.PopCode(const aFlags: TPopCodeFlags); +var + csi: TCodeStackItem; +begin + csi := fCode.PopLast(false); + try + if not csi.Empty and (aFlags * [pcfAppend, pcfPrepend] <> []) then begin + if (pcfPrepend in aFlags) then begin + if (pcfAddEmptyLine in aFlags) then + csi.AddLineEnd; + Code.Merge(csi, 1); + end else begin + if (pcfAddEmptyLine in aFlags) then + Code.AddLineEnd; + Code.Merge(csi, Code.Items.Count); + end; + end; + finally + FreeAndNil(csi); + end; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengGenCodeArgs.ExtractCode: TCodeStackItem; +begin + result := fCode.PopLast(false); +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +procedure TengGenCodeArgs.PopCurrentCommand(const aRetType, aFuncName: String); +var + csi: TCodeStackItem; +begin + csi := fCommands.PopLast(false); + try + Code.ReplaceReturns(csi, aRetType, aFuncName, fInlineRetCounter); + inc(fInlineRetCounter); + finally + FreeAndNil(csi); + end; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +procedure TengGenCodeArgs.PopFlags; +begin + fFlags.PopLast(true); +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +procedure TengGenCodeArgs.PopProcParams; +begin + fProcParams.PopLast; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +procedure TengGenCodeArgs.AddProcedure(const aProc: TengShaderPartProc); + + function FindProc(const aName: String): TProcWrapper; + begin + for result in fProcedures do + if (result.Proc.Name = aName) then + exit; + result := nil; + end; + +var + w: TProcWrapper; +begin + w := FindProc(aProc.Name); + if Assigned(w) then begin + if (aProc <> w.Proc) then + raise EengDuplicateIdentifier.Create(w.Proc.Name, aProc, w.Proc); + exit; + end; + + w := TProcWrapper.Create; + w.Proc := aProc; + fProcedures.Add(w); + + PushCode; // push current code + PushFlags(Flags + [gcfGenProcedure]); + try + w.Proc.GenCodeIntern(self); + finally + w.Code := ExtractCode; // pop procedure code and store it in wrapper + PopFlags; + end; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +procedure TengGenCodeArgs.AddCodeProperty(const aProp: TengShaderPartCodeProperty); +var + p: TengShaderPartCodeProperty; +begin + p := fProperties[aProp.Name]; + if Assigned(p) then begin + if not p.IsEquals(aProp) then + raise EengDuplicateIdentifier.Create(p.Name, aProp, p); + exit; + end; + fProperties.Add(aProp.Name, aProp); +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +procedure TengGenCodeArgs.AddMeta(const aMeta: IengMetaData); +begin + fShaderCode.AddMeta(aMeta); +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengGenCodeArgs.HasCodeProperty(const aName: String): Boolean; +begin + result := fProperties.Contains(aName); +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +procedure TengGenCodeArgs.GenProcedureCode(const aAppend: Boolean); +var + w: TProcWrapper; +begin + for w in fProcedures do begin + if not Assigned(w.Code) then + continue; + + InsertCode(w.Code); // push stored code ... + w.Code := nil; + PopCode([pcfPrepend, pcfAddEmptyLine]); // and pop it back to the code tree (this will merge the code) + end; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +procedure TengGenCodeArgs.GenCodePropertyCode(const aTypes: array of CengShaderPart); +var + p: TengShaderPartCodeProperty; + m: TCodePropertyMap; +begin + PushCode; + PushFlags(Flags + [gcfGenCodeProp]); + m := TCodePropertyMap.Create(false); + try + fMaxPropNameLen := 0; + for p in fProperties do + if CheckType(p, aTypes) then begin + fMaxPropNameLen := Max(fMaxPropNameLen, Length(p.PropType)); + m.Add(p.PropType+p.Name, p); + end; + for p in m do begin + p.GenCodeIntern(self); + Code.AddLineEnd; + end; + finally + FreeAndNil(m); + PopCode([pcfPrepend, pcfAddEmptyLine]); + PopFlags; + end; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +procedure TengGenCodeArgs.GenMetaCode; +var + m: IengMetaData; + s: String; + vCompat: Boolean; + vMax: Integer; + layouts: TStringList; +begin + vCompat := false; + vMax := 0; + PushCode; + layouts := TStringList.Create; + try + for m in fShaderCode.MetaList do begin + case m.MetaType of + metaVersion: begin + if (m.Values[0] = VERSION_EXTRA_COMPAT) then + vCompat := true + else + vMax := Max(vMax, StrToInt(m.Values[0])); + if (m.Count > 1) and (m.Values[1] = VERSION_EXTRA_COMPAT) then + vCompat := true; + end; + + metaExtension: begin + Code.AddText(format('#extension %s : %s', [m.Values[0], m.Values[1]])); + Code.AddLineEnd; + end; + + metaLayout: begin + layouts.Add(format('layout%s;', [m.Values[0]])); + end; + end; + end; + + if (vMax >= LAYOUT_MIN_VERSION) then + for s in layouts do begin + Code.AddText(s); + Code.AddLineEnd; + end; + + if (vMax > 0) then begin + PushCode; + try + Code.AddText('#version ' + IntToStr(vMax)); + if vCompat then + Code.AddText(' ' + VERSION_EXTRA_COMPAT); + Code.AddLineEnd; + finally + PopCode([pcfPrepend]); + end; + end; + finally + PopCode([pcfPrepend, pcfAddEmptyLine]); + FreeAndNil(layouts); + end; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +constructor TengGenCodeArgs.Create(const aShaderCode: TengShaderCodeIntern; const aRoot: TengShaderPartScope); +begin + inherited Create; + fRoot := aRoot; + fProcedures := TProcedureList.Create(true); + fProperties := TCodePropertyMap.Create(false); + fFlags := TGenCodeFlagsStack.Create(true); + fCode := TCodeStack.Create(true); + fCommands := TCodeStack.Create(true); + fProcParams := TProcParamStack.Create(false); + fShaderCode := aShaderCode; + PushCode; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +destructor TengGenCodeArgs.Destroy; +begin + fShaderCode.Text := GetText; + FreeAndNil(fProcParams); + FreeAndNil(fCommands); + FreeAndNil(fCode); + FreeAndNil(fFlags); + FreeAndNil(fProperties); + FreeAndNil(fProcedures); + inherited Destroy; +end; + + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//DEBUG///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +{$IFDEF DEBUG} +procedure SaveAsXMindXml(const aShaderPart: TengShaderPart; const aDirectory: String); +var + linkStr: String; + + function Escape(const aText: String): String; + begin + result := StringReplace(aText, '''', '' { ' }, [rfReplaceAll]); + result := StringReplace(result, '"', '"', [rfReplaceAll]); + result := StringReplace(result, '&', '&', [rfReplaceAll]); + result := StringReplace(result, '<', '<', [rfReplaceAll]); + result := StringReplace(result, '>', '>', [rfReplaceAll]); + end; + + function MakeID(const aItem: TengShaderPart): String; + begin + result := Format('%p', [Pointer(aItem)]); + end; + + function GetTitle(const aItem: TengShaderPart): String; + var + i: Integer; + s: String; + begin + // TengShaderPartIf + if (aItem.Parent is TengShaderPartIf) then begin + if (aItem.Parent.Children[0] = aItem) then + result := '- TRUE -' + else if (aItem.Parent.Count > 1) and (aItem.Parent.Children[1] = aItem) then + result := '- FALSE -' + else + result := '- UNKNOWN -'; + + // TengShaderPartClass + end else if (aItem is TengShaderPartClass) then + result := aItem.GetTokenName + ' ' + (aItem as TengShaderPartClass).Name + + // TengShaderPartInclude + else if (aItem is TengShaderPartInclude) then + result := aItem.GetTokenName + + // TengShaderFile + else if (aItem is TengShaderFile) then + result := ExtractFileName((aItem as TengShaderFile).Filename) + + // TengShaderPartProperty + else if (aItem is TengShaderPartProperty) then with (aItem as TengShaderPartProperty) do + result := aItem.GetTokenName + ' ' + Name + + // TengShaderPartCodeProperty + else if (aItem is TengShaderPartCodeProperty) then with (aItem as TengShaderPartCodeProperty) do + result := aItem.GetTokenName + ' ' + fType + ' ' + fName + + // TengShaderPartCall + else if (aItem is TengShaderPartCall) then with (aItem as TengShaderPartCall) do + result := aItem.GetTokenName + ' ' + fName + + // TengShaderPartProc + else if (aItem is TengShaderPartProc) then with (aItem as TengShaderPartProc) do + result := aItem.GetTokenName + ' ' + fName + + // TengShaderPartMeta + else if (aItem is TengShaderPartMeta) then with (aItem as TengShaderPartMeta) do begin + result := aItem.GetTokenName + ' ' + fMetaData.Name; + for i := 0 to fMetaData.Count-1 do + result := result + ' ' + fMetaData[i]; + + // TengShaderPartMeta + end else if (aItem is TengShaderPartIf) then with (aItem as TengShaderPartIf) do + result := aItem.GetTokenName + ' ' + fExpression.GetText + + // TengShaderPartEcho + else if (aItem is TengShaderPartEcho) then with (aItem as TengShaderPartEcho) do + result := aItem.GetTokenName + ' ' + fName + + // TengShaderPartMessage + else if (aItem is TengShaderPartMessage) then with (aItem as TengShaderPartMessage) do + result := aItem.GetTokenName + ' ' + fMessage + + else if (aItem is TengShaderPartInherited) then with (aItem as TengShaderPartInherited) do begin + result := aItem.GetTokenName + ' ' + fInheritedName; + for s in fParameters do + result := ' ' + s; + + end else + result := 'TODO: ' + aItem.GetTokenName; + result := Escape(result); + end; + + function GetDesc(const aItem: TengShaderPart): String; + begin + result := ''; //'Your Description Here'; + end; + + function MakeLinks(const aItem: TengShaderPartScope): String; + var + p: TengShaderPart; + begin + result := ''; + for p in aItem.fInherited do // red + result := result + ''; + for p in aItem.fChildScopes do // green + result := result + ''; + for p in aItem.fMappedParts do // blue + result := result + ''; + end; + + function CreateCodeItem(var aCode: String): String; + var + sl: TStringList; + begin + sl := TStringList.Create; + try + sl.Text := aCode; + while (sl.Count > 0) and (Trim(sl[0]) = '') do + sl.Delete(0); + while (sl.Count > 0) and (Trim(sl[sl.Count-1]) = '') do + sl.Delete(sl.Count-1); + if (sl.Count > 0) then + result := '- CODE -' + + '' + Escape(sl.Text) + '' + else + result := ''; + aCode := ''; + finally + FreeAndNil(sl); + end; + end; + + function DoItem(const aItem: TengShaderPart; const aIsRoot: Boolean = false): String; + var + p: TengShaderPart; + code: String; + begin + code := ''; + result := '' + GetTitle(aItem) + '' + GetDesc(aItem); + + if (aItem is TengShaderPartScope) then + linkStr := linkStr + MakeLinks(aItem as TengShaderPartScope); + + if (aItem.Count > 0) then begin + result := result + ''; + for p in aItem do begin + if (p is TengShaderPartCode) then + code := code + (p as TengShaderPartCode).Text + else if (p is TengShaderPartCommandEnd) then + code := code + (p as TengShaderPartCommandEnd).fToken + else if (p is TengShaderPartLineBreak) then + code := code + (p as TengShaderPartLineBreak).Text + else + result := result + CreateCodeItem(code) + DoItem(p); + end; + result := result + CreateCodeItem(code) + ''; + end; + result := result + ''; + end; + +var + fs: TFileStream; + s: String; + len: Integer; +begin + linkStr := ''; + s := '' + + DoItem(aShaderPart, true) + 'glslPreCompiler Code Tree'; + if (linkStr <> '') then + s := s + '' + linkStr + ''; + s := s + ''; + len := Length(s); + if (len > 0) then begin + fs := TFileStream.Create(IncludeTrailingPathDelimiter(aDirectory) + 'content.xml', fmCreate); + try + fs.Write(s[1], len); + finally + FreeAndNil(fs); + end; + + s := '' + + '' + + '' + + '' + + '' + + ''; + len := Length(s); + fs := TFileStream.Create(IncludeTrailingPathDelimiter(aDirectory) + 'styles.xml', fmCreate); + try + fs.Write(s[1], len); + finally + FreeAndNil(fs); + end; + end; +end; +{$ENDIF} + + +end. + diff --git a/uengShaderFile.pas b/uengShaderFile.pas new file mode 100644 index 0000000..1acb50c --- /dev/null +++ b/uengShaderFile.pas @@ -0,0 +1,96 @@ +unit uengShaderFile; + +{ Package: SpaceEngine + Prefix: eng - ENGine + Beschreibung: stellt Klassen zum laden von Shader-Datein zur Verfügung + beim laden des Codes wird gleichzeitig die Präprozessor-Sprache ausgewertet } + +{$mode objfpc}{$H+} +{$I uengShaderFile.inc} + +interface + +uses + Classes, sysutils, + uengShaderCodeGenerator, uengShaderFileParser, uengShaderFileTypes + +{$IFDEF USE_BITSPACE_UTILS} + , uutlSerialization +{$ENDIF} + ; + +type +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + TengShaderFile = class(TengShaderCodeGenerator) + { Code Loading & Storage } + private + fFilename: String; + fFileReader: IutlFileReader; + fFileWriter: IutlFileWriter; + protected { virtual getter } + function GetFilename: String; override; + function GetFileReader: IengShaderFileReader; override; + function GetFileWriter: IengShaderFileWriter; override; + public { general methods } + procedure LoadCode(const aFilename: String; const aFileReader: IengShaderFileReader = nil); + end; + +implementation + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//TengShaderFile//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengShaderFile.GetFilename: String; +begin + result := fFilename; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengShaderFile.GetFileReader: IengShaderFileReader; +begin + result := fFileReader; + if not Assigned(result) and Assigned(Parent) then + result := Parent.FileReader; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengShaderFile.GetFileWriter: IengShaderFileWriter; +begin + result := fFileWriter; + if not Assigned(result) and Assigned(Parent) then + result := Parent.FileWriter; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +procedure TengShaderFile.LoadCode(const aFilename: String; const aFileReader: IengShaderFileReader); +var + args: TengParseArgs; + token: String; + ms: TMemoryStream; +begin + fFileReader := aFileReader; + if not Assigned(fFileReader) then + fFileReader := GetFileReader; + if not Assigned(fFileReader) then + fFileReader := TengShaderFileReader.Create; + ms := TMemoryStream.Create; + try + Clear; + if not fFileReader.LoadStream(aFilename, ms) then + raise EengShaderPart.Create('unable to open file: ' + aFilename, Line, Col, Filename); + ms.Position := 0; + args := TengParseArgs.Create(ms, Filename); + try + token := ParseText(args); + if (token <> '') then with args do + raise EengShaderPart.Create('unknown token ''' + token + '''', Line, Col, Filename); + finally + FreeAndNil(args); + end; + finally + fFileReader := nil; + end; +end; + +end. + diff --git a/uengShaderFileConstants.pas b/uengShaderFileConstants.pas new file mode 100644 index 0000000..adf56eb --- /dev/null +++ b/uengShaderFileConstants.pas @@ -0,0 +1,93 @@ +unit uengShaderFileConstants; + +{$mode objfpc}{$H+} +{$I uengShaderFile.inc} + +interface + +const +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + PRECOMPILER_STATEMENT_BEGIN = '{'; + PRECOMPILER_STATEMENT_END = '}'; + + TOKEN_CHAR_BEGIN = '{'; + TOKEN_CHAR_END = '}'; + TOKEN_CHAR_QUOTE = ''''; + TOKEN_CHAR_IDENT = '$'; + TOKEN_CHAR_COMMENT = '.'; + TOKEN_CHAR_COMMANT_END = ';'; + TOKEN_CHAR_SCOPE_BEGIN = '{'; + TOKEN_CHAR_SCOPE_END = '}'; + + UNKNOWN_FILENAME = 'unknown file'; + TOKEN_LINE_BREAK = sLineBreak; + TOKEN_NONE = '[none]'; + + TOKEN_CLASS = TOKEN_CHAR_IDENT + 'CLASS'; //{$CLASS PhongLight $EXTENDS Normal Glow} + TOKEN_EXTENDS = TOKEN_CHAR_IDENT + 'EXTENDS'; + TOKEN_INHERITED = TOKEN_CHAR_IDENT + 'INHERITED'; //{$INHERITED} {$INHERITED BaseClass} + + TOKEN_INCLUDE = TOKEN_CHAR_IDENT + 'INCLUDE'; //{$INCLUDE 'Normal.frag'} + + TOKEN_META = TOKEN_CHAR_IDENT + 'META'; //{$META 'Fuu' 'Bar'} + TOKEN_VERSION = TOKEN_CHAR_IDENT + 'VERSION'; //{$META $VERSION 'version'} + TOKEN_EXTENSION = TOKEN_CHAR_IDENT + 'EXTENSION'; //{$META $EXTENSION 'GL_ARB_geometry_shader4' 'enable'} + TOKEN_LAYOUT = TOKEN_CHAR_IDENT + 'LAYOUT'; //{$META $LAYOUT '(line_strip, max_vertices = 6) out'} + + TOKEN_PROPERTY = TOKEN_CHAR_IDENT + 'PROPERTY'; //{$PROPERTY InvertRoughmap 'false'} + TOKEN_DEFINE = TOKEN_CHAR_IDENT + 'DEFINE'; //{$DEFINE RENDER_FACE_FRONT '0'} + TOKEN_ECHO = TOKEN_CHAR_IDENT + 'ECHO'; //{$ECHO InvertRoughmap} + + TOKEN_VAR = TOKEN_CHAR_IDENT + 'VAR'; //{$VAR 'float' 'refractivity' '0.0'} + TOKEN_VARYING = TOKEN_CHAR_IDENT + 'VARYING'; //{$VARYING 'vec3' 'vVertex'} + TOKEN_UNIFORM = TOKEN_CHAR_IDENT + 'UNIFORM'; //{$UNIFORM 'sampler2D' 'uShadowMap'} + + TOKEN_CALL = TOKEN_CHAR_IDENT + 'CALL'; //{$CALL CalcLight} + TOKEN_PROC = TOKEN_CHAR_IDENT + 'PROC'; //{$PROC CalcLight} Code... {$END} + TOKEN_FUNC = TOKEN_CHAR_IDENT + 'FUNC'; //{$FUND 'float' 'ShadowPoisson' 'vec2' 'shadowMapST' 'float' 'receiver'} Code... {$END} + TOKEN_MAIN = TOKEN_CHAR_IDENT + 'MAIN'; + TOKEN_INLINE = TOKEN_CHAR_IDENT + 'INLINE'; //{$PROC CalcLight $INLINE} Code... {$END} + + TOKEN_IF = TOKEN_CHAR_IDENT + 'IF'; //{$IF PhongLight = '0'} Code ... {$END} + TOKEN_ELIF = TOKEN_CHAR_IDENT + 'ELIF'; + TOKEN_ELSE = TOKEN_CHAR_IDENT + 'ELSE'; + TOKEN_END = TOKEN_CHAR_IDENT + 'END'; + + TOKEN_MESSAGE = TOKEN_CHAR_IDENT + 'MESSAGE'; //{$MESSAGE 'message'} + TOKEN_WARNING = TOKEN_CHAR_IDENT + 'WARNING'; //{$WARNING 'message'} + TOKEN_ERROR = TOKEN_CHAR_IDENT + 'ERROR'; //{$ERROR 'message'} + + TOKEN_OP_LOGICAL_NOT = TOKEN_CHAR_IDENT + 'NOT'; //{$IF $NOT test} + TOKEN_OP_LOGICAL_OR = TOKEN_CHAR_IDENT + 'OR'; //{$IF test1 $OR test2} + TOKEN_OP_LOGICAL_AND = TOKEN_CHAR_IDENT + 'AND'; //{$IF test1 $AND test2} + TOKEN_OP_LOGICAL_XOR = TOKEN_CHAR_IDENT + 'XOR'; //{$IF test1 $XOR test2} + TOKEN_OP_DEFINED = TOKEN_CHAR_IDENT + 'DEFINED'; //{$IF $DEFINED test2} + TOKEN_OP_SET = TOKEN_CHAR_IDENT + 'SET'; //{$IF $SET vVertex} + TOKEN_OP_ADD = '+'; //{$IF test1 + test2} + TOKEN_OP_SUBTRACT = '-'; //{$IF test1 - test2} + TOKEN_OP_MULTIPLY = '*'; //{$IF test1 * test2} + TOKEN_OP_DIVIDE = '/'; //{$IF test1 / test2} + TOKEN_OP_EQUALS = '='; //{$IF test1 = test2} + TOKEN_OP_LESSER = '<'; //{$IF test1 < test2} + TOKEN_OP_GREATER = '>'; //{$IF test1 > test2} + TOKEN_OP_LEQUALS = '<='; //{$IF test1 <= test2} + TOKEN_OP_GEQUALS = '>='; //{$IF test1 >= test2} + TOKEN_OP_UNEQUALS = '<>'; //{$IF test1 <> test2} + TOKEN_OP_BINARY_OR = '|'; //{$IF test1 | test2} + TOKEN_OP_BINARY_AND = '&'; //{$IF test1 & test2} + TOKEN_OP_BINARY_XOR = '^'; //{$IF test1 ^ test2} + TOKEN_OP_BINARY_NOT = '!'; //{$IF !test1} + TOKEN_OP_GROUP_BEGIN = '('; //{$IF (test1 $OR test2) >= '0'} + TOKEN_OP_GROUP_END = ')'; + + VALID_IDENT_CHARS = ['A'..'Z', 'a'..'z', '0'..'9', '_']; + VALID_TOKEN_CHARS = ['$'] + VALID_IDENT_CHARS; + TOKEN_SPLIT_CHARS = [' ', #9, TOKEN_OP_GROUP_BEGIN, TOKEN_OP_GROUP_END]; + COMMAND_END_TOKENS = [TOKEN_CHAR_COMMANT_END, TOKEN_CHAR_SCOPE_BEGIN, TOKEN_CHAR_SCOPE_END]; + + VERSION_EXTRA_COMPAT = 'compatibility'; //{$META $VERSION 'compatibility'} + +implementation + +end. + diff --git a/uengShaderFileExpression.pas b/uengShaderFileExpression.pas new file mode 100644 index 0000000..78f5a57 --- /dev/null +++ b/uengShaderFileExpression.pas @@ -0,0 +1,630 @@ +unit uengShaderFileExpression; + +{$mode objfpc}{$H+} +{$I uengShaderFile.inc} + +interface + +uses + Classes, SysUtils, variants, + uengShaderFileParser; + +type +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + TengExpressionItem = class(TObject) + private + fLine: Integer; + fCol: Integer; + fFilename: String; + public + property Line: Integer read fLine; + property Col: Integer read fCol; + property Filename: String read fFilename; + + function GetText: String; virtual; + function GetValue: Variant; virtual; + constructor Create(const aLine, aCol: Integer; const aFilename: String); + end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + TengExpressionValue = class(TengExpressionItem) + private + fValue: Variant; + public + function GetText: String; override; + function GetValue: Variant; override; + constructor Create(const aValue: Variant; const aLine, aCol: Integer; const aFilename: String); + end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + TengExpressionVariable = class(TengExpressionItem) + private + fName: String; + public + function GetText: String; override; + function GetValue: Variant; override; + constructor Create(const aName: String; const aLine, aCol: Integer; const aFilename: String); + end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + TengExpressionGroup = class(TengExpressionItem) + private + fChild: TengExpressionItem; + public + property Child: TengExpressionItem read fChild write fChild; + function GetText: String; override; + function GetValue: Variant; override; + constructor Create(const aChild: TengExpressionItem; const aLine, aCol: Integer; const aFilename: String); + destructor Destroy; override; + end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + TengExpressionUnaryOperator = ( + opBinaryNot, + opLogicalNot, + opDefined, + opSet + ); + TengExpressionUnaryOperation = class(TengExpressionItem) + private + fChild: TengExpressionItem; + fUnaryOp: TengExpressionUnaryOperator; + public + property Child: TengExpressionItem read fChild write fChild; + property UnaryOp: TengExpressionUnaryOperator read fUnaryOp; + + function GetText: String; override; + function GetValue: Variant; override; + + constructor Create(const aUnaryOp: TengExpressionUnaryOperator; const aLine, aCol: Integer; const aFilename: String); + destructor Destroy; override; + end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + TengExpressionBinaryOperator = ( //order of elements in this enum is also the weight of the operators + opBinaryOr, opBinaryAnd, opBinaryXor, // binary + opMultiply, opDivide, opAdd, opSubtract, // arithmetic + opLogicalOr, opLogicalAnd, opLogicalXor, // logical + opEquals, opLesser, opGreater, opLEquals, opGEquals, opUnequals // comparison + ); + TengExpressionBinaryOperation = class(TengExpressionItem) + private + fFirst: TengExpressionItem; + fSecond: TengExpressionItem; + fBinaryOp: TengExpressionBinaryOperator; + public + property First: TengExpressionItem read fFirst write fFirst; + property Second: TengExpressionItem read fSecond write fSecond; + property BinaryOp: TengExpressionBinaryOperator read fBinaryOp; + + function GetText: String; override; + function GetValue: Variant; override; + + constructor Create(const aOperator: TengExpressionBinaryOperator; const aLine, aCol: Integer; const aFilename: String); + destructor Destroy; override; + end; + + function ParseExpression(const aParam: TengTokenParameterList; aIndex: Integer): TengExpressionItem; + +implementation + +uses + uengShaderFileConstants, uengShaderFileTypes, uengShaderFileHelper + {$IFDEF USE_BITSPACE_UTILS} + , uutlGenerics + {$ELSE} + , fgl + {$ENDIF} + ; + +const + EXPRESSION_UNARY_OPERATIONS: array[TengExpressionUnaryOperator] of String = ( + TOKEN_OP_BINARY_NOT, //opBinaryNot + TOKEN_OP_LOGICAL_NOT, //opLogicalNot + TOKEN_OP_DEFINED, //opDefined + TOKEN_OP_SET //opSet + ); + + EXPRESSION_BINARY_OPERATIONS: array[TengExpressionBinaryOperator] of String = ( + TOKEN_OP_BINARY_OR, //opBinaryOr + TOKEN_OP_BINARY_AND, //opBinaryAnd + TOKEN_OP_BINARY_XOR, //opBinaryXor + + TOKEN_OP_MULTIPLY, //opMultiply + TOKEN_OP_DIVIDE, //opDivide + TOKEN_OP_ADD, //opAdd + TOKEN_OP_SUBTRACT, //opSubtract + + TOKEN_OP_LOGICAL_OR, //opLogicalOr + TOKEN_OP_LOGICAL_AND, //opLogicalAnd + TOKEN_OP_LOGICAL_XOR, //opLogicalXor + + TOKEN_OP_EQUALS, //opEquals + TOKEN_OP_LESSER, //opLesser + TOKEN_OP_GREATER, //opGreater + TOKEN_OP_LEQUALS, //opLEquals + TOKEN_OP_GEQUALS, //opGEquals + TOKEN_OP_UNEQUALS //opUnequals, + ); + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//TengExpressionItem//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengExpressionItem.GetText: String; +begin + result := ''; // DUMMY +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengExpressionItem.GetValue: Variant; +begin + result := Unassigned; // DUMMY +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +constructor TengExpressionItem.Create(const aLine, aCol: Integer; const aFilename: String); +begin + inherited Create; + fLine := aLine; + fCol := aCol; + fFilename := aFilename; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//TengExpressionValue/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengExpressionValue.GetText: String; +begin + result := TOKEN_CHAR_QUOTE + fValue + TOKEN_CHAR_QUOTE; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengExpressionValue.GetValue: Variant; +begin + result := fValue; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +constructor TengExpressionValue.Create(const aValue: Variant; const aLine, aCol: Integer; const aFilename: String); +begin + inherited Create(aLine, aCol, aFilename); + fValue := aValue; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//TengExpressionVariable//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengExpressionVariable.GetText: String; +begin + result := fName; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengExpressionVariable.GetValue: Variant; +begin + result := Unassigned; // TODO +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +constructor TengExpressionVariable.Create(const aName: String; const aLine, aCol: Integer; const aFilename: String); +begin + inherited Create(aLine, aCol, aFilename); + fName := aName; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +///TengExpressionGroup////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengExpressionGroup.GetText: String; +begin + if Assigned(fChild) + then result := TOKEN_OP_GROUP_BEGIN + fChild.GetText + TOKEN_OP_GROUP_END + else result := ''; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengExpressionGroup.GetValue: Variant; +begin + if Assigned(fChild) + then result := fChild.GetValue + else result := Unassigned; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +constructor TengExpressionGroup.Create(const aChild: TengExpressionItem; const aLine, aCol: Integer; const aFilename: String); +begin + inherited Create(aLine, aCol, aFilename); + fChild := aChild; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +destructor TengExpressionGroup.Destroy; +begin + FreeAndNil(fChild); + inherited Destroy; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//TengExpressionUnaryOperation////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengExpressionUnaryOperation.GetText: String; +begin + if not Assigned(fChild) then + EengExpression.Create('no child assigned', Line, Col, Filename); + result := + {$IFDEF EXPRESSION_ADD_BRACKET}TOKEN_OP_GROUP_BEGIN+{$ENDIF} + EXPRESSION_UNARY_OPERATIONS[fUnaryOp] + ' ' + fChild.GetText + {$IFDEF EXPRESSION_ADD_BRACKET}+TOKEN_OP_GROUP_END{$ENDIF}; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengExpressionUnaryOperation.GetValue: Variant; +var + v: Variant; +begin + if not Assigned(fChild) then + raise EengExpression.Create('no child assigned', Line, Col, Filename); + try + case fUnaryOp of + + opBinaryNot: begin + v := fChild.GetValue; + result := not Integer(v); + end; + + opLogicalNot: begin + v := fChild.GetValue; + result := not Boolean(v); + end; + + opDefined: begin + // TODO + end; + + opSet: begin + // TODO + end; + + else + result := inherited GetValue; + end; + except + on ex: Exception do + raise EengInvalidParamter.Create( + ex.Message + '("' + GetText + '" ==> ' + + EXPRESSION_UNARY_OPERATIONS[fUnaryOp] + ' ' + v + '")', + Line, Col, Filename); + end; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +constructor TengExpressionUnaryOperation.Create(const aUnaryOp: TengExpressionUnaryOperator; const aLine, aCol: Integer; const aFilename: String); +begin + inherited Create(aLine, aCol, aFilename); + fChild := nil; + fUnaryOp := aUnaryOp; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +destructor TengExpressionUnaryOperation.Destroy; +begin + FreeAndNil(fChild); + inherited Destroy; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//TengExpressionBinaryOperation///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengExpressionBinaryOperation.GetText: String; +begin + if not Assigned(fFirst) or not Assigned(fSecond) then + raise EengExpression.Create('first or second item not assigned'); + result := + {$IFDEF EXPRESSION_ADD_BRACKET}TOKEN_OP_GROUP_BEGIN +{$ENDIF} + fFirst.GetText + ' ' + EXPRESSION_BINARY_OPERATIONS[fBinaryOp] + ' ' + fSecond.GetText + {$IFDEF EXPRESSION_ADD_BRACKET} + TOKEN_OP_GROUP_END{$ENDIF}; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengExpressionBinaryOperation.GetValue: Variant; +var + v1: Variant; + v2: Variant; +begin + if not Assigned(fFirst) or not Assigned(fSecond) then + raise EengExpression.Create('first or second item not assigned'); + v1 := fFirst.GetValue; + v2 := fSecond.GetValue; + try + case fBinaryOp of + opBinaryOr: result := (Integer(v1) or Integer(v2)); + opBinaryAnd: result := (Integer(v1) and Integer(v2)); + opBinaryXor: result := (Integer(v1) xor Integer(v2)); + + opMultiply: result := (v1 * v2); + opDivide: result := (v1 / v2); + opAdd: result := (v1 + v2); + opSubtract: result := (v1 - v2); + + opLogicalOr: result := (Boolean(v1) or Boolean(v2)); + opLogicalAnd: result := (Boolean(v1) and Boolean(v2)); + opLogicalXor: result := (Boolean(v1) xor Boolean(v2)); + + opEquals: result := (v1 = v2); + opLesser: result := (v1 < v2); + opGreater: result := (v1 > v2); + opLEquals: result := (v1 <= v2); + opGEquals: result := (v1 >= v2); + opUnequals: result := (v1 <> v2); + else + result := inherited GetValue; + end; + except + on ex: Exception do + raise EengInvalidParamter.Create( + ex.Message + ' ("' + GetText + '" ==> "' + v1 + ' ' + + EXPRESSION_BINARY_OPERATIONS[fBinaryOp] + ' ' + v2 + '")', + fLine, fCol, fFilename); + end; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +constructor TengExpressionBinaryOperation.Create(const aOperator: TengExpressionBinaryOperator; const aLine, aCol: Integer; const aFilename: String); +begin + inherited Create(aLine, aCol, aFilename); + fBinaryOp := aOperator; + fFirst := nil; + fSecond := nil; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +destructor TengExpressionBinaryOperation.Destroy; +begin + FreeAndNil(fFirst); + FreeAndNil(fSecond); + inherited Destroy; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +type + TExpectedParam = (exVariable, exValue, exGroupBegin, exGroupEnd, exUnaryOperation, exBinaryOperation); + TExpectedParams = set of TExpectedParam; +{$IFDEF USE_BITSPACE_UTILS} + TExpressionItemStack = specialize TutlSimpleList; +{$ELSE} + TExpressionItemStack = class(specialize TFPList) + public + + end; +{$ENDIF} + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function ParseExpression(const aParam: TengTokenParameterList; aIndex: Integer): TengExpressionItem; +var + p: TengTokenParameter; + + procedure RaiseEx(const aMsg: String); + begin + raise EengExpression.Create(aMsg, p.Line, p.Col, aParam.Filename); + end; + + function NextParam: Boolean; + begin + inc(aIndex); + result := (aIndex < aParam.Count); + if result then + p := aParam[aIndex]; + end; + + function IsUnaryOperation(const aParam: String; out aOperator: TengExpressionUnaryOperator): Boolean; + begin + result := true; + for aOperator in TengExpressionUnaryOperator do + if (aParam = EXPRESSION_UNARY_OPERATIONS[aOperator]) then + exit; + result := false; + end; + + function IsBinaryOperation(const aParam: String; out aOperator: TengExpressionBinaryOperator): Boolean; + begin + result := true; + for aOperator in TengExpressionBinaryOperator do + if (aParam = EXPRESSION_BINARY_OPERATIONS[aOperator]) then + exit; + result := false; + end; + + procedure MergeItems(const aStack: TExpressionItemStack; var aNew: TengExpressionItem); + var + item: TengExpressionItem; + begin + try + if (aStack.Count = 0) then begin + aStack.PushLast(aNew); + aNew := nil; + exit; + end; + + item := aStack.Last; + if (item is TengExpressionBinaryOperation) then begin + if (aNew is TengExpressionBinaryOperation) then begin + //both are binary operators, new is weaker then existing + if ((aNew as TengExpressionBinaryOperation).BinaryOp < + (item as TengExpressionBinaryOperation).BinaryOp) then + begin + (aNew as TengExpressionBinaryOperation).First := item; + aStack.PopLast; + aStack.PushLast(aNew); + aNew := nil; + + //both are binary operators, new is stronger than existing + end else begin + if not Assigned((item as TengExpressionBinaryOperation).Second) then + RaiseEx('inconsistent state'); + (aNew as TengExpressionBinaryOperation).First := (item as TengExpressionBinaryOperation).Second; + (item as TengExpressionBinaryOperation).Second := aNew; + aStack.PushLast(aNew); + aNew := nil; + end; + + //existing is binary operator, new is normal + end else begin + if Assigned((item as TengExpressionBinaryOperation).Second) then + RaiseEx('inconsistent state'); + (item as TengExpressionBinaryOperation).Second := aNew; + aNew := nil; + while (aStack.Count > 1) do + aStack.PopLast; //remove all but first + end; + end else begin + //existing is normal item, new is binary operation + if (aNew is TengExpressionBinaryOperation) then begin + aStack.PopLast; + (aNew as TengExpressionBinaryOperation).First := item; + aStack.PushLast(aNew); + aNew := nil; + + //existing is unary operation, new is normal item or unary operation + end else if (item is TengExpressionUnaryOperation) then begin + if Assigned((item as TengExpressionUnaryOperation).Child) then + RaiseEx('inconsistent state'); + (item as TengExpressionUnaryOperation).Child := aNew; + if not (aNew is TengExpressionUnaryOperation) then begin + while (aStack.Count > 1) do + aStack.PopLast; //remove all but first + end else + aStack.PushLast(aNew); + aNew := nil; + + //existing and new are both normal items + end else + RaiseEx('inconsistent state'); + end; + except + FreeAndNil(aNew); + raise; + end; + end; + + function BuildTree(const aDepth: Integer = 0): TengExpressionItem; + var + uOp: TengExpressionUnaryOperator; + bOp: TengExpressionBinaryOperator; + expected: TExpectedParams; + stack: TExpressionItemStack; + l, c: Integer; + ei, tmp: TengExpressionItem; + begin + expected := [exVariable, exValue, exGroupBegin, exUnaryOperation]; + result := nil; + stack := TExpressionItemStack.Create(false); + try try + repeat + // GroupBegin + if (p.Name = TOKEN_OP_GROUP_BEGIN) then begin + if not (exGroupBegin in expected) then + RaiseEx('unexpected ''' + p.Name + ''''); + l := p.Line; + c := p.Col; + if not NextParam then + RaiseEx('unexpected end'); + tmp := BuildTree(aDepth + 1); + ei := TengExpressionGroup.Create(tmp, l, c, aParam.Filename); + try + MergeItems(stack, ei); + if (p.Name <> TOKEN_OP_GROUP_END) then + RaiseEx('missing ''' + TOKEN_OP_GROUP_END + ''''); + expected := [exBinaryOperation, exGroupEnd]; + except + FreeAndNil(ei); + raise; + end; + + // GroupEnd + end else if (p.Name = TOKEN_OP_GROUP_END) then begin + if not (exGroupEnd in expected) or (aDepth = 0) then + RaiseEx('unexpected ''' + TOKEN_OP_GROUP_END + ''''); + exit; + + // UnaryOperation + end else if IsUnaryOperation(p.Name, uOp) then begin + if not (exUnaryOperation in expected) then + RaiseEx('unexpected operator: ' + p.Name); + ei := TengExpressionUnaryOperation.Create(uOp, p.Line, p.Col, aParam.Filename); + try + MergeItems(stack, ei); + expected := [exVariable]; + if (uOp <> opDefined) then + expected := expected + [exValue, exGroupBegin, exUnaryOperation] + except + FreeAndNil(ei); + raise; + end; + + // BinaryOperation + end else if IsBinaryOperation(p.Name, bOp) then begin + if not (exBinaryOperation in expected) then + RaiseEx('unexpected operator: ' + p.Name); + ei := TengExpressionBinaryOperation.Create(bOp, p.Line, p.Col, aParam.Filename); + try + MergeItems(stack, ei); + expected := [exVariable, exValue, exGroupBegin, exUnaryOperation]; + except + FreeAndNil(ei); + raise; + end; + + // Value + end else if p.Quoted and IsValidIdentifier(p.Name) then begin + if not (exValue in expected) then + RaiseEx('unexpected value: ' + p.Name); + ei := TengExpressionValue.Create(p.Name, p.Line, p.Col, aParam.Filename); + try + MergeItems(stack, ei); + expected := [exGroupEnd, exBinaryOperation]; + except + FreeAndNil(ei); + raise; + end; + + // Variable + end else if IsValidIdentifier(p.Name) then begin + if not (exVariable in expected) then + RaiseEx('unexpected variable: ' + p.Name); + ei := TengExpressionVariable.Create(p.Name, p.Line, p.Col, aParam.Filename); + try + MergeItems(stack, ei); + expected := [exGroupEnd, exBinaryOperation]; + except + FreeAndNil(ei); + raise + end; + + // Unknown + end else + RaiseEx('invalid parameter: ' + p.Name); + until not NextParam; + except + if (stack.Count > 0) then begin + stack[0].Free; + stack[0] := nil; + end; + raise; + end; + finally + if (stack.Count > 0) then + result := stack[0]; + FreeAndNil(stack); + end; + end; + +begin + dec(aIndex); + if not NextParam then with aParam[0] do + raise EengShaderPartInternal.Create('invalid parameter count in expression', Line, Col, aParam.Filename); + result := BuildTree; +end; + +end. diff --git a/uengShaderFileHelper.pas b/uengShaderFileHelper.pas new file mode 100644 index 0000000..989911a --- /dev/null +++ b/uengShaderFileHelper.pas @@ -0,0 +1,56 @@ +unit uengShaderFileHelper; + +{$mode objfpc}{$H+} +{$I uengShaderFile.inc} + +interface + +uses + uengShaderPart, uengShaderFileParser; + +function IsValidIdentifier(const aIdent: String): Boolean; +function CheckEndToken(const aArgs: TengParseArgs; const aShaderPart: TengShaderPart): String; + +implementation + +uses + sysutils, + uengShaderFileConstants, uengShaderFileTypes; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function IsValidIdentifier(const aIdent: String): Boolean; +var + i, len: Integer; +begin + len := Length(aIdent); + result := false; + for i := 1 to len do + if not (aIdent[i] in VALID_IDENT_CHARS) then + exit; + result := true; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function CheckEndToken(const aArgs: TengParseArgs; const aShaderPart: TengShaderPart): String; +var + oldLine, oldCol: Integer; + param: TengTokenParameterList; +begin + param := TengTokenParameterList.Create(''); + try + oldLine := aArgs.Line; + oldCol := aArgs.Col; + if not aArgs.ExtractToken(param) then + raise EengUnexpectedToken.Create(TOKEN_NONE, TOKEN_END, oldLine, oldCol, aShaderPart.Filename); + if (param[0].Name <> TOKEN_END) then + raise EengUnexpectedToken.Create(param[0].Name, TOKEN_END, oldLine, oldCol, aShaderPart.Filename); + if (param.Count <> 1) then + raise EengInvalidParamterCount.Create(TOKEN_END, 1, oldLine, oldCol, aShaderPart.Filename); + result := ''; + finally + FreeAndNil(param); + end; +end; + +end. + diff --git a/uengShaderFileParser.pas b/uengShaderFileParser.pas new file mode 100644 index 0000000..7f87058 --- /dev/null +++ b/uengShaderFileParser.pas @@ -0,0 +1,333 @@ +unit uengShaderFileParser; + +{$mode objfpc}{$H+} +{$I uengShaderFile.inc} + +interface + +uses + Classes, SysUtils + +{$IFDEF USE_BITSPACE_UTILS} + , uutlGenerics +{$ELSE} + , fgl +{$ENDIF} + ; + +type +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + TengTokenParameter = packed record + Name: String; + Quoted: Boolean; + Line: Integer; + Col: Integer; + end; + TengTokenParameterList = class(specialize TutlSimpleList) + private + fFilename: String; + public + property Filename: String read fFilename; + constructor Create(const aFilename: String); + end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + TengParseArgs = class + private + fFilename: String; + fCode: TStringList; + fLineLength: Integer; + fLineCount: Integer; + fCurrentLine: String; + fCurrentChar: Char; + fCol: Integer; + fLine: Integer; + + procedure SetCol(const aValue: Integer); + procedure SetLine(const aValue: Integer); + + function GetEndOfLine: Boolean; + function GetEndOfFile: Boolean; + function GetCode: TStrings; + public + property Code: TStrings read GetCode; + property LineLength: Integer read fLineLength; + property LineCount: Integer read fLineCount; + property CurrentLine: String read fCurrentLine; + property CurrentChar: Char read fCurrentChar; + property EndOfLine: Boolean read GetEndOfLine; + property EndOfFile: Boolean read GetEndOfFile; + property Filename: String read fFilename; + property Col: Integer read fCol write SetCol; + property Line: Integer read fLine write SetLine; + + procedure NextCol; + procedure NextLine; + function ExtractToken(const aParameters: TengTokenParameterList): Boolean; + function GetTokenPreview(var aToken: String): Boolean; + + constructor Create(const aStream: TStream; const aFilename: String); + destructor Destroy; override; + end; + +implementation + +uses + uengShaderFileConstants, uengShaderFileTypes; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//TengTokenParameterList//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +constructor TengTokenParameterList.Create(const aFilename: String); +begin + inherited Create(true); + fFilename := aFilename; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//TengParseArgs///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +procedure TengParseArgs.SetCol(const aValue: Integer); +begin + fCol := aValue; + if not EndOfLine + then fCurrentChar := fCurrentLine[fCol] + else fCurrentChar := #0; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +procedure TengParseArgs.SetLine(const aValue: Integer); +begin + fLine := aValue; + if not EndOfFile then begin + fCurrentLine := fCode[fLine]; + fLineLength := Length(fCurrentLine); + end else begin + fCurrentLine := ''; + fLineLength := 0; + end; + Col := 1; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengParseArgs.GetEndOfLine: Boolean; +begin + result := (fCol > fLineLength) +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengParseArgs.GetEndOfFile: Boolean; +begin + result := (fLine >= fLineCount); +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +procedure TengParseArgs.NextCol; +begin + Col := Col + 1; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +procedure TengParseArgs.NextLine; +begin + Line := Line + 1; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengParseArgs.ExtractToken(const aParameters: TengTokenParameterList): Boolean; +type + TCharType = ( + ctUnknown, + ctValidTokenChar, + ctInvalidTokenChar + ); + TParseFlag = ( + pfQuote, + pfInToken, + pfIsComment, + pfCommentTokenAdded + ); + TParseFlags = set of TParseFlag; + +var + flags: TParseFlags; + ct: TCharType; + s: String; + pLine, pCol, oldLine, oldCol: Integer; + + procedure AddPart(const aTrimAndCheck: Boolean = true); + var + len: Integer; + p: TengTokenParameter; + begin + if aTrimAndCheck then + s := Trim(s); + if not aTrimAndCheck or (s <> '') then begin + len := Length(s); + if aTrimAndCheck and + ( (s[1] = TOKEN_CHAR_QUOTE) and + (s[len] = TOKEN_CHAR_QUOTE)) then + begin + if not (s[1] = TOKEN_CHAR_QUOTE) then + raise EengShaderPart.Create('missing leading quote char', Line, Col, Filename); + if not (s[len] = TOKEN_CHAR_QUOTE) then + raise EengShaderPart.Create('missing trailing quote char', Line, Col, Filename); + delete(s, len, 1); + delete(s, 1, 1); + p.Quoted := true; + end else + p.Quoted := false; + p.Name := s; + p.Line := pLine; + p.Col := pCol; + aParameters.Add(p); + end; + s := ''; + pLine := Line; + pCol := Col; + ct := ctUnknown; + end; + +begin + result := false; + aParameters.Clear; + if (CurrentChar <> TOKEN_CHAR_BEGIN) or + (Col + 1 > LineLength) or + ( (CurrentLine[Col+1] <> TOKEN_CHAR_IDENT) and + (CurrentLine[Col+1] <> TOKEN_CHAR_COMMENT)) + then + exit; + + result := true; + s := ''; + ct := ctUnknown; + oldLine := Line; + oldCol := Col; + flags := []; + if (CurrentLine[Col+1] = TOKEN_CHAR_COMMENT) then + Include(flags, pfIsComment); + AddPart; // initialize + + while not EndOfFile do begin + while not EndOfLine do begin + case CurrentChar of + TOKEN_CHAR_BEGIN: begin + if (pfQuote in flags) then + s := s + CurrentChar + else if not (pfInToken in flags) then + Include(flags, pfInToken) + else + EengShaderPart.Create('invalid char in token', Line, Col, Filename); + end; + + TOKEN_CHAR_END: begin + if not (pfQuote in flags) then begin + AddPart(not (pfIsComment in flags)); + NextCol; + if (aParameters.Count <= 0) or (aParameters[0].Name = TOKEN_CHAR_IDENT) then + raise EengShaderPart.Create('empty token', Line, Col, Filename); + exit; + end else + s := s + CurrentChar; + end; + + TOKEN_CHAR_QUOTE: begin + if not (pfQuote in flags) and not (pfIsComment in flags) then + AddPart; + s := s + CurrentChar; + if (pfQuote in flags) + then exclude(flags, pfQuote) + else include(flags, pfQuote); + if not (pfQuote in flags) and not (pfIsComment in flags) then + AddPart; + end; + + TOKEN_CHAR_COMMENT: begin + s := s + CurrentChar; + if (pfIsComment in flags) and not (pfCommentTokenAdded in flags) then begin + include(flags, pfCommentTokenAdded); + AddPart(false); + end; + end; + else + if not (pfQuote in flags) and not (pfIsComment in flags) then begin + if (CurrentChar in TOKEN_SPLIT_CHARS) then begin + AddPart; + end else if (CurrentChar in VALID_TOKEN_CHARS) then begin + if (ct <> ctValidTokenChar) then + AddPart; + ct := ctValidTokenChar; + end else begin + if (ct <> ctInvalidTokenChar) then + AddPart; + ct := ctInvalidTokenChar; + end; + end; + s := s + CurrentChar; + end; + NextCol; + end; + s := s + sLineBreak; + NextLine; + end; + raise EengShaderPart.Create('incomplete token', oldLine, oldCol, Filename); +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengParseArgs.GetCode: TStrings; +begin + result := fCode; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengParseArgs.GetTokenPreview(var aToken: String): Boolean; +var + c: Integer; +begin + result := false; + if (CurrentChar <> TOKEN_CHAR_BEGIN) or + (Col >= LineLength) or + not (CurrentLine[Col + 1] in [TOKEN_CHAR_IDENT, TOKEN_CHAR_COMMENT]) + then exit; + result := true; + aToken := CurrentChar; + if (aToken = TOKEN_CHAR_COMMANT_END) then + exit; + c := Col + 1; + case CurrentLine[c] of + TOKEN_CHAR_IDENT: begin + aToken := ''; + repeat + aToken := aToken + CurrentLine[c]; + inc(c); + until (c > LineLength) or not (CurrentLine[c] in VALID_TOKEN_CHARS); + aToken := Trim(aToken); + if (aToken = TOKEN_CHAR_IDENT) then + raise EengInvalidToken.Create('empty token', Line, Col, Filename); + end; + + TOKEN_CHAR_COMMENT: + aToken := TOKEN_CHAR_COMMENT; + end; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +constructor TengParseArgs.Create(const aStream: TStream; const aFilename: String); +begin + inherited Create; + fFilename := aFilename; + fCode := TStringList.Create; + fCode.LoadFromStream(aStream); + fLineCount := fCode.Count; + Line := 0; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +destructor TengParseArgs.Destroy; +begin + FreeAndNil(fCode); + inherited Destroy; +end; + +end. + diff --git a/uengShaderFileScope.pas b/uengShaderFileScope.pas new file mode 100644 index 0000000..99fb992 --- /dev/null +++ b/uengShaderFileScope.pas @@ -0,0 +1,23 @@ +unit uengShaderFileScope; + +{$mode objfpc}{$H+} + +{$I uengShaderFile.inc} + +interface + +uses + Classes, SysUtils, + + uengShaderFilePart; + +type +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + TengShaderFileScope = class(TengShaderPart) + + end; + +implementation + +end. + diff --git a/uengShaderFileTypes.pas b/uengShaderFileTypes.pas new file mode 100644 index 0000000..bf830c4 --- /dev/null +++ b/uengShaderFileTypes.pas @@ -0,0 +1,148 @@ +unit uengShaderFileTypes; + +{$mode objfpc}{$H+} +{$I uengShaderFile.inc} + +interface + +uses + Classes, SysUtils + +{$IFDEF USE_BITSPACE_UTILS} + , uutlSerialization, uutlCommon +{$ENDIF} + ; + +type +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +{$IFDEF USE_BITSPACE_UTILS} + IengShaderFileWriter = uutlSerialization.IutlFileWriter; + IengShaderFileReader = uutlSerialization.IutlFileReader; + TengShaderFileReader = uutlSerialization.TutlSimpleFileReader; + TengShaderFileWriter = uutlSerialization.TutlSimpleFileWriter; + TIntfObjNoRefCount = uutlCommon.TutlInterfaceNoRefCount; +{$ENDIF} + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + EengShaderPart = class(Exception) + public + Line: Integer; + Col: Integer; + Filename: String; + + constructor Create(const aMsg: String; const aLine, aCol: Integer; const aFilename: String); overload; + end; + EengShaderPartInternal = class(EengShaderPart); + EengExpression = class(EengShaderPart); + + EengInvalidToken = class(EengShaderPartInternal) + constructor Create(const aClassName: String; const aToken: String; const aLine, aCol: Integer; const aFilename: String); overload; + end; + + EengUnexpectedToken = class(EengShaderPart) + constructor Create(const aToken, aExpected: String; const aLine, aCol: Integer; const aFilename: String); overload; + end; + + EengInvalidParamter = class(EengShaderPart) + constructor Create(const aParam, aExpected: String; const aLine, aCol: Integer; const aFilename: String); overload; + end; + + EengInvalidParamterCount = class(EengShaderPart) + constructor Create(const aToken: String; const aExpected, aLine, aCol: Integer; const aFilename: String); overload; + constructor Create(const aToken: String; const aExpectedMin, aExpectedMax, aLine, aCol: Integer; const aFilename: String); overload; + end; + + EengInvalidIdentifier = class(EengShaderPart) + constructor Create(const aIdentifier: String; const aLine, aCol: Integer; const aFilename: String); overload; + end; + + EengOutOfRange = class(EengShaderPartInternal) + constructor Create(const aMin, aMax, aIndex, aLine, aCol: Integer; const aFilename: String); overload; + end; + +implementation + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//EengShaderPart//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +constructor EengShaderPart.Create(const aMsg: String; const aLine, aCol: Integer; const aFilename: String); +begin + inherited Create(Format('%s (file: %s; line: %d; col: %d): %s', [ClassName, ExtractFileName(aFilename), aLine+1, aCol, aMsg])); + Line := aLine; + Col := aCol; + Filename := aFilename; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//EengInvalidToken////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +constructor EengInvalidToken.Create(const aClassName: String; const aToken: String; const aLine, aCol: Integer; const aFilename: String); +begin + inherited Create('invalid token: ' + aClassName + ' <> '+ aToken, aLine, aCol, aFilename); +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//EengUnexpectedToken/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +constructor EengUnexpectedToken.Create(const aToken, aExpected: String; const aLine, aCol: Integer; const aFilename: String); +var + s: String; +begin + s := 'unexpected token: ' + aToken; + if (aExpected <> '') then + s := s + '(expected ' + aExpected + ')'; + inherited Create(s, aLine, aCol, aFilename); +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//EengInvalidParamter/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +constructor EengInvalidParamter.Create(const aParam, aExpected: String; const aLine, aCol: Integer; const aFilename: String); +var + s: String; +begin + s := 'invalid parameter: ' + aParam; + if (aExpected <> '') then + s := s + '(expected ' + aExpected + ')'; + inherited Create(s, aLine, aCol, aFilename); +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//EengInvalidParamterCount////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +constructor EengInvalidParamterCount.Create(const aToken: String; const aExpected, aLine, aCol: Integer; const aFilename: String); +begin + inherited Create('invalid parameter count in ' + aToken + '(expected ' + IntToStr(aExpected) + ' parameter)', aLine, aCol, aFilename); +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +constructor EengInvalidParamterCount.Create(const aToken: String; const aExpectedMin, aExpectedMax, aLine, aCol: Integer; const aFilename: String); +var + s: String; +begin + s := 'invalid parameter count in ' + aToken + '(expected '; + if (aExpectedMax < 0) + then s := s + ' at least '+ IntToStr(aExpectedMin) + else s := s + IntToStr(aExpectedMin) + ' to ' + IntToStr(aExpectedMax); + s := s + ' parameter)'; + inherited Create(s, aLine, aCol, aFilename); +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//EengInvalidIdentifier///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +constructor EengInvalidIdentifier.Create(const aIdentifier: String; const aLine, aCol: Integer; const aFilename: String); +begin + inherited Create('invalid identifier: ' + aIdentifier, aLine, aCol, aFilename); +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//EengOutOfRange//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +constructor EengOutOfRange.Create(const aMin, aMax, aIndex, aLine, aCol: Integer; const aFilename: String); +begin + inherited Create(format('index (%d) out of range (%d:%d)', [aIndex, aMin, aMax]), aLine, aCol, aFilename); +end; + +end. + diff --git a/uengShaderPart.pas b/uengShaderPart.pas new file mode 100644 index 0000000..684a213 --- /dev/null +++ b/uengShaderPart.pas @@ -0,0 +1,233 @@ +unit uengShaderPart; + +{$mode objfpc}{$H+} +{$I uengShaderFile.inc} + +interface + +uses + Classes, SysUtils, + + uengShaderFileParser, uengShaderFileTypes + +{$IFDEF USE_BITSPACE_UTILS} + , uutlGenerics; +{$ELSE} + , fgl; +{$ENDIF} + +type +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + CengShaderPart = class of TengShaderPart; + TengShaderPart = class(TIntfObjNoRefCount) + { Nested Types } + public type + TEnumerator = class(TObject) + private + fOwner: TengShaderPart; + fPosition: Integer; + function GetCurrent: TengShaderPart; + public + property Current: TengShaderPart read GetCurrent; + function MoveNext: Boolean; + constructor Create(const aOwner: TengShaderPart); + end; + + { Code Loading & Storage } + private { members } + fRoot: TengShaderPart; + fParent: TengShaderPart; + fLine: Integer; + fCol: Integer; + protected { virtual getter } + function GetCount: Integer; virtual; + function GetChild(const aIndex: Integer): TengShaderPart; virtual; + function GetText: String; virtual; + function GetFilename: String; virtual; + function GetFileReader: IengShaderFileReader; virtual; + function GetFileWriter: IengShaderFileWriter; virtual; + protected { parse methodes } + function ParseIntern(const aArgs: TengParseArgs; const aParams: TengTokenParameterList): String; virtual; + public + function ParseText(const aArgs: TengParseArgs): String; + + { General } + public { general methods } + property Root: TengShaderPart read fRoot; + property Parent: TengShaderPart read fParent; + property Line: Integer read fLine; + property Col: Integer read fCol; + property Filename: String read GetFilename; + property Text: String read GetText; + property Count: Integer read GetCount; + + property FileReader: IengShaderFileReader read GetFileReader; + property FileWriter: IengShaderFileWriter read GetFileWriter; + + property Children[const aIndex: Integer]: TengShaderPart read GetChild; default; + + function HasParent(const aType: CengShaderPart; const aIncludeSelf: Boolean = false): Boolean; + function GetParent(const aType: CengShaderPart; out aPart): Boolean; + function GetEnumerator: TEnumerator; + + constructor Create(const aParent: TengShaderPart); virtual; + + { Class Methods } + public + class function GetTokenName: String; virtual; + class function CheckToken(const aToken: String): Boolean; virtual; + class procedure Validate(const aArgs: TengParseArgs; const aParent: TengShaderPart); virtual; + end; + TengShaderPartList = specialize TutlSimpleList; + +implementation + +uses + uengShaderFileConstants; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//TengShaderPart.TEnumerator//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengShaderPart.TEnumerator.GetCurrent: TengShaderPart; +begin + result := fOwner[fPosition]; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengShaderPart.TEnumerator.MoveNext: Boolean; +begin + inc(fPosition); + result := (fPosition < fOwner.Count); +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +constructor TengShaderPart.TEnumerator.Create(const aOwner: TengShaderPart); +begin + inherited Create; + fOwner := aOwner; + fPosition := -1; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//TengShaderPart//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengShaderPart.GetCount: Integer; +begin + result := 0; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengShaderPart.{%H-}GetChild(const aIndex: Integer): TengShaderPart; +begin + EengShaderPartInternal.Create('this part does not have any children'); +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengShaderPart.GetText: String; +begin + result := ''; //DUMMY +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengShaderPart.GetFilename: String; +begin + if Assigned(fParent) + then result := fParent.Filename + else result := UNKNOWN_FILENAME; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengShaderPart.GetFileReader: IengShaderFileReader; +begin + if Assigned(fParent) + then result := fParent.GetFileReader + else result := nil; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengShaderPart.GetFileWriter: IengShaderFileWriter; +begin + if Assigned(fParent) + then result := fParent.GetFileWriter + else result := nil; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengShaderPart.ParseText(const aArgs: TengParseArgs): String; +var + params: TengTokenParameterList; +begin + params := TengTokenParameterList.Create(Filename); + try + fCol := aArgs.Col; + fLine := aArgs.Line; + if (GetTokenName <> '') then + aArgs.ExtractToken(params); + result := ParseIntern(aArgs, params); + finally + FreeAndNil(params); + end; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengShaderPart.ParseIntern(const aArgs: TengParseArgs; const aParams: TengTokenParameterList): String; +begin + result := ''; // DUMMY +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengShaderPart.HasParent(const aType: CengShaderPart; const aIncludeSelf: Boolean): Boolean; +var + p: TengShaderPart; +begin + result := (aIncludeSelf and (self is aType)) or GetParent(aType, p); +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengShaderPart.GetParent(const aType: CengShaderPart; out aPart): Boolean; +begin + result := true; + if (fParent is aType) then + TengShaderPart(aPart) := fParent + else if Assigned(fParent) then + result := fParent.GetParent(aType, aPart) + else + result := false; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengShaderPart.GetEnumerator: TEnumerator; +begin + result := TEnumerator.Create(self); +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +constructor TengShaderPart.Create(const aParent: TengShaderPart); +begin + inherited Create; + fParent := aParent; + if Assigned(fParent) + then fRoot := fParent.Root + else fRoot := nil; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +class function TengShaderPart.GetTokenName: String; +begin + result := ''; // DUMMY +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +class function TengShaderPart.CheckToken(const aToken: String): Boolean; +begin + result := (aToken = GetTokenName); +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +class procedure TengShaderPart.Validate(const aArgs: TengParseArgs; const aParent: TengShaderPart); +begin + // DUMMY +end; + +end. + diff --git a/uengShaderPartCall.pas b/uengShaderPartCall.pas new file mode 100644 index 0000000..2d335e5 --- /dev/null +++ b/uengShaderPartCall.pas @@ -0,0 +1,158 @@ +unit uengShaderPartCall; + +{$mode objfpc}{$H+} +{$I uengShaderFile.inc} + +interface + +uses + Classes, SysUtils, + uengShaderPart, uengShaderFileParser; + +type +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + TengShaderPartCall = class(TengShaderPart) + { Code Loading & Storage } + private { member } + fName: String; + fParameters: TStringList; + protected { virtual getter } + function GetText: String; override; + function ParseIntern(const aArgs: TengParseArgs; const aParams: TengTokenParameterList): String; override; + + { General } + private + function GetParameters: TStrings; + public + property Name: String read fName; + property Parameters: TStrings read GetParameters; + + constructor Create(const aParent: TengShaderPart); override; + destructor Destroy; override; + + { Class Methods } + public + class function GetTokenName: String; override; + end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + TengShaderPartInherited = class(TengShaderPartCall) + { Class Methods } + protected + function ParseIntern(const aArgs: TengParseArgs; const aParams: TengTokenParameterList): String; override; + public + class function GetTokenName: String; override; + class procedure Validate(const aArgs: TengParseArgs; const aParent: TengShaderPart); override; + end; + +implementation + +uses + uengShaderPartProc, uengShaderPartClass, uengShaderFileConstants, uengShaderFileTypes, uengShaderFileHelper; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//TengShaderPartCall//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengShaderPartCall.GetText: String; +var + i: Integer; +begin + result := TOKEN_CHAR_BEGIN + GetTokenName; + if (fName <> '') then + result := result + ' ' + fName; + for i := 0 to fParameters.Count-1 do begin + if (PtrInt(fParameters.Objects[i]) <> 0) + then result := result + ' ' + TOKEN_CHAR_QUOTE + fParameters[i] + TOKEN_CHAR_QUOTE + else result := result + ' ' + fParameters[i]; + end; + result := result + TOKEN_CHAR_END; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengShaderPartCall.ParseIntern(const aArgs: TengParseArgs; const aParams: TengTokenParameterList): String; +var + i: Integer; +begin + if (aParams[0].Name <> GetTokenName) then + raise EengInvalidToken.Create(ClassName, aParams[0].Name, Line, Col, Filename); + if (aParams.Count < 2) then + raise EengInvalidParamterCount.Create(GetTokenName, 2, -1, Line, Col, Filename); + + result := ''; + fParameters.Clear; + with aParams[1] do begin + if not IsValidIdentifier(fName) then + raise EengInvalidIdentifier.Create(Name, Line, Col, Filename); + fName := Name; + end; + for i := 2 to aParams.Count-1 do + fParameters.AddObject(aParams[i].Name, TObject(PtrInt(aParams[i].Quoted))); +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengShaderPartCall.GetParameters: TStrings; +begin + result := fParameters; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +constructor TengShaderPartCall.Create(const aParent: TengShaderPart); +begin + inherited Create(aParent); + fParameters := TStringList.Create; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +destructor TengShaderPartCall.Destroy; +begin + FreeAndNil(fParameters); + inherited Destroy; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +class function TengShaderPartCall.GetTokenName: String; +begin + result := TOKEN_CALL; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//TengShaderPartInherited/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengShaderPartInherited.ParseIntern(const aArgs: TengParseArgs; const aParams: TengTokenParameterList): String; +var + i: Integer; +begin + if (aParams[0].Name <> GetTokenName) then with aParams[0] do + raise EengInvalidToken.Create(ClassName, Name, Line, Col, Filename); + + fName := ''; + fParameters.Clear; + if (aParams.Count >= 2) then begin + if not IsValidIdentifier(aParams[1].Name) and (aParams[1].Name <> TOKEN_MAIN) then + with aParams[1] do + raise EengInvalidIdentifier.Create(Name, Line, Col, Filename); + fName := aParams[1].Name; + for i := 2 to aParams.Count-1 do + fParameters.AddObject(aParams[i].Name, TObject(PtrInt(aParams[i].Quoted))); + end; + result := ''; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +class function TengShaderPartInherited.GetTokenName: String; +begin + result := TOKEN_INHERITED; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +class procedure TengShaderPartInherited.Validate(const aArgs: TengParseArgs; const aParent: TengShaderPart); +begin + inherited Validate(aArgs, aParent); + if not aParent.HasParent(TengShaderPartProc, true) or + not aParent.HasParent(TengShaderPartClass, true) then + raise EengShaderPart.Create(GetTokenName + ' is not allowed outside of ' + + TOKEN_PROC + ', ' + TOKEN_FUNC + ', ' + TOKEN_MAIN + ' or ' + TOKEN_CLASS); +end; + +end. + diff --git a/uengShaderPartClass.pas b/uengShaderPartClass.pas new file mode 100644 index 0000000..0dca36b --- /dev/null +++ b/uengShaderPartClass.pas @@ -0,0 +1,117 @@ +unit uengShaderPartClass; + +{$mode objfpc}{$H+} +{$I uengShaderFile.inc} + +interface + +uses + Classes, SysUtils, + uengShaderPart, uengShaderCodeGenerator, uengShaderFileParser; + +type +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + TengShaderPartClass = class(TengShaderCodeGenerator) + { Code Loading & Storage } + private { member } + fName: String; + fExtends: TStringList; + private { getter } + function GetExtends: TStrings; + protected { virtual getter } + function GetText: String; override; + function ParseIntern(const aArgs: TengParseArgs; const aParams: TengTokenParameterList): String; override; + + { General } + public + property Name: String read fName; + property Extends: TStrings read GetExtends; + constructor Create(const aParent: TengShaderPart); override; + destructor Destroy; override; + + { Class Methods } + public + class function GetTokenName: String; override; + end; + +implementation + +uses + uengShaderFileConstants, uengShaderFileTypes, uengShaderFileHelper; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//TengShaderPartClass/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengShaderPartClass.GetExtends: TStrings; +begin + result := fExtends; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengShaderPartClass.GetText: String; +var + s: String; +begin + result := TOKEN_CHAR_BEGIN + GetTokenName + ' ' + fName; + if (fExtends.Count > 0) then begin + result := result + ' ' + TOKEN_EXTENDS; + for s in fExtends do + result := result + ' ' + s; + end; + result := result + TOKEN_CHAR_END + + inherited GetText + + TOKEN_CHAR_BEGIN + TOKEN_END + TOKEN_CHAR_END; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengShaderPartClass.ParseIntern(const aArgs: TengParseArgs; const aParams: TengTokenParameterList): String; +var + i: Integer; +begin + if (aParams[0].Name <> GetTokenName) then + raise EengInvalidToken.Create(ClassName, aParams[0].Name, Line, Col, Filename); + if (aParams.Count < 2) then + raise EengInvalidParamterCount.Create(GetTokenName, 2, -1, Line, Col, Filename); + with aParams[1] do begin + if not IsValidIdentifier(Name) then + raise EengInvalidIdentifier.Create(Name, Line, Col, Filename); + fName := Name; + end; + if (aParams.Count > 2) then begin + if (aParams.Count < 4) then + raise EengInvalidParamterCount.Create(GetTokenName, 4, -1, Line, Col, Filename); + if (aParams[2].Name <> TOKEN_EXTENDS) then with aParams[2] do + raise EengInvalidParamter.Create(aParams[2].Name, TOKEN_EXTENDS, Line, Col, Filename); + fExtends.Clear; + for i := 3 to aParams.Count-1 do + fExtends.Add(aParams[i].Name); + end; + + // TODO fRoot.AddClass ? + + result := inherited ParseIntern(aArgs, aParams); + result := CheckEndToken(aArgs, self); +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +constructor TengShaderPartClass.Create(const aParent: TengShaderPart); +begin + inherited Create(aParent); + fExtends := TStringList.Create; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +destructor TengShaderPartClass.Destroy; +begin + FreeAndNil(fExtends); + inherited Destroy; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +class function TengShaderPartClass.GetTokenName: String; +begin + result := TOKEN_CLASS; +end; + +end. + diff --git a/uengShaderPartCntr.pas b/uengShaderPartCntr.pas new file mode 100644 index 0000000..3f17ea3 --- /dev/null +++ b/uengShaderPartCntr.pas @@ -0,0 +1,159 @@ +unit uengShaderPartCntr; + +{$mode objfpc}{$H+} +{$I uengShaderFile.inc} + +interface + +uses + Classes, SysUtils, + uengShaderPart, uengShaderFileParser; + +type +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + TengShaderPartCntr = class(TengShaderPart) + { Code Loading & Storage } + private + fChildren: TengShaderPartList; + procedure AddChild(const aChild: TengShaderPart; const aPrepend: Boolean = false); + function HandleToken(const aToken: String; const aArgs: TengParseArgs): String; + protected { virtual getter } + function GetCount: Integer; override; + function GetChild(const aIndex: Integer): TengShaderPart; override; + function GetText: String; override; + function ParseIntern(const aArgs: TengParseArgs; const aParams: TengTokenParameterList): String; override; + public { general methods } + procedure Clear; + constructor Create(const aParent: TengShaderPart); override; + destructor Destroy; override; + end; + +implementation + +uses + uengShaderPartKeyValuePair, uengShaderPartClass, uengShaderPartMessage, uengShaderPartMeta, + uengShaderPartCall, uengShaderPartProc, uengShaderPartText, uengShaderPartEcho, uengShaderPartIf, + uengShaderPartInclude, uengShaderPartParameter, uengShaderPartComment; + +const + TOKEN_CLASSES: array[0..20] of CengShaderPart = ( + TengShaderPartCall, + TengShaderPartClass, + TengShaderPartDefine, + TengShaderPartLineBreak, + TengShaderPartCommandEnd, + TengShaderPartComment, + TengShaderPartEcho, + TengShaderPartError, + TengShaderPartMain, + TengShaderPartIf, + TengShaderPartInclude, + TengShaderPartInherited, + TengShaderPartFunc, + TengShaderPartMessage, + TengShaderPartMeta, + TengShaderPartProc, + TengShaderPartProperty, + TengShaderPartUniform, + TengShaderPartVar, + TengShaderPartVarying, + TengShaderPartWarning + ); + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//TengShaderPartCntr//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +procedure TengShaderPartCntr.AddChild(const aChild: TengShaderPart; const aPrepend: Boolean); +begin + if aPrepend + then fChildren.PushFirst(aChild) + else fChildren.PushLast(aChild); +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengShaderPartCntr.HandleToken(const aToken: String; const aArgs: TengParseArgs): String; +var + p: TengShaderPart; + c: CengShaderPart; +begin + p := nil; + for c in TOKEN_CLASSES do begin + if c.CheckToken(aToken) then begin + c.Validate(aArgs, self); + p := c.Create(self); + AddChild(p); + break; + end; + end; + if Assigned(p) + then result := p.ParseText(aArgs) + else result := aToken; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengShaderPartCntr.GetCount: Integer; +begin + result := fChildren.Count; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengShaderPartCntr.GetChild(const aIndex: Integer): TengShaderPart; +begin + result := fChildren[aIndex]; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengShaderPartCntr.GetText: String; +var + p: TengShaderPart; +begin + result := ''; + for p in self do + result := result + p.Text; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengShaderPartCntr.ParseIntern(const aArgs: TengParseArgs; const aParams: TengTokenParameterList): String; +var + TextObj: TengShaderPartText; +begin + result := ''; + fChildren.Clear; + while not aArgs.EndOfFile and (result = '') do begin + TextObj := TengShaderPartText.Create(self); + try + result := TextObj.ParseText(aArgs); + if not TextObj.IsEmpty + then AddChild(TextObj) + else FreeAndNil(TextObj); + except + FreeAndNil(TextObj); + raise; + end; + if (result <> '') then + result := HandleToken(result, aArgs); + end; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +procedure TengShaderPartCntr.Clear; +begin + fChildren.Clear; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +constructor TengShaderPartCntr.Create(const aParent: TengShaderPart); +begin + inherited Create(aParent); + fChildren := TengShaderPartList.Create(true); +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +destructor TengShaderPartCntr.Destroy; +begin + FreeAndNil(fChildren); + inherited Destroy; +end; + +end. + diff --git a/uengShaderPartComment.pas b/uengShaderPartComment.pas new file mode 100644 index 0000000..d590948 --- /dev/null +++ b/uengShaderPartComment.pas @@ -0,0 +1,55 @@ +unit uengShaderPartComment; + +{$mode objfpc}{$H+} +{$I uengShaderFile.inc} + +interface + +uses + Classes, SysUtils, + uengShaderPart, uengShaderFileParser; + +type +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + TengShaderPartComment = class(TengShaderPart) + { Code Loading & Storage } + private + fText: String; + protected + function GetText: String; override; + function ParseIntern(const aArgs: TengParseArgs; const aParams: TengTokenParameterList): String; override; + public + class function GetTokenName: String; override; + end; + +implementation + +uses + uengShaderFileConstants, uengShaderFileTypes; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//TengShaderPartComment///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengShaderPartComment.GetText: String; +begin + result := TOKEN_CHAR_BEGIN + GetTokenName + fText + TOKEN_CHAR_END; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengShaderPartComment.ParseIntern(const aArgs: TengParseArgs; const aParams: TengTokenParameterList): String; +begin + if (aParams[0].Name <> GetTokenName) then with aParams[0] do + raise EengInvalidToken.Create(ClassName, Name, Line, Col, Filename); + if (aParams.Count > 1) then + fText := aParams[1].Name; + result := ''; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +class function TengShaderPartComment.GetTokenName: String; +begin + result := TOKEN_CHAR_COMMENT; +end; + +end. + diff --git a/uengShaderPartEcho.pas b/uengShaderPartEcho.pas new file mode 100644 index 0000000..36fca55 --- /dev/null +++ b/uengShaderPartEcho.pas @@ -0,0 +1,62 @@ +unit uengShaderPartEcho; + +{$mode objfpc}{$H+} +{$I uengShaderFile.inc} + +interface + +uses + Classes, SysUtils, + uengShaderPart, uengShaderFileParser; + +type +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + TengShaderPartEcho = class(TengShaderPart) + { Code Loading & Storage } + private + fName: String; + protected + function GetText: String; override; + function ParseIntern(const aArgs: TengParseArgs; const aParams: TengTokenParameterList): String; override; + + { General } + public + class function GetTokenName: String; override; + end; + +implementation + +uses + uengShaderFileConstants, uengShaderFileTypes, uengShaderFileHelper; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//TengShaderPartEcho//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengShaderPartEcho.GetText: String; +begin + result := TOKEN_CHAR_BEGIN + GetTokenName + ' ' + fName + TOKEN_CHAR_END; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengShaderPartEcho.ParseIntern(const aArgs: TengParseArgs; const aParams: TengTokenParameterList): String; +begin + if (aParams[0].Name <> GetTokenName) then with aParams[0] do + raise EengInvalidToken.Create(ClassName, Name, Line, Col, Filename); + if (aParams.Count <> 2) then + raise EengInvalidParamterCount.Create(GetTokenName, 2, Line, Col, Filename); + result := ''; + with aParams[1] do begin + if not IsValidIdentifier(Name) then + raise EengInvalidIdentifier.Create(Name, Line, Col, Filename); + fName := Name; + end; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +class function TengShaderPartEcho.GetTokenName: String; +begin + result := TOKEN_ECHO; +end; + +end. + diff --git a/uengShaderPartIf.pas b/uengShaderPartIf.pas new file mode 100644 index 0000000..f8a01f1 --- /dev/null +++ b/uengShaderPartIf.pas @@ -0,0 +1,183 @@ +unit uengShaderPartIf; + +{$mode objfpc}{$H+} +{$I uengShaderFile.inc} + +interface + +uses + Classes, SysUtils, + uengShaderPart, uengShaderPartCntr, uengShaderFileExpression, uengShaderFileParser; + +type +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + TengShaderPartIf = class(TengShaderPart) + { Code Loading & Storage } + private + fExpression: TengExpressionItem; + fIfPart: TengShaderPart; + fElsePart: TengShaderPart; + function HandleToken(const aToken: String; const aArgs: TengParseArgs): String; + protected + function HandeEndToken(const aToken: String; const aArgs: TengParseArgs): String; virtual; + function GetCount: Integer; override; + function GetChild(const aIndex: Integer): TengShaderPart; override; + function GetText: String; override; + function ParseIntern(const aArgs: TengParseArgs; const aParams: TengTokenParameterList): String; override; + + { General } + public + destructor Destroy; override; + + { Class Methods } + public + class function GetTokenName: String; override; + end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + TengShaderPartElIf = class(TengShaderPartIf) + { Code Loading & Storage } + protected + function HandeEndToken(const aToken: String; const aArgs: TengParseArgs): String; override; + + { Class Methods } + public + class function GetTokenName: String; override; + end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + TengShaderPartElse = class(TengShaderPartCntr) + { Code Loading & Storage } + protected + function GetText: String; override; + + { Class Methods } + public + class function GetTokenName: String; override; + end; + +implementation + +uses + uengShaderFileTypes, uengShaderFileConstants, uengShaderFileHelper; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//TengShaderPartIf////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengShaderPartIf.HandleToken(const aToken: String; const aArgs: TengParseArgs): String; +const + TOKEN_CLASSES: array[0..1] of CengShaderPart = ( + TengShaderPartElse, + TengShaderPartElIf + ); +var + c: CengShaderPart; +begin + for c in TOKEN_CLASSES do begin + if c.CheckToken(aToken) then begin + c.Validate(aArgs, self); + fElsePart := c.Create(self); + break; + end; + end; + if Assigned(fElsePart) then + result := fElsePart.ParseText(aArgs); + result := HandeEndToken(result, aArgs); +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengShaderPartIf.HandeEndToken(const aToken: String; const aArgs: TengParseArgs): String; +begin + result := CheckEndToken(aArgs, self); +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengShaderPartIf.GetCount: Integer; +begin + result := 1; + if Assigned(fElsePart) then + inc(result, 1); +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengShaderPartIf.GetChild(const aIndex: Integer): TengShaderPart; +begin + if (aIndex < 0) or (aIndex >= Count) then + raise EengOutOfRange.Create(0, Count-1, aIndex, Line, Col, Filename); + case aIndex of + 0: result := fIfPart; + 1: result := fElsePart; + end; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengShaderPartIf.GetText: String; +begin + result := TOKEN_CHAR_BEGIN + GetTokenName + ' ' + fExpression.GetText + TOKEN_CHAR_END + fIfPart.Text; + if Assigned(fElsePart) then + result := result + fElsePart.Text; + result := result + TOKEN_CHAR_BEGIN + TOKEN_END + TOKEN_CHAR_END; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengShaderPartIf.ParseIntern(const aArgs: TengParseArgs; const aParams: TengTokenParameterList): String; +begin + if (aParams[0].Name <> GetTokenName) then with aParams[0] do + raise EengInvalidToken.Create(ClassName, Name, Line, Col, Filename); + if (aParams.Count < 2) then + raise EengInvalidParamterCount.Create(GetTokenName, 2, -1, Line, Col, Filename); + + fExpression := ParseExpression(aParams, 1); + + fIfPart := TengShaderPartCntr.Create(self); + result := fIfPart.ParseText(aArgs); + result := HandleToken(result, aArgs); +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +destructor TengShaderPartIf.Destroy; +begin + FreeAndNil(fExpression); + FreeAndNil(fIfPart); + FreeAndNil(fElsePart); + inherited Destroy; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +class function TengShaderPartIf.GetTokenName: String; +begin + result := TOKEN_IF; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//TengShaderPartElIf//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengShaderPartElIf.HandeEndToken(const aToken: String; const aArgs: TengParseArgs): String; +begin + result := aToken; + if (result <> TOKEN_END) then + raise EengInvalidToken.Create(ClassName, result, aArgs.Line, aArgs.Col, Filename); +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +class function TengShaderPartElIf.GetTokenName: String; +begin + result := TOKEN_ELIF; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//TengShaderPartElse//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengShaderPartElse.GetText: String; +begin + result := TOKEN_CHAR_BEGIN + GetTokenName + TOKEN_CHAR_END + inherited GetText; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +class function TengShaderPartElse.GetTokenName: String; +begin + result := TOKEN_ELSE; +end; + +end. + diff --git a/uengShaderPartInclude.pas b/uengShaderPartInclude.pas new file mode 100644 index 0000000..07a6047 --- /dev/null +++ b/uengShaderPartInclude.pas @@ -0,0 +1,100 @@ +unit uengShaderPartInclude; + +{$mode objfpc}{$H+} +{$I uengShaderFile.inc} + +interface + +uses + Classes, SysUtils, + uengShaderPart, uengShaderFile, uengShaderFileParser; + +type +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + TengShaderPartInclude = class(TengShaderPart) + { Code Loading & Storage } + private + fShaderFile: TengShaderFile; + fIncludeFile: String; + fAbsoluteFile: String; + protected + function GetCount: Integer; override; + function GetChild(const aIndex: Integer): TengShaderPart; override; + function GetText: String; override; + function ParseIntern(const aArgs: TengParseArgs; const aParams: TengTokenParameterList): String; override; + + { General } + public + property IncludeFile: String read fIncludeFile; + constructor Create(const aParent: TengShaderPart); override; + destructor Destroy; override; + + { Class Methods } + public + class function GetTokenName: String; override; + end; + +implementation + +uses + FileUtil, + uengShaderFileTypes, uengShaderFileConstants; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//TengShaderPartInclude///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengShaderPartInclude.GetCount: Integer; +begin + if Assigned(fShaderFile) + then result := 1 + else result := 0; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengShaderPartInclude.GetChild(const aIndex: Integer): TengShaderPart; +begin + if Assigned(fShaderFile) and (aIndex = 0) + then result := fShaderFile + else raise EengOutOfRange.Create(0, Count-1, aIndex, Line, Col, Filename); +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengShaderPartInclude.GetText: String; +begin + result := TOKEN_CHAR_BEGIN + GetTokenName + ' ''' + fIncludeFile + '''' + TOKEN_CHAR_END; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengShaderPartInclude.ParseIntern(const aArgs: TengParseArgs; const aParams: TengTokenParameterList): String; +begin + if (aParams[0].Name <> GetTokenName) then with aParams[0] do + raise EengInvalidToken.Create(ClassName, Name, Line, Col, Filename); + if (aParams.Count <> 2) then + raise EengInvalidParamterCount.Create(GetTokenName, 2, Line, Col, Filename); + fIncludeFile := aParams[1].Name; + fAbsoluteFile := CreateAbsolutePath(fIncludeFile, ExtractFilePath(Filename)); + result := ''; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +constructor TengShaderPartInclude.Create(const aParent: TengShaderPart); +begin + inherited Create(aParent); + fShaderFile := nil; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +destructor TengShaderPartInclude.Destroy; +begin + FreeAndNil(fShaderFile); + inherited Destroy; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +class function TengShaderPartInclude.GetTokenName: String; +begin + result := TOKEN_INCLUDE; +end; + +end. + diff --git a/uengShaderPartKeyValuePair.pas b/uengShaderPartKeyValuePair.pas new file mode 100644 index 0000000..573256e --- /dev/null +++ b/uengShaderPartKeyValuePair.pas @@ -0,0 +1,106 @@ +unit uengShaderPartKeyValuePair; + +{$mode objfpc}{$H+} +{$I uengShaderFile.inc} + +interface + +uses + Classes, SysUtils, variants, + uengShaderPart, uengShaderFileParser; + +type +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + TengShaderPartKeyValuePair = class(TengShaderPart) + { Code Loading & Storage } + private + fName: String; + fValue: Variant; + fValueName: String; + protected + function GetText: String; override; + function ParseIntern(const aArgs: TengParseArgs; const aParams: TengTokenParameterList): String; override; + + { General } + public + property Name: String read fName; + property Value: Variant read fValue; + property ValueName: String read fValueName; + end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + TengShaderPartProperty = class(TengShaderPartKeyValuePair) + { Class Methods } + public + class function GetTokenName: String; override; + end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + TengShaderPartDefine = class(TengShaderPartKeyValuePair) + { Class Methods } + public + class function GetTokenName: String; override; + end; + +implementation + +uses + uengShaderFileConstants, uengShaderFileTypes, uengShaderFileHelper; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//TengShaderPartKeyValuePair//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengShaderPartKeyValuePair.GetText: String; +begin + result := TOKEN_CHAR_BEGIN + GetTokenName + ' ' + fName; + if (fValueName <> '') then + result := result + ' ' + fValueName + else if (fValue <> Unassigned) then + result := result + TOKEN_CHAR_QUOTE + String(fValue) + TOKEN_CHAR_QUOTE; + result := result + TOKEN_CHAR_END; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengShaderPartKeyValuePair.ParseIntern(const aArgs: TengParseArgs; const aParams: TengTokenParameterList): String; +begin + if (aParams[0].Name <> GetTokenName) then with aParams[0] do + raise EengInvalidToken.Create(ClassName, GetTokenName, Line, Col, Filename); + if (aParams.Count < 2) or (aParams.Count > 3) then + raise EengInvalidParamterCount.Create(GetTokenName, 2, 3, Line, Col, Filename); + + result := ''; + fName := aParams[1].Name; + if not IsValidIdentifier(fName) then with aParams[1] do + raise EengInvalidIdentifier.Create(fName, Line, Col, Filename); + if (aParams.Count >= 3) then + if aParams[2].Quoted then begin + fValue := aParams[2].Name; + fValueName := ''; + end else begin + fValue := Unassigned; + fValueName := aParams[2].Name; + end + else begin + fValue := Unassigned; + fValueName := ''; + end; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//TengShaderPartProperty//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +class function TengShaderPartProperty.GetTokenName: String; +begin + result := TOKEN_PROPERTY; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//TengShaderPartDefine////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +class function TengShaderPartDefine.GetTokenName: String; +begin + result := TOKEN_DEFINE; +end; + +end. + diff --git a/uengShaderPartMessage.pas b/uengShaderPartMessage.pas new file mode 100644 index 0000000..b9b8b48 --- /dev/null +++ b/uengShaderPartMessage.pas @@ -0,0 +1,31 @@ +unit uengShaderPartMessage; + +{$mode objfpc}{$H+} +{$I uengShaderFile.inc} + +interface + +uses + Classes, SysUtils, + uengShaderPart; + +type +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + TengShaderPartMessage = class(TengShaderPart) + + end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + TengShaderPartWarning = class(TengShaderPartMessage) + + end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + TengShaderPartError = class(TengShaderPartMessage) + + end; + +implementation + +end. + diff --git a/uengShaderPartMeta.pas b/uengShaderPartMeta.pas new file mode 100644 index 0000000..0ad2f55 --- /dev/null +++ b/uengShaderPartMeta.pas @@ -0,0 +1,175 @@ +unit uengShaderPartMeta; + +{$mode objfpc}{$H+} +{$I uengShaderFile.inc} + +interface + +uses + Classes, SysUtils, + uengShaderPart, uengShaderFileParser; + +type +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + TengMetaType = ( + metaUnknown, + metaNormal, + metaVersion, + metaExtension, + metaLayout); + TengMetaData = class(TObject) + private + fMetaType: TengMetaType; + fName: String; + fValues: TStringList; + function GetValues: TStrings; + public + property MetaType: TengMetaType read fMetaType; + property Name: String read fName; + property Values: TStrings read GetValues; + + constructor Create(const aName: String; const aType: TengMetaType); + destructor Destroy; override; + end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + TengShaderPartMeta = class(TengShaderPart) + { Code Loading & Storage } + private + fData: TengMetaData; + protected + function GetText: String; override; + function ParseIntern(const aArgs: TengParseArgs; const aParams: TengTokenParameterList): String; override; + + { General } + public + property Data: TengMetaData read fData; + constructor Create(const aParent: TengShaderPart); override; + destructor Destroy; override; + + { Classs Methods } + public + class function GetTokenName: String; override; + end; + +implementation + +uses + uengShaderFileConstants, uengShaderFileTypes; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//TengMetaData////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengMetaData.GetValues: TStrings; +begin + result := fValues; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +constructor TengMetaData.Create(const aName: String; const aType: TengMetaType); +begin + inherited Create; + fName := aName; + fMetaType := aType; + fValues := TStringList.Create; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +destructor TengMetaData.Destroy; +begin + FreeAndNil(fValues); + inherited Destroy; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//TengShaderPartMeta//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengShaderPartMeta.GetText: String; +var + i: Integer; +begin + result := TOKEN_CHAR_BEGIN + GetTokenName + ' ' + fData.Name; + for i := 0 to fData.Values.Count-1 do begin + if (PtrInt(fData.Values.Objects[i]) <> 0) + then result := result + ' ' + TOKEN_CHAR_QUOTE + fData.Values[i] + TOKEN_CHAR_QUOTE + else result := result + ' ' + fData.Values[i]; + end; + result := result + TOKEN_CHAR_END; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengShaderPartMeta.ParseIntern(const aArgs: TengParseArgs; const aParams: TengTokenParameterList): String; +var + i: Integer; + t: TengMetaType; + n: String; +begin + if (aParams[0].Name <> GetTokenName) then with aParams[0] do + raise EengInvalidToken.Create(ClassName, Name, Line, Col, Filename); + if (aParams.Count < 2) then + raise EengInvalidParamterCount.Create(GetTokenName, 2, -1, Line, Col, Filename); + + result := ''; + n := aParams[1].Name; + + {.$VERSION} + if (n = TOKEN_VERSION) then begin + t := metaVersion; + if (aParams.Count = 3) then begin + if (aParams[2].Name <> VERSION_EXTRA_COMPAT) and not TryStrToInt(aParams[2].Name, i) then with aParams[2] do + raise EengInvalidParamter.Create('version must be an number or "' + VERSION_EXTRA_COMPAT + '"', Line, Col, Filename); + end else if (aParams.Count = 4) then begin + if (aParams[2].Name <> VERSION_EXTRA_COMPAT) and not TryStrToInt(aParams[2].Name, i) then with aParams[2] do + raise EengInvalidParamter.Create('version must be an number or "' + VERSION_EXTRA_COMPAT + '"', Line, Col, Filename); + if (aParams[3].Name <> VERSION_EXTRA_COMPAT) then with aParams[3] do + raise EengInvalidParamter.Create('only "' + VERSION_EXTRA_COMPAT + '" is alowed as second parameter', Line, Col, Filename); + end else + raise EengInvalidParamterCount.Create(GetTokenName, 3, 4, Line, Col, Filename); + + {.$EXTENSION} + end else if (n = TOKEN_EXTENSION) then begin + t := metaExtension; + if (aParams.Count <> 4) then + raise EengInvalidParamterCount.Create(GetTokenName, 4, Line, Col, Filename); + + {.$LAYOUT} + end else if (n = TOKEN_LAYOUT) then begin + t := metaLayout; + if (aParams.Count <> 3) then + raise EengInvalidParamterCount.Create(GetTokenName, 3, Line, Col, Filename); + + {.VALUES} + end else + t := metaNormal; + + fData := TengMetaData.Create(n, t); + try + for i := 2 to aParams.Count-1 do + fData.Values.AddObject(aParams[i].Name, TObject(PtrInt(aParams[i].Quoted))); + except + FreeAndNil(fData); + end; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +constructor TengShaderPartMeta.Create(const aParent: TengShaderPart); +begin + inherited Create(aParent); + fData := nil; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +destructor TengShaderPartMeta.Destroy; +begin + FreeAndNil(fData); + inherited Destroy; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +class function TengShaderPartMeta.GetTokenName: String; +begin + result := TOKEN_META; +end; + +end. + diff --git a/uengShaderPartParameter.pas b/uengShaderPartParameter.pas new file mode 100644 index 0000000..456b9a7 --- /dev/null +++ b/uengShaderPartParameter.pas @@ -0,0 +1,143 @@ +unit uengShaderPartParameter; + +{$mode objfpc}{$H+} +{$I uengShaderFile.inc} + +interface + +uses + Classes, SysUtils, + uengShaderPart, uengShaderFileParser; + +type +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + TengShaderPartParameter = class(TengShaderPart) + { Code Loading & Storage } + private + fName: String; + fType: String; + protected + function GetText: String; override; + function ParseIntern(const aArgs: TengParseArgs; const aParams: TengTokenParameterList): String; override; + + { General } + public + property Name: String read fName; + property Typ: String read fType; + end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + TengShaderPartVar = class(TengShaderPartParameter) + { Code Loading & Storage } + private + fDefaultValue: String; + protected + function GetText: String; override; + function ParseIntern(const aArgs: TengParseArgs; const aParams: TengTokenParameterList): String; override; + + { General } + public + property DefaultValue: String read fDefaultValue; + + { Class Methods } + public + class function GetTokenName: String; override; + end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + TengShaderPartVarying = class(TengShaderPartParameter) + { Class Methods } + public + class function GetTokenName: String; override; + end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + TengShaderPartUniform = class(TengShaderPartParameter) + { Class Methods } + public + class function GetTokenName: String; override; + end; + +implementation + +uses + uengShaderFileConstants, uengShaderFileTypes; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengShaderPartParameter.GetText: String; +begin + result := TOKEN_CHAR_BEGIN + GetTokenName + ' ' + + TOKEN_CHAR_QUOTE + fType + TOKEN_CHAR_QUOTE + ' ' + + TOKEN_CHAR_QUOTE + fName + TOKEN_CHAR_QUOTE + + TOKEN_CHAR_END; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengShaderPartParameter.ParseIntern(const aArgs: TengParseArgs; const aParams: TengTokenParameterList): String; +begin + if (aParams[0].Name <> GetTokenName) then with aParams[0] do + raise EengInvalidToken.Create(ClassName, Name, Line, Col, Filename); + if (aParams.Count <> 3) then + raise EengInvalidParamterCount.Create(GetTokenName, 3, Line, Col, Filename); + + result := ''; + fType := aParams[1].Name; + fName := aParams[2].Name; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//TengShaderPartVar///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengShaderPartVar.GetText: String; +begin + result := TOKEN_CHAR_BEGIN + GetTokenName + ' ' + + TOKEN_CHAR_QUOTE + fType + TOKEN_CHAR_QUOTE + ' ' + + TOKEN_CHAR_QUOTE + fName + TOKEN_CHAR_QUOTE; + if (fDefaultValue <> '') then + result := result + ' ' + TOKEN_CHAR_QUOTE + fDefaultValue + TOKEN_CHAR_QUOTE; + result := result + TOKEN_CHAR_END; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengShaderPartVar.ParseIntern(const aArgs: TengParseArgs; const aParams: TengTokenParameterList): String; +begin + if (aParams[0].Name <> GetTokenName) then with aParams[0] do + raise EengInvalidToken.Create(ClassName, Name, Line, Col, Filename); + if (aParams.Count < 3) or (aParams.Count > 4) then + raise EengInvalidParamterCount.Create(GetTokenName, 3, 4, Line, Col, Filename); + + result := ''; + fType := aParams[1].Name; + fName := aParams[2].Name; + if (aParams.Count >= 4) then + fDefaultValue := aParams[3].Name + else + fDefaultValue := ''; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +class function TengShaderPartVar.GetTokenName: String; +begin + result := TOKEN_VAR; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//TengShaderPartVarying///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +class function TengShaderPartVarying.GetTokenName: String; +begin + result := TOKEN_VARYING; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//TengShaderPartUniform///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +class function TengShaderPartUniform.GetTokenName: String; +begin + result := TOKEN_UNIFORM; +end; + +end. + diff --git a/uengShaderPartProc.pas b/uengShaderPartProc.pas new file mode 100644 index 0000000..fa7f024 --- /dev/null +++ b/uengShaderPartProc.pas @@ -0,0 +1,251 @@ +unit uengShaderPartProc; + +{$mode objfpc}{$H+} +{$I uengShaderFile.inc} + +interface + +uses + Classes, SysUtils, + uengShaderPart, uengShaderPartScope, uengShaderFileParser + +{$IFDEF USE_BITSPACE_UTILS} + , uutlGenerics; +{$ELSE} + , fgl; +{$ENDIF} + +type +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + TengShaderPartProcParam = packed record + Typ: String; + Name: String; + end; + TengShaderPartProcParamList = specialize TutlSimpleList; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + TengShaderPartProc = class(TengShaderPartScope) + { Code Loading & Storage } + private + fName: String; + fIsInline: Boolean; + fParameters: TengShaderPartProcParamList; + protected + function GetHeaderText: String; virtual; + function GetText: String; override; + function ParseIntern(const aArgs: TengParseArgs; const aParams: TengTokenParameterList): String; override; + + { General } + public + property Name: String read fName; + property IsInline: Boolean read fIsInline; + + constructor Create(const aParent: TengShaderPart); override; + destructor Destroy; override; + + { Class Members } + public + class function GetTokenName: String; override; + class procedure Validate(const aArgs: TengParseArgs; const aParent: TengShaderPart); override; + end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + TengShaderPartMain = class(TengShaderPartProc) + { Code Loading & Storage } + protected + function GetHeaderText: String; override; + function ParseIntern(const aArgs: TengParseArgs; const aParams: TengTokenParameterList): String; override; + + { General } + public + class function GetTokenName: String; override; + end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + TengShaderPartFunc = class(TengShaderPartProc) + { Code Loading & Storage } + private + fReturnType: String; + protected + function GetHeaderText: String; override; + function ParseIntern(const aArgs: TengParseArgs; const aParams: TengTokenParameterList): String; override; + + { Class Methods } + public + class function GetTokenName: String; override; + end; + +implementation + +uses + uengShaderFileConstants, uengShaderFileTypes, uengShaderFileHelper; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//TengShaderPartProc//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengShaderPartProc.GetHeaderText: String; +var + p: TengShaderPartProcParam; +begin + result := TOKEN_CHAR_BEGIN + GetTokenName + ' ' + TOKEN_CHAR_QUOTE + fName + TOKEN_CHAR_QUOTE; + for p in fParameters do begin + result := result + ' ' + TOKEN_CHAR_QUOTE + p.Typ + TOKEN_CHAR_QUOTE + + ' ' + TOKEN_CHAR_QUOTE + p.Name + TOKEN_CHAR_QUOTE; + end; + result := result + TOKEN_CHAR_END; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengShaderPartProc.GetText: String; +begin + result := GetHeaderText + + inherited GetText + + TOKEN_CHAR_BEGIN + TOKEN_END + TOKEN_CHAR_END; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengShaderPartProc.ParseIntern(const aArgs: TengParseArgs; const aParams: TengTokenParameterList): String; +type + TParseArgsState = (pasType, pasName); +var + i: Integer; + state: TParseArgsState; + param: TengShaderPartProcParam; +begin + if (aParams[0].Name <> GetTokenName) then with aParams[0] do + raise EengInvalidToken.Create(ClassName, Name, Line, Col, Filename); + if (aParams.Count < 2) then + raise EengInvalidParamterCount.Create(GetTokenName, 2, -1, Line, Col, Filename); + + i := 2; + result := ''; + fName := aParams[1].Name; + state := pasType; + fParameters.Clear; + while (i < aParams.Count) do begin + case state of + pasType: begin + if (aParams[i].Name <> TOKEN_INLINE) then begin + param.Typ := aParams[i].Name; + state := pasName; + end else + fIsInline := true; + end; + + pasName: begin + if (aParams[i].Name = TOKEN_INLINE) then begin + with aParams[i] do + raise EengInvalidParamter.Create('expected parameter name (found ' + TOKEN_INLINE + ')', Line, Col, Filename); + end else begin + param.Name := aParams[i].Name; + fParameters.Add(param); + state := pasType; + end; + end; + end; + inc(i); + end; + if (state <> pasType) then + raise EengInvalidParamterCount.Create('invalid parameter count in ' + GetTokenName + '(expected multiple of 2)', Line, Col, Filename); + inherited ParseIntern(aArgs, aParams); + result := CheckEndToken(aArgs, self); +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +constructor TengShaderPartProc.Create(const aParent: TengShaderPart); +begin + inherited Create(aParent); + fParameters := TengShaderPartProcParamList.Create(true); +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +destructor TengShaderPartProc.Destroy; +begin + FreeAndNil(fParameters); + inherited Destroy; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +class function TengShaderPartProc.GetTokenName: String; +begin + result := TOKEN_PROC; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +class procedure TengShaderPartProc.Validate(const aArgs: TengParseArgs; const aParent: TengShaderPart); +begin + if (aParent.HasParent(TengShaderPartProc, true)) then with aArgs do + raise EengShaderPart.Create('token ' + GetTokenName + ' is not allowed inside ' + + TOKEN_PROC + ', ' + TOKEN_FUNC + ' or + ' + TOKEN_MAIN, Line, Col, aParent.Filename); +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//TengShaderPartMain//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengShaderPartMain.GetHeaderText: String; +begin + result := TOKEN_CHAR_BEGIN + GetTokenName + TOKEN_CHAR_END; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengShaderPartMain.ParseIntern(const aArgs: TengParseArgs; const aParams: TengTokenParameterList): String; +var + p: TengTokenParameter; +begin + if (aParams[0].Name <> GetTokenName) then with aParams[0] do + raise EengInvalidToken.Create(ClassName, Name, Line, Col, Filename); + if (aParams.Count <> 1) then + raise EengInvalidParamterCount.Create(GetTokenName, 1, Line, Col, Filename); + + result := ''; + p.Name := 'main'; + p.Quoted := false; + p.Line := Line; + p.Col := Col + Length(GetTokenName); + aParams.Add(p); + inherited ParseIntern(aArgs, aParams); +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +class function TengShaderPartMain.GetTokenName: String; +begin + result := TOKEN_MAIN; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//TengShaderPartFunc//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengShaderPartFunc.GetHeaderText: String; +var + p: TengShaderPartProcParam; +begin + result := TOKEN_CHAR_BEGIN + GetTokenName + ' ' + + TOKEN_CHAR_QUOTE + fReturnType + TOKEN_CHAR_QUOTE + ' ' + + TOKEN_CHAR_QUOTE + fName + TOKEN_CHAR_QUOTE; + for p in fParameters do + result := result + ' ' + TOKEN_CHAR_QUOTE + p.Typ + TOKEN_CHAR_QUOTE + + ' ' + TOKEN_CHAR_QUOTE + p.Name + TOKEN_CHAR_QUOTE; + result := result + TOKEN_CHAR_END; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengShaderPartFunc.ParseIntern(const aArgs: TengParseArgs; const aParams: TengTokenParameterList): String; +begin + if (aParams[0].Name <> GetTokenName) then with aParams[0] do + raise EengInvalidToken.Create(ClassName, aParams[0].Name, Line, Col, Filename); + if (aParams.Count < 3) then + raise EengInvalidParamterCount.Create(GetTokenName, 3, Line, Col, Filename); + + fReturnType := aParams[1].Name; + aParams.Delete(1); + result := inherited ParseIntern(aArgs, aParams); +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +class function TengShaderPartFunc.GetTokenName: String; +begin + result := TOKEN_FUNC; +end; + +end. + diff --git a/uengShaderPartScope.pas b/uengShaderPartScope.pas new file mode 100644 index 0000000..a00a14e --- /dev/null +++ b/uengShaderPartScope.pas @@ -0,0 +1,20 @@ +unit uengShaderPartScope; + +{$mode objfpc}{$H+} +{$I uengShaderFile.inc} + +interface + +uses + Classes, SysUtils, + uengShaderPartCntr; + +type + TengShaderPartScope = class(TengShaderPartCntr) + + end; + +implementation + +end. + diff --git a/uengShaderPartText.pas b/uengShaderPartText.pas new file mode 100644 index 0000000..ba03e85 --- /dev/null +++ b/uengShaderPartText.pas @@ -0,0 +1,143 @@ +unit uengShaderPartText; + +{$mode objfpc}{$H+} +{$I uengShaderFile.inc} + +interface + +uses + Classes, SysUtils, + uengShaderPart, uengShaderFileParser; + +type +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + TengShaderPartText = class(TengShaderPart) + { Code Loading & Storage } + private + fText: String; + function GetIsEmpty: Boolean; + protected + function GetText: String; override; + function ParseIntern(const aArgs: TengParseArgs; const aParams: TengTokenParameterList): String; override; + public + property Text: String read fText; + property IsEmpty: Boolean read GetIsEmpty; + end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + TengShaderPartLineBreak = class(TengShaderPart) + { Code Loading & Storage } + protected + function GetText: String; override; + function ParseIntern(const aArgs: TengParseArgs; const aParams: TengTokenParameterList): String; override; + + { Class Methods } + public + class function GetTokenName: String; override; + end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + TengShaderPartCommandEnd = class(TengShaderPart) + { Code Loading & Storage } + private + fToken: String; + protected + function GetText: String; override; + function ParseIntern(const aArgs: TengParseArgs; const aParams: TengTokenParameterList): String; override; + + { Class Methods } + public + class function CheckToken(const aToken: String): Boolean; override; + end; + +implementation + +uses + uengShaderFileConstants, uengShaderFileTypes; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//TengShaderPartText//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengShaderPartText.GetIsEmpty: Boolean; +begin + result := (fText = ''); +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengShaderPartText.GetText: String; +begin + result := fText; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengShaderPartText.ParseIntern(const aArgs: TengParseArgs; const aParams: TengTokenParameterList): String; +begin + fText := ''; + result := ''; + while not aArgs.EndOfLine do begin + if aArgs.GetTokenPreview(result) then begin + exit; + end else if (aArgs.CurrentChar in COMMAND_END_TOKENS) then begin + result := aArgs.CurrentChar; + exit; + end else begin + fText := fText + aArgs.CurrentChar; + aArgs.NextCol; + end; + end; + result := TOKEN_LINE_BREAK; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//TengShaderPartLineBreak/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengShaderPartLineBreak.GetText: String; +begin + result := TOKEN_LINE_BREAK; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengShaderPartLineBreak.ParseIntern(const aArgs: TengParseArgs; const aParams: TengTokenParameterList): String; +begin + if not aArgs.EndOfLine then + raise EengInvalidToken.Create(ClassName, '[LineBreak]', Line, Col, Filename); + aArgs.NextLine; + result := ''; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +class function TengShaderPartLineBreak.GetTokenName: String; +begin + result := TOKEN_LINE_BREAK; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//TengShaderPartCommandEnd////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengShaderPartCommandEnd.GetText: String; +begin + result := fToken; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengShaderPartCommandEnd.ParseIntern(const aArgs: TengParseArgs; const aParams: TengTokenParameterList): String; +begin + result := ''; + fToken := aArgs.CurrentChar; + aArgs.NextCol; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +class function TengShaderPartCommandEnd.CheckToken(const aToken: String): Boolean; +var + s: String; +begin + result := true; + for s in COMMAND_END_TOKENS do + if (s = aToken) then + exit; + result := false; +end; + +end. +