unit uengShaderGenerator; {$mode objfpc}{$H+} {$I uengShaderFile.inc} interface uses Classes, SysUtils, uengShaderPart, uengShaderFileTypes, uengShaderFileParser, uengShaderPartScope, uengShaderPartKeyValuePair, uengShaderGeneratorArgs; type //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// TengShaderGenerator = class(TengShaderPartScope) { Code Loading & Storage } private fPropertyMap: TengShaderPartPropertyMap; function GetPropertyByIndex(const aIndex: Integer): Variant; function GetPropertyByName(const aName: String): Variant; function GetPropertyCount: Integer; function GetPropertyNames(const aIndex: Integer): String; procedure SetPropertyByIndex(const aIndex: Integer; aValue: Variant); procedure SetPropertyByName(const aName: String; aValue: Variant); protected procedure AddProperty(const aProp: TengShaderPartProperty; const aShowWarning: Boolean = true); procedure CopyProperties(const aGen: TengShaderGenerator); procedure UpdateProperties; virtual; function ParseIntern(const aArgs: TengParseArgs; const aParams: TengTokenParameterList): String; override; public property PropertyByName [const aName: String]: Variant read GetPropertyByName write SetPropertyByName; property PropertyByIndex[const aIndex: Integer]: Variant read GetPropertyByIndex write SetPropertyByIndex; property PropertyNames [const aIndex: Integer]: String read GetPropertyNames; property PropertyCount: Integer read GetPropertyCount; function TryGetProperty(const aName: String; out aValue: Variant): Boolean; function TrySetProperty(const aName: String; const aValue: Variant): Boolean; procedure ListProperties(const aPropertyNames: TStrings); { Generate Shader Code } public procedure GenerateCode(const aCode: TengShaderCode); { General } public constructor Create(const aParent: TengShaderPart); override; destructor Destroy; override; end; implementation uses uengShaderFile, uengShaderFileHelper, uengShaderPartProc, uengShaderPartParameter; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //TengShaderGenerator/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function TengShaderGenerator.GetPropertyByIndex(const aIndex: Integer): Variant; begin result := fPropertyMap.ValueAt[aIndex].Value; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function TengShaderGenerator.GetPropertyByName(const aName: String): Variant; var l: TengShaderPartPropertyList; begin l := fPropertyMap[aName]; if not Assigned(l) then EengUnknownIdentifier.Create(aName, self); result := l.Value; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function TengShaderGenerator.GetPropertyCount: Integer; begin result := fPropertyMap.Count; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function TengShaderGenerator.GetPropertyNames(const aIndex: Integer): String; begin result := fPropertyMap.KeyValuePairs[aIndex].Key; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// procedure TengShaderGenerator.SetPropertyByIndex(const aIndex: Integer; aValue: Variant); begin fPropertyMap.ValueAt[aIndex].Value := aValue; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// procedure TengShaderGenerator.SetPropertyByName(const aName: String; aValue: Variant); var l: TengShaderPartPropertyList; begin l := fPropertyMap[aName]; if not Assigned(l) then raise EengUnknownIdentifier.Create(aName, self); l.Value := aValue; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// procedure TengShaderGenerator.AddProperty(const aProp: TengShaderPartProperty; const aShowWarning: Boolean); var i: Integer; l: TengShaderPartPropertyList; p: TengShaderPartProperty; s: String; begin i := -1; l := fPropertyMap[aProp.Name]; if Assigned(l) then begin i := l.IndexOf(aProp); if aShowWarning and (i >= 0) then begin p := l.Last; s := Format('use of duplicate identifier: %s (%s %d:%d)', [aProp.Name, aProp.Filename, aProp.Line + 1, aProp.Col]) + sLineBreak + 'previously declared here:' + sLineBreak + Format(' %s %d:%d', [p.Filename, p.Line + 1, p.Col]) + sLineBreak; LogMsg(llWarning, s); end; end else begin l := TengShaderPartPropertyList.Create; fPropertyMap.Add(aProp.Name, l); end; if (i < 0) then begin l.Add(aProp); if (aProp.Value <> Unassigned) then l.Value := aProp.Value; end; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// procedure TengShaderGenerator.CopyProperties(const aGen: TengShaderGenerator); var l: TengShaderPartPropertyList; p: TengShaderPartProperty; begin for l in fPropertyMap do for p in l do aGen.AddProperty(p, false); end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// procedure TengShaderGenerator.UpdateProperties; begin fPropertyMap.Clear; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function TengShaderGenerator.ParseIntern(const aArgs: TengParseArgs; const aParams: TengTokenParameterList): String; begin result := inherited ParseIntern(aArgs, aParams); UpdateProperties; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function TengShaderGenerator.TryGetProperty(const aName: String; out aValue: Variant): Boolean; var l: TengShaderPartPropertyList; begin l := fPropertyMap[aName]; result := Assigned(l); if result then aValue := l.Value else aValue := unassigned; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function TengShaderGenerator.TrySetProperty(const aName: String; const aValue: Variant): Boolean; var l: TengShaderPartPropertyList; begin l := fPropertyMap[aName]; result := Assigned(l); if result then l.Value := aValue; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// procedure TengShaderGenerator.ListProperties(const aPropertyNames: TStrings); var s: String; begin for s in fPropertyMap.Keys do aPropertyNames.Add(s); end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// procedure TengShaderGenerator.GenerateCode(const aCode: TengShaderCode); var args: TengShaderGeneratorArgs; sr: TengSearchResults; walker: TengSearchWalker; main: TengShaderPartMain; begin args := TengShaderGeneratorArgs.Create(self); try fPropertyMap.ApplyValues; GenerateCodeIntern(args); args.PushCode; sr := TengSearchResults.Create; walker := TengSearchWalker.Create(sr); try walker.SearchFlags := [sfSearchChildren, sfEvaluateIf]; walker.ResultTypes := CengShaderPartArr.Create(TengShaderPartMain); walker.ChildrenDoNotLeave := CengShaderPartArr.Create(TengShaderGenerator); walker.ChildrenForceLeave := CengShaderPartArr.Create(TengShaderFile); walker.Run(self); if (self is TengShaderFile) then main := (ExtractSearchResult(self, TengShaderPartMain.GetTokenName, sr, []) as TengShaderPartMain) else main := (ExtractSearchResult(self, TengShaderPartMain.GetTokenName, sr) as TengShaderPartMain); if Assigned(main) then begin args.PushFlags((args.Flags * [gfAddProcedureItem, gfAddParameterItem]) + [gfGenerateProcedureCode, gfGenerateProcedureMain]); try main.GenerateCodeIntern(args); finally args.PopFlags; end; end; finally FreeAndNil(walker); FreeAndNil(sr); args.PopCode([pcfAppend, pcfAddEmptyLine]); end; args.GenerateProcedureCode; args.GenerateParameterCode(CengShaderPartArr.Create(TengShaderPartVar)); args.GenerateParameterCode(CengShaderPartArr.Create(TengShaderPartVarying)); args.GenerateParameterCode(CengShaderPartArr.Create(TengShaderPartUniform)); args.PushCode; try args.GenerateMetaCode; finally args.PopCode([pcfPrepend, pcfAddEmptyLine]); end; args.GenerateCode(aCode); finally FreeAndNil(args); end; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// constructor TengShaderGenerator.Create(const aParent: TengShaderPart); begin inherited Create(aParent); fPropertyMap := TengShaderPartPropertyMap.Create(true); end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// destructor TengShaderGenerator.Destroy; begin FreeAndNil(fPropertyMap); inherited Destroy; end; end.