unit uengShaderGeneratorArgs; {$mode objfpc}{$H+} {$I uengShaderFile.inc} interface uses Classes, SysUtils, uengShaderFileTypes, uengShaderPart {$IFDEF USE_BITSPACE_UTILS} , uutlGenerics {$ENDIF} ; type //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// TengGenerateFlag = ( gfGenerateProcedureCode, // generate procedure code gfGenerateProcedureCall, // generate procedure call gfGenerateInlineCode, // generate procedure as inline code gfGenerateParameterCode, // generate code for parameter items gfAddProcedureItem, // add procedure item to generator args gfAddParameterItem // add parameter items to generator args ); TengGenerateFlags = set of TengGenerateFlag; TengGenerateFlagsStack = specialize TutlSimpleList; TengPopCodeFlag = ( pcfAppend, pcfPrepend, pcfAddEmptyLine ); TengPopCodeFlags = set of TengPopCodeFlag; TengShaderGeneratorArgs = class(TObject) private type TengGeneratorToken = ( gtNormal = 0, // normal text gtLineBreak = 1, // line break gtCommandEnd = 2, // command end (like ';') gtBlockBegin = 3, // code block begin (to calculate indent) gtBlockEnd = 4, // code block end (to calculate indent) gtAppendToPrev = 5, // append current line to prev line gtToken = 6 // code token (like '$INCLUDE' or '$IF') ); TCodePart = class(TObject) private fText: String; fIndent: Integer; fToken: TengGeneratorToken; function GetDebugText: String; function GetCode: String; public property Text: String read fText write fText; property Code: String read GetCode; property DebugText: String read GetDebugText; property Indent: Integer read fIndent; property Token: TengGeneratorToken read fToken; constructor Create(const aToken: TengGeneratorToken; const aText: String; const aIndent: Integer = 0); end; TCodePartList = specialize TutlSimpleList; public type TCodeStackItem = class(TObject) private fItems: TCodePartList; function GetIsEmpty: Boolean; public property Items: TCodePartList read fItems; property IsEmpty: Boolean read GetIsEmpty; procedure GenerateCode(const aCode: TengShaderCode); procedure Merge(const aItem: TCodeStackItem; aIndex: Integer); constructor Create; destructor Destroy; override; end; private type TCodeStack = specialize TutlSimpleList; TParameterMap = specialize TutlMap; TProcedureList = specialize TutlSimpleList; TProcParamStack = specialize TutlSimpleList; private fInlineReturnCounter: Integer; fCode: TCodeStack; fRoot: TengShaderPart; fFlagStack: TengGenerateFlagsStack; fMetaDataList: TengMetaDataList; fParameters: TParameterMap; fProcedures: TProcedureList; fProcParams: TProcParamStack; fMaxParameterLength: Integer; function GetFlags: TengGenerateFlags; function GetProcParams: TStrings; procedure GenerateParameterCode(const aTypes: CengShaderPartArr); procedure GenerateProcedureCode; procedure GenerateMetaCode; public property Root: TengShaderPart read fRoot; property Flags: TengGenerateFlags read GetFlags; property ProcParams: TStrings read GetProcParams; property MaxParameterLength: Integer read fMaxParameterLength; procedure PushCode; procedure PushFlags(const aFlags: TengGenerateFlags); procedure PushProcParams(const aParams: TStrings); procedure PopCode(const aFlags: TengPopCodeFlags); procedure PopFlags; procedure PopProcParams; function AddText(const aText: String): TengShaderGeneratorArgs; function AddToken(const aToken: String): TengShaderGeneratorArgs; function AddCommandEnd(const aToken: String): TengShaderGeneratorArgs; function AddLineBreak: TengShaderGeneratorArgs; function BeginBlock(const aIndent: Integer = 0): TengShaderGeneratorArgs; function EndBlock(const aCanAppend: Boolean = false): TengShaderGeneratorArgs; function AppendToPrevLine: TengShaderGeneratorArgs; procedure AddMeta(const aMeta: TengMetaData); procedure AddParameter(const aParam: TengShaderPart); procedure AddProcedure(const aProc: TengShaderPart); function ExtractCurrentCommand(const aCommand: TCodeStackItem): Integer; procedure ReplaceIdents(const aOld, aNew: TStrings); procedure ReplaceReturns(const aCommand: TCodeStackItem; const aRetType, aName: String); procedure GenerateCode(const aCode: TengShaderCode); constructor Create(const aRoot: TengShaderPart); destructor Destroy; override; end; implementation uses Math, RegExpr, uengShaderFileHelper, uengShaderFileConstants, uengShaderPartParameter, uengShaderPartProc; const WHITESPACES = [' ', #9]; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //TengShaderGeneratorArgs.TCodePart/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function TengShaderGeneratorArgs.TCodePart.GetCode: String; begin case fToken of gtNormal, gtCommandEnd: result := fText; gtLineBreak: result := sLineBreak; else result := ''; end; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function TengShaderGeneratorArgs.TCodePart.GetDebugText: String; begin case fToken of gtNormal: result := '[N]' + fText; gtLineBreak: result := sLineBreak; gtCommandEnd: result := '[C]' + fText; gtBlockBegin: result := format('[B%d]', [fIndent]); gtBlockEnd: result := '[E]'; gtToken: result := '[T' + fText + ']'; gtAppendToPrev: result := '[A]'; else result := '[' + IntToStr(Integer(fToken)) + ']' + fText end; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// constructor TengShaderGeneratorArgs.TCodePart.Create(const aToken: TengGeneratorToken; const aText: String; const aIndent: Integer); begin inherited Create; fToken := aToken; fText := aText; fIndent := aIndent; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //TengShaderGeneratorArgs.TCodeStackItem////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function TengShaderGeneratorArgs.TCodeStackItem.GetIsEmpty: Boolean; begin result := (fItems.Count = 0); end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// procedure TengShaderGeneratorArgs.TCodeStackItem.GenerateCode(const aCode: TengShaderCode); type TGenFlag = ( gfToken, // current line has a token in it gfTokenOnly, // current line has only a token (or whitespaces) in it gfPrevIsEmpty, // previouse line was empty (or whitespaces only) gfCodeIsEmpty, // nothing has added to code gfAddToPrev // add current line to previouse line ); TGenFlags = set of TGenFlag; var i: Integer; f: TGenFlags; line: String; 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 aCodePart: TCodePart): Integer; begin result := GetStrOffset(line); end; function GetMinOffset(aStartIndex: Integer): Integer; begin if (Trim(line) <> '') then result := GetStrOffset(line) else result := High(Integer); while (aStartIndex < aCode.Count) do begin if (Trim(aCode[aStartIndex]) <> '') then result := Min(result, GetStrOffset(aCode[aStartIndex])); inc(aStartIndex); end; if (result >= High(Integer)) then result := 0; 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 aIndent: Integer); var o: Integer; begin o := aIndent - GetMinOffset(aStartIndex); while (aStartIndex < aCode.Count) do begin aCode[aStartIndex] := PrepareStr(aCode[aStartIndex], o); inc(aStartIndex); end; if (Trim(line) <> '') then line := PrepareStr(line, o); end; procedure ProgressBlock(const aIndent: Integer); var s: String; cp: TCodePart; FirstLineIndex: Integer; begin FirstLineIndex := aCode.Count; while (i < fItems.Count) do begin cp := fItems[i]; inc(i); case cp.Token of gtLineBreak: begin if (Trim(line) = '') then begin if (f * [gfTokenOnly, gfPrevIsEmpty] = []) then begin aCode.Add(line); Include(f, gfPrevIsEmpty); end; end else begin if (gfAddToPrev in f) and not (gfCodeIsEmpty in f) then aCode[aCode.Count-1] := aCode[aCode.Count-1] + TrimLeft(line) else aCode.Add(line); Exclude(f, gfPrevIsEmpty); Exclude(f, gfCodeIsEmpty); end; Exclude(f, gfToken); Exclude(f, gfTokenOnly); Exclude(f, gfAddToPrev); line := ''; end; gtToken: begin Include(f, gfToken); if (Trim(line) = '') then Include(f, gfTokenOnly); end; gtBlockBegin: begin Include(f, gfPrevIsEmpty); ProgressBlock(GetStrOffset(line) + cp.Indent); end; gtBlockEnd: begin IndentBlock(FirstLineIndex, aIndent); exit; end; gtAppendToPrev: begin if (Trim(line) = '') and not (gfPrevIsEmpty in f) then include(f, gfAddToPrev); end; else s := cp.Code; line := line + s; end; end; end; {$IFDEF DEBUG} procedure GenerateDebugCode; var cp: TCodePart; s: String; sl: TStringList; begin s := ''; for cp in fItems do s := s + cp.DebugText; sl := TStringList.Create; try sl.Text := s; sl.SaveToFile('C:\Users\Erik\Desktop\tmp\debug.txt'); finally FreeAndNil(sl); end; end; {$ENDIF} begin i := 0; f := [gfPrevIsEmpty, gfCodeIsEmpty]; line := ''; {$IFDEF DEBUG} GenerateDebugCode; {$ENDIF} ProgressBlock(0); end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// procedure TengShaderGeneratorArgs.TCodeStackItem.Merge(const aItem: TCodeStackItem; aIndex: Integer); begin if (aIndex < 0) then aIndex := 0; if (aIndex > fItems.Count) then aIndex := fItems.Count; while (aItem.Items.Count > 0) do fItems.Insert(aIndex, aItem.Items.PopLast(false)); end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// constructor TengShaderGeneratorArgs.TCodeStackItem.Create; begin inherited Create; fItems := TCodePartList.Create(true); end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// destructor TengShaderGeneratorArgs.TCodeStackItem.Destroy; begin FreeAndNil(fItems); inherited Destroy; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //TengShaderGeneratorArgs/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function TengShaderGeneratorArgs.GetFlags: TengGenerateFlags; begin result := fFlagStack.Last; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function TengShaderGeneratorArgs.GetProcParams: TStrings; begin result := fProcParams.Last; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// procedure TengShaderGeneratorArgs.GenerateParameterCode(const aTypes: CengShaderPartArr); var m: TParameterMap; p: TengShaderPart; begin PushCode; PushFlags(Flags + [gfGenerateParameterCode] - [gfAddParameterItem]); m := TParameterMap.Create(false); try fMaxParameterLength := 0; for p in fParameters do begin if CheckType(p, aTypes) then with (p as TengShaderPartParameter) do begin fMaxParameterLength := Max(fMaxParameterLength, Length(Typ)); m.Add(Typ+Name, p); end; end; for p in m do begin (p as TengShaderPartParameter).GenerateCodeIntern(self); AddLineBreak; end; finally FreeAndNil(m); PopFlags; PopCode([pcfPrepend, pcfAddEmptyLine]); end; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// procedure TengShaderGeneratorArgs.GenerateProcedureCode; var i: Integer; begin i := 0; while (i < fProcedures.Count) do begin PushCode; PushFlags([gfGenerateProcedureCode, gfAddParameterItem]); try (fProcedures[i] as TengShaderPartProc).GenerateCodeIntern(self); finally PopFlags; PopCode([pcfPrepend, pcfAddEmptyLine]); end; inc(i); end; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// procedure TengShaderGeneratorArgs.GenerateMetaCode; var layouts: TStringList; m: TengMetaData; vCompat: Boolean; vMax, i: Integer; s: String; begin PushCode; vMax := 0; vCompat := false; layouts := TStringList.Create; try for m in fMetaDataList do begin case m.MetaType of metaVersion: begin if (m.Values[0] = VERSION_EXTRA_COMPAT) then vCompat := true else if TryStrToInt(m.Values[0], i) then vMax := max(vMax, i); if (m.Count > 1) and (m.Values[1] = VERSION_EXTRA_COMPAT) then vCompat := true; end; metaExtension: begin AddText(format('#extension %s : %s', [m.Values[0], m.Values[1]])); AddLineBreak; end; metaLayout: begin layouts.Add('layout' + m.Values[0] + ';'); end; end; end; if (vMax >= LAYOUT_MIN_VERSION) then begin for s in layouts do begin AddText(s); AddLineBreak; end; end; if (vMax > 0) then begin PushCode; try AddText('#version ' + IntToStr(vMax)); if vCompat then AddText(' ' + VERSION_EXTRA_COMPAT); AddLineBreak; finally PopCode([pcfPrepend]); end; end; finally PopCode([pcfPrepend, pcfAddEmptyLine]); FreeAndNil(layouts); end; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// procedure TengShaderGeneratorArgs.PushCode; begin fCode.PushLast(TCodeStackItem.Create); end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// procedure TengShaderGeneratorArgs.PushFlags(const aFlags: TengGenerateFlags); begin fFlagStack.PushLast(aFlags); end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// procedure TengShaderGeneratorArgs.PushProcParams(const aParams: TStrings); begin fProcParams.PushLast(aParams); end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// procedure TengShaderGeneratorArgs.PopCode(const aFlags: TengPopCodeFlags); var csi: TCodeStackItem; begin csi := fCode.PopLast(false); try if csi.IsEmpty then exit; if (pcfPrepend in aFlags) then begin if (pcfAddEmptyLine in aFlags) then csi.Items.Add(TCodePart.Create(gtLineBreak, '')); fCode.Last.Merge(csi, 1); end else if (pcfAppend in aFlags) then begin if (pcfAddEmptyLine in aFlags) then fCode.Last.Items.Add(TCodePart.Create(gtLineBreak, '')); fCode.Last.Merge(csi, fCode.Last.Items.Count); end; finally FreeAndNil(csi); end; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// procedure TengShaderGeneratorArgs.PopFlags; begin fFlagStack.PopLast(true); end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// procedure TengShaderGeneratorArgs.PopProcParams; begin fProcParams.PopLast; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function TengShaderGeneratorArgs.AddText(const aText: String): TengShaderGeneratorArgs; begin fCode.Last.Items.Add(TCodePart.Create(gtNormal, aText)); result := self; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function TengShaderGeneratorArgs.AddToken(const aToken: String): TengShaderGeneratorArgs; begin fCode.Last.Items.Add(TCodePart.Create(gtToken, aToken)); result := self; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function TengShaderGeneratorArgs.AddCommandEnd(const aToken: String): TengShaderGeneratorArgs; begin fCode.Last.Items.Add(TCodePart.Create(gtCommandEnd, aToken)); result := self; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function TengShaderGeneratorArgs.AddLineBreak: TengShaderGeneratorArgs; begin fCode.Last.Items.Add(TCodePart.Create(gtLineBreak, '')); result := self; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function TengShaderGeneratorArgs.BeginBlock(const aIndent: Integer): TengShaderGeneratorArgs; begin fCode.Last.Items.Add(TCodePart.Create(gtBlockBegin, '', aIndent)); result := self; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function TengShaderGeneratorArgs.EndBlock(const aCanAppend: Boolean): TengShaderGeneratorArgs; begin fCode.Last.Items.Add(TCodePart.Create(gtBlockEnd, '')); result := self; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function TengShaderGeneratorArgs.AppendToPrevLine: TengShaderGeneratorArgs; begin fCode.Last.Items.Add(TCodePart.Create(gtAppendToPrev, '')); result := self; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// procedure TengShaderGeneratorArgs.AddMeta(const aMeta: TengMetaData); begin fMetaDataList.Add(aMeta); end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// procedure TengShaderGeneratorArgs.AddParameter(const aParam: TengShaderPart); var p: TengShaderPart; s: String; begin if not (aParam is TengShaderPartParameter) then raise EengShaderPartInternal.Create('parameter (' + aParam.ClassName + ') is not a ' + TengShaderPartParameter.ClassName, aParam); with (aParam as TengShaderPartParameter) do begin p := fParameters[Name]; if Assigned(p) then begin s := Format('use of duplicate identifier: %s (%s %d:%d)', [Name, Filename, Line + 1, Col]) + sLineBreak + 'previously declared here:' + sLineBreak + Format(' %s %d:%d', [p.Filename, p.Line + 1, p.Col]) + sLineBreak; fRoot.LogMsg(llWarning, s); fParameters[Name] := aParam; end else fParameters.Add(Name, aParam); end; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// procedure TengShaderGeneratorArgs.AddProcedure(const aProc: TengShaderPart); begin if not (aProc is TengShaderPartProc) then raise EengShaderPartInternal.Create('parameter (' + aProc.ClassName + ') is not a ' + TengShaderPartProc.ClassName, aProc); fProcedures.Add(aProc); end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function TengShaderGeneratorArgs.ExtractCurrentCommand(const aCommand: TCodeStackItem): Integer; var csi: TCodeStackItem; i, len: Integer; s: String; begin csi := fCode.Last; if not Assigned(aCommand) then exit; // find last command end token while (csi.Items.Last.Token <> gtCommandEnd) do aCommand.Items.PushFirst(csi.Items.PopLast(false)); // move forward to first code part with text while (aCommand.Items.First.Token <> gtNormal) or (Trim(aCommand.Items.First.Text) = '') do csi.Items.PushLast(aCommand.Items.PopFirst(false)); // extract leading whitespaces i := 1; s := aCommand.Items.First.Text; len := Length(s); while (s[i] in WHITESPACES) and (i <= len) do inc(i); csi.Items.PushLast(TCodePart.Create(gtNormal, Copy(s, 1, i-1))); aCommand.Items.First.Text := copy(s, i, len-i+1); result := i - 1; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// procedure TengShaderGeneratorArgs.ReplaceIdents(const aOld, aNew: TStrings); var rx: TRegExpr; i: Integer; cp: TCodePart; begin if (aOld.Count <> aNew.Count) then raise EengShaderPartInternal.Create('old and new ident 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 cp in fCode.Last.Items do cp.Text := rx.Replace(cp.Text, '$1' + aNew[i] + '$2', true); end; finally FreeAndNil(rx); end; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// procedure TengShaderGeneratorArgs.ReplaceReturns(const aCommand: TCodeStackItem; const aRetType, aName: String); var rx: TRegExpr; RetCount, i, j: Integer; csi: TCodeStackItem; cp: TCodePart; s: String; begin rx := TRegExpr.Create; try rx.Expression := '([^A-z0-9_]+|^)return([^A-z0-9_]+|$)'; csi := fCode.Last; // find number of "return" in code RetCount := 0; for cp in csi.Items do begin s := cp.Code; if rx.Exec(s) then inc(RetCount); end; // no "return" found if (RetCount = 0) then begin raise EengShaderPartInternal.Create('expected "return" token in function'); // more than one "return" end else if (RetCount > 1) then begin // find block begin i := 0; while (csi.Items[i].Token <> gtBlockBegin) and (i < csi.Items.Count) do inc(i); if (i < csi.Items.Count) then inc(i) else i := 0; // insert temp variable s := Format('%s_ret%.4d', [aName, fInlineReturnCounter]); inc(fInlineReturnCounter); csi.Items.Insert(i, TCodePart.Create(gtLineBreak, '')); csi.Items.Insert(i+1, TCodePart.Create(gtNormal, aRetType + ' ' + s)); csi.Items.Insert(i+2, TCodePart.Create(gtCommandEnd, ';')); csi.Items.Insert(i+3, TCodePart.Create(gtLineBreak, '')); // replace "return" with temp variable for cp in csi.Items do cp.Text := rx.Replace(cp.Text, '$1' + s + ' =$2', true); // merge code csi.Merge(aCommand, csi.Items.Count); AddText(s); // exact one "return" end else begin i := csi.Items.Count-1; while (i > 0) do begin cp := csi.Items[i]; if rx.Exec(cp.Text) then begin csi.Items.Insert(i, TCodePart.Create(gtNormal, rx.Match[1])); cp.Text := rx.Replace(cp.Text, '(', true); // replace last gtCommandEnd with ')' and delete everything behind j := csi.Items.Count-1; while (j > i) and not (csi.Items[j].Token = gtCommandEnd) do dec(j); if (j > i) then csi.Items[j] := TCodePart.Create(gtNormal, ')'); while (csi.Items.Count-1 > j) do csi.Items.PopLast(true); // merge csi.Merge(aCommand, i+1); end; dec(i); end; end; finally FreeAndNil(rx); end; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// procedure TengShaderGeneratorArgs.GenerateCode(const aCode: TengShaderCode); begin GenerateProcedureCode; GenerateParameterCode(CengShaderPartArr.Create(TengShaderPartVar)); GenerateParameterCode(CengShaderPartArr.Create(TengShaderPartVarying)); GenerateParameterCode(CengShaderPartArr.Create(TengShaderPartUniform)); GenerateMetaCode; fCode.Last.GenerateCode(aCode); end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// constructor TengShaderGeneratorArgs.Create(const aRoot: TengShaderPart); begin inherited Create; fCode := TCodeStack.Create(true); fFlagStack := TengGenerateFlagsStack.Create(); fMetaDataList := TengMetaDataList.Create(false); fParameters := TParameterMap.Create(false); fProcedures := TProcedureList.Create(false); fProcParams := TProcParamStack.Create(false); fRoot := aRoot; fInlineReturnCounter := 0; PushCode; PushFlags([ gfAddParameterItem, gfAddProcedureItem ]); end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// destructor TengShaderGeneratorArgs.Destroy; begin FreeAndNil(fProcParams); FreeAndNil(fProcedures); FreeAndNil(fParameters); FreeAndNil(fMetaDataList); FreeAndNil(fFlagStack); FreeAndNil(fCode); inherited Destroy; end; end.