Browse Source

* finished code generator implementation for shader files (classes need some more tests)

master
Bergmann89 10 years ago
parent
commit
3411c92c3d
14 changed files with 1020 additions and 212 deletions
  1. +31
    -7
      uengShaderFile.pas
  2. +2
    -1
      uengShaderFileConstants.pas
  3. +5
    -5
      uengShaderFileExpression.pas
  4. +87
    -12
      uengShaderFileHelper.pas
  5. +67
    -1
      uengShaderFileTypes.pas
  6. +18
    -17
      uengShaderGenerator.pas
  7. +490
    -86
      uengShaderGeneratorArgs.pas
  8. +1
    -1
      uengShaderPart.pas
  9. +97
    -2
      uengShaderPartCall.pas
  10. +24
    -4
      uengShaderPartClass.pas
  11. +5
    -1
      uengShaderPartCntr.pas
  12. +3
    -60
      uengShaderPartMeta.pas
  13. +12
    -12
      uengShaderPartParameter.pas
  14. +178
    -3
      uengShaderPartProc.pas

+ 31
- 7
uengShaderFile.pas View File

@@ -23,7 +23,7 @@ uses
type
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
TengShaderFileLogEvent = procedure(const aSender: TengShaderPart; const aLogLevel: TengShaderPartLogLevel; const aMsg: String) of object;
TengShaderFile = class(TengShaderCodeGenerator)
TengShaderFile = class(TengShaderGenerator)
{ Code Loading & Storage }
private
fFilename: String;
@@ -31,7 +31,7 @@ type
fFileWriter: IutlFileWriter;
fClasses: TengShaderPartClassMap;
private
function GetGenerator(const aName: String): TengShaderCodeGenerator;
function GetGenerator(const aName: String): TengShaderGenerator;
function GetGeneratorCount: Integer;
function GetGeneratorNames(const aIndex: Integer): String;
procedure UpdateClasses;
@@ -54,7 +54,7 @@ type
protected
procedure LogMsgIntern(const aSender: TengShaderPart; const aLogLevel: TengShaderPartLogLevel; const aMsg: String); override;
public
property Generator [const aName: String]: TengShaderCodeGenerator read GetGenerator;
property Generator [const aName: String]: TengShaderGenerator read GetGenerator;
property GeneratorNames[const aIndex: Integer]: String read GetGeneratorNames;
property GeneratorCount: Integer read GetGeneratorCount;
property OnLog: TengShaderFileLogEvent read fOnLog write fOnLog;
@@ -67,12 +67,12 @@ type
implementation

uses
uengShaderPartInclude, uengShaderPartKeyValuePair, uengShaderFileHelper;
uengShaderPartInclude, uengShaderPartKeyValuePair, uengShaderFileHelper, uengShaderPartProc;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//TengShaderFile////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function TengShaderFile.GetGenerator(const aName: String): TengShaderCodeGenerator;
function TengShaderFile.GetGenerator(const aName: String): TengShaderGenerator;
begin
result := fClasses[aName];
if not Assigned(result) then
@@ -170,7 +170,7 @@ begin
walker.Owner := self;
walker.SearchFlags := [sfSearchChildren, sfIgnoreOwner];
walker.ResultTypes := CengShaderPartArr.Create(TengShaderFile);
walker.ChildrenDoNotLeave := CengShaderPartArr.Create(TengShaderCodeGenerator);
walker.ChildrenDoNotLeave := CengShaderPartArr.Create(TengShaderGenerator);
walker.Run(self);
for p in sr do
(p as TengShaderFile).CopyProperties(self);
@@ -260,10 +260,34 @@ end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
procedure TengShaderFile.GenerateCodeIntern(const aArgs: TengShaderGeneratorArgs);
var
sr: TengSearchResults;
walker: TengSearchWalker;
main: TengShaderPartMain;
begin
inherited GenerateCodeIntern(aArgs);
if (aArgs.Root = self) then begin
// TODO generate main routine code (if exists)
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);
main := (ExtractSearchResult(self, TengShaderPartMain.GetTokenName, sr, []) as TengShaderPartMain);
if Assigned(main) then begin
aArgs.PushFlags((aArgs.Flags * [gfAddProcedureItem, gfAddParameterItem]) + [gfGenerateProcedureCode]);
try
main.GenerateCodeIntern(aArgs);
finally
aArgs.PopFlags;
end;
end;
finally
FreeAndNil(walker);
FreeAndNil(sr);
end;
end;
end;



+ 2
- 1
uengShaderFileConstants.pas View File

@@ -25,7 +25,7 @@ const

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_INHERITED = TOKEN_CHAR_IDENT + 'INHERITED'; //{$INHERITED BaseClassMethod 'param1' 'param2'}

TOKEN_INCLUDE = TOKEN_CHAR_IDENT + 'INCLUDE'; //{$INCLUDE 'Normal.frag'}

@@ -85,6 +85,7 @@ const
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];

LAYOUT_MIN_VERSION = 150;
VERSION_EXTRA_COMPAT = 'compatibility'; //{$META $VERSION 'compatibility'}

implementation


+ 5
- 5
uengShaderFileExpression.pas View File

@@ -692,14 +692,14 @@ begin
sr := TengSearchResults.Create;
walker := TengKeyValuePairSearchWalker.Create(sr);
try
walker.Name := param.Name;
walker.SearchFlags := [sfSearchChildrenLazy, sfSearchParents];
walker.ResultTypes := CengShaderPartArr.Create(TengShaderPartProperty, TengShaderPartStatic);
walker.Name := param.Name;
walker.SearchFlags := [sfSearchChildrenLazy, sfSearchParents];
walker.ResultTypes := CengShaderPartArr.Create(TengShaderPartProperty, TengShaderPartStatic);
walker.ChildrenDoNotLeave := CengShaderPartArr.Create(TengShaderPartScope);
walker.ChildrenForceLeave := CengShaderPartArr.Create(TengShaderFile);
walker.ChildrenForceLeave := CengShaderPartArr.Create(TengShaderFile);
walker.ParentsDoNotLeave := CengShaderPartArr.Create(TengShaderFile);
walker.Run(fParent);
tmp := ExtractSearchResult(fParent, param.Name, sr, param.Line, param.Col);
tmp := ExtractSearchResult(fParent, param.Name, sr, [ifWarning, ifRaiseEx], param.Line, param.Col);
result := TengExpressionVariable.Create(param.Name, (tmp as TengShaderPartKeyValuePair), param.Line, param.Col);
finally
FreeAndNil(walker);


+ 87
- 12
uengShaderFileHelper.pas View File

@@ -8,15 +8,33 @@ interface
uses
uengShaderPart, uengShaderFileParser;

type
TInfoFlag = (
ifWarning,
ifRaiseEx
);
TInfoFlags = set of TInfoFlag;

function IsValidIdentifier(const aIdent: String): Boolean;
function CheckEndToken(const aArgs: TengParseArgs; const aShaderPart: TengShaderPart): String;
function ExtractSearchResult(const aSender: TengShaderPart; const aIdent: String; const aList: TengShaderPartList; aLine: Integer = -1; aCol: Integer = -1; aFilename: String = ''): TengShaderPart;
function CheckType(const aShaderPart: TengShaderPart; const aTypes: array of CengShaderPart): Boolean;
function ExtractSearchResult(
const aSender: TengShaderPart;
const aIdent: String;
const aList: TengShaderPartList;
const aFlags: TInfoFlags = [ifWarning, ifRaiseEx];
aLine: Integer = -1;
aCol: Integer = -1;
aFilename: String = ''): TengShaderPart;

type
TengSearchFlag = (
sfSearchChildren, // search in children
sfEvaluateIf, // evaluate if and search in suitable subtree
sfIgnoreIf, // do not search in if items
sfSearchChildrenLazy, // set sfSearchChildren in next recursion level
sfSearchParents, // search in Parents
sfSearchInherited, // search in inherited classes
sfIgnoreOwner // ignore owner of search walker
);
TengSearchFlags = set of TengSearchFlag;
@@ -65,11 +83,21 @@ type
property Name: String read fName write fName;
end;

TengProcSearchWalker = class(TengSearchWalker)
private
fName: String;
protected
function Check(const aPart: TengShaderPart): Boolean; override;
public
property Name: String read fName write fName;
constructor Create(const aResults: TengSearchResults);
end;

implementation

uses
sysutils,
uengShaderFileConstants, uengShaderFileTypes, uengShaderPartKeyValuePair;
uengShaderFileConstants, uengShaderFileTypes, uengShaderPartKeyValuePair, uengShaderPartProc, uengShaderPartIf;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function IsValidIdentifier(const aIdent: String): Boolean;
@@ -106,9 +134,21 @@ begin
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 ExtractSearchResult(const aSender: TengShaderPart; const aIdent: String; const aList: TengShaderPartList;
aLine: Integer; aCol: Integer; aFilename: String): TengShaderPart;
const aFlags: TInfoFlags; aLine: Integer; aCol: Integer; aFilename: String): TengShaderPart;
var
s: String;
i: Integer;
@@ -122,10 +162,13 @@ begin
if (aFilename = '') then
aFilename := aSender.Filename;
end;
if (aList.Count <= 0) then
raise EengUnknownIdentifier.Create(aIdent, aLine, aCol, aFilename, aSender);
if (aList.Count <= 0) then begin
if (ifRaiseEx in aFlags) then
raise EengUnknownIdentifier.Create(aIdent, aLine, aCol, aFilename, aSender);
exit;
end;
result := aList[aList.Count-1];
if (aList.Count > 1) and Assigned(aSender) then begin
if (aList.Count > 1) and Assigned(aSender) and (ifWarning in aFlags) then begin
s := Format('use of duplicate identifier: %s (%s %d:%d)', [aIdent, result.Filename, result.Line + 1, result.Col]) + sLineBreak +
'previously declared here:' + sLineBreak;
i := aList.Count - 2;
@@ -183,7 +226,7 @@ var
end;

var
c: TengShaderPart;
p: TengShaderPart;
nextArgs: TArgs;
begin
if not Assigned(aPart) then
@@ -193,6 +236,7 @@ begin
else
args.Flags := fSearchFlags;

// visit parent
nextArgs := args;
if (sfSearchChildrenLazy in nextArgs.Flags) then
nextArgs.Flags := nextArgs.Flags + [sfSearchChildren] - [sfSearchChildrenLazy];
@@ -201,12 +245,25 @@ begin
if VisitParent then
Visit(aPart.Parent, aPart, @nextArgs);

// visit children
if (sfSearchChildren in args.Flags) then begin
for c in aPart do begin
if Check(c) then
fResults.Add(c);
if VisitChild(c) then
Visit(c, aPart, @args);
if (aPart is TengShaderPartIf) then with (aPart as TengShaderPartIf) do begin
if (sfEvaluateIf in args.Flags) then begin
if Expression.GetValue
then p := IfPart
else p := ElsePart;
if Assigned(p) then
Visit(p, aPart, @args);
exit;
end else if (sfIgnoreIf in args.Flags) then
exit;
end;

for p in aPart do begin
if Check(p) then
fResults.Add(p);
if VisitChild(p) then
Visit(p, aPart, @args);
end;
end;
end;
@@ -242,5 +299,23 @@ begin
((aPart as TengShaderPartKeyValuePair).Name = fName);
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//TengProcSearchWalker//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function TengProcSearchWalker.Check(const aPart: TengShaderPart): Boolean;
begin
result :=
inherited Check(aPart) and
(aPart is TengShaderPartProc) and
((aPart as TengShaderPartProc).Name = fName);
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
constructor TengProcSearchWalker.Create(const aResults: TengSearchResults);
begin
inherited Create(aResults);
ResultTypes := CengShaderPartArr.Create(TengShaderPartProc);
end;

end.


+ 67
- 1
uengShaderFileTypes.pas View File

@@ -9,7 +9,7 @@ uses
Classes, SysUtils

{$IFDEF USE_BITSPACE_UTILS}
, uutlSerialization, uutlCommon
, uutlSerialization, uutlCommon, uutlGenerics
{$ENDIF}
;

@@ -36,6 +36,33 @@ type

end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
TengMetaType = (
metaUnknown,
metaNormal,
metaVersion,
metaExtension,
metaLayout);
TengMetaData = class(TObject)
private
fMetaType: TengMetaType;
fName: String;
fValues: TStringList;
function GetCount: Integer;
function GetValues: TStrings;
public
property MetaType: TengMetaType read fMetaType;
property Name: String read fName;
property Count: Integer read GetCount;
property Values: TStrings read GetValues;

procedure Assign(const aValues: TengMetaData);

constructor Create(const aName: String; const aType: TengMetaType);
destructor Destroy; override;
end;
TengMetaDataList = specialize TutlSimpleList<TengMetaData>;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//Exceptions////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -159,6 +186,45 @@ implementation
uses
uengShaderPart;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//TengMetaData//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function TengMetaData.GetCount: Integer;
begin
result := fValues.Count;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function TengMetaData.GetValues: TStrings;
begin
result := fValues;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
procedure TengMetaData.Assign(const aValues: TengMetaData);
begin
fName := aValues.Name;
fMetaType := aValues.MetaType;
fValues.Clear;
fValues.AddStrings(aValues.Values);
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;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//EengExpressionInternal////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////


+ 18
- 17
uengShaderGenerator.pas View File

@@ -12,7 +12,7 @@ uses

type
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
TengShaderCodeGenerator = class(TengShaderPartScope)
TengShaderGenerator = class(TengShaderPartScope)
{ Code Loading & Storage }
private
fPropertyMap: TengShaderPartPropertyMap;
@@ -26,7 +26,7 @@ type
procedure SetPropertyByName(const aName: String; aValue: Variant);
protected
procedure AddProperty(const aProp: TengShaderPartProperty; const aShowWarning: Boolean = true);
procedure CopyProperties(const aGen: TengShaderCodeGenerator);
procedure CopyProperties(const aGen: TengShaderGenerator);
procedure UpdateProperties; virtual;
function ParseIntern(const aArgs: TengParseArgs; const aParams: TengTokenParameterList): String; override;
public
@@ -48,15 +48,15 @@ type
implementation

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//TengShaderCodeGenerator///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//TengShaderGenerator///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function TengShaderCodeGenerator.GetPropertyByIndex(const aIndex: Integer): Variant;
function TengShaderGenerator.GetPropertyByIndex(const aIndex: Integer): Variant;
begin
result := fPropertyMap.ValueAt[aIndex].Value;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function TengShaderCodeGenerator.GetPropertyByName(const aName: String): Variant;
function TengShaderGenerator.GetPropertyByName(const aName: String): Variant;
var
l: TengShaderPartPropertyList;
begin
@@ -67,25 +67,25 @@ begin
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function TengShaderCodeGenerator.GetPropertyCount: Integer;
function TengShaderGenerator.GetPropertyCount: Integer;
begin
result := fPropertyMap.Count;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function TengShaderCodeGenerator.GetPropertyNames(const aIndex: Integer): String;
function TengShaderGenerator.GetPropertyNames(const aIndex: Integer): String;
begin
result := fPropertyMap.KeyValuePairs[aIndex].Key;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
procedure TengShaderCodeGenerator.SetPropertyByIndex(const aIndex: Integer; aValue: Variant);
procedure TengShaderGenerator.SetPropertyByIndex(const aIndex: Integer; aValue: Variant);
begin
fPropertyMap.ValueAt[aIndex].Value := aValue;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
procedure TengShaderCodeGenerator.SetPropertyByName(const aName: String; aValue: Variant);
procedure TengShaderGenerator.SetPropertyByName(const aName: String; aValue: Variant);
var
l: TengShaderPartPropertyList;
begin
@@ -96,7 +96,7 @@ begin
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
procedure TengShaderCodeGenerator.AddProperty(const aProp: TengShaderPartProperty; const aShowWarning: Boolean);
procedure TengShaderGenerator.AddProperty(const aProp: TengShaderPartProperty; const aShowWarning: Boolean);
var
l: TengShaderPartPropertyList;
p: TengShaderPartProperty;
@@ -121,7 +121,7 @@ begin
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
procedure TengShaderCodeGenerator.CopyProperties(const aGen: TengShaderCodeGenerator);
procedure TengShaderGenerator.CopyProperties(const aGen: TengShaderGenerator);
var
l: TengShaderPartPropertyList;
p: TengShaderPartProperty;
@@ -132,26 +132,27 @@ begin
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
procedure TengShaderCodeGenerator.UpdateProperties;
procedure TengShaderGenerator.UpdateProperties;
begin
fPropertyMap.Clear;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function TengShaderCodeGenerator.ParseIntern(const aArgs: TengParseArgs; const aParams: TengTokenParameterList): String;
function TengShaderGenerator.ParseIntern(const aArgs: TengParseArgs; const aParams: TengTokenParameterList): String;
begin
result := inherited ParseIntern(aArgs, aParams);
UpdateProperties;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
procedure TengShaderCodeGenerator.GenerateCode(const aCode: TengShaderCode);
procedure TengShaderGenerator.GenerateCode(const aCode: TengShaderCode);
var
args: TengShaderGeneratorArgs;
begin
args := TengShaderGeneratorArgs.Create(self);
try
inherited GenerateCodeIntern(args);
fPropertyMap.ApplyValues;
GenerateCodeIntern(args);
args.GenerateCode(aCode);
finally
FreeAndNil(args);
@@ -159,14 +160,14 @@ begin
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
constructor TengShaderCodeGenerator.Create(const aParent: TengShaderPart);
constructor TengShaderGenerator.Create(const aParent: TengShaderPart);
begin
inherited Create(aParent);
fPropertyMap := TengShaderPartPropertyMap.Create(true);
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
destructor TengShaderCodeGenerator.Destroy;
destructor TengShaderGenerator.Destroy;
begin
FreeAndNil(fPropertyMap);
inherited Destroy;


+ 490
- 86
uengShaderGeneratorArgs.pas View File

@@ -17,33 +17,52 @@ uses
type
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
TengGenerateFlag = (
gfGenerateParameterItemCode, // generate code for parameter items
gfAddParameterItem // add parameter items to generator args
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, // normal text
gtLineBreak, // line break
gtCommandEnd, // command end (like ';')
gtBlockBegin, // code block begin (to calculate indent)
gtBlockEnd, // code block end (to calculate indent)
gtToken // code token (like '$INCLUDE' or '$IF')
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)
gtToken = 5 // code token (like '$INCLUDE' or '$IF')
);

TCodePart = class(TObject)
private
fText: String;
fIndent: Integer;
fToken: TengGeneratorToken;
function GetText: String;
function GetDebugText: String;
function GetCode: String;
public
property Text: String read GetText;
property Token: TengGeneratorToken read fToken;
constructor Create(const aToken: TengGeneratorToken; const aText: String);
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;
@@ -53,33 +72,64 @@ type
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;
fFlags: TengGenerateFlags;
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 fFlags;
property Root: TengShaderPart read fRoot;
property Flags: TengGenerateFlags read GetFlags;
property ProcParams: TStrings read GetProcParams;
property MaxParameterLength: Integer read fMaxParameterLength;

procedure PushCode;
procedure PopCode;
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: TengShaderGeneratorArgs;

procedure AddText(const aText: String);
procedure AddToken(const aToken: String);
procedure AddCommandEnd(const aToken: String);
procedure AddLineBreak;
procedure BeginBlock;
procedure EndBlock;
procedure AddMeta(const aMeta: TengMetaData);
procedure AddParameter(const aParam: TengShaderPart);
procedure AddProcedure(const aProc: TengShaderPart);

procedure AddMeta(const aMeta: TengShaderPart);
procedure AddParam(const aParam: 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);

@@ -90,12 +140,16 @@ type
implementation

uses
Math;
Math, RegExpr,
uengShaderFileHelper, uengShaderFileConstants, uengShaderPartParameter, uengShaderPartProc;

const
WHITESPACES = [' ', #9];

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//TengShaderGeneratorArgs.TCodePart///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function TengShaderGeneratorArgs.TCodePart.GetText: String;
function TengShaderGeneratorArgs.TCodePart.GetCode: String;
begin
case fToken of
gtNormal,
@@ -109,11 +163,27 @@ begin
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
constructor TengShaderGeneratorArgs.TCodePart.Create(const aToken: TengGeneratorToken; const aText: String);
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 + ']';
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;
fToken := aToken;
fText := aText;
fIndent := aIndent;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -131,15 +201,10 @@ type
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
gfAddToPrevLine, // add current line to previous line
gfAddNextLine // add next line to current line (set gfAddToPrevLine on linebreak)
gfCodeIsEmpty // nothing has added to code
);
TGenFlags = set of TGenFlag;

const
WHITESPACES = [' ', #9];

var
i: Integer;
f: TGenFlags;
@@ -171,7 +236,7 @@ var
inc(aStartIndex);
end;
if (result >= High(Integer)) then
result := -1;
result := 0;
end;

function TrimLeftLen(const aStr: String; aLen: Integer): String;
@@ -189,23 +254,22 @@ var

function PrepareStr(const aStr: String; const aOffset: Integer): String;
begin
if (aOffset < 0)
then result := StringOfChar(' ', -aOffset) + aStr
else result := TrimLeftLen(aStr, aOffset);
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 := GetMinOffset(aStartIndex) - aIndent;
if (o <= 0) then
exit;
o := aIndent - GetMinOffset(aStartIndex);
while (aStartIndex < aCode.Count) do begin
aCode[aStartIndex] := PrepareStr(aCode[aStartIndex], o);
inc(aStartIndex);
end;
line := PrepareStr(line, o);
if (Trim(line) <> '') then
line := PrepareStr(line, o);
end;

procedure ProgressBlock(const aIndent: Integer);
@@ -221,33 +285,18 @@ var

case cp.Token of
gtLineBreak: begin

// line has whitespaces only
if (Trim(line) = '') then begin
if (f * [gfToken, gfPrevIsEmpty] = []) then begin
if (f * [gfTokenOnly, gfPrevIsEmpty] = []) then begin
aCode.Add(line);
Include(f, gfPrevIsEmpty);
end;
if not (gfTokenOnly in f) then
Exclude(f, gfAddToPrevLine);

// line has text
end else begin
if (gfAddToPrevLine in f) and not (gfCodeIsEmpty in f) then begin
aCode[aCode.Count-1] := aCode[aCode.Count-1] + TrimLeft(line)
end else begin
aCode.Add(line);
Exclude(f, gfPrevIsEmpty);
Exclude(f, gfCodeIsEmpty);
end;
Exclude(f, gfAddToPrevLine);
aCode.Add(line);
Exclude(f, gfPrevIsEmpty);
Exclude(f, gfCodeIsEmpty);
end;
Exclude(f, gfToken);
Exclude(f, gfTokenOnly);
if (gfAddNextLine in f) then begin
Exclude(f, gfAddNextLine);
Include(f, gfAddToPrevLine);
end;
line := '';
end;

@@ -258,35 +307,59 @@ var
end;

gtBlockBegin: begin
if (Trim(line) <> '') then
Include(f, gfAddNextLine);
Include(f, gfPrevIsEmpty);
ProgressBlock(GetOffset(cp));
ProgressBlock(GetStrOffset(line) + cp.Indent);
end;

gtBlockEnd: begin
if (Trim(line) = '') then
Include(f, gfAddToPrevLine);
IndentBlock(FirstLineIndex, aIndent);
exit;
end;

else
s := cp.GetText;
if (gfAddNextLine in f) and (Trim(s) <> '') then
Exclude(f, gfAddNextLine);
s := cp.Code;
line := line + s;
end;
end;
end;

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;

begin
i := 0;
f := [gfPrevIsEmpty, gfCodeIsEmpty];
line := '';
GenerateDebugCode;
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
@@ -302,7 +375,126 @@ begin
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//TengShaderGeneratorArgs/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//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
@@ -310,69 +502,269 @@ begin
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
procedure TengShaderGeneratorArgs.PopCode;
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
// TODO merge
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.AddText(const aText: String);
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;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
procedure TengShaderGeneratorArgs.AddToken(const aToken: String);
function TengShaderGeneratorArgs.AddToken(const aToken: String): TengShaderGeneratorArgs;
begin
fCode.Last.Items.Add(TCodePart.Create(gtToken, aToken));
result := self;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
procedure TengShaderGeneratorArgs.AddCommandEnd(const aToken: String);
function TengShaderGeneratorArgs.AddCommandEnd(const aToken: String): TengShaderGeneratorArgs;
begin
fCode.Last.Items.Add(TCodePart.Create(gtCommandEnd, aToken));
result := self;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
procedure TengShaderGeneratorArgs.AddLineBreak;
function TengShaderGeneratorArgs.AddLineBreak: TengShaderGeneratorArgs;
begin
fCode.Last.Items.Add(TCodePart.Create(gtLineBreak, ''));
result := self;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
procedure TengShaderGeneratorArgs.BeginBlock;
function TengShaderGeneratorArgs.BeginBlock(const aIndent: Integer): TengShaderGeneratorArgs;
begin
fCode.Last.Items.Add(TCodePart.Create(gtBlockBegin, ''));
fCode.Last.Items.Add(TCodePart.Create(gtBlockBegin, '', aIndent));
result := self;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
procedure TengShaderGeneratorArgs.EndBlock;
function TengShaderGeneratorArgs.EndBlock: TengShaderGeneratorArgs;
begin
fCode.Last.Items.Add(TCodePart.Create(gtBlockEnd, ''));
result := self;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
procedure TengShaderGeneratorArgs.AddMeta(const aMeta: TengShaderPart);
procedure TengShaderGeneratorArgs.AddMeta(const aMeta: TengMetaData);
begin
// TODO
fMetaDataList.Add(aMeta);
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
procedure TengShaderGeneratorArgs.AddParam(const aParam: TengShaderPart);
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
// TODO
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;

@@ -380,14 +772,26 @@ end;
constructor TengShaderGeneratorArgs.Create(const aRoot: TengShaderPart);
begin
inherited Create;
fCode := TCodeStack.Create(true);
fRoot := aRoot;
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;


+ 1
- 1
uengShaderPart.pas View File

@@ -226,7 +226,7 @@ end;
function TengShaderPart.GetParent(const aType: CengShaderPart): TengShaderPart;
begin
if not GetParent(aType, result) then
raise EengShaderPartInternal.Create(GetTokenName + ' ha sno parent of type ' + aType.GetTokenName, self);
raise EengShaderPartInternal.Create(GetTokenName + ' has no parent of type ' + aType.GetTokenName, self);
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////


+ 97
- 2
uengShaderPartCall.pas View File

@@ -44,6 +44,12 @@ type
{ Class Methods }
protected
function ParseIntern(const aArgs: TengParseArgs; const aParams: TengTokenParameterList): String; override;

{ Code Generation }
public
procedure GenerateCodeIntern(const aArgs: TengShaderGeneratorArgs); override;

{ Class Methods }
public
class function GetTokenName: String; override;
class procedure Validate(const aArgs: TengParseArgs; const aParent: TengShaderPart); override;
@@ -52,7 +58,8 @@ type
implementation

uses
uengShaderPartProc, uengShaderPartClass, uengShaderFileConstants, uengShaderFileTypes, uengShaderFileHelper;
uengShaderPartProc, uengShaderPartClass, uengShaderFileConstants, uengShaderFileTypes,
uengShaderFileHelper, uengShaderGenerator, uengShaderFile;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//TengShaderPartCall////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -95,9 +102,34 @@ end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
procedure TengShaderPartCall.GenerateCodeIntern(const aArgs: TengShaderGeneratorArgs);
var
sr: TengSearchResults;
walker: TengProcSearchWalker;
proc: TengShaderPartProc;
begin
inherited GenerateCodeIntern(aArgs);
// TODO
sr := TengSearchResults.Create;
walker := TengProcSearchWalker.Create(sr);
try
walker.Name := Name;
walker.SearchFlags := [sfEvaluateIf, sfSearchChildren, sfSearchInherited];
walker.ChildrenDoNotLeave := CengShaderPartArr.Create(TengShaderGenerator);
walker.ChildrenForceLeave := CengShaderPartArr.Create(TengShaderFile);
walker.Run(aArgs.Root);
proc := (ExtractSearchResult(self, walker.Name, sr) as TengShaderPartProc);

aArgs.PushProcParams(fParameters);
aArgs.PushFlags(aArgs.Flags - [gfGenerateProcedureCode, gfGenerateInlineCode] + [gfGenerateProcedureCall]);
try
proc.GenerateCodeIntern(aArgs);
finally
aArgs.PopFlags;
aArgs.PopProcParams;
end;
finally
FreeAndNil(walker);
FreeAndNil(sr);
end;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -149,6 +181,69 @@ begin
result := '';
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
procedure TengShaderPartInherited.GenerateCodeIntern(const aArgs: TengShaderGeneratorArgs);

function FindProc: TengShaderPartProc;
var
sr: TengSearchResults;
walker: TengProcSearchWalker;
ParentProc: TengShaderPartProc;
begin
sr := TengSearchResults.Create;
walker := TengProcSearchWalker.Create(sr);
try
ParentProc := (GetParent(TengShaderPartProc) as TengShaderPartProc);
walker.Name := Name;
if (walker.Name = '') then
walker.Name := ParentProc.Name;
walker.Owner := ParentProc;
walker.SearchFlags := [sfEvaluateIf, sfIgnoreOwner, sfSearchChildrenLazy, sfSearchInherited, sfSearchParents];
walker.ParentsDoNotLeave := CengShaderPartArr.Create(TengShaderPartClass);
walker.ChildrenDoNotLeave := CengShaderPartArr.Create(TengShaderPartClass);
walker.Run(ParentProc);
result := (ExtractSearchResult(self, walker.Name, sr) as TengShaderPartProc);
finally
FreeAndNil(walker);
FreeAndNil(sr);
end;
end;

procedure GenCode(const aProc: TengShaderPartProc; const aParams: TStrings);
begin
aArgs.PushFlags(aArgs.Flags + [gfGenerateInlineCode]);
aArgs.PushProcParams(aParams);
try
aProc.GenerateCodeIntern(aArgs);
finally
aArgs.PopProcParams;
aArgs.PopFlags;
end;
end;

var
proc: TengShaderPartProc;
i: Integer;
params: TStringList;
begin
aArgs.AddToken(GetTokenName);
proc := FindProc;
if (fParameters.Count > 0) then begin
if (fParameters.Count <> proc.ParameterCount) then
raise EengInvalidParamterCount.Create(proc.name + ' expexts ' + IntToStr(proc.ParameterCount) + ' parameters', self);
GenCode(proc, fParameters);
end else begin
params := TStringList.Create;
try
for i := 0 to proc.ParameterCount-1 do
params.Add(proc.Parameters[i].Name);
GenCode(proc, params);
finally
FreeAndNil(params);
end;
end;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
class function TengShaderPartInherited.GetTokenName: String;
begin


+ 24
- 4
uengShaderPartClass.pas View File

@@ -18,7 +18,7 @@ type
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
TengShaderPartClass = class;
TengShaderPartClassList = specialize TutlSimpleList<TengShaderPartClass>;
TengShaderPartClass = class(TengShaderCodeGenerator)
TengShaderPartClass = class(TengShaderGenerator)
{ Code Loading & Storage }
private { member }
fName: String;
@@ -54,7 +54,8 @@ type
implementation

uses
uengShaderFileConstants, uengShaderFileTypes, uengShaderFileHelper, uengShaderPartKeyValuePair, uengShaderPartScope, uengShaderFile;
uengShaderFileConstants, uengShaderFileTypes, uengShaderFileHelper, uengShaderPartKeyValuePair,
uengShaderPartScope, uengShaderFile, uengShaderPartProc;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//TengShaderPartClass///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -173,7 +174,7 @@ begin
walker := TengSearchWalker.Create(sr);
try
walker.ResultTypes := CengShaderPartArr.Create(TengShaderPartProperty);
walker.ChildrenDoNotLeave := CengShaderPartArr.Create(TengShaderCodeGenerator);
walker.ChildrenDoNotLeave := CengShaderPartArr.Create(TengShaderGenerator);
walker.ChildrenForceLeave := CengShaderPartArr.Create(TengShaderFile);
walker.Run(self);
for p in sr.GetReverseEnumerator do
@@ -188,6 +189,9 @@ end;
procedure TengShaderPartClass.GenerateCodeIntern(const aArgs: TengShaderGeneratorArgs);
var
c: TengShaderPartClass;
sr: TengSearchResults;
walker: TengSearchWalker;
main: TengShaderPartMain;
begin
if (aArgs.Root <> self) then
exit;
@@ -195,7 +199,23 @@ begin
c.GenerateCodeIntern(aArgs);
inherited GenerateCodeIntern(aArgs);

// TODO generate main routine
sr := TengSearchResults.Create;
walker := TengSearchWalker.Create(sr);
try
walker.SearchFlags := [sfSearchChildren, sfEvaluateIf];
walker.ResultTypes := CengShaderPartArr.Create(TengShaderPartMain);
walker.Run(self);
main := (ExtractSearchResult(self, TengShaderPartMain.GetTokenName, sr) as TengShaderPartMain);
aArgs.PushFlags([gfGenerateProcedureCode]);
try
main.GenerateCodeIntern(aArgs);
finally
aArgs.PopFlags;
end;
finally
FreeAndNil(walker);
FreeAndNil(sr);
end;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////


+ 5
- 1
uengShaderPartCntr.pas View File

@@ -154,8 +154,12 @@ end;
procedure TengShaderPartCntr.GenerateCodeIntern(const aArgs: TengShaderGeneratorArgs);
var
p: TengShaderCodePart;
s: String;
begin
aArgs.AddToken(GetTokenName);
s := GetTokenName;
if (s = '') then
s := ClassName;
aArgs.AddToken(s);
try
for p in fChildren do
p.GenerateCodeIntern(aArgs);


+ 3
- 60
uengShaderPartMeta.pas View File

@@ -7,33 +7,9 @@ interface

uses
Classes, SysUtils,
uengShaderPart, uengShaderCodePart, uengShaderFileParser, uengShaderGeneratorArgs;
uengShaderPart, uengShaderCodePart, uengShaderFileParser, uengShaderGeneratorArgs, uengShaderFileTypes;

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;

procedure Assign(const aValues: TengMetaData);

constructor Create(const aName: String; const aType: TengMetaType);
destructor Destroy; override;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
TengShaderPartMeta = class(TengShaderCodePart)
{ Code Loading & Storage }
@@ -61,40 +37,7 @@ type
implementation

uses
uengShaderFileConstants, uengShaderFileTypes;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//TengMetaData//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function TengMetaData.GetValues: TStrings;
begin
result := fValues;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
procedure TengMetaData.Assign(const aValues: TengMetaData);
begin
fName := aValues.Name;
fMetaType := aValues.MetaType;
fValues.Clear;
fValues.AddStrings(aValues.Values);
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;
uengShaderFileConstants;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//TengShaderPartMeta////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -170,7 +113,7 @@ end;
procedure TengShaderPartMeta.GenerateCodeIntern(const aArgs: TengShaderGeneratorArgs);
begin
inherited GenerateCodeIntern(aArgs);
aArgs.AddMeta(self);
aArgs.AddMeta(fData);
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////


+ 12
- 12
uengShaderPartParameter.pas View File

@@ -129,7 +129,7 @@ procedure TengShaderPartParameter.GenerateCodeIntern(const aArgs: TengShaderGene
begin
if (gfAddParameterItem in aArgs.Flags) then begin
inherited GenerateCodeIntern(aArgs);
aArgs.AddParam(self);
aArgs.AddParameter(self);
end;
end;

@@ -167,8 +167,11 @@ end;
procedure TengShaderPartVar.GenerateCodeIntern(const aArgs: TengShaderGeneratorArgs);
begin
inherited GenerateCodeIntern(aArgs);
if (gfGenerateParameterItemCode in aArgs.Flags) then begin
// TODO
if (gfGenerateParameterCode in aArgs.Flags) then begin
aArgs.AddText(format('%*s %s', [aArgs.MaxParameterLength, fType, fName]));
if (fDefaultValue <> '') then
aArgs.AddText(' = ' + fDefaultValue);
aArgs.AddCommandEnd(';');
end;
end;

@@ -184,9 +187,8 @@ end;
procedure TengShaderPartVarying.GenerateCodeIntern(const aArgs: TengShaderGeneratorArgs);
begin
inherited GenerateCodeIntern(aArgs);
if (gfGenerateParameterItemCode in aArgs.Flags) then begin
// TODO
end;
if (gfGenerateParameterCode in aArgs.Flags) then
aArgs.AddText(Format('varying %*s %s;', [aArgs.MaxParameterLength, fType, fName]));
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -201,9 +203,8 @@ end;
procedure TengShaderPartUniform.GenerateCodeIntern(const aArgs: TengShaderGeneratorArgs);
begin
inherited GenerateCodeIntern(aArgs);
if (gfGenerateParameterItemCode in aArgs.Flags) then begin
// TODO
end;
if (gfGenerateParameterCode in aArgs.Flags) then
aArgs.AddText(Format('uniform %*s %s;', [aArgs.MaxParameterLength, fType, fName]));
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -242,9 +243,8 @@ end;
procedure TengShaderPartConst.GenerateCodeIntern(const aArgs: TengShaderGeneratorArgs);
begin
inherited GenerateCodeIntern(aArgs);
if (gfGenerateParameterItemCode in aArgs.Flags) then begin
// TODO
end;
if (gfGenerateParameterCode in aArgs.Flags) then
aArgs.AddText(Format('const %*s %s;', [aArgs.MaxParameterLength, fType, fName]));
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////


+ 178
- 3
uengShaderPartProc.pas View File

@@ -7,7 +7,7 @@ interface

uses
Classes, SysUtils,
uengShaderPart, uengShaderPartScope, uengShaderFileParser
uengShaderPart, uengShaderPartScope, uengShaderFileParser, uengShaderGeneratorArgs

{$IFDEF USE_BITSPACE_UTILS}
, uutlGenerics;
@@ -30,15 +30,26 @@ type
fName: String;
fIsInline: Boolean;
fParameters: TengShaderPartProcParamList;
function GetParameter(const aIndex: Integer): TengShaderPartProcParam;
function GetParameterCount: Integer;
protected
function GetHeaderText: String; virtual;
function GetText: String; override;
function ParseIntern(const aArgs: TengParseArgs; const aParams: TengTokenParameterList): String; override;

{ Code Generation }
protected
function GenerateHeaderCode: String; virtual;
procedure GenerateInlineCode(const aArgs: TengShaderGeneratorArgs); virtual;
public
procedure GenerateCodeIntern(const aArgs: TengShaderGeneratorArgs); override;

{ General }
public
property Name: String read fName;
property IsInline: Boolean read fIsInline;
property Name: String read fName;
property IsInline: Boolean read fIsInline;
property ParameterCount: Integer read GetParameterCount;
property Parameters[const aIndex: Integer]: TengShaderPartProcParam read GetParameter;

constructor Create(const aParent: TengShaderPart); override;
destructor Destroy; override;
@@ -55,6 +66,10 @@ type
function GetHeaderText: String; override;
function ParseIntern(const aArgs: TengParseArgs; const aParams: TengTokenParameterList): String; override;

{ Code Generation }
protected
function GenerateHeaderCode: String; override;

{ General }
public
class function GetTokenName: String; override;
@@ -69,6 +84,11 @@ type
function GetHeaderText: String; override;
function ParseIntern(const aArgs: TengParseArgs; const aParams: TengTokenParameterList): String; override;

{ Code Generation }
protected
function GenerateHeaderCode: String; override;
procedure GenerateInlineCode(const aArgs: TengShaderGeneratorArgs); override;

{ Class Methods }
public
class function GetTokenName: String; override;
@@ -77,10 +97,23 @@ type
implementation

uses
RegExpr,
uengShaderFileConstants, uengShaderFileTypes, uengShaderFileHelper;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//TengShaderPartProc////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function TengShaderPartProc.GetParameter(const aIndex: Integer): TengShaderPartProcParam;
begin
result := fParameters[aIndex];
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function TengShaderPartProc.GetParameterCount: Integer;
begin
result := fParameters.Count;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function TengShaderPartProc.GetHeaderText: String;
var
@@ -150,6 +183,102 @@ begin
result := CheckEndToken(aArgs, self);
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function TengShaderPartProc.GenerateHeaderCode: 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.GenerateInlineCode(const aArgs: TengShaderGeneratorArgs);
var
p: TengShaderPartProcParam;
old, new: TStringList;
rx: TRegExpr;
s: String;
begin
aArgs.PushCode;
rx := TRegExpr.Create;
old := TStringList.Create;
new := TStringList.Create;
try
inherited GenerateCodeIntern(aArgs);

// prepare old parameters
for p in fParameters do
old.Add(p.Name);

// prepate new paramaters
rx.Expression := '[^A-z0-9_]+';
for s in aArgs.ProcParams do begin
if rx.Exec(s)
then new.Add('(' + s + ')')
else new.Add(s);
end;

// replace parameters
aArgs.ReplaceIdents(old, new);
finally
FreeAndNil(rx);
FreeAndNil(old);
FreeAndNil(new);
aArgs.PopCode([pcfAppend]);
end;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
procedure TengShaderPartProc.GenerateCodeIntern(const aArgs: TengShaderGeneratorArgs);
var
s, params: String;
begin
// generate inline code
if (aArgs.Flags * [gfGenerateProcedureCall, gfGenerateProcedureCode] <> []) and
((gfGenerateInlineCode in aArgs.Flags) or fIsInline) then
begin
GenerateInlineCode(aArgs);
// TODO: ignore next command end?!

// generate code
end else if (gfGenerateProcedureCode in aArgs.Flags) then begin
aArgs
.AddLineBreak
.AddText(GenerateHeaderCode)
.AddLineBreak
.AddCommandEnd('{')
.AddLineBreak
.BeginBlock(4);
try
inherited GenerateCodeIntern(aArgs);
finally
aArgs
.EndBlock
.AddCommandEnd('}')
.AddLineBreak;
end;

// generate call
end else if (gfGenerateProcedureCall in aArgs.Flags) then begin
params := '';
for s in aArgs.ProcParams do begin
if (params <> '') then
params := params + ', ';
params := params + s;
end;
aArgs.AddText(fName + '(' + params + ')');
aArgs.AddProcedure(self);
end;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
constructor TengShaderPartProc.Create(const aParent: TengShaderPart);
begin
@@ -197,6 +326,12 @@ begin
inherited ParseIntern(aArgs, aParams);
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function TengShaderPartMain.GenerateHeaderCode: String;
begin
result := 'void main(void)';
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
class function TengShaderPartMain.GetTokenName: String;
begin
@@ -232,6 +367,46 @@ begin
result := inherited ParseIntern(aArgs, aParams);
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function TengShaderPartFunc.GenerateHeaderCode: 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;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
procedure TengShaderPartFunc.GenerateInlineCode(const aArgs: TengShaderGeneratorArgs);
var
csi: TengShaderGeneratorArgs.TCodeStackItem;
indent: Integer;
begin
csi := TengShaderGeneratorArgs.TCodeStackItem.Create;
try
indent := aArgs.ExtractCurrentCommand(csi);
aArgs.PushCode;
aArgs.BeginBlock;
try
inherited GenerateInlineCode(aArgs);
finally
aArgs.EndBlock;
aArgs.AddText(StringOfChar(' ', indent));
aArgs.ReplaceReturns(csi, fReturnType, fName);
aArgs.PopCode([pcfAppend]);
end;
finally
FreeAndNil(csi);
end;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
class function TengShaderPartFunc.GetTokenName: String;
begin


Loading…
Cancel
Save