diff --git a/uengShaderFile.pas b/uengShaderFile.pas index 1acb50c..6f9b004 100644 --- a/uengShaderFile.pas +++ b/uengShaderFile.pas @@ -12,7 +12,7 @@ interface uses Classes, sysutils, - uengShaderCodeGenerator, uengShaderFileParser, uengShaderFileTypes + uengShaderPart, uengShaderCodeGenerator, uengShaderFileParser, uengShaderFileTypes {$IFDEF USE_BITSPACE_UTILS} , uutlSerialization @@ -31,12 +31,21 @@ type function GetFilename: String; override; function GetFileReader: IengShaderFileReader; override; function GetFileWriter: IengShaderFileWriter; override; - public { general methods } - procedure LoadCode(const aFilename: String; const aFileReader: IengShaderFileReader = nil); + + { General } + protected + procedure FindIntern(aFlags: TengShaderFileSearchFlags; aDepth: Integer; aTypes: array of CengShaderPart; const aList: TSearchList); override; + public + procedure LoadFromFile(const aFilename: String; const aFlags: TengShaderFileLoadFlags = []; const aFileReader: IengShaderFileReader = nil); + procedure SaveToFile(const aFilename: String; const aFileWriter: IengShaderFileWriter = nil); + destructor Destroy; override; end; implementation +uses + uengShaderPartInclude; + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //TengShaderFile//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -62,7 +71,16 @@ begin end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -procedure TengShaderFile.LoadCode(const aFilename: String; const aFileReader: IengShaderFileReader); +procedure TengShaderFile.FindIntern(aFlags: TengShaderFileSearchFlags; aDepth: Integer; aTypes: array of CengShaderPart; const aList: TSearchList); +begin + if (sfCurrentFileOnly in aFlags) then + exclude(aFlags, sfSearchParents); + inherited FindIntern(aFlags, aDepth, aTypes, aList); +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +procedure TengShaderFile.LoadFromFile(const aFilename: String; const aFlags: TengShaderFileLoadFlags; + const aFileReader: IengShaderFileReader); var args: TengParseArgs; token: String; @@ -79,8 +97,10 @@ begin if not fFileReader.LoadStream(aFilename, ms) then raise EengShaderPart.Create('unable to open file: ' + aFilename, Line, Col, Filename); ms.Position := 0; + fFilename := aFilename; args := TengParseArgs.Create(ms, Filename); try + args.Flags := aFlags; token := ParseText(args); if (token <> '') then with args do raise EengShaderPart.Create('unknown token ''' + token + '''', Line, Col, Filename); @@ -88,9 +108,51 @@ begin FreeAndNil(args); end; finally - fFileReader := nil; + if not (lfLazyInclude in aFlags) then + fFileReader := nil; end; end; +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +procedure TengShaderFile.SaveToFile(const aFilename: String; const aFileWriter: IengShaderFileWriter); +var + l: TengShaderPart.TSearchList; + i: Integer; + sl: TStringList; + ms: TMemoryStream; +begin + fFileWriter := aFileWriter; + if not Assigned(fFileWriter) then + fFileWriter := FileWriter; + if not Assigned(fFileWriter) then + fFileWriter := TengShaderFileWriter.Create; + + l := TengShaderPart.TSearchList.Create; + sl := TStringList.Create; + ms := TMemoryStream.Create; + try + FindAll([sfSearchChildren, sfCurrentFileOnly], [TengShaderPartInclude], l); + for i := 0 to l.Count-1 do + (l[i] as TengShaderPartInclude).SaveToFile(aFilename, aFileWriter); + sl.Text := Text; + sl.SaveToStream(ms); + ms.Position := 0; + fFileWriter.SaveStream(aFilename, ms); + finally + FreeAndNil(l); + FreeAndNil(sl); + FreeAndNil(ms); + fFileWriter := nil; + end; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +destructor TengShaderFile.Destroy; +begin + fFileReader := nil; + fFileWriter := nil; + inherited Destroy; +end; + end. diff --git a/uengShaderFileParser.pas b/uengShaderFileParser.pas index 7f87058..7d25dc3 100644 --- a/uengShaderFileParser.pas +++ b/uengShaderFileParser.pas @@ -6,7 +6,8 @@ unit uengShaderFileParser; interface uses - Classes, SysUtils + Classes, SysUtils, + uengShaderFileTypes {$IFDEF USE_BITSPACE_UTILS} , uutlGenerics @@ -36,6 +37,7 @@ type private fFilename: String; fCode: TStringList; + fFlags: TengShaderFileLoadFlags; fLineLength: Integer; fLineCount: Integer; fCurrentLine: String; @@ -61,6 +63,8 @@ type property Col: Integer read fCol write SetCol; property Line: Integer read fLine write SetLine; + property Flags: TengShaderFileLoadFlags read fFlags write fFlags; + procedure NextCol; procedure NextLine; function ExtractToken(const aParameters: TengTokenParameterList): Boolean; @@ -73,7 +77,7 @@ type implementation uses - uengShaderFileConstants, uengShaderFileTypes; + uengShaderFileConstants; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //TengTokenParameterList//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -150,7 +154,7 @@ type TParseFlags = set of TParseFlag; var - flags: TParseFlags; + pf: TParseFlags; ct: TCharType; s: String; pLine, pCol, oldLine, oldCol: Integer; @@ -203,26 +207,26 @@ begin ct := ctUnknown; oldLine := Line; oldCol := Col; - flags := []; + pf := []; if (CurrentLine[Col+1] = TOKEN_CHAR_COMMENT) then - Include(flags, pfIsComment); + Include(pf, 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 + if (pfQuote in pf) then s := s + CurrentChar - else if not (pfInToken in flags) then - Include(flags, pfInToken) + else if not (pfInToken in pf) then + Include(pf, 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)); + if not (pfQuote in pf) then begin + AddPart(not (pfIsComment in pf)); NextCol; if (aParameters.Count <= 0) or (aParameters[0].Name = TOKEN_CHAR_IDENT) then raise EengShaderPart.Create('empty token', Line, Col, Filename); @@ -232,25 +236,25 @@ begin end; TOKEN_CHAR_QUOTE: begin - if not (pfQuote in flags) and not (pfIsComment in flags) then + if not (pfQuote in pf) and not (pfIsComment in pf) 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 + if (pfQuote in pf) + then exclude(pf, pfQuote) + else include(pf, pfQuote); + if not (pfQuote in pf) and not (pfIsComment in pf) then AddPart; end; TOKEN_CHAR_COMMENT: begin s := s + CurrentChar; - if (pfIsComment in flags) and not (pfCommentTokenAdded in flags) then begin - include(flags, pfCommentTokenAdded); + if (pfIsComment in pf) and not (pfCommentTokenAdded in pf) then begin + include(pf, pfCommentTokenAdded); AddPart(false); end; end; else - if not (pfQuote in flags) and not (pfIsComment in flags) then begin + if not (pfQuote in pf) and not (pfIsComment in pf) then begin if (CurrentChar in TOKEN_SPLIT_CHARS) then begin AddPart; end else if (CurrentChar in VALID_TOKEN_CHARS) then begin diff --git a/uengShaderFileTypes.pas b/uengShaderFileTypes.pas index bf830c4..d86020e 100644 --- a/uengShaderFileTypes.pas +++ b/uengShaderFileTypes.pas @@ -23,6 +23,12 @@ type TIntfObjNoRefCount = uutlCommon.TutlInterfaceNoRefCount; {$ENDIF} +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + TengShaderFileLoadFlag = ( + lfLazyInclude // include files will only be loaded when needed (this will store a reference to the passed IengShaderFileReader) + ); + TengShaderFileLoadFlags = set of TengShaderFileLoadFlag; + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// EengShaderPart = class(Exception) public diff --git a/uengShaderPart.pas b/uengShaderPart.pas index 684a213..c174712 100644 --- a/uengShaderPart.pas +++ b/uengShaderPart.pas @@ -18,7 +18,18 @@ uses type //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + TengShaderFileSearchFlag = ( + sfFirstOnly, // search first match only + sfEvaluateIf, // evaluate if statements before search and process with suitable subtree + sfSearchChildren, // search in children + sfSearchParents, // search in parents + sfCurrentFileOnly // do not search in other files + ); + TengShaderFileSearchFlags = set of TengShaderFileSearchFlag; + + TengShaderPart = class; CengShaderPart = class of TengShaderPart; + TengShaderPartList = specialize TutlSimpleList; TengShaderPart = class(TIntfObjNoRefCount) { Nested Types } public type @@ -33,6 +44,11 @@ type constructor Create(const aOwner: TengShaderPart); end; + TSearchList = class(TengShaderPartList) + public + constructor Create; + end; + { Code Loading & Storage } private { members } fRoot: TengShaderPart; @@ -52,6 +68,8 @@ type function ParseText(const aArgs: TengParseArgs): String; { General } + protected + procedure FindIntern(aFlags: TengShaderFileSearchFlags; aDepth: Integer; aTypes: array of CengShaderPart; const aList: TSearchList); virtual; public { general methods } property Root: TengShaderPart read fRoot; property Parent: TengShaderPart read fParent; @@ -68,6 +86,8 @@ type function HasParent(const aType: CengShaderPart; const aIncludeSelf: Boolean = false): Boolean; function GetParent(const aType: CengShaderPart; out aPart): Boolean; + function FindFirst(const aFlags: TengShaderFileSearchFlags; const aTypes: array of CengShaderPart): TengShaderPart; + procedure FindAll(const aFlags: TengShaderFileSearchFlags; const aTypes: array of CengShaderPart; const aList: TSearchList); function GetEnumerator: TEnumerator; constructor Create(const aParent: TengShaderPart); virtual; @@ -78,13 +98,25 @@ type 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; +function CheckType(const aShaderPart: TengShaderPart; const aTypes: array of CengShaderPart): Boolean; +var + c: CengShaderPart; +begin + result := true; + if (Length(aTypes) = 0) then + exit; + for c in aTypes do + if (aShaderPart is c) then + exit; + result := false; +end; + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //TengShaderPart.TEnumerator//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -108,6 +140,14 @@ begin fPosition := -1; end; +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//TengShaderPart.TSearchList//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +constructor TengShaderPart.TSearchList.Create; +begin + inherited Create(false); +end; + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //TengShaderPart//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -169,6 +209,26 @@ begin end; end; +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +procedure TengShaderPart.FindIntern(aFlags: TengShaderFileSearchFlags; aDepth: Integer; aTypes: array of CengShaderPart; const aList: TSearchList); +var + c: TengShaderPart; +begin + if (sfFirstOnly in aFlags) and (aList.Count > 0) then + exit; + + if CheckType(self, aTypes) then + aList.Add(self); + + if (sfSearchChildren in aFlags) then begin + for c in self do + c.FindIntern(aFlags, aDepth+1, aTypes, aList); + end; + + if (sfSearchParents in aFlags) and Assigned(Parent) then + Parent.FindIntern(aFlags, aDepth-1, aTypes, aList); +end; + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function TengShaderPart.ParseIntern(const aArgs: TengParseArgs; const aParams: TengTokenParameterList): String; begin @@ -195,6 +255,28 @@ begin result := false; end; +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +function TengShaderPart.FindFirst(const aFlags: TengShaderFileSearchFlags; const aTypes: array of CengShaderPart): TengShaderPart; +var + l: TSearchList; +begin + l := TSearchList.Create; + try + FindIntern(aFlags + [sfFirstOnly], 0, aTypes, l); + if (l.Count > 0) + then result := l[0] + else result := nil; + finally + FreeAndNil(l); + end; +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +procedure TengShaderPart.FindAll(const aFlags: TengShaderFileSearchFlags; const aTypes: array of CengShaderPart; const aList: TSearchList); +begin + FindIntern(aFlags, 0, aTypes, aList); +end; + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function TengShaderPart.GetEnumerator: TEnumerator; begin diff --git a/uengShaderPartInclude.pas b/uengShaderPartInclude.pas index 07a6047..016b79e 100644 --- a/uengShaderPartInclude.pas +++ b/uengShaderPartInclude.pas @@ -7,7 +7,7 @@ interface uses Classes, SysUtils, - uengShaderPart, uengShaderFile, uengShaderFileParser; + uengShaderPart, uengShaderFile, uengShaderFileParser, uengShaderFileTypes; type //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// @@ -17,6 +17,7 @@ type fShaderFile: TengShaderFile; fIncludeFile: String; fAbsoluteFile: String; + procedure LoadShaderFile(const aFlags: TengShaderFileLoadFlags); protected function GetCount: Integer; override; function GetChild(const aIndex: Integer): TengShaderPart; override; @@ -24,8 +25,11 @@ type function ParseIntern(const aArgs: TengParseArgs; const aParams: TengTokenParameterList): String; override; { General } + protected + procedure FindIntern(aFlags: TengShaderFileSearchFlags; aDepth: Integer; aTypes: array of CengShaderPart; const aList: TSearchList); override; public property IncludeFile: String read fIncludeFile; + procedure SaveToFile(const aFilename: String; const aFileWriter: IengShaderFileWriter = nil); constructor Create(const aParent: TengShaderPart); override; destructor Destroy; override; @@ -38,10 +42,19 @@ implementation uses FileUtil, - uengShaderFileTypes, uengShaderFileConstants; + uengShaderFileConstants; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //TengShaderPartInclude///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +procedure TengShaderPartInclude.LoadShaderFile(const aFlags: TengShaderFileLoadFlags); +begin + if not Assigned(fShaderFile) then + fShaderFile := TengShaderFile.Create(self); + if (fShaderFile.Filename <> fAbsoluteFile) then + fShaderFile.LoadFromFile(fAbsoluteFile, aFlags); +end; + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function TengShaderPartInclude.GetCount: Integer; begin @@ -74,6 +87,25 @@ begin fIncludeFile := aParams[1].Name; fAbsoluteFile := CreateAbsolutePath(fIncludeFile, ExtractFilePath(Filename)); result := ''; + if not (lfLazyInclude in aArgs.Flags) then + LoadShaderFile(aArgs.Flags); +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +procedure TengShaderPartInclude.FindIntern(aFlags: TengShaderFileSearchFlags; aDepth: Integer; aTypes: array of CengShaderPart; const aList: TSearchList); +begin + if (sfCurrentFileOnly in aFlags) then + exclude(aFlags, sfSearchChildren); + inherited FindIntern(aFlags, aDepth, aTypes, aList); +end; + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +procedure TengShaderPartInclude.SaveToFile(const aFilename: String; const aFileWriter: IengShaderFileWriter); +begin + LoadShaderFile([]); + fIncludeFile := Format('%p_', [Pointer(fShaderFile)]) + ExtractFileName(fIncludeFile); + fAbsoluteFile := CreateAbsolutePath(fIncludeFile, ExtractFilePath(aFilename)); + fShaderFile.SaveToFile(fAbsoluteFile, aFileWriter); end; ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////