@@ -0,0 +1,36 @@ | |||
{$STATIC BaseVec 'vec2(0.0)'} | |||
{$CLASS Base1} | |||
{$FUNC 'vec2' 'TestProc' 'vec2' 'aVec'} | |||
vec2 tmp = aVec; | |||
tmp += vec2(1.0); | |||
return tmp; | |||
{$END} | |||
{$END} | |||
{$CLASS Base2} | |||
{$FUNC 'vec2' 'TestProc' 'vec2' 'aVec'} | |||
return aVec + vec2(1.0); | |||
{$END} | |||
{$END} | |||
{$CLASS SimpleClass $EXTENDS Base1 Base2} | |||
{$UNIFORM 'sampler2D' 'uTexture0'} | |||
{$UNIFORM 'sampler2D' 'uTexture1'} | |||
{$UNIFORM 'vec4' 'uColor'} | |||
{$FUNC 'vec2' 'TestProc' 'vec2' 'aVec'} | |||
vec2 v = aVec; | |||
v = {$INHERITED Base1 TestProc BaseVec $INLINE}; | |||
v = {$INHERITED Base2 'v'}; | |||
return v; | |||
{$END} | |||
{$MAIN} | |||
vec2 texCoord = {$CALL TestProc 'gl_TexCoord[0]'}; | |||
gl_FragColor = | |||
texture2D(uTexture0, texCoord) * | |||
texture2D(uTexture1, texCoord) * | |||
uColor; | |||
{$END} | |||
{$END} |
@@ -0,0 +1,19 @@ | |||
{$CLASS Base1} | |||
{$MAIN} | |||
gl_FragColor.r = 1.0; | |||
{$END} | |||
{$END} | |||
{$CLASS Base2} | |||
{$MAIN} | |||
gl_FragColor.g = 1.0; | |||
{$END} | |||
{$END} | |||
{$CLASS SimpleClass $EXTENDS Base1 Base2} | |||
{$MAIN} | |||
{$INHERITED Base1}; | |||
{$INHERITED Base2}; | |||
gl_FragColor.ba = vec2(1.0); | |||
{$END} | |||
{$END} |
@@ -0,0 +1,27 @@ | |||
uniform sampler2D uTexture0; | |||
uniform sampler2D uTexture1; | |||
uniform vec4 uColor; | |||
vec2 Base2_TestProc(vec2 aVec) | |||
{ | |||
return aVec + vec2(1.0); | |||
} | |||
vec2 SimpleClass_TestProc(vec2 aVec) | |||
{ | |||
vec2 v = aVec; | |||
vec2 tmp = (vec2(0.0)); | |||
tmp += vec2(1.0); | |||
v = (tmp); | |||
v = Base2_TestProc(v); | |||
return v; | |||
} | |||
void main(void) | |||
{ | |||
vec2 texCoord = SimpleClass_TestProc(gl_TexCoord[0]); | |||
gl_FragColor = | |||
texture2D(uTexture0, texCoord) * | |||
texture2D(uTexture1, texCoord) * | |||
uColor; | |||
} |
@@ -0,0 +1,16 @@ | |||
void Base2_main(void) | |||
{ | |||
gl_FragColor.g = 1.0; | |||
} | |||
void Base1_main(void) | |||
{ | |||
gl_FragColor.r = 1.0; | |||
} | |||
void main(void) | |||
{ | |||
Base1_main(); | |||
Base2_main(); | |||
gl_FragColor.ba = vec2(1.0); | |||
} |
@@ -48,6 +48,8 @@ type | |||
TTestCase_Class = class(TShaderFileTestCase) | |||
published | |||
procedure Simple; | |||
procedure InheritedFunc; | |||
procedure InheritedMain; | |||
end; | |||
implementation | |||
@@ -194,6 +196,16 @@ begin | |||
DoTest('code_Class_Simple.shdr', 'SimpleClass', 'result_Class_Simple.shdr'); | |||
end; | |||
procedure TTestCase_Class.InheritedFunc; | |||
begin | |||
DoTest('code_Class_InheritedFunc.shdr', 'SimpleClass', 'result_Class_InheritedFunc.shdr'); | |||
end; | |||
procedure TTestCase_Class.InheritedMain; | |||
begin | |||
DoTest('code_Class_InheritedMain.shdr', 'SimpleClass', 'result_Class_InheritedMain.shdr'); | |||
end; | |||
initialization | |||
RegisterTest(TTestCase_IfElifElseEnd); | |||
RegisterTest(TTestCase_FuncProcMain); | |||
@@ -1,3 +1,3 @@ | |||
{.$DEFINE EXPRESSION_ADD_BRACKET} // add brackets to expressions | |||
{$DEFINE USE_BITSPACE_UTILS} // use bitSpace Utils | |||
{$DEFINE DEBUG} // enable debug output | |||
{.$DEFINE DEBUG} // enable debug output |
@@ -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 BaseClassMethod 'param1' 'param2'} | |||
TOKEN_INHERITED = TOKEN_CHAR_IDENT + 'INHERITED'; //{$INHERITED BaseClass MethodName 'param1' 'param2' $INLINE} | |||
TOKEN_INCLUDE = TOKEN_CHAR_IDENT + 'INCLUDE'; //{$INCLUDE 'Normal.frag'} | |||
@@ -693,7 +693,7 @@ begin | |||
walker := TengKeyValuePairSearchWalker.Create(sr); | |||
try | |||
walker.Name := param.Name; | |||
walker.SearchFlags := [sfSearchChildrenLazy, sfSearchParents]; | |||
walker.SearchFlags := [sfSearchChildren, sfSearchParents]; | |||
walker.ResultTypes := CengShaderPartArr.Create(TengShaderPartProperty, TengShaderPartStatic); | |||
walker.ChildrenDoNotLeave := CengShaderPartArr.Create(TengShaderPartScope); | |||
walker.ChildrenForceLeave := CengShaderPartArr.Create(TengShaderFile); | |||
@@ -6,7 +6,7 @@ unit uengShaderFileHelper; | |||
interface | |||
uses | |||
uengShaderPart, uengShaderFileParser; | |||
uengShaderPart, uengShaderFileParser, uengShaderPartClass; | |||
type | |||
TInfoFlag = ( | |||
@@ -83,6 +83,16 @@ type | |||
property Name: String read fName write fName; | |||
end; | |||
TengInheritedSearchWalker = class(TengSearchWalker) | |||
private | |||
fName: String; | |||
protected | |||
function Check(const aPart: TengShaderPart): Boolean; override; | |||
public | |||
property Name: String read fName write fName; | |||
constructor Create(const aClass: TengShaderPartClass; const aResults: TengSearchResults); | |||
end; | |||
TengProcSearchWalker = class(TengSearchWalker) | |||
private | |||
fName: String; | |||
@@ -98,7 +108,7 @@ implementation | |||
uses | |||
sysutils, | |||
uengShaderFileConstants, uengShaderFileTypes, uengShaderPartKeyValuePair, uengShaderPartProc, | |||
uengShaderPartIf, uengShaderPartClass; | |||
uengShaderPartIf; | |||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
function IsValidIdentifier(const aIdent: String): Boolean; | |||
@@ -195,14 +205,12 @@ end; | |||
//TengSearchWalker////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
procedure TengSearchWalker.Visit(const aPart, aSender: TengShaderPart; const aArgs: Pointer); | |||
var | |||
args: TArgs; | |||
function VisitChild(const aItem: TengShaderPart): Boolean; | |||
var | |||
c: CengShaderPart; | |||
begin | |||
result := (sfSearchChildren in args.Flags) and Assigned(aItem) and (aItem <> aSender); | |||
result := Assigned(aItem) and (aItem <> aSender); | |||
if not result then | |||
exit; | |||
for c in fChildrenDoNotLeave do | |||
@@ -217,7 +225,7 @@ var | |||
var | |||
c: CengShaderPart; | |||
begin | |||
result := (sfSearchParents in args.Flags) and Assigned(aPart.Parent) and (aPart.Parent <> aSender); | |||
result := Assigned(aPart.Parent) and (aPart.Parent <> aSender); | |||
if not result then | |||
exit; | |||
for c in fParentsDoNotLeave do | |||
@@ -231,6 +239,7 @@ var | |||
var | |||
p: TengShaderPart; | |||
c: TengShaderPartClass; | |||
args: TArgs; | |||
nextArgs: TArgs; | |||
begin | |||
if not Assigned(aPart) then | |||
@@ -240,23 +249,31 @@ begin | |||
else | |||
args.Flags := fSearchFlags; | |||
// visit parent | |||
// calculate args for next iteration | |||
nextArgs := args; | |||
if (sfSearchChildrenLazy in nextArgs.Flags) then | |||
nextArgs.Flags := nextArgs.Flags + [sfSearchChildren] - [sfSearchChildrenLazy]; | |||
if Check(aPart.Parent) then | |||
fResults.Add(aPart.Parent); | |||
if VisitParent then | |||
Visit(aPart.Parent, aPart, @nextArgs); | |||
// visit inherited | |||
// sfSearchParents | |||
if (sfSearchParents in args.Flags) then begin | |||
if Check(aPart.Parent) then | |||
fResults.Add(aPart.Parent); | |||
if VisitParent then | |||
Visit(aPart.Parent, aPart, @nextArgs); | |||
end; | |||
// sfSearchInherited | |||
if (sfSearchInherited in args.Flags) and (aPart is TengShaderPartClass) then begin | |||
for c in (aPart as TengShaderPartClass).InheritedClasses do | |||
for c in (aPart as TengShaderPartClass).InheritedClasses do begin | |||
if Check(c) then | |||
fResults.Add(c); | |||
Visit(c, aPart, @nextArgs); | |||
end; | |||
end; | |||
// visit children | |||
// sfSearchChildren | |||
if (sfSearchChildren in args.Flags) then begin | |||
// sfEvaluateIf, sfIgnoreIf | |||
if (aPart is TengShaderPartIf) then with (aPart as TengShaderPartIf) do begin | |||
if (sfEvaluateIf in args.Flags) then begin | |||
if Expression.GetValue | |||
@@ -269,6 +286,7 @@ begin | |||
exit; | |||
end; | |||
// normal children | |||
for p in aPart do begin | |||
if Check(p) then | |||
fResults.Add(p); | |||
@@ -309,6 +327,26 @@ begin | |||
((aPart as TengShaderPartKeyValuePair).Name = fName); | |||
end; | |||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
//TengInheritedSearchWalker///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
function TengInheritedSearchWalker.Check(const aPart: TengShaderPart): Boolean; | |||
begin | |||
result := | |||
inherited Check(aPart) and | |||
(aPart is TengShaderPartClass) and | |||
((aPart as TengShaderPartClass).Name = fName); | |||
end; | |||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
constructor TengInheritedSearchWalker.Create(const aClass: TengShaderPartClass; const aResults: TengSearchResults); | |||
begin | |||
inherited Create(aResults); | |||
ResultTypes := CengShaderPartArr.Create(TengShaderPartClass); | |||
SearchFlags := [sfSearchInherited, sfIgnoreOwner]; | |||
Owner := aClass; | |||
end; | |||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
//TengProcSearchWalker////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
@@ -17,6 +17,7 @@ uses | |||
type | |||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
TengGenerateFlag = ( | |||
gfGenerateProcedureMain, // generate main procedure code | |||
gfGenerateProcedureCode, // generate procedure code | |||
gfGenerateProcedureCall, // generate procedure call | |||
gfGenerateInlineCode, // generate procedure as inline code | |||
@@ -59,7 +60,7 @@ type | |||
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); | |||
constructor Create(const aToken: TengGeneratorToken; const aText: String; const aIndent: Integer = High(Integer)); | |||
end; | |||
TCodePartList = specialize TutlSimpleList<TCodePart>; | |||
@@ -109,19 +110,19 @@ type | |||
property ProcParams: TStrings read GetProcParams; | |||
property MaxParameterLength: Integer read fMaxParameterLength; | |||
procedure PushCode; | |||
procedure PushFlags(const aFlags: TengGenerateFlags); | |||
procedure PushProcParams(const aParams: TStrings); | |||
function PushCode: TengShaderGeneratorArgs; | |||
function PushFlags(const aFlags: TengGenerateFlags): TengShaderGeneratorArgs; | |||
function PushProcParams(const aParams: TStrings): TengShaderGeneratorArgs; | |||
procedure PopCode(const aFlags: TengPopCodeFlags); | |||
procedure PopFlags; | |||
procedure PopProcParams; | |||
function PopCode(const aFlags: TengPopCodeFlags): TengShaderGeneratorArgs; | |||
function PopFlags: TengShaderGeneratorArgs; | |||
function PopProcParams: TengShaderGeneratorArgs; | |||
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 BeginBlock(const aIndent: Integer = High(Integer)): TengShaderGeneratorArgs; | |||
function EndBlock(const aCanAppend: Boolean = false): TengShaderGeneratorArgs; | |||
function AppendToPrevLine: TengShaderGeneratorArgs; | |||
@@ -130,8 +131,8 @@ type | |||
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); | |||
function ReplaceIdents(const aOld, aNew: TStrings): TengShaderGeneratorArgs; | |||
function ReplaceReturns(const aCommand: TCodeStackItem; const aRetType, aName: String): TengShaderGeneratorArgs; | |||
procedure GenerateCode(const aCode: TengShaderCode); | |||
@@ -234,7 +235,9 @@ begin | |||
gtNormal: result := '[N]' + fText; | |||
gtLineBreak: result := sLineBreak; | |||
gtCommandEnd: result := '[C]' + fText; | |||
gtBlockBegin: result := format('[B%d]', [fIndent]); | |||
gtBlockBegin: if (fIndent = High(Integer)) | |||
then result := '[B]' | |||
else result := format('[B%d]', [fIndent]); | |||
gtBlockEnd: result := '[E]'; | |||
gtToken: result := '[T' + fText + ']'; | |||
gtAppendToPrev: result := '[A]'; | |||
@@ -276,11 +279,36 @@ var | |||
f: TGenFlags; | |||
cb: TCodeBlock; | |||
function GetCurrentIndent(const aStr: String): Integer; | |||
{$IFDEF DEBUG} | |||
procedure GenerateDebugCode; | |||
var | |||
cp: TCodePart; | |||
s: String; | |||
begin | |||
s := ''; | |||
for cp in fItems do | |||
s := s + cp.DebugText; | |||
aCode.Text := aCode.Text + s + sLineBreak + sLineBreak; | |||
end; | |||
procedure GenerateCurrentCode(const aHeader: String); | |||
var | |||
i: Integer; | |||
begin | |||
aCode.Add(aHeader); | |||
for i := 0 to cb.Count-1 do | |||
aCode.Add(Format('[%02d]%s|', [cb.Depth[i], cb[i]])); | |||
aCode.Add(''); | |||
aCode.Add(''); | |||
aCode.Add(''); | |||
end; | |||
{$ENDIF} | |||
function GetCurrentIndent(const aStr: String; const aIgnoreEmptyLines: Boolean): Integer; | |||
var | |||
len: Integer; | |||
begin | |||
if (Trim(aStr) <> '') then begin | |||
if (Trim(aStr) <> '') or not aIgnoreEmptyLines then begin | |||
result := 1; | |||
len := Length(aStr); | |||
while (result <= len) and (aStr[result] in WHITESPACES) do | |||
@@ -290,10 +318,12 @@ var | |||
result := High(Integer); | |||
end; | |||
function IndentStr(const aStr: String; const aIndent: Integer): String; | |||
function IndentStr(const aStr: String; aIndent: Integer): String; | |||
var | |||
i, l: Integer; | |||
begin | |||
if (aStr = '') then | |||
aIndent := 0; | |||
if (aIndent < 0) then begin | |||
i := 1; | |||
l := Length(aStr); | |||
@@ -306,26 +336,26 @@ var | |||
result := aStr; | |||
end; | |||
procedure IndentBlock(aDepth, aIndent: Integer); | |||
procedure IndentBlock(aDepth, aAbsIndent: Integer); | |||
var | |||
i, minCurIndent: Integer; | |||
i, indent, minCurIndent: Integer; | |||
begin | |||
i := cb.Count-1; | |||
minCurIndent := High(Integer); | |||
while (i >= 0) and (cb.Depth[i] = aDepth) do begin | |||
minCurIndent := min(minCurIndent, GetCurrentIndent(cb[i])); | |||
minCurIndent := min(minCurIndent, GetCurrentIndent(cb[i], true)); | |||
dec(i); | |||
end; | |||
inc(i); | |||
aIndent := aIndent - minCurIndent; | |||
indent := aAbsIndent - minCurIndent; | |||
while (i < cb.Count) do begin | |||
cb[i] := IndentStr(cb[i], aIndent); | |||
cb[i] := IndentStr(cb[i], indent); | |||
cb.Depth[i] := cb.Depth[i] - 1; | |||
inc(i); | |||
end; | |||
end; | |||
procedure ProgressBlock(const aIndent, aDepth: Integer); | |||
procedure ProgressBlock(const aCurrentBlockIndent, aDepth: Integer); | |||
var | |||
cp: TCodePart; | |||
tmp: Integer; | |||
@@ -364,18 +394,25 @@ var | |||
gtBlockBegin: begin | |||
Include(f, gfPrevIsEmpty); | |||
tmp := GetCurrentIndent(cb.Last); | |||
if (tmp <> High(Integer)) | |||
then tmp := aIndent + tmp | |||
else tmp := aIndent; | |||
tmp := GetCurrentIndent(cb.Last, false); | |||
if (tmp = High(Integer)) then | |||
tmp := 0; | |||
if (Trim(cb.Last) <> '') then | |||
inc(tmp, 4); | |||
inc(tmp, cp.Indent); | |||
if (cp.Indent <> High(Integer)) then | |||
inc(tmp, cp.Indent); | |||
tmp := max(tmp, aCurrentBlockIndent); | |||
ProgressBlock(tmp, aDepth + 1); | |||
end; | |||
gtBlockEnd: begin | |||
IndentBlock(aDepth, aIndent); | |||
{$IFDEF DEBUG} | |||
GenerateCurrentCode(Format('------====== DEBUG STEP BEFORE INDENT (%d) ======------', [aCurrentBlockIndent])); | |||
{$ENDIF} | |||
IndentBlock(aDepth, aCurrentBlockIndent); | |||
{$IFDEF DEBUG} | |||
GenerateCurrentCode(Format('------====== DEBUG STEP AFTER INDENT (%d) ======------', [aCurrentBlockIndent])); | |||
{$ENDIF} | |||
exit; | |||
end; | |||
@@ -389,19 +426,6 @@ var | |||
end; | |||
end; | |||
{$IFDEF DEBUG} | |||
procedure GenerateDebugCode; | |||
var | |||
cp: TCodePart; | |||
s: String; | |||
begin | |||
s := ''; | |||
for cp in fItems do | |||
s := s + cp.DebugText; | |||
aCode.Text := aCode.Text + s + sLineBreak + sLineBreak; | |||
end; | |||
{$ENDIF} | |||
var | |||
s, e: Integer; | |||
begin | |||
@@ -423,7 +447,7 @@ begin | |||
for i := s to e do | |||
aCode.Add( | |||
{$IFDEF DEBUG} | |||
Format('[%02d]%s', [cb.Depth[i], cb[i]]) | |||
Format('[%02d]%s|', [cb.Depth[i], cb[i]]) | |||
{$ELSE} | |||
cb[i] | |||
{$ENDIF} | |||
@@ -580,25 +604,28 @@ begin | |||
end; | |||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
procedure TengShaderGeneratorArgs.PushCode; | |||
function TengShaderGeneratorArgs.PushCode: TengShaderGeneratorArgs; | |||
begin | |||
fCode.PushLast(TCodeStackItem.Create); | |||
result := self; | |||
end; | |||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
procedure TengShaderGeneratorArgs.PushFlags(const aFlags: TengGenerateFlags); | |||
function TengShaderGeneratorArgs.PushFlags(const aFlags: TengGenerateFlags): TengShaderGeneratorArgs; | |||
begin | |||
fFlagStack.PushLast(aFlags); | |||
result := self; | |||
end; | |||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
procedure TengShaderGeneratorArgs.PushProcParams(const aParams: TStrings); | |||
function TengShaderGeneratorArgs.PushProcParams(const aParams: TStrings): TengShaderGeneratorArgs; | |||
begin | |||
fProcParams.PushLast(aParams); | |||
result := self; | |||
end; | |||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
procedure TengShaderGeneratorArgs.PopCode(const aFlags: TengPopCodeFlags); | |||
function TengShaderGeneratorArgs.PopCode(const aFlags: TengPopCodeFlags): TengShaderGeneratorArgs; | |||
var | |||
csi: TCodeStackItem; | |||
begin | |||
@@ -618,18 +645,21 @@ begin | |||
finally | |||
FreeAndNil(csi); | |||
end; | |||
result := self; | |||
end; | |||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
procedure TengShaderGeneratorArgs.PopFlags; | |||
function TengShaderGeneratorArgs.PopFlags: TengShaderGeneratorArgs; | |||
begin | |||
fFlagStack.PopLast(true); | |||
result := self; | |||
end; | |||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
procedure TengShaderGeneratorArgs.PopProcParams; | |||
function TengShaderGeneratorArgs.PopProcParams: TengShaderGeneratorArgs; | |||
begin | |||
fProcParams.PopLast; | |||
result := self; | |||
end; | |||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
@@ -747,7 +777,7 @@ begin | |||
end; | |||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
procedure TengShaderGeneratorArgs.ReplaceIdents(const aOld, aNew: TStrings); | |||
function TengShaderGeneratorArgs.ReplaceIdents(const aOld, aNew: TStrings): TengShaderGeneratorArgs; | |||
var | |||
rx: TRegExpr; | |||
i: Integer; | |||
@@ -765,10 +795,11 @@ begin | |||
finally | |||
FreeAndNil(rx); | |||
end; | |||
result := self; | |||
end; | |||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
procedure TengShaderGeneratorArgs.ReplaceReturns(const aCommand: TCodeStackItem; const aRetType, aName: String); | |||
function TengShaderGeneratorArgs.ReplaceReturns(const aCommand: TCodeStackItem; const aRetType, aName: String): TengShaderGeneratorArgs; | |||
var | |||
rx: TRegExpr; | |||
RetCount, i, j: Integer; | |||
@@ -778,7 +809,7 @@ var | |||
begin | |||
rx := TRegExpr.Create; | |||
try | |||
rx.Expression := '([^A-z0-9_]+|^)return([^A-z0-9_]+|$)'; | |||
rx.Expression := '^(.*?\s+)return\s*(.*)$'; | |||
csi := fCode.Last; | |||
// find number of "return" in code | |||
@@ -812,7 +843,7 @@ begin | |||
// replace "return" with temp variable | |||
for cp in csi.Items do | |||
cp.Text := rx.Replace(cp.Text, '$1' + s + ' =$2', true); | |||
cp.Text := rx.Replace(cp.Text, '$1' + s + ' = $2', true); | |||
// merge code | |||
csi.Merge(aCommand, csi.Items.Count); | |||
@@ -825,16 +856,20 @@ 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); | |||
cp.Text := rx.Replace(cp.Text, '($2', true); | |||
// replace last gtCommandEnd with ')' and delete everything behind | |||
// replace last gtCommandEnd with ')' and delete everything code 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); | |||
inc(j); | |||
while (j < csi.Items.Count) do begin | |||
if (csi.Items[j].Token in [gtNormal, gtLineBreak, gtCommandEnd]) | |||
then csi.Items.Delete(j) | |||
else inc(j); | |||
end; | |||
// merge | |||
csi.Merge(aCommand, i+1); | |||
@@ -845,6 +880,7 @@ begin | |||
finally | |||
FreeAndNil(rx); | |||
end; | |||
result := self; | |||
end; | |||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
@@ -7,7 +7,8 @@ interface | |||
uses | |||
Classes, SysUtils, | |||
uengShaderPart, uengShaderCodePart, uengShaderFileParser, uengShaderGeneratorArgs; | |||
uengShaderPart, uengShaderCodePart, uengShaderFileParser, uengShaderGeneratorArgs, uengShaderPartClass, | |||
uengShaderPartProc, uengShaderPartKeyValuePair; | |||
type | |||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
@@ -16,6 +17,8 @@ type | |||
private { member } | |||
fName: String; | |||
fParameters: TStringList; | |||
function FindKeyValuePair(const aName: String): TengShaderPartKeyValuePair; | |||
protected { virtual getter } | |||
function GetText: String; override; | |||
function ParseIntern(const aArgs: TengParseArgs; const aParams: TengTokenParameterList): String; override; | |||
@@ -28,7 +31,6 @@ type | |||
private | |||
function GetParameters: TStrings; | |||
public | |||
property Name: String read fName; | |||
property Parameters: TStrings read GetParameters; | |||
constructor Create(const aParent: TengShaderPart); override; | |||
@@ -41,8 +43,12 @@ type | |||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
TengShaderPartInherited = class(TengShaderPartCall) | |||
{ Class Methods } | |||
{ Code Loading & Storage } | |||
private | |||
fInline: Boolean; | |||
fClass: TengShaderPartClass; | |||
protected | |||
function GetText: String; override; | |||
function ParseIntern(const aArgs: TengParseArgs; const aParams: TengTokenParameterList): String; override; | |||
{ Code Generation } | |||
@@ -58,23 +64,44 @@ type | |||
implementation | |||
uses | |||
uengShaderPartProc, uengShaderPartClass, uengShaderFileConstants, uengShaderFileTypes, | |||
uengShaderFileHelper, uengShaderGenerator, uengShaderFile; | |||
uengShaderFileConstants, uengShaderFileTypes, uengShaderFileHelper, uengShaderGenerator, | |||
uengShaderFile, uengShaderPartScope; | |||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
//TengShaderPartCall//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
function TengShaderPartCall.FindKeyValuePair(const aName: String): TengShaderPartKeyValuePair; | |||
var | |||
sr: TengSearchResults; | |||
walker: TengKeyValuePairSearchWalker; | |||
begin | |||
sr := TengSearchResults.Create; | |||
walker := TengKeyValuePairSearchWalker.Create(sr); | |||
try | |||
walker.Name := aName; | |||
walker.SearchFlags := [sfSearchChildren, sfSearchParents]; | |||
walker.ResultTypes := CengShaderPartArr.Create(TengShaderPartProperty, TengShaderPartStatic); | |||
walker.ChildrenDoNotLeave := CengShaderPartArr.Create(TengShaderPartScope); | |||
walker.ChildrenForceLeave := CengShaderPartArr.Create(TengShaderFile); | |||
walker.ParentsDoNotLeave := CengShaderPartArr.Create(TengShaderFile); | |||
walker.Run(fParent); | |||
result := (ExtractSearchResult(self, aName, sr) as TengShaderPartKeyValuePair); | |||
finally | |||
FreeAndNil(walker); | |||
FreeAndNil(sr); | |||
end; | |||
end; | |||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
function TengShaderPartCall.GetText: String; | |||
var | |||
i: Integer; | |||
begin | |||
result := TOKEN_CHAR_BEGIN + GetTokenName; | |||
if (fName <> '') then | |||
result := result + ' ' + fName; | |||
result := TOKEN_CHAR_BEGIN + GetTokenName + ' ' + fName; | |||
for i := 0 to fParameters.Count-1 do begin | |||
if (PtrInt(fParameters.Objects[i]) <> 0) | |||
then result := result + ' ' + TOKEN_CHAR_QUOTE + fParameters[i] + TOKEN_CHAR_QUOTE | |||
else result := result + ' ' + fParameters[i]; | |||
if Assigned(fParameters.Objects[i]) | |||
then result := result + ' ' + TengShaderPartKeyValuePair(fParameters.Objects[i]).Name | |||
else result := result + ' ' + TOKEN_CHAR_QUOTE + fParameters[i] + TOKEN_CHAR_QUOTE; | |||
end; | |||
result := result + TOKEN_CHAR_END; | |||
end; | |||
@@ -89,15 +116,18 @@ begin | |||
if (aParams.Count < 2) then | |||
raise EengInvalidParamterCount.Create(GetTokenName, 2, -1, self); | |||
result := ''; | |||
fParameters.Clear; | |||
with aParams[1] do begin | |||
if not IsValidIdentifier(fName) then | |||
raise EengInvalidIdentifier.Create(Name, self); | |||
fName := Name; | |||
result := ''; | |||
fName := aParams[1].Name; | |||
if not IsValidIdentifier(fName) then | |||
raise EengInvalidIdentifier.Create(fName, aParams[1].Line, aParams[1].Col, Filename, self); | |||
for i := 2 to aParams.Count-1 do begin | |||
if not aParams[i].Quoted | |||
then fParameters.AddObject(aParams[i].Name, FindKeyValuePair(aParams[i].Name)) | |||
else fParameters.AddObject(aParams[i].Name, nil); | |||
end; | |||
for i := 2 to aParams.Count-1 do | |||
fParameters.AddObject(aParams[i].Name, TObject(PtrInt(aParams[i].Quoted))); | |||
end; | |||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
@@ -111,7 +141,7 @@ begin | |||
sr := TengSearchResults.Create; | |||
walker := TengProcSearchWalker.Create(sr); | |||
try | |||
walker.Name := Name; | |||
walker.Name := fName; | |||
walker.SearchFlags := [sfEvaluateIf, sfSearchChildren, sfSearchInherited]; | |||
walker.ChildrenDoNotLeave := CengShaderPartArr.Create(TengShaderGenerator); | |||
walker.ChildrenForceLeave := CengShaderPartArr.Create(TengShaderFile); | |||
@@ -160,25 +190,92 @@ end; | |||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
//TengShaderPartInherited/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
function TengShaderPartInherited.GetText: String; | |||
begin | |||
result := inherited GetText; | |||
if fInline then | |||
Insert(' ' + TOKEN_INLINE, result, Length(result) - 1); | |||
end; | |||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
function TengShaderPartInherited.ParseIntern(const aArgs: TengParseArgs; const aParams: TengTokenParameterList): String; | |||
function FindInheritedClass(const aName: string): TengShaderPartClass; | |||
var | |||
sr: TengSearchResults; | |||
walker: TengInheritedSearchWalker; | |||
begin | |||
sr := TengSearchResults.Create; | |||
walker := TengInheritedSearchWalker.Create((GetParent(TengShaderPartClass) as TengShaderPartClass), sr); | |||
try | |||
walker.Name := aName; | |||
walker.Run(walker.Owner); | |||
result := (ExtractSearchResult(self, aName, sr, [ifWarning]) as TengShaderPartClass); | |||
finally | |||
FreeAndNil(walker); | |||
FreeAndNil(sr); | |||
end; | |||
end; | |||
type | |||
TExpectedPart = (epClass, epProc, epParam); | |||
TExpectedParts = set of TExpectedPart; | |||
var | |||
i: Integer; | |||
expected: TExpectedParts; | |||
begin | |||
if (aParams[0].Name <> GetTokenName) then with aParams[0] do | |||
raise EengInvalidToken.Create(ClassName, Name, Line, Col, Filename, self); | |||
fName := ''; | |||
fName := ''; | |||
result := ''; | |||
fClass := nil; | |||
fInline := false; | |||
expected := [epClass, epProc, epParam]; | |||
fParameters.Clear; | |||
if (aParams.Count >= 2) then begin | |||
if not IsValidIdentifier(aParams[1].Name) and (aParams[1].Name <> TOKEN_MAIN) then | |||
with aParams[1] do | |||
raise EengInvalidIdentifier.Create(Name, Line, Col, Filename, self); | |||
fName := aParams[1].Name; | |||
for i := 2 to aParams.Count-1 do | |||
fParameters.AddObject(aParams[i].Name, TObject(PtrInt(aParams[i].Quoted))); | |||
for i := 1 to aParams.Count-1 do begin | |||
// quoted parameter | |||
if aParams[i].Quoted then begin | |||
if not (epParam in expected) then | |||
raise EengUnexpectedToken.Create(aParams[i].Name, '[none]', aParams[i].Line, aParams[i].Col, Filename, self); | |||
fParameters.AddObject(aParams[i].Name, nil); | |||
expected := expected - [epClass, epProc]; | |||
continue; | |||
end; | |||
// inline | |||
if (aParams[i].Name = TOKEN_INLINE) then begin | |||
fInline := true; | |||
continue; | |||
end; | |||
// class | |||
if (epClass in expected) then begin | |||
fClass := FindInheritedClass(aParams[i].Name); | |||
if Assigned(fClass) then begin | |||
expected := expected - [epClass]; | |||
continue; | |||
end; | |||
end; | |||
// proc | |||
if (epProc in expected) then begin | |||
fName := aParams[i].Name; | |||
expected := expected - [epClass, epProc]; | |||
continue; | |||
end; | |||
// unquoted param | |||
if (epParam in expected) then begin | |||
fParameters.AddObject(aParams[i].Name, FindKeyValuePair(aParams[i].Name)); | |||
continue; | |||
end; | |||
raise EengUnexpectedToken.Create(aParams[i].Name, '[none]', aParams[i].Line, aParams[i].Col, Filename, self); | |||
end; | |||
result := ''; | |||
end; | |||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
@@ -188,20 +285,22 @@ procedure TengShaderPartInherited.GenerateCodeIntern(const aArgs: TengShaderGene | |||
var | |||
sr: TengSearchResults; | |||
walker: TengProcSearchWalker; | |||
ParentProc: TengShaderPartProc; | |||
c: TengShaderPartClass; | |||
begin | |||
sr := TengSearchResults.Create; | |||
walker := TengProcSearchWalker.Create(sr); | |||
try | |||
ParentProc := (GetParent(TengShaderPartProc) as TengShaderPartProc); | |||
walker.Name := Name; | |||
walker.Name := fName; | |||
if (walker.Name = '') then | |||
walker.Name := ParentProc.Name; | |||
walker.Owner := ParentProc; | |||
walker.SearchFlags := [sfEvaluateIf, sfIgnoreOwner, sfSearchChildrenLazy, sfSearchInherited]; | |||
walker.Name := (GetParent(TengShaderPartProc) as TengShaderPartProc).Name; | |||
walker.SearchFlags := [sfEvaluateIf, sfSearchChildren, sfSearchInherited]; | |||
walker.ParentsDoNotLeave := CengShaderPartArr.Create(TengShaderPartClass); | |||
walker.ChildrenDoNotLeave := CengShaderPartArr.Create(TengShaderPartClass); | |||
walker.Run(ParentProc); | |||
if not Assigned(fClass) then begin | |||
for c in (GetParent(TengShaderPartClass) as TengShaderPartClass).InheritedClasses do | |||
walker.Run(c); | |||
end else | |||
walker.Run(fClass); | |||
result := (ExtractSearchResult(self, walker.Name, sr) as TengShaderPartProc); | |||
finally | |||
FreeAndNil(walker); | |||
@@ -211,7 +310,9 @@ procedure TengShaderPartInherited.GenerateCodeIntern(const aArgs: TengShaderGene | |||
procedure GenCode(const aProc: TengShaderPartProc; const aParams: TStrings); | |||
begin | |||
aArgs.PushFlags(aArgs.Flags + [gfGenerateInlineCode]); | |||
if fInline | |||
then aArgs.PushFlags(aArgs.Flags + [gfGenerateInlineCode, gfGenerateProcedureCall] - [gfGenerateProcedureCode]) | |||
else aArgs.PushFlags(aArgs.Flags + [gfGenerateProcedureCall] - [gfGenerateProcedureCode]); | |||
aArgs.PushProcParams(aParams); | |||
try | |||
aProc.GenerateCodeIntern(aArgs); | |||
@@ -231,6 +332,9 @@ begin | |||
if (fParameters.Count > 0) then begin | |||
if (fParameters.Count <> proc.ParameterCount) then | |||
raise EengInvalidParamterCount.Create(proc.name + ' expexts ' + IntToStr(proc.ParameterCount) + ' parameters', self); | |||
for i := 0 to fParameters.Count-1 do | |||
if Assigned(fParameters.Objects[i]) then | |||
fParameters[i] := TengShaderPartKeyValuePair(fParameters.Objects[i]).Value; | |||
GenCode(proc, fParameters); | |||
end else begin | |||
params := TStringList.Create; | |||
@@ -207,7 +207,7 @@ begin | |||
walker.ResultTypes := CengShaderPartArr.Create(TengShaderPartMain); | |||
walker.Run(self); | |||
main := (ExtractSearchResult(self, TengShaderPartMain.GetTokenName, sr) as TengShaderPartMain); | |||
aArgs.PushFlags([gfGenerateProcedureCode]); | |||
aArgs.PushFlags([gfGenerateProcedureCode, gfGenerateProcedureMain]); | |||
try | |||
main.GenerateCodeIntern(aArgs); | |||
finally | |||
@@ -68,7 +68,6 @@ begin | |||
walker.ParentsDoNotLeave := CengShaderPartArr.Create(TengShaderFile); | |||
walker.SearchFlags := [ | |||
sfSearchChildrenLazy, | |||
sfSearchChildren, | |||
sfSearchParents | |||
]; | |||
walker.Run(self); | |||
@@ -147,7 +147,6 @@ begin | |||
walker.ParentsDoNotLeave := CengShaderPartArr.Create(TengShaderFile); | |||
walker.SearchFlags := [ | |||
sfSearchChildrenLazy, | |||
sfSearchChildren, | |||
sfSearchParents | |||
]; | |||
walker.Run(self); | |||
@@ -39,7 +39,7 @@ type | |||
{ Code Generation } | |||
protected | |||
function GenerateHeaderCode: String; virtual; | |||
function GenerateHeaderCode(const aArgs: TengShaderGeneratorArgs): String; virtual; | |||
procedure GenerateInlineCode(const aArgs: TengShaderGeneratorArgs); virtual; | |||
public | |||
procedure GenerateCodeIntern(const aArgs: TengShaderGeneratorArgs); override; | |||
@@ -68,7 +68,7 @@ type | |||
{ Code Generation } | |||
protected | |||
function GenerateHeaderCode: String; override; | |||
function GenerateHeaderCode(const aArgs: TengShaderGeneratorArgs): String; override; | |||
{ General } | |||
public | |||
@@ -86,7 +86,7 @@ type | |||
{ Code Generation } | |||
protected | |||
function GenerateHeaderCode: String; override; | |||
function GenerateHeaderCode(const aArgs: TengShaderGeneratorArgs): String; override; | |||
procedure GenerateInlineCode(const aArgs: TengShaderGeneratorArgs); override; | |||
{ Class Methods } | |||
@@ -98,7 +98,7 @@ implementation | |||
uses | |||
RegExpr, | |||
uengShaderFileConstants, uengShaderFileTypes, uengShaderFileHelper; | |||
uengShaderFileConstants, uengShaderFileTypes, uengShaderFileHelper, uengShaderPartClass; | |||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
//TengShaderPartProc//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
@@ -184,9 +184,10 @@ begin | |||
end; | |||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
function TengShaderPartProc.GenerateHeaderCode: String; | |||
function TengShaderPartProc.GenerateHeaderCode(const aArgs: TengShaderGeneratorArgs): String; | |||
var | |||
p: TengShaderPartProcParam; | |||
c: TengShaderPartClass; | |||
begin | |||
result := ''; | |||
for p in fParameters do begin | |||
@@ -196,7 +197,9 @@ begin | |||
end; | |||
if (result = '') then | |||
result := 'void'; | |||
result := 'void ' + fName + '(' + result + ')'; | |||
if GetParent(TengShaderPartClass, c) | |||
then result := 'void ' + c.Name + '_' + fName + '(' + result + ')' | |||
else result := 'void ' + fName + '(' + result + ')'; | |||
end; | |||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
@@ -240,6 +243,7 @@ end; | |||
procedure TengShaderPartProc.GenerateCodeIntern(const aArgs: TengShaderGeneratorArgs); | |||
var | |||
s, params: String; | |||
c: TengShaderPartClass; | |||
begin | |||
// generate inline code | |||
if (aArgs.Flags * [gfGenerateProcedureCall, gfGenerateProcedureCode] <> []) and | |||
@@ -252,7 +256,7 @@ begin | |||
end else if (gfGenerateProcedureCode in aArgs.Flags) then begin | |||
aArgs | |||
.AddLineBreak | |||
.AddText(GenerateHeaderCode) | |||
.AddText(GenerateHeaderCode(aArgs)) | |||
.AddLineBreak | |||
.AddCommandEnd('{') | |||
.AddLineBreak | |||
@@ -274,7 +278,9 @@ begin | |||
params := params + ', '; | |||
params := params + s; | |||
end; | |||
aArgs.AddText(fName + '(' + params + ')'); | |||
if GetParent(TengShaderPartClass, c) | |||
then aArgs.AddText(c.Name + '_' + fName + '(' + params + ')') | |||
else aArgs.AddText(fName + '(' + params + ')'); | |||
aArgs.AddProcedure(self); | |||
end; | |||
end; | |||
@@ -327,9 +333,13 @@ begin | |||
end; | |||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
function TengShaderPartMain.GenerateHeaderCode: String; | |||
function TengShaderPartMain.GenerateHeaderCode(const aArgs: TengShaderGeneratorArgs): String; | |||
var | |||
c: TengShaderPartClass; | |||
begin | |||
result := 'void main(void)'; | |||
if not (gfGenerateProcedureMain in aArgs.Flags) and GetParent(TengShaderPartClass, c) | |||
then result := 'void ' + c.Name + '_main(void)' | |||
else result := 'void main(void)'; | |||
end; | |||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
@@ -368,9 +378,10 @@ begin | |||
end; | |||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
function TengShaderPartFunc.GenerateHeaderCode: String; | |||
function TengShaderPartFunc.GenerateHeaderCode(const aArgs: TengShaderGeneratorArgs): String; | |||
var | |||
p: TengShaderPartProcParam; | |||
c: TengShaderPartClass; | |||
begin | |||
result := ''; | |||
for p in fParameters do begin | |||
@@ -380,7 +391,9 @@ begin | |||
end; | |||
if (result = '') then | |||
result := 'void'; | |||
result := fReturnType + ' ' + fName + '(' + result + ')'; | |||
if GetParent(TengShaderPartClass, c) | |||
then result := fReturnType + ' ' + c.Name + '_' + fName + '(' + result + ')' | |||
else result := fReturnType + ' ' + fName + '(' + result + ')'; | |||
end; | |||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
@@ -392,15 +405,17 @@ begin | |||
csi := TengShaderGeneratorArgs.TCodeStackItem.Create; | |||
try | |||
indent := aArgs.ExtractCurrentCommand(csi); | |||
aArgs.PushCode; | |||
aArgs.BeginBlock; | |||
aArgs | |||
.PushCode | |||
.BeginBlock; | |||
try | |||
inherited GenerateInlineCode(aArgs); | |||
finally | |||
aArgs.EndBlock; | |||
aArgs.AddText(StringOfChar(' ', indent)); | |||
aArgs.ReplaceReturns(csi, fReturnType, fName); | |||
aArgs.PopCode([pcfAppend]); | |||
aArgs | |||
.EndBlock | |||
.AddText(StringOfChar(' ', indent)) | |||
.ReplaceReturns(csi, fReturnType, fName) | |||
.PopCode([pcfAppend]); | |||
end; | |||
finally | |||
FreeAndNil(csi); | |||