|
- 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<TengGenerateFlags>;
-
- 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<TCodePart>;
-
- 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<TCodeStackItem>;
- TParameterMap = specialize TutlMap<string, TengShaderPart>;
- TProcedureList = specialize TutlSimpleList<TengShaderPart>;
- TProcParamStack = specialize TutlSimpleList<TStrings>;
-
- 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.
|