Browse Source

* initial commit

master
Bergmann89 8 years ago
commit
c190e95c5c
25 changed files with 8980 additions and 0 deletions
  1. +21
    -0
      uengShaderCodeGenerator.pas
  2. +3
    -0
      uengShaderFile.inc
  3. +5641
    -0
      uengShaderFile.old.pas
  4. +96
    -0
      uengShaderFile.pas
  5. +93
    -0
      uengShaderFileConstants.pas
  6. +630
    -0
      uengShaderFileExpression.pas
  7. +56
    -0
      uengShaderFileHelper.pas
  8. +333
    -0
      uengShaderFileParser.pas
  9. +23
    -0
      uengShaderFileScope.pas
  10. +148
    -0
      uengShaderFileTypes.pas
  11. +233
    -0
      uengShaderPart.pas
  12. +158
    -0
      uengShaderPartCall.pas
  13. +117
    -0
      uengShaderPartClass.pas
  14. +159
    -0
      uengShaderPartCntr.pas
  15. +55
    -0
      uengShaderPartComment.pas
  16. +62
    -0
      uengShaderPartEcho.pas
  17. +183
    -0
      uengShaderPartIf.pas
  18. +100
    -0
      uengShaderPartInclude.pas
  19. +106
    -0
      uengShaderPartKeyValuePair.pas
  20. +31
    -0
      uengShaderPartMessage.pas
  21. +175
    -0
      uengShaderPartMeta.pas
  22. +143
    -0
      uengShaderPartParameter.pas
  23. +251
    -0
      uengShaderPartProc.pas
  24. +20
    -0
      uengShaderPartScope.pas
  25. +143
    -0
      uengShaderPartText.pas

+ 21
- 0
uengShaderCodeGenerator.pas View File

@@ -0,0 +1,21 @@
unit uengShaderCodeGenerator;

{$mode objfpc}{$H+}
{$I uengShaderFile.inc}

interface

uses
Classes, SysUtils,
uengShaderPartCntr;

type
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
TengShaderCodeGenerator = class(TengShaderPartCntr)

end;

implementation

end.


+ 3
- 0
uengShaderFile.inc View File

@@ -0,0 +1,3 @@
{$DEFINE EXPRESSION_ADD_BRACKET} // add brackets to expressions
{$DEFINE USE_BITSPACE_UTILS} // use bitSpace Utils
{$DEFINE DEBUG} // enable debug output

+ 5641
- 0
uengShaderFile.old.pas
File diff suppressed because it is too large
View File


+ 96
- 0
uengShaderFile.pas View File

@@ -0,0 +1,96 @@
unit uengShaderFile;

{ Package: SpaceEngine
Prefix: eng - ENGine
Beschreibung: stellt Klassen zum laden von Shader-Datein zur Verfügung
beim laden des Codes wird gleichzeitig die Präprozessor-Sprache ausgewertet }

{$mode objfpc}{$H+}
{$I uengShaderFile.inc}

interface

uses
Classes, sysutils,
uengShaderCodeGenerator, uengShaderFileParser, uengShaderFileTypes

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

type
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
TengShaderFile = class(TengShaderCodeGenerator)
{ Code Loading & Storage }
private
fFilename: String;
fFileReader: IutlFileReader;
fFileWriter: IutlFileWriter;
protected { virtual getter }
function GetFilename: String; override;
function GetFileReader: IengShaderFileReader; override;
function GetFileWriter: IengShaderFileWriter; override;
public { general methods }
procedure LoadCode(const aFilename: String; const aFileReader: IengShaderFileReader = nil);
end;

implementation

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//TengShaderFile////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function TengShaderFile.GetFilename: String;
begin
result := fFilename;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function TengShaderFile.GetFileReader: IengShaderFileReader;
begin
result := fFileReader;
if not Assigned(result) and Assigned(Parent) then
result := Parent.FileReader;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function TengShaderFile.GetFileWriter: IengShaderFileWriter;
begin
result := fFileWriter;
if not Assigned(result) and Assigned(Parent) then
result := Parent.FileWriter;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
procedure TengShaderFile.LoadCode(const aFilename: String; const aFileReader: IengShaderFileReader);
var
args: TengParseArgs;
token: String;
ms: TMemoryStream;
begin
fFileReader := aFileReader;
if not Assigned(fFileReader) then
fFileReader := GetFileReader;
if not Assigned(fFileReader) then
fFileReader := TengShaderFileReader.Create;
ms := TMemoryStream.Create;
try
Clear;
if not fFileReader.LoadStream(aFilename, ms) then
raise EengShaderPart.Create('unable to open file: ' + aFilename, Line, Col, Filename);
ms.Position := 0;
args := TengParseArgs.Create(ms, Filename);
try
token := ParseText(args);
if (token <> '') then with args do
raise EengShaderPart.Create('unknown token ''' + token + '''', Line, Col, Filename);
finally
FreeAndNil(args);
end;
finally
fFileReader := nil;
end;
end;

end.


+ 93
- 0
uengShaderFileConstants.pas View File

@@ -0,0 +1,93 @@
unit uengShaderFileConstants;

{$mode objfpc}{$H+}
{$I uengShaderFile.inc}

interface

const
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
PRECOMPILER_STATEMENT_BEGIN = '{';
PRECOMPILER_STATEMENT_END = '}';

TOKEN_CHAR_BEGIN = '{';
TOKEN_CHAR_END = '}';
TOKEN_CHAR_QUOTE = '''';
TOKEN_CHAR_IDENT = '$';
TOKEN_CHAR_COMMENT = '.';
TOKEN_CHAR_COMMANT_END = ';';
TOKEN_CHAR_SCOPE_BEGIN = '{';
TOKEN_CHAR_SCOPE_END = '}';

UNKNOWN_FILENAME = 'unknown file';
TOKEN_LINE_BREAK = sLineBreak;
TOKEN_NONE = '[none]';

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_INCLUDE = TOKEN_CHAR_IDENT + 'INCLUDE'; //{$INCLUDE 'Normal.frag'}

TOKEN_META = TOKEN_CHAR_IDENT + 'META'; //{$META 'Fuu' 'Bar'}
TOKEN_VERSION = TOKEN_CHAR_IDENT + 'VERSION'; //{$META $VERSION 'version'}
TOKEN_EXTENSION = TOKEN_CHAR_IDENT + 'EXTENSION'; //{$META $EXTENSION 'GL_ARB_geometry_shader4' 'enable'}
TOKEN_LAYOUT = TOKEN_CHAR_IDENT + 'LAYOUT'; //{$META $LAYOUT '(line_strip, max_vertices = 6) out'}

TOKEN_PROPERTY = TOKEN_CHAR_IDENT + 'PROPERTY'; //{$PROPERTY InvertRoughmap 'false'}
TOKEN_DEFINE = TOKEN_CHAR_IDENT + 'DEFINE'; //{$DEFINE RENDER_FACE_FRONT '0'}
TOKEN_ECHO = TOKEN_CHAR_IDENT + 'ECHO'; //{$ECHO InvertRoughmap}

TOKEN_VAR = TOKEN_CHAR_IDENT + 'VAR'; //{$VAR 'float' 'refractivity' '0.0'}
TOKEN_VARYING = TOKEN_CHAR_IDENT + 'VARYING'; //{$VARYING 'vec3' 'vVertex'}
TOKEN_UNIFORM = TOKEN_CHAR_IDENT + 'UNIFORM'; //{$UNIFORM 'sampler2D' 'uShadowMap'}

TOKEN_CALL = TOKEN_CHAR_IDENT + 'CALL'; //{$CALL CalcLight}
TOKEN_PROC = TOKEN_CHAR_IDENT + 'PROC'; //{$PROC CalcLight} Code... {$END}
TOKEN_FUNC = TOKEN_CHAR_IDENT + 'FUNC'; //{$FUND 'float' 'ShadowPoisson' 'vec2' 'shadowMapST' 'float' 'receiver'} Code... {$END}
TOKEN_MAIN = TOKEN_CHAR_IDENT + 'MAIN';
TOKEN_INLINE = TOKEN_CHAR_IDENT + 'INLINE'; //{$PROC CalcLight $INLINE} Code... {$END}

TOKEN_IF = TOKEN_CHAR_IDENT + 'IF'; //{$IF PhongLight = '0'} Code ... {$END}
TOKEN_ELIF = TOKEN_CHAR_IDENT + 'ELIF';
TOKEN_ELSE = TOKEN_CHAR_IDENT + 'ELSE';
TOKEN_END = TOKEN_CHAR_IDENT + 'END';

TOKEN_MESSAGE = TOKEN_CHAR_IDENT + 'MESSAGE'; //{$MESSAGE 'message'}
TOKEN_WARNING = TOKEN_CHAR_IDENT + 'WARNING'; //{$WARNING 'message'}
TOKEN_ERROR = TOKEN_CHAR_IDENT + 'ERROR'; //{$ERROR 'message'}

TOKEN_OP_LOGICAL_NOT = TOKEN_CHAR_IDENT + 'NOT'; //{$IF $NOT test}
TOKEN_OP_LOGICAL_OR = TOKEN_CHAR_IDENT + 'OR'; //{$IF test1 $OR test2}
TOKEN_OP_LOGICAL_AND = TOKEN_CHAR_IDENT + 'AND'; //{$IF test1 $AND test2}
TOKEN_OP_LOGICAL_XOR = TOKEN_CHAR_IDENT + 'XOR'; //{$IF test1 $XOR test2}
TOKEN_OP_DEFINED = TOKEN_CHAR_IDENT + 'DEFINED'; //{$IF $DEFINED test2}
TOKEN_OP_SET = TOKEN_CHAR_IDENT + 'SET'; //{$IF $SET vVertex}
TOKEN_OP_ADD = '+'; //{$IF test1 + test2}
TOKEN_OP_SUBTRACT = '-'; //{$IF test1 - test2}
TOKEN_OP_MULTIPLY = '*'; //{$IF test1 * test2}
TOKEN_OP_DIVIDE = '/'; //{$IF test1 / test2}
TOKEN_OP_EQUALS = '='; //{$IF test1 = test2}
TOKEN_OP_LESSER = '<'; //{$IF test1 < test2}
TOKEN_OP_GREATER = '>'; //{$IF test1 > test2}
TOKEN_OP_LEQUALS = '<='; //{$IF test1 <= test2}
TOKEN_OP_GEQUALS = '>='; //{$IF test1 >= test2}
TOKEN_OP_UNEQUALS = '<>'; //{$IF test1 <> test2}
TOKEN_OP_BINARY_OR = '|'; //{$IF test1 | test2}
TOKEN_OP_BINARY_AND = '&'; //{$IF test1 & test2}
TOKEN_OP_BINARY_XOR = '^'; //{$IF test1 ^ test2}
TOKEN_OP_BINARY_NOT = '!'; //{$IF !test1}
TOKEN_OP_GROUP_BEGIN = '('; //{$IF (test1 $OR test2) >= '0'}
TOKEN_OP_GROUP_END = ')';

VALID_IDENT_CHARS = ['A'..'Z', 'a'..'z', '0'..'9', '_'];
VALID_TOKEN_CHARS = ['$'] + VALID_IDENT_CHARS;
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];

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

implementation

end.


+ 630
- 0
uengShaderFileExpression.pas View File

@@ -0,0 +1,630 @@
unit uengShaderFileExpression;

{$mode objfpc}{$H+}
{$I uengShaderFile.inc}

interface

uses
Classes, SysUtils, variants,
uengShaderFileParser;

type
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
TengExpressionItem = class(TObject)
private
fLine: Integer;
fCol: Integer;
fFilename: String;
public
property Line: Integer read fLine;
property Col: Integer read fCol;
property Filename: String read fFilename;

function GetText: String; virtual;
function GetValue: Variant; virtual;
constructor Create(const aLine, aCol: Integer; const aFilename: String);
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
TengExpressionValue = class(TengExpressionItem)
private
fValue: Variant;
public
function GetText: String; override;
function GetValue: Variant; override;
constructor Create(const aValue: Variant; const aLine, aCol: Integer; const aFilename: String);
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
TengExpressionVariable = class(TengExpressionItem)
private
fName: String;
public
function GetText: String; override;
function GetValue: Variant; override;
constructor Create(const aName: String; const aLine, aCol: Integer; const aFilename: String);
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
TengExpressionGroup = class(TengExpressionItem)
private
fChild: TengExpressionItem;
public
property Child: TengExpressionItem read fChild write fChild;
function GetText: String; override;
function GetValue: Variant; override;
constructor Create(const aChild: TengExpressionItem; const aLine, aCol: Integer; const aFilename: String);
destructor Destroy; override;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
TengExpressionUnaryOperator = (
opBinaryNot,
opLogicalNot,
opDefined,
opSet
);
TengExpressionUnaryOperation = class(TengExpressionItem)
private
fChild: TengExpressionItem;
fUnaryOp: TengExpressionUnaryOperator;
public
property Child: TengExpressionItem read fChild write fChild;
property UnaryOp: TengExpressionUnaryOperator read fUnaryOp;

function GetText: String; override;
function GetValue: Variant; override;

constructor Create(const aUnaryOp: TengExpressionUnaryOperator; const aLine, aCol: Integer; const aFilename: String);
destructor Destroy; override;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
TengExpressionBinaryOperator = ( //order of elements in this enum is also the weight of the operators
opBinaryOr, opBinaryAnd, opBinaryXor, // binary
opMultiply, opDivide, opAdd, opSubtract, // arithmetic
opLogicalOr, opLogicalAnd, opLogicalXor, // logical
opEquals, opLesser, opGreater, opLEquals, opGEquals, opUnequals // comparison
);
TengExpressionBinaryOperation = class(TengExpressionItem)
private
fFirst: TengExpressionItem;
fSecond: TengExpressionItem;
fBinaryOp: TengExpressionBinaryOperator;
public
property First: TengExpressionItem read fFirst write fFirst;
property Second: TengExpressionItem read fSecond write fSecond;
property BinaryOp: TengExpressionBinaryOperator read fBinaryOp;

function GetText: String; override;
function GetValue: Variant; override;

constructor Create(const aOperator: TengExpressionBinaryOperator; const aLine, aCol: Integer; const aFilename: String);
destructor Destroy; override;
end;

function ParseExpression(const aParam: TengTokenParameterList; aIndex: Integer): TengExpressionItem;

implementation

uses
uengShaderFileConstants, uengShaderFileTypes, uengShaderFileHelper
{$IFDEF USE_BITSPACE_UTILS}
, uutlGenerics
{$ELSE}
, fgl
{$ENDIF}
;

const
EXPRESSION_UNARY_OPERATIONS: array[TengExpressionUnaryOperator] of String = (
TOKEN_OP_BINARY_NOT, //opBinaryNot
TOKEN_OP_LOGICAL_NOT, //opLogicalNot
TOKEN_OP_DEFINED, //opDefined
TOKEN_OP_SET //opSet
);

EXPRESSION_BINARY_OPERATIONS: array[TengExpressionBinaryOperator] of String = (
TOKEN_OP_BINARY_OR, //opBinaryOr
TOKEN_OP_BINARY_AND, //opBinaryAnd
TOKEN_OP_BINARY_XOR, //opBinaryXor

TOKEN_OP_MULTIPLY, //opMultiply
TOKEN_OP_DIVIDE, //opDivide
TOKEN_OP_ADD, //opAdd
TOKEN_OP_SUBTRACT, //opSubtract

TOKEN_OP_LOGICAL_OR, //opLogicalOr
TOKEN_OP_LOGICAL_AND, //opLogicalAnd
TOKEN_OP_LOGICAL_XOR, //opLogicalXor

TOKEN_OP_EQUALS, //opEquals
TOKEN_OP_LESSER, //opLesser
TOKEN_OP_GREATER, //opGreater
TOKEN_OP_LEQUALS, //opLEquals
TOKEN_OP_GEQUALS, //opGEquals
TOKEN_OP_UNEQUALS //opUnequals,
);

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//TengExpressionItem////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function TengExpressionItem.GetText: String;
begin
result := ''; // DUMMY
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function TengExpressionItem.GetValue: Variant;
begin
result := Unassigned; // DUMMY
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
constructor TengExpressionItem.Create(const aLine, aCol: Integer; const aFilename: String);
begin
inherited Create;
fLine := aLine;
fCol := aCol;
fFilename := aFilename;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//TengExpressionValue///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function TengExpressionValue.GetText: String;
begin
result := TOKEN_CHAR_QUOTE + fValue + TOKEN_CHAR_QUOTE;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function TengExpressionValue.GetValue: Variant;
begin
result := fValue;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
constructor TengExpressionValue.Create(const aValue: Variant; const aLine, aCol: Integer; const aFilename: String);
begin
inherited Create(aLine, aCol, aFilename);
fValue := aValue;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//TengExpressionVariable////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function TengExpressionVariable.GetText: String;
begin
result := fName;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function TengExpressionVariable.GetValue: Variant;
begin
result := Unassigned; // TODO
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
constructor TengExpressionVariable.Create(const aName: String; const aLine, aCol: Integer; const aFilename: String);
begin
inherited Create(aLine, aCol, aFilename);
fName := aName;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///TengExpressionGroup//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function TengExpressionGroup.GetText: String;
begin
if Assigned(fChild)
then result := TOKEN_OP_GROUP_BEGIN + fChild.GetText + TOKEN_OP_GROUP_END
else result := '';
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function TengExpressionGroup.GetValue: Variant;
begin
if Assigned(fChild)
then result := fChild.GetValue
else result := Unassigned;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
constructor TengExpressionGroup.Create(const aChild: TengExpressionItem; const aLine, aCol: Integer; const aFilename: String);
begin
inherited Create(aLine, aCol, aFilename);
fChild := aChild;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
destructor TengExpressionGroup.Destroy;
begin
FreeAndNil(fChild);
inherited Destroy;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//TengExpressionUnaryOperation//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function TengExpressionUnaryOperation.GetText: String;
begin
if not Assigned(fChild) then
EengExpression.Create('no child assigned', Line, Col, Filename);
result :=
{$IFDEF EXPRESSION_ADD_BRACKET}TOKEN_OP_GROUP_BEGIN+{$ENDIF}
EXPRESSION_UNARY_OPERATIONS[fUnaryOp] + ' ' + fChild.GetText
{$IFDEF EXPRESSION_ADD_BRACKET}+TOKEN_OP_GROUP_END{$ENDIF};
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function TengExpressionUnaryOperation.GetValue: Variant;
var
v: Variant;
begin
if not Assigned(fChild) then
raise EengExpression.Create('no child assigned', Line, Col, Filename);
try
case fUnaryOp of

opBinaryNot: begin
v := fChild.GetValue;
result := not Integer(v);
end;

opLogicalNot: begin
v := fChild.GetValue;
result := not Boolean(v);
end;

opDefined: begin
// TODO
end;

opSet: begin
// TODO
end;

else
result := inherited GetValue;
end;
except
on ex: Exception do
raise EengInvalidParamter.Create(
ex.Message + '("' + GetText + '" ==> ' +
EXPRESSION_UNARY_OPERATIONS[fUnaryOp] + ' ' + v + '")',
Line, Col, Filename);
end;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
constructor TengExpressionUnaryOperation.Create(const aUnaryOp: TengExpressionUnaryOperator; const aLine, aCol: Integer; const aFilename: String);
begin
inherited Create(aLine, aCol, aFilename);
fChild := nil;
fUnaryOp := aUnaryOp;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
destructor TengExpressionUnaryOperation.Destroy;
begin
FreeAndNil(fChild);
inherited Destroy;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//TengExpressionBinaryOperation/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function TengExpressionBinaryOperation.GetText: String;
begin
if not Assigned(fFirst) or not Assigned(fSecond) then
raise EengExpression.Create('first or second item not assigned');
result :=
{$IFDEF EXPRESSION_ADD_BRACKET}TOKEN_OP_GROUP_BEGIN +{$ENDIF}
fFirst.GetText + ' ' + EXPRESSION_BINARY_OPERATIONS[fBinaryOp] + ' ' + fSecond.GetText
{$IFDEF EXPRESSION_ADD_BRACKET} + TOKEN_OP_GROUP_END{$ENDIF};
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function TengExpressionBinaryOperation.GetValue: Variant;
var
v1: Variant;
v2: Variant;
begin
if not Assigned(fFirst) or not Assigned(fSecond) then
raise EengExpression.Create('first or second item not assigned');
v1 := fFirst.GetValue;
v2 := fSecond.GetValue;
try
case fBinaryOp of
opBinaryOr: result := (Integer(v1) or Integer(v2));
opBinaryAnd: result := (Integer(v1) and Integer(v2));
opBinaryXor: result := (Integer(v1) xor Integer(v2));

opMultiply: result := (v1 * v2);
opDivide: result := (v1 / v2);
opAdd: result := (v1 + v2);
opSubtract: result := (v1 - v2);

opLogicalOr: result := (Boolean(v1) or Boolean(v2));
opLogicalAnd: result := (Boolean(v1) and Boolean(v2));
opLogicalXor: result := (Boolean(v1) xor Boolean(v2));

opEquals: result := (v1 = v2);
opLesser: result := (v1 < v2);
opGreater: result := (v1 > v2);
opLEquals: result := (v1 <= v2);
opGEquals: result := (v1 >= v2);
opUnequals: result := (v1 <> v2);
else
result := inherited GetValue;
end;
except
on ex: Exception do
raise EengInvalidParamter.Create(
ex.Message + ' ("' + GetText + '" ==> "' + v1 + ' ' +
EXPRESSION_BINARY_OPERATIONS[fBinaryOp] + ' ' + v2 + '")',
fLine, fCol, fFilename);
end;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
constructor TengExpressionBinaryOperation.Create(const aOperator: TengExpressionBinaryOperator; const aLine, aCol: Integer; const aFilename: String);
begin
inherited Create(aLine, aCol, aFilename);
fBinaryOp := aOperator;
fFirst := nil;
fSecond := nil;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
destructor TengExpressionBinaryOperation.Destroy;
begin
FreeAndNil(fFirst);
FreeAndNil(fSecond);
inherited Destroy;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
type
TExpectedParam = (exVariable, exValue, exGroupBegin, exGroupEnd, exUnaryOperation, exBinaryOperation);
TExpectedParams = set of TExpectedParam;
{$IFDEF USE_BITSPACE_UTILS}
TExpressionItemStack = specialize TutlSimpleList<TengExpressionItem>;
{$ELSE}
TExpressionItemStack = class(specialize TFPList<TengExpressionItem>)
public

end;
{$ENDIF}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function ParseExpression(const aParam: TengTokenParameterList; aIndex: Integer): TengExpressionItem;
var
p: TengTokenParameter;

procedure RaiseEx(const aMsg: String);
begin
raise EengExpression.Create(aMsg, p.Line, p.Col, aParam.Filename);
end;

function NextParam: Boolean;
begin
inc(aIndex);
result := (aIndex < aParam.Count);
if result then
p := aParam[aIndex];
end;

function IsUnaryOperation(const aParam: String; out aOperator: TengExpressionUnaryOperator): Boolean;
begin
result := true;
for aOperator in TengExpressionUnaryOperator do
if (aParam = EXPRESSION_UNARY_OPERATIONS[aOperator]) then
exit;
result := false;
end;

function IsBinaryOperation(const aParam: String; out aOperator: TengExpressionBinaryOperator): Boolean;
begin
result := true;
for aOperator in TengExpressionBinaryOperator do
if (aParam = EXPRESSION_BINARY_OPERATIONS[aOperator]) then
exit;
result := false;
end;

procedure MergeItems(const aStack: TExpressionItemStack; var aNew: TengExpressionItem);
var
item: TengExpressionItem;
begin
try
if (aStack.Count = 0) then begin
aStack.PushLast(aNew);
aNew := nil;
exit;
end;

item := aStack.Last;
if (item is TengExpressionBinaryOperation) then begin
if (aNew is TengExpressionBinaryOperation) then begin
//both are binary operators, new is weaker then existing
if ((aNew as TengExpressionBinaryOperation).BinaryOp <
(item as TengExpressionBinaryOperation).BinaryOp) then
begin
(aNew as TengExpressionBinaryOperation).First := item;
aStack.PopLast;
aStack.PushLast(aNew);
aNew := nil;

//both are binary operators, new is stronger than existing
end else begin
if not Assigned((item as TengExpressionBinaryOperation).Second) then
RaiseEx('inconsistent state');
(aNew as TengExpressionBinaryOperation).First := (item as TengExpressionBinaryOperation).Second;
(item as TengExpressionBinaryOperation).Second := aNew;
aStack.PushLast(aNew);
aNew := nil;
end;

//existing is binary operator, new is normal
end else begin
if Assigned((item as TengExpressionBinaryOperation).Second) then
RaiseEx('inconsistent state');
(item as TengExpressionBinaryOperation).Second := aNew;
aNew := nil;
while (aStack.Count > 1) do
aStack.PopLast; //remove all but first
end;
end else begin
//existing is normal item, new is binary operation
if (aNew is TengExpressionBinaryOperation) then begin
aStack.PopLast;
(aNew as TengExpressionBinaryOperation).First := item;
aStack.PushLast(aNew);
aNew := nil;

//existing is unary operation, new is normal item or unary operation
end else if (item is TengExpressionUnaryOperation) then begin
if Assigned((item as TengExpressionUnaryOperation).Child) then
RaiseEx('inconsistent state');
(item as TengExpressionUnaryOperation).Child := aNew;
if not (aNew is TengExpressionUnaryOperation) then begin
while (aStack.Count > 1) do
aStack.PopLast; //remove all but first
end else
aStack.PushLast(aNew);
aNew := nil;

//existing and new are both normal items
end else
RaiseEx('inconsistent state');
end;
except
FreeAndNil(aNew);
raise;
end;
end;

function BuildTree(const aDepth: Integer = 0): TengExpressionItem;
var
uOp: TengExpressionUnaryOperator;
bOp: TengExpressionBinaryOperator;
expected: TExpectedParams;
stack: TExpressionItemStack;
l, c: Integer;
ei, tmp: TengExpressionItem;
begin
expected := [exVariable, exValue, exGroupBegin, exUnaryOperation];
result := nil;
stack := TExpressionItemStack.Create(false);
try try
repeat
// GroupBegin
if (p.Name = TOKEN_OP_GROUP_BEGIN) then begin
if not (exGroupBegin in expected) then
RaiseEx('unexpected ''' + p.Name + '''');
l := p.Line;
c := p.Col;
if not NextParam then
RaiseEx('unexpected end');
tmp := BuildTree(aDepth + 1);
ei := TengExpressionGroup.Create(tmp, l, c, aParam.Filename);
try
MergeItems(stack, ei);
if (p.Name <> TOKEN_OP_GROUP_END) then
RaiseEx('missing ''' + TOKEN_OP_GROUP_END + '''');
expected := [exBinaryOperation, exGroupEnd];
except
FreeAndNil(ei);
raise;
end;

// GroupEnd
end else if (p.Name = TOKEN_OP_GROUP_END) then begin
if not (exGroupEnd in expected) or (aDepth = 0) then
RaiseEx('unexpected ''' + TOKEN_OP_GROUP_END + '''');
exit;

// UnaryOperation
end else if IsUnaryOperation(p.Name, uOp) then begin
if not (exUnaryOperation in expected) then
RaiseEx('unexpected operator: ' + p.Name);
ei := TengExpressionUnaryOperation.Create(uOp, p.Line, p.Col, aParam.Filename);
try
MergeItems(stack, ei);
expected := [exVariable];
if (uOp <> opDefined) then
expected := expected + [exValue, exGroupBegin, exUnaryOperation]
except
FreeAndNil(ei);
raise;
end;

// BinaryOperation
end else if IsBinaryOperation(p.Name, bOp) then begin
if not (exBinaryOperation in expected) then
RaiseEx('unexpected operator: ' + p.Name);
ei := TengExpressionBinaryOperation.Create(bOp, p.Line, p.Col, aParam.Filename);
try
MergeItems(stack, ei);
expected := [exVariable, exValue, exGroupBegin, exUnaryOperation];
except
FreeAndNil(ei);
raise;
end;

// Value
end else if p.Quoted and IsValidIdentifier(p.Name) then begin
if not (exValue in expected) then
RaiseEx('unexpected value: ' + p.Name);
ei := TengExpressionValue.Create(p.Name, p.Line, p.Col, aParam.Filename);
try
MergeItems(stack, ei);
expected := [exGroupEnd, exBinaryOperation];
except
FreeAndNil(ei);
raise;
end;

// Variable
end else if IsValidIdentifier(p.Name) then begin
if not (exVariable in expected) then
RaiseEx('unexpected variable: ' + p.Name);
ei := TengExpressionVariable.Create(p.Name, p.Line, p.Col, aParam.Filename);
try
MergeItems(stack, ei);
expected := [exGroupEnd, exBinaryOperation];
except
FreeAndNil(ei);
raise
end;

// Unknown
end else
RaiseEx('invalid parameter: ' + p.Name);
until not NextParam;
except
if (stack.Count > 0) then begin
stack[0].Free;
stack[0] := nil;
end;
raise;
end;
finally
if (stack.Count > 0) then
result := stack[0];
FreeAndNil(stack);
end;
end;

begin
dec(aIndex);
if not NextParam then with aParam[0] do
raise EengShaderPartInternal.Create('invalid parameter count in expression', Line, Col, aParam.Filename);
result := BuildTree;
end;

end.

+ 56
- 0
uengShaderFileHelper.pas View File

@@ -0,0 +1,56 @@
unit uengShaderFileHelper;

{$mode objfpc}{$H+}
{$I uengShaderFile.inc}

interface

uses
uengShaderPart, uengShaderFileParser;

function IsValidIdentifier(const aIdent: String): Boolean;
function CheckEndToken(const aArgs: TengParseArgs; const aShaderPart: TengShaderPart): String;

implementation

uses
sysutils,
uengShaderFileConstants, uengShaderFileTypes;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function IsValidIdentifier(const aIdent: String): Boolean;
var
i, len: Integer;
begin
len := Length(aIdent);
result := false;
for i := 1 to len do
if not (aIdent[i] in VALID_IDENT_CHARS) then
exit;
result := true;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function CheckEndToken(const aArgs: TengParseArgs; const aShaderPart: TengShaderPart): String;
var
oldLine, oldCol: Integer;
param: TengTokenParameterList;
begin
param := TengTokenParameterList.Create('');
try
oldLine := aArgs.Line;
oldCol := aArgs.Col;
if not aArgs.ExtractToken(param) then
raise EengUnexpectedToken.Create(TOKEN_NONE, TOKEN_END, oldLine, oldCol, aShaderPart.Filename);
if (param[0].Name <> TOKEN_END) then
raise EengUnexpectedToken.Create(param[0].Name, TOKEN_END, oldLine, oldCol, aShaderPart.Filename);
if (param.Count <> 1) then
raise EengInvalidParamterCount.Create(TOKEN_END, 1, oldLine, oldCol, aShaderPart.Filename);
result := '';
finally
FreeAndNil(param);
end;
end;

end.


+ 333
- 0
uengShaderFileParser.pas View File

@@ -0,0 +1,333 @@
unit uengShaderFileParser;

{$mode objfpc}{$H+}
{$I uengShaderFile.inc}

interface

uses
Classes, SysUtils

{$IFDEF USE_BITSPACE_UTILS}
, uutlGenerics
{$ELSE}
, fgl
{$ENDIF}
;

type
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
TengTokenParameter = packed record
Name: String;
Quoted: Boolean;
Line: Integer;
Col: Integer;
end;
TengTokenParameterList = class(specialize TutlSimpleList<TengTokenParameter>)
private
fFilename: String;
public
property Filename: String read fFilename;
constructor Create(const aFilename: String);
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
TengParseArgs = class
private
fFilename: String;
fCode: TStringList;
fLineLength: Integer;
fLineCount: Integer;
fCurrentLine: String;
fCurrentChar: Char;
fCol: Integer;
fLine: Integer;

procedure SetCol(const aValue: Integer);
procedure SetLine(const aValue: Integer);

function GetEndOfLine: Boolean;
function GetEndOfFile: Boolean;
function GetCode: TStrings;
public
property Code: TStrings read GetCode;
property LineLength: Integer read fLineLength;
property LineCount: Integer read fLineCount;
property CurrentLine: String read fCurrentLine;
property CurrentChar: Char read fCurrentChar;
property EndOfLine: Boolean read GetEndOfLine;
property EndOfFile: Boolean read GetEndOfFile;
property Filename: String read fFilename;
property Col: Integer read fCol write SetCol;
property Line: Integer read fLine write SetLine;

procedure NextCol;
procedure NextLine;
function ExtractToken(const aParameters: TengTokenParameterList): Boolean;
function GetTokenPreview(var aToken: String): Boolean;

constructor Create(const aStream: TStream; const aFilename: String);
destructor Destroy; override;
end;

implementation

uses
uengShaderFileConstants, uengShaderFileTypes;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//TengTokenParameterList////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
constructor TengTokenParameterList.Create(const aFilename: String);
begin
inherited Create(true);
fFilename := aFilename;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//TengParseArgs/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
procedure TengParseArgs.SetCol(const aValue: Integer);
begin
fCol := aValue;
if not EndOfLine
then fCurrentChar := fCurrentLine[fCol]
else fCurrentChar := #0;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
procedure TengParseArgs.SetLine(const aValue: Integer);
begin
fLine := aValue;
if not EndOfFile then begin
fCurrentLine := fCode[fLine];
fLineLength := Length(fCurrentLine);
end else begin
fCurrentLine := '';
fLineLength := 0;
end;
Col := 1;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function TengParseArgs.GetEndOfLine: Boolean;
begin
result := (fCol > fLineLength)
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function TengParseArgs.GetEndOfFile: Boolean;
begin
result := (fLine >= fLineCount);
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
procedure TengParseArgs.NextCol;
begin
Col := Col + 1;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
procedure TengParseArgs.NextLine;
begin
Line := Line + 1;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function TengParseArgs.ExtractToken(const aParameters: TengTokenParameterList): Boolean;
type
TCharType = (
ctUnknown,
ctValidTokenChar,
ctInvalidTokenChar
);
TParseFlag = (
pfQuote,
pfInToken,
pfIsComment,
pfCommentTokenAdded
);
TParseFlags = set of TParseFlag;

var
flags: TParseFlags;
ct: TCharType;
s: String;
pLine, pCol, oldLine, oldCol: Integer;

procedure AddPart(const aTrimAndCheck: Boolean = true);
var
len: Integer;
p: TengTokenParameter;
begin
if aTrimAndCheck then
s := Trim(s);
if not aTrimAndCheck or (s <> '') then begin
len := Length(s);
if aTrimAndCheck and
( (s[1] = TOKEN_CHAR_QUOTE) and
(s[len] = TOKEN_CHAR_QUOTE)) then
begin
if not (s[1] = TOKEN_CHAR_QUOTE) then
raise EengShaderPart.Create('missing leading quote char', Line, Col, Filename);
if not (s[len] = TOKEN_CHAR_QUOTE) then
raise EengShaderPart.Create('missing trailing quote char', Line, Col, Filename);
delete(s, len, 1);
delete(s, 1, 1);
p.Quoted := true;
end else
p.Quoted := false;
p.Name := s;
p.Line := pLine;
p.Col := pCol;
aParameters.Add(p);
end;
s := '';
pLine := Line;
pCol := Col;
ct := ctUnknown;
end;

begin
result := false;
aParameters.Clear;
if (CurrentChar <> TOKEN_CHAR_BEGIN) or
(Col + 1 > LineLength) or
( (CurrentLine[Col+1] <> TOKEN_CHAR_IDENT) and
(CurrentLine[Col+1] <> TOKEN_CHAR_COMMENT))
then
exit;

result := true;
s := '';
ct := ctUnknown;
oldLine := Line;
oldCol := Col;
flags := [];
if (CurrentLine[Col+1] = TOKEN_CHAR_COMMENT) then
Include(flags, pfIsComment);
AddPart; // initialize

while not EndOfFile do begin
while not EndOfLine do begin
case CurrentChar of
TOKEN_CHAR_BEGIN: begin
if (pfQuote in flags) then
s := s + CurrentChar
else if not (pfInToken in flags) then
Include(flags, pfInToken)
else
EengShaderPart.Create('invalid char in token', Line, Col, Filename);
end;

TOKEN_CHAR_END: begin
if not (pfQuote in flags) then begin
AddPart(not (pfIsComment in flags));
NextCol;
if (aParameters.Count <= 0) or (aParameters[0].Name = TOKEN_CHAR_IDENT) then
raise EengShaderPart.Create('empty token', Line, Col, Filename);
exit;
end else
s := s + CurrentChar;
end;

TOKEN_CHAR_QUOTE: begin
if not (pfQuote in flags) and not (pfIsComment in flags) then
AddPart;
s := s + CurrentChar;
if (pfQuote in flags)
then exclude(flags, pfQuote)
else include(flags, pfQuote);
if not (pfQuote in flags) and not (pfIsComment in flags) then
AddPart;
end;

TOKEN_CHAR_COMMENT: begin
s := s + CurrentChar;
if (pfIsComment in flags) and not (pfCommentTokenAdded in flags) then begin
include(flags, pfCommentTokenAdded);
AddPart(false);
end;
end;
else
if not (pfQuote in flags) and not (pfIsComment in flags) then begin
if (CurrentChar in TOKEN_SPLIT_CHARS) then begin
AddPart;
end else if (CurrentChar in VALID_TOKEN_CHARS) then begin
if (ct <> ctValidTokenChar) then
AddPart;
ct := ctValidTokenChar;
end else begin
if (ct <> ctInvalidTokenChar) then
AddPart;
ct := ctInvalidTokenChar;
end;
end;
s := s + CurrentChar;
end;
NextCol;
end;
s := s + sLineBreak;
NextLine;
end;
raise EengShaderPart.Create('incomplete token', oldLine, oldCol, Filename);
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function TengParseArgs.GetCode: TStrings;
begin
result := fCode;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function TengParseArgs.GetTokenPreview(var aToken: String): Boolean;
var
c: Integer;
begin
result := false;
if (CurrentChar <> TOKEN_CHAR_BEGIN) or
(Col >= LineLength) or
not (CurrentLine[Col + 1] in [TOKEN_CHAR_IDENT, TOKEN_CHAR_COMMENT])
then exit;
result := true;
aToken := CurrentChar;
if (aToken = TOKEN_CHAR_COMMANT_END) then
exit;
c := Col + 1;
case CurrentLine[c] of
TOKEN_CHAR_IDENT: begin
aToken := '';
repeat
aToken := aToken + CurrentLine[c];
inc(c);
until (c > LineLength) or not (CurrentLine[c] in VALID_TOKEN_CHARS);
aToken := Trim(aToken);
if (aToken = TOKEN_CHAR_IDENT) then
raise EengInvalidToken.Create('empty token', Line, Col, Filename);
end;

TOKEN_CHAR_COMMENT:
aToken := TOKEN_CHAR_COMMENT;
end;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
constructor TengParseArgs.Create(const aStream: TStream; const aFilename: String);
begin
inherited Create;
fFilename := aFilename;
fCode := TStringList.Create;
fCode.LoadFromStream(aStream);
fLineCount := fCode.Count;
Line := 0;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
destructor TengParseArgs.Destroy;
begin
FreeAndNil(fCode);
inherited Destroy;
end;

end.


+ 23
- 0
uengShaderFileScope.pas View File

@@ -0,0 +1,23 @@
unit uengShaderFileScope;

{$mode objfpc}{$H+}

{$I uengShaderFile.inc}

interface

uses
Classes, SysUtils,

uengShaderFilePart;

type
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
TengShaderFileScope = class(TengShaderPart)

end;

implementation

end.


+ 148
- 0
uengShaderFileTypes.pas View File

@@ -0,0 +1,148 @@
unit uengShaderFileTypes;

{$mode objfpc}{$H+}
{$I uengShaderFile.inc}

interface

uses
Classes, SysUtils

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

type
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
{$IFDEF USE_BITSPACE_UTILS}
IengShaderFileWriter = uutlSerialization.IutlFileWriter;
IengShaderFileReader = uutlSerialization.IutlFileReader;
TengShaderFileReader = uutlSerialization.TutlSimpleFileReader;
TengShaderFileWriter = uutlSerialization.TutlSimpleFileWriter;
TIntfObjNoRefCount = uutlCommon.TutlInterfaceNoRefCount;
{$ENDIF}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
EengShaderPart = class(Exception)
public
Line: Integer;
Col: Integer;
Filename: String;

constructor Create(const aMsg: String; const aLine, aCol: Integer; const aFilename: String); overload;
end;
EengShaderPartInternal = class(EengShaderPart);
EengExpression = class(EengShaderPart);

EengInvalidToken = class(EengShaderPartInternal)
constructor Create(const aClassName: String; const aToken: String; const aLine, aCol: Integer; const aFilename: String); overload;
end;

EengUnexpectedToken = class(EengShaderPart)
constructor Create(const aToken, aExpected: String; const aLine, aCol: Integer; const aFilename: String); overload;
end;

EengInvalidParamter = class(EengShaderPart)
constructor Create(const aParam, aExpected: String; const aLine, aCol: Integer; const aFilename: String); overload;
end;

EengInvalidParamterCount = class(EengShaderPart)
constructor Create(const aToken: String; const aExpected, aLine, aCol: Integer; const aFilename: String); overload;
constructor Create(const aToken: String; const aExpectedMin, aExpectedMax, aLine, aCol: Integer; const aFilename: String); overload;
end;

EengInvalidIdentifier = class(EengShaderPart)
constructor Create(const aIdentifier: String; const aLine, aCol: Integer; const aFilename: String); overload;
end;

EengOutOfRange = class(EengShaderPartInternal)
constructor Create(const aMin, aMax, aIndex, aLine, aCol: Integer; const aFilename: String); overload;
end;

implementation

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//EengShaderPart////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
constructor EengShaderPart.Create(const aMsg: String; const aLine, aCol: Integer; const aFilename: String);
begin
inherited Create(Format('%s (file: %s; line: %d; col: %d): %s', [ClassName, ExtractFileName(aFilename), aLine+1, aCol, aMsg]));
Line := aLine;
Col := aCol;
Filename := aFilename;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//EengInvalidToken//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
constructor EengInvalidToken.Create(const aClassName: String; const aToken: String; const aLine, aCol: Integer; const aFilename: String);
begin
inherited Create('invalid token: ' + aClassName + ' <> '+ aToken, aLine, aCol, aFilename);
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//EengUnexpectedToken///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
constructor EengUnexpectedToken.Create(const aToken, aExpected: String; const aLine, aCol: Integer; const aFilename: String);
var
s: String;
begin
s := 'unexpected token: ' + aToken;
if (aExpected <> '') then
s := s + '(expected ' + aExpected + ')';
inherited Create(s, aLine, aCol, aFilename);
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//EengInvalidParamter///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
constructor EengInvalidParamter.Create(const aParam, aExpected: String; const aLine, aCol: Integer; const aFilename: String);
var
s: String;
begin
s := 'invalid parameter: ' + aParam;
if (aExpected <> '') then
s := s + '(expected ' + aExpected + ')';
inherited Create(s, aLine, aCol, aFilename);
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//EengInvalidParamterCount//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
constructor EengInvalidParamterCount.Create(const aToken: String; const aExpected, aLine, aCol: Integer; const aFilename: String);
begin
inherited Create('invalid parameter count in ' + aToken + '(expected ' + IntToStr(aExpected) + ' parameter)', aLine, aCol, aFilename);
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
constructor EengInvalidParamterCount.Create(const aToken: String; const aExpectedMin, aExpectedMax, aLine, aCol: Integer; const aFilename: String);
var
s: String;
begin
s := 'invalid parameter count in ' + aToken + '(expected ';
if (aExpectedMax < 0)
then s := s + ' at least '+ IntToStr(aExpectedMin)
else s := s + IntToStr(aExpectedMin) + ' to ' + IntToStr(aExpectedMax);
s := s + ' parameter)';
inherited Create(s, aLine, aCol, aFilename);
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//EengInvalidIdentifier/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
constructor EengInvalidIdentifier.Create(const aIdentifier: String; const aLine, aCol: Integer; const aFilename: String);
begin
inherited Create('invalid identifier: ' + aIdentifier, aLine, aCol, aFilename);
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//EengOutOfRange////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
constructor EengOutOfRange.Create(const aMin, aMax, aIndex, aLine, aCol: Integer; const aFilename: String);
begin
inherited Create(format('index (%d) out of range (%d:%d)', [aIndex, aMin, aMax]), aLine, aCol, aFilename);
end;

end.


+ 233
- 0
uengShaderPart.pas View File

@@ -0,0 +1,233 @@
unit uengShaderPart;

{$mode objfpc}{$H+}
{$I uengShaderFile.inc}

interface

uses
Classes, SysUtils,

uengShaderFileParser, uengShaderFileTypes

{$IFDEF USE_BITSPACE_UTILS}
, uutlGenerics;
{$ELSE}
, fgl;
{$ENDIF}

type
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
CengShaderPart = class of TengShaderPart;
TengShaderPart = class(TIntfObjNoRefCount)
{ Nested Types }
public type
TEnumerator = class(TObject)
private
fOwner: TengShaderPart;
fPosition: Integer;
function GetCurrent: TengShaderPart;
public
property Current: TengShaderPart read GetCurrent;
function MoveNext: Boolean;
constructor Create(const aOwner: TengShaderPart);
end;

{ Code Loading & Storage }
private { members }
fRoot: TengShaderPart;
fParent: TengShaderPart;
fLine: Integer;
fCol: Integer;
protected { virtual getter }
function GetCount: Integer; virtual;
function GetChild(const aIndex: Integer): TengShaderPart; virtual;
function GetText: String; virtual;
function GetFilename: String; virtual;
function GetFileReader: IengShaderFileReader; virtual;
function GetFileWriter: IengShaderFileWriter; virtual;
protected { parse methodes }
function ParseIntern(const aArgs: TengParseArgs; const aParams: TengTokenParameterList): String; virtual;
public
function ParseText(const aArgs: TengParseArgs): String;

{ General }
public { general methods }
property Root: TengShaderPart read fRoot;
property Parent: TengShaderPart read fParent;
property Line: Integer read fLine;
property Col: Integer read fCol;
property Filename: String read GetFilename;
property Text: String read GetText;
property Count: Integer read GetCount;

property FileReader: IengShaderFileReader read GetFileReader;
property FileWriter: IengShaderFileWriter read GetFileWriter;

property Children[const aIndex: Integer]: TengShaderPart read GetChild; default;

function HasParent(const aType: CengShaderPart; const aIncludeSelf: Boolean = false): Boolean;
function GetParent(const aType: CengShaderPart; out aPart): Boolean;
function GetEnumerator: TEnumerator;

constructor Create(const aParent: TengShaderPart); virtual;

{ Class Methods }
public
class function GetTokenName: String; virtual;
class function CheckToken(const aToken: String): Boolean; virtual;
class procedure Validate(const aArgs: TengParseArgs; const aParent: TengShaderPart); virtual;
end;
TengShaderPartList = specialize TutlSimpleList<TengShaderPart>;

implementation

uses
uengShaderFileConstants;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//TengShaderPart.TEnumerator////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function TengShaderPart.TEnumerator.GetCurrent: TengShaderPart;
begin
result := fOwner[fPosition];
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function TengShaderPart.TEnumerator.MoveNext: Boolean;
begin
inc(fPosition);
result := (fPosition < fOwner.Count);
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
constructor TengShaderPart.TEnumerator.Create(const aOwner: TengShaderPart);
begin
inherited Create;
fOwner := aOwner;
fPosition := -1;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//TengShaderPart////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function TengShaderPart.GetCount: Integer;
begin
result := 0;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function TengShaderPart.{%H-}GetChild(const aIndex: Integer): TengShaderPart;
begin
EengShaderPartInternal.Create('this part does not have any children');
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function TengShaderPart.GetText: String;
begin
result := ''; //DUMMY
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function TengShaderPart.GetFilename: String;
begin
if Assigned(fParent)
then result := fParent.Filename
else result := UNKNOWN_FILENAME;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function TengShaderPart.GetFileReader: IengShaderFileReader;
begin
if Assigned(fParent)
then result := fParent.GetFileReader
else result := nil;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function TengShaderPart.GetFileWriter: IengShaderFileWriter;
begin
if Assigned(fParent)
then result := fParent.GetFileWriter
else result := nil;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function TengShaderPart.ParseText(const aArgs: TengParseArgs): String;
var
params: TengTokenParameterList;
begin
params := TengTokenParameterList.Create(Filename);
try
fCol := aArgs.Col;
fLine := aArgs.Line;
if (GetTokenName <> '') then
aArgs.ExtractToken(params);
result := ParseIntern(aArgs, params);
finally
FreeAndNil(params);
end;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function TengShaderPart.ParseIntern(const aArgs: TengParseArgs; const aParams: TengTokenParameterList): String;
begin
result := ''; // DUMMY
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function TengShaderPart.HasParent(const aType: CengShaderPart; const aIncludeSelf: Boolean): Boolean;
var
p: TengShaderPart;
begin
result := (aIncludeSelf and (self is aType)) or GetParent(aType, p);
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function TengShaderPart.GetParent(const aType: CengShaderPart; out aPart): Boolean;
begin
result := true;
if (fParent is aType) then
TengShaderPart(aPart) := fParent
else if Assigned(fParent) then
result := fParent.GetParent(aType, aPart)
else
result := false;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function TengShaderPart.GetEnumerator: TEnumerator;
begin
result := TEnumerator.Create(self);
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
constructor TengShaderPart.Create(const aParent: TengShaderPart);
begin
inherited Create;
fParent := aParent;
if Assigned(fParent)
then fRoot := fParent.Root
else fRoot := nil;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
class function TengShaderPart.GetTokenName: String;
begin
result := ''; // DUMMY
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
class function TengShaderPart.CheckToken(const aToken: String): Boolean;
begin
result := (aToken = GetTokenName);
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
class procedure TengShaderPart.Validate(const aArgs: TengParseArgs; const aParent: TengShaderPart);
begin
// DUMMY
end;

end.


+ 158
- 0
uengShaderPartCall.pas View File

@@ -0,0 +1,158 @@
unit uengShaderPartCall;

{$mode objfpc}{$H+}
{$I uengShaderFile.inc}

interface

uses
Classes, SysUtils,
uengShaderPart, uengShaderFileParser;

type
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
TengShaderPartCall = class(TengShaderPart)
{ Code Loading & Storage }
private { member }
fName: String;
fParameters: TStringList;
protected { virtual getter }
function GetText: String; override;
function ParseIntern(const aArgs: TengParseArgs; const aParams: TengTokenParameterList): String; override;

{ General }
private
function GetParameters: TStrings;
public
property Name: String read fName;
property Parameters: TStrings read GetParameters;

constructor Create(const aParent: TengShaderPart); override;
destructor Destroy; override;

{ Class Methods }
public
class function GetTokenName: String; override;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
TengShaderPartInherited = class(TengShaderPartCall)
{ Class Methods }
protected
function ParseIntern(const aArgs: TengParseArgs; const aParams: TengTokenParameterList): String; override;
public
class function GetTokenName: String; override;
class procedure Validate(const aArgs: TengParseArgs; const aParent: TengShaderPart); override;
end;

implementation

uses
uengShaderPartProc, uengShaderPartClass, uengShaderFileConstants, uengShaderFileTypes, uengShaderFileHelper;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//TengShaderPartCall////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function TengShaderPartCall.GetText: String;
var
i: Integer;
begin
result := TOKEN_CHAR_BEGIN + GetTokenName;
if (fName <> '') then
result := result + ' ' + 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];
end;
result := result + TOKEN_CHAR_END;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function TengShaderPartCall.ParseIntern(const aArgs: TengParseArgs; const aParams: TengTokenParameterList): String;
var
i: Integer;
begin
if (aParams[0].Name <> GetTokenName) then
raise EengInvalidToken.Create(ClassName, aParams[0].Name, Line, Col, Filename);
if (aParams.Count < 2) then
raise EengInvalidParamterCount.Create(GetTokenName, 2, -1, Line, Col, Filename);

result := '';
fParameters.Clear;
with aParams[1] do begin
if not IsValidIdentifier(fName) then
raise EengInvalidIdentifier.Create(Name, Line, Col, Filename);
fName := Name;
end;
for i := 2 to aParams.Count-1 do
fParameters.AddObject(aParams[i].Name, TObject(PtrInt(aParams[i].Quoted)));
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function TengShaderPartCall.GetParameters: TStrings;
begin
result := fParameters;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
constructor TengShaderPartCall.Create(const aParent: TengShaderPart);
begin
inherited Create(aParent);
fParameters := TStringList.Create;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
destructor TengShaderPartCall.Destroy;
begin
FreeAndNil(fParameters);
inherited Destroy;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
class function TengShaderPartCall.GetTokenName: String;
begin
result := TOKEN_CALL;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//TengShaderPartInherited///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function TengShaderPartInherited.ParseIntern(const aArgs: TengParseArgs; const aParams: TengTokenParameterList): String;
var
i: Integer;
begin
if (aParams[0].Name <> GetTokenName) then with aParams[0] do
raise EengInvalidToken.Create(ClassName, Name, Line, Col, Filename);

fName := '';
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);
fName := aParams[1].Name;
for i := 2 to aParams.Count-1 do
fParameters.AddObject(aParams[i].Name, TObject(PtrInt(aParams[i].Quoted)));
end;
result := '';
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
class function TengShaderPartInherited.GetTokenName: String;
begin
result := TOKEN_INHERITED;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
class procedure TengShaderPartInherited.Validate(const aArgs: TengParseArgs; const aParent: TengShaderPart);
begin
inherited Validate(aArgs, aParent);
if not aParent.HasParent(TengShaderPartProc, true) or
not aParent.HasParent(TengShaderPartClass, true) then
raise EengShaderPart.Create(GetTokenName + ' is not allowed outside of ' +
TOKEN_PROC + ', ' + TOKEN_FUNC + ', ' + TOKEN_MAIN + ' or ' + TOKEN_CLASS);
end;

end.


+ 117
- 0
uengShaderPartClass.pas View File

@@ -0,0 +1,117 @@
unit uengShaderPartClass;

{$mode objfpc}{$H+}
{$I uengShaderFile.inc}

interface

uses
Classes, SysUtils,
uengShaderPart, uengShaderCodeGenerator, uengShaderFileParser;

type
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
TengShaderPartClass = class(TengShaderCodeGenerator)
{ Code Loading & Storage }
private { member }
fName: String;
fExtends: TStringList;
private { getter }
function GetExtends: TStrings;
protected { virtual getter }
function GetText: String; override;
function ParseIntern(const aArgs: TengParseArgs; const aParams: TengTokenParameterList): String; override;

{ General }
public
property Name: String read fName;
property Extends: TStrings read GetExtends;
constructor Create(const aParent: TengShaderPart); override;
destructor Destroy; override;

{ Class Methods }
public
class function GetTokenName: String; override;
end;

implementation

uses
uengShaderFileConstants, uengShaderFileTypes, uengShaderFileHelper;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//TengShaderPartClass///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function TengShaderPartClass.GetExtends: TStrings;
begin
result := fExtends;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function TengShaderPartClass.GetText: String;
var
s: String;
begin
result := TOKEN_CHAR_BEGIN + GetTokenName + ' ' + fName;
if (fExtends.Count > 0) then begin
result := result + ' ' + TOKEN_EXTENDS;
for s in fExtends do
result := result + ' ' + s;
end;
result := result + TOKEN_CHAR_END +
inherited GetText +
TOKEN_CHAR_BEGIN + TOKEN_END + TOKEN_CHAR_END;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function TengShaderPartClass.ParseIntern(const aArgs: TengParseArgs; const aParams: TengTokenParameterList): String;
var
i: Integer;
begin
if (aParams[0].Name <> GetTokenName) then
raise EengInvalidToken.Create(ClassName, aParams[0].Name, Line, Col, Filename);
if (aParams.Count < 2) then
raise EengInvalidParamterCount.Create(GetTokenName, 2, -1, Line, Col, Filename);
with aParams[1] do begin
if not IsValidIdentifier(Name) then
raise EengInvalidIdentifier.Create(Name, Line, Col, Filename);
fName := Name;
end;
if (aParams.Count > 2) then begin
if (aParams.Count < 4) then
raise EengInvalidParamterCount.Create(GetTokenName, 4, -1, Line, Col, Filename);
if (aParams[2].Name <> TOKEN_EXTENDS) then with aParams[2] do
raise EengInvalidParamter.Create(aParams[2].Name, TOKEN_EXTENDS, Line, Col, Filename);
fExtends.Clear;
for i := 3 to aParams.Count-1 do
fExtends.Add(aParams[i].Name);
end;

// TODO fRoot.AddClass ?

result := inherited ParseIntern(aArgs, aParams);
result := CheckEndToken(aArgs, self);
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
constructor TengShaderPartClass.Create(const aParent: TengShaderPart);
begin
inherited Create(aParent);
fExtends := TStringList.Create;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
destructor TengShaderPartClass.Destroy;
begin
FreeAndNil(fExtends);
inherited Destroy;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
class function TengShaderPartClass.GetTokenName: String;
begin
result := TOKEN_CLASS;
end;

end.


+ 159
- 0
uengShaderPartCntr.pas View File

@@ -0,0 +1,159 @@
unit uengShaderPartCntr;

{$mode objfpc}{$H+}
{$I uengShaderFile.inc}

interface

uses
Classes, SysUtils,
uengShaderPart, uengShaderFileParser;

type
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
TengShaderPartCntr = class(TengShaderPart)
{ Code Loading & Storage }
private
fChildren: TengShaderPartList;
procedure AddChild(const aChild: TengShaderPart; const aPrepend: Boolean = false);
function HandleToken(const aToken: String; const aArgs: TengParseArgs): String;
protected { virtual getter }
function GetCount: Integer; override;
function GetChild(const aIndex: Integer): TengShaderPart; override;
function GetText: String; override;
function ParseIntern(const aArgs: TengParseArgs; const aParams: TengTokenParameterList): String; override;
public { general methods }
procedure Clear;
constructor Create(const aParent: TengShaderPart); override;
destructor Destroy; override;
end;

implementation

uses
uengShaderPartKeyValuePair, uengShaderPartClass, uengShaderPartMessage, uengShaderPartMeta,
uengShaderPartCall, uengShaderPartProc, uengShaderPartText, uengShaderPartEcho, uengShaderPartIf,
uengShaderPartInclude, uengShaderPartParameter, uengShaderPartComment;

const
TOKEN_CLASSES: array[0..20] of CengShaderPart = (
TengShaderPartCall,
TengShaderPartClass,
TengShaderPartDefine,
TengShaderPartLineBreak,
TengShaderPartCommandEnd,
TengShaderPartComment,
TengShaderPartEcho,
TengShaderPartError,
TengShaderPartMain,
TengShaderPartIf,
TengShaderPartInclude,
TengShaderPartInherited,
TengShaderPartFunc,
TengShaderPartMessage,
TengShaderPartMeta,
TengShaderPartProc,
TengShaderPartProperty,
TengShaderPartUniform,
TengShaderPartVar,
TengShaderPartVarying,
TengShaderPartWarning
);

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//TengShaderPartCntr////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
procedure TengShaderPartCntr.AddChild(const aChild: TengShaderPart; const aPrepend: Boolean);
begin
if aPrepend
then fChildren.PushFirst(aChild)
else fChildren.PushLast(aChild);
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function TengShaderPartCntr.HandleToken(const aToken: String; const aArgs: TengParseArgs): String;
var
p: TengShaderPart;
c: CengShaderPart;
begin
p := nil;
for c in TOKEN_CLASSES do begin
if c.CheckToken(aToken) then begin
c.Validate(aArgs, self);
p := c.Create(self);
AddChild(p);
break;
end;
end;
if Assigned(p)
then result := p.ParseText(aArgs)
else result := aToken;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function TengShaderPartCntr.GetCount: Integer;
begin
result := fChildren.Count;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function TengShaderPartCntr.GetChild(const aIndex: Integer): TengShaderPart;
begin
result := fChildren[aIndex];
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function TengShaderPartCntr.GetText: String;
var
p: TengShaderPart;
begin
result := '';
for p in self do
result := result + p.Text;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function TengShaderPartCntr.ParseIntern(const aArgs: TengParseArgs; const aParams: TengTokenParameterList): String;
var
TextObj: TengShaderPartText;
begin
result := '';
fChildren.Clear;
while not aArgs.EndOfFile and (result = '') do begin
TextObj := TengShaderPartText.Create(self);
try
result := TextObj.ParseText(aArgs);
if not TextObj.IsEmpty
then AddChild(TextObj)
else FreeAndNil(TextObj);
except
FreeAndNil(TextObj);
raise;
end;
if (result <> '') then
result := HandleToken(result, aArgs);
end;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
procedure TengShaderPartCntr.Clear;
begin
fChildren.Clear;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
constructor TengShaderPartCntr.Create(const aParent: TengShaderPart);
begin
inherited Create(aParent);
fChildren := TengShaderPartList.Create(true);
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
destructor TengShaderPartCntr.Destroy;
begin
FreeAndNil(fChildren);
inherited Destroy;
end;

end.


+ 55
- 0
uengShaderPartComment.pas View File

@@ -0,0 +1,55 @@
unit uengShaderPartComment;

{$mode objfpc}{$H+}
{$I uengShaderFile.inc}

interface

uses
Classes, SysUtils,
uengShaderPart, uengShaderFileParser;

type
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
TengShaderPartComment = class(TengShaderPart)
{ Code Loading & Storage }
private
fText: String;
protected
function GetText: String; override;
function ParseIntern(const aArgs: TengParseArgs; const aParams: TengTokenParameterList): String; override;
public
class function GetTokenName: String; override;
end;

implementation

uses
uengShaderFileConstants, uengShaderFileTypes;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//TengShaderPartComment/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function TengShaderPartComment.GetText: String;
begin
result := TOKEN_CHAR_BEGIN + GetTokenName + fText + TOKEN_CHAR_END;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function TengShaderPartComment.ParseIntern(const aArgs: TengParseArgs; const aParams: TengTokenParameterList): String;
begin
if (aParams[0].Name <> GetTokenName) then with aParams[0] do
raise EengInvalidToken.Create(ClassName, Name, Line, Col, Filename);
if (aParams.Count > 1) then
fText := aParams[1].Name;
result := '';
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
class function TengShaderPartComment.GetTokenName: String;
begin
result := TOKEN_CHAR_COMMENT;
end;

end.


+ 62
- 0
uengShaderPartEcho.pas View File

@@ -0,0 +1,62 @@
unit uengShaderPartEcho;

{$mode objfpc}{$H+}
{$I uengShaderFile.inc}

interface

uses
Classes, SysUtils,
uengShaderPart, uengShaderFileParser;

type
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
TengShaderPartEcho = class(TengShaderPart)
{ Code Loading & Storage }
private
fName: String;
protected
function GetText: String; override;
function ParseIntern(const aArgs: TengParseArgs; const aParams: TengTokenParameterList): String; override;

{ General }
public
class function GetTokenName: String; override;
end;

implementation

uses
uengShaderFileConstants, uengShaderFileTypes, uengShaderFileHelper;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//TengShaderPartEcho////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function TengShaderPartEcho.GetText: String;
begin
result := TOKEN_CHAR_BEGIN + GetTokenName + ' ' + fName + TOKEN_CHAR_END;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function TengShaderPartEcho.ParseIntern(const aArgs: TengParseArgs; const aParams: TengTokenParameterList): String;
begin
if (aParams[0].Name <> GetTokenName) then with aParams[0] do
raise EengInvalidToken.Create(ClassName, Name, Line, Col, Filename);
if (aParams.Count <> 2) then
raise EengInvalidParamterCount.Create(GetTokenName, 2, Line, Col, Filename);
result := '';
with aParams[1] do begin
if not IsValidIdentifier(Name) then
raise EengInvalidIdentifier.Create(Name, Line, Col, Filename);
fName := Name;
end;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
class function TengShaderPartEcho.GetTokenName: String;
begin
result := TOKEN_ECHO;
end;

end.


+ 183
- 0
uengShaderPartIf.pas View File

@@ -0,0 +1,183 @@
unit uengShaderPartIf;

{$mode objfpc}{$H+}
{$I uengShaderFile.inc}

interface

uses
Classes, SysUtils,
uengShaderPart, uengShaderPartCntr, uengShaderFileExpression, uengShaderFileParser;

type
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
TengShaderPartIf = class(TengShaderPart)
{ Code Loading & Storage }
private
fExpression: TengExpressionItem;
fIfPart: TengShaderPart;
fElsePart: TengShaderPart;
function HandleToken(const aToken: String; const aArgs: TengParseArgs): String;
protected
function HandeEndToken(const aToken: String; const aArgs: TengParseArgs): String; virtual;
function GetCount: Integer; override;
function GetChild(const aIndex: Integer): TengShaderPart; override;
function GetText: String; override;
function ParseIntern(const aArgs: TengParseArgs; const aParams: TengTokenParameterList): String; override;

{ General }
public
destructor Destroy; override;

{ Class Methods }
public
class function GetTokenName: String; override;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
TengShaderPartElIf = class(TengShaderPartIf)
{ Code Loading & Storage }
protected
function HandeEndToken(const aToken: String; const aArgs: TengParseArgs): String; override;

{ Class Methods }
public
class function GetTokenName: String; override;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
TengShaderPartElse = class(TengShaderPartCntr)
{ Code Loading & Storage }
protected
function GetText: String; override;

{ Class Methods }
public
class function GetTokenName: String; override;
end;

implementation

uses
uengShaderFileTypes, uengShaderFileConstants, uengShaderFileHelper;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//TengShaderPartIf//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function TengShaderPartIf.HandleToken(const aToken: String; const aArgs: TengParseArgs): String;
const
TOKEN_CLASSES: array[0..1] of CengShaderPart = (
TengShaderPartElse,
TengShaderPartElIf
);
var
c: CengShaderPart;
begin
for c in TOKEN_CLASSES do begin
if c.CheckToken(aToken) then begin
c.Validate(aArgs, self);
fElsePart := c.Create(self);
break;
end;
end;
if Assigned(fElsePart) then
result := fElsePart.ParseText(aArgs);
result := HandeEndToken(result, aArgs);
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function TengShaderPartIf.HandeEndToken(const aToken: String; const aArgs: TengParseArgs): String;
begin
result := CheckEndToken(aArgs, self);
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function TengShaderPartIf.GetCount: Integer;
begin
result := 1;
if Assigned(fElsePart) then
inc(result, 1);
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function TengShaderPartIf.GetChild(const aIndex: Integer): TengShaderPart;
begin
if (aIndex < 0) or (aIndex >= Count) then
raise EengOutOfRange.Create(0, Count-1, aIndex, Line, Col, Filename);
case aIndex of
0: result := fIfPart;
1: result := fElsePart;
end;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function TengShaderPartIf.GetText: String;
begin
result := TOKEN_CHAR_BEGIN + GetTokenName + ' ' + fExpression.GetText + TOKEN_CHAR_END + fIfPart.Text;
if Assigned(fElsePart) then
result := result + fElsePart.Text;
result := result + TOKEN_CHAR_BEGIN + TOKEN_END + TOKEN_CHAR_END;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function TengShaderPartIf.ParseIntern(const aArgs: TengParseArgs; const aParams: TengTokenParameterList): String;
begin
if (aParams[0].Name <> GetTokenName) then with aParams[0] do
raise EengInvalidToken.Create(ClassName, Name, Line, Col, Filename);
if (aParams.Count < 2) then
raise EengInvalidParamterCount.Create(GetTokenName, 2, -1, Line, Col, Filename);

fExpression := ParseExpression(aParams, 1);

fIfPart := TengShaderPartCntr.Create(self);
result := fIfPart.ParseText(aArgs);
result := HandleToken(result, aArgs);
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
destructor TengShaderPartIf.Destroy;
begin
FreeAndNil(fExpression);
FreeAndNil(fIfPart);
FreeAndNil(fElsePart);
inherited Destroy;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
class function TengShaderPartIf.GetTokenName: String;
begin
result := TOKEN_IF;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//TengShaderPartElIf////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function TengShaderPartElIf.HandeEndToken(const aToken: String; const aArgs: TengParseArgs): String;
begin
result := aToken;
if (result <> TOKEN_END) then
raise EengInvalidToken.Create(ClassName, result, aArgs.Line, aArgs.Col, Filename);
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
class function TengShaderPartElIf.GetTokenName: String;
begin
result := TOKEN_ELIF;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//TengShaderPartElse////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function TengShaderPartElse.GetText: String;
begin
result := TOKEN_CHAR_BEGIN + GetTokenName + TOKEN_CHAR_END + inherited GetText;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
class function TengShaderPartElse.GetTokenName: String;
begin
result := TOKEN_ELSE;
end;

end.


+ 100
- 0
uengShaderPartInclude.pas View File

@@ -0,0 +1,100 @@
unit uengShaderPartInclude;

{$mode objfpc}{$H+}
{$I uengShaderFile.inc}

interface

uses
Classes, SysUtils,
uengShaderPart, uengShaderFile, uengShaderFileParser;

type
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
TengShaderPartInclude = class(TengShaderPart)
{ Code Loading & Storage }
private
fShaderFile: TengShaderFile;
fIncludeFile: String;
fAbsoluteFile: String;
protected
function GetCount: Integer; override;
function GetChild(const aIndex: Integer): TengShaderPart; override;
function GetText: String; override;
function ParseIntern(const aArgs: TengParseArgs; const aParams: TengTokenParameterList): String; override;

{ General }
public
property IncludeFile: String read fIncludeFile;
constructor Create(const aParent: TengShaderPart); override;
destructor Destroy; override;

{ Class Methods }
public
class function GetTokenName: String; override;
end;

implementation

uses
FileUtil,
uengShaderFileTypes, uengShaderFileConstants;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//TengShaderPartInclude/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function TengShaderPartInclude.GetCount: Integer;
begin
if Assigned(fShaderFile)
then result := 1
else result := 0;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function TengShaderPartInclude.GetChild(const aIndex: Integer): TengShaderPart;
begin
if Assigned(fShaderFile) and (aIndex = 0)
then result := fShaderFile
else raise EengOutOfRange.Create(0, Count-1, aIndex, Line, Col, Filename);
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function TengShaderPartInclude.GetText: String;
begin
result := TOKEN_CHAR_BEGIN + GetTokenName + ' ''' + fIncludeFile + '''' + TOKEN_CHAR_END;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function TengShaderPartInclude.ParseIntern(const aArgs: TengParseArgs; const aParams: TengTokenParameterList): String;
begin
if (aParams[0].Name <> GetTokenName) then with aParams[0] do
raise EengInvalidToken.Create(ClassName, Name, Line, Col, Filename);
if (aParams.Count <> 2) then
raise EengInvalidParamterCount.Create(GetTokenName, 2, Line, Col, Filename);
fIncludeFile := aParams[1].Name;
fAbsoluteFile := CreateAbsolutePath(fIncludeFile, ExtractFilePath(Filename));
result := '';
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
constructor TengShaderPartInclude.Create(const aParent: TengShaderPart);
begin
inherited Create(aParent);
fShaderFile := nil;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
destructor TengShaderPartInclude.Destroy;
begin
FreeAndNil(fShaderFile);
inherited Destroy;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
class function TengShaderPartInclude.GetTokenName: String;
begin
result := TOKEN_INCLUDE;
end;

end.


+ 106
- 0
uengShaderPartKeyValuePair.pas View File

@@ -0,0 +1,106 @@
unit uengShaderPartKeyValuePair;

{$mode objfpc}{$H+}
{$I uengShaderFile.inc}

interface

uses
Classes, SysUtils, variants,
uengShaderPart, uengShaderFileParser;

type
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
TengShaderPartKeyValuePair = class(TengShaderPart)
{ Code Loading & Storage }
private
fName: String;
fValue: Variant;
fValueName: String;
protected
function GetText: String; override;
function ParseIntern(const aArgs: TengParseArgs; const aParams: TengTokenParameterList): String; override;

{ General }
public
property Name: String read fName;
property Value: Variant read fValue;
property ValueName: String read fValueName;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
TengShaderPartProperty = class(TengShaderPartKeyValuePair)
{ Class Methods }
public
class function GetTokenName: String; override;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
TengShaderPartDefine = class(TengShaderPartKeyValuePair)
{ Class Methods }
public
class function GetTokenName: String; override;
end;

implementation

uses
uengShaderFileConstants, uengShaderFileTypes, uengShaderFileHelper;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//TengShaderPartKeyValuePair////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function TengShaderPartKeyValuePair.GetText: String;
begin
result := TOKEN_CHAR_BEGIN + GetTokenName + ' ' + fName;
if (fValueName <> '') then
result := result + ' ' + fValueName
else if (fValue <> Unassigned) then
result := result + TOKEN_CHAR_QUOTE + String(fValue) + TOKEN_CHAR_QUOTE;
result := result + TOKEN_CHAR_END;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function TengShaderPartKeyValuePair.ParseIntern(const aArgs: TengParseArgs; const aParams: TengTokenParameterList): String;
begin
if (aParams[0].Name <> GetTokenName) then with aParams[0] do
raise EengInvalidToken.Create(ClassName, GetTokenName, Line, Col, Filename);
if (aParams.Count < 2) or (aParams.Count > 3) then
raise EengInvalidParamterCount.Create(GetTokenName, 2, 3, Line, Col, Filename);

result := '';
fName := aParams[1].Name;
if not IsValidIdentifier(fName) then with aParams[1] do
raise EengInvalidIdentifier.Create(fName, Line, Col, Filename);
if (aParams.Count >= 3) then
if aParams[2].Quoted then begin
fValue := aParams[2].Name;
fValueName := '';
end else begin
fValue := Unassigned;
fValueName := aParams[2].Name;
end
else begin
fValue := Unassigned;
fValueName := '';
end;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//TengShaderPartProperty////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
class function TengShaderPartProperty.GetTokenName: String;
begin
result := TOKEN_PROPERTY;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//TengShaderPartDefine//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
class function TengShaderPartDefine.GetTokenName: String;
begin
result := TOKEN_DEFINE;
end;

end.


+ 31
- 0
uengShaderPartMessage.pas View File

@@ -0,0 +1,31 @@
unit uengShaderPartMessage;

{$mode objfpc}{$H+}
{$I uengShaderFile.inc}

interface

uses
Classes, SysUtils,
uengShaderPart;

type
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
TengShaderPartMessage = class(TengShaderPart)

end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
TengShaderPartWarning = class(TengShaderPartMessage)

end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
TengShaderPartError = class(TengShaderPartMessage)

end;

implementation

end.


+ 175
- 0
uengShaderPartMeta.pas View File

@@ -0,0 +1,175 @@
unit uengShaderPartMeta;

{$mode objfpc}{$H+}
{$I uengShaderFile.inc}

interface

uses
Classes, SysUtils,
uengShaderPart, uengShaderFileParser;

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;

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

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
TengShaderPartMeta = class(TengShaderPart)
{ Code Loading & Storage }
private
fData: TengMetaData;
protected
function GetText: String; override;
function ParseIntern(const aArgs: TengParseArgs; const aParams: TengTokenParameterList): String; override;

{ General }
public
property Data: TengMetaData read fData;
constructor Create(const aParent: TengShaderPart); override;
destructor Destroy; override;

{ Classs Methods }
public
class function GetTokenName: String; override;
end;

implementation

uses
uengShaderFileConstants, uengShaderFileTypes;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//TengMetaData//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function TengMetaData.GetValues: TStrings;
begin
result := fValues;
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;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//TengShaderPartMeta////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function TengShaderPartMeta.GetText: String;
var
i: Integer;
begin
result := TOKEN_CHAR_BEGIN + GetTokenName + ' ' + fData.Name;
for i := 0 to fData.Values.Count-1 do begin
if (PtrInt(fData.Values.Objects[i]) <> 0)
then result := result + ' ' + TOKEN_CHAR_QUOTE + fData.Values[i] + TOKEN_CHAR_QUOTE
else result := result + ' ' + fData.Values[i];
end;
result := result + TOKEN_CHAR_END;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function TengShaderPartMeta.ParseIntern(const aArgs: TengParseArgs; const aParams: TengTokenParameterList): String;
var
i: Integer;
t: TengMetaType;
n: String;
begin
if (aParams[0].Name <> GetTokenName) then with aParams[0] do
raise EengInvalidToken.Create(ClassName, Name, Line, Col, Filename);
if (aParams.Count < 2) then
raise EengInvalidParamterCount.Create(GetTokenName, 2, -1, Line, Col, Filename);

result := '';
n := aParams[1].Name;

{.$VERSION}
if (n = TOKEN_VERSION) then begin
t := metaVersion;
if (aParams.Count = 3) then begin
if (aParams[2].Name <> VERSION_EXTRA_COMPAT) and not TryStrToInt(aParams[2].Name, i) then with aParams[2] do
raise EengInvalidParamter.Create('version must be an number or "' + VERSION_EXTRA_COMPAT + '"', Line, Col, Filename);
end else if (aParams.Count = 4) then begin
if (aParams[2].Name <> VERSION_EXTRA_COMPAT) and not TryStrToInt(aParams[2].Name, i) then with aParams[2] do
raise EengInvalidParamter.Create('version must be an number or "' + VERSION_EXTRA_COMPAT + '"', Line, Col, Filename);
if (aParams[3].Name <> VERSION_EXTRA_COMPAT) then with aParams[3] do
raise EengInvalidParamter.Create('only "' + VERSION_EXTRA_COMPAT + '" is alowed as second parameter', Line, Col, Filename);
end else
raise EengInvalidParamterCount.Create(GetTokenName, 3, 4, Line, Col, Filename);

{.$EXTENSION}
end else if (n = TOKEN_EXTENSION) then begin
t := metaExtension;
if (aParams.Count <> 4) then
raise EengInvalidParamterCount.Create(GetTokenName, 4, Line, Col, Filename);

{.$LAYOUT}
end else if (n = TOKEN_LAYOUT) then begin
t := metaLayout;
if (aParams.Count <> 3) then
raise EengInvalidParamterCount.Create(GetTokenName, 3, Line, Col, Filename);

{.VALUES}
end else
t := metaNormal;

fData := TengMetaData.Create(n, t);
try
for i := 2 to aParams.Count-1 do
fData.Values.AddObject(aParams[i].Name, TObject(PtrInt(aParams[i].Quoted)));
except
FreeAndNil(fData);
end;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
constructor TengShaderPartMeta.Create(const aParent: TengShaderPart);
begin
inherited Create(aParent);
fData := nil;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
destructor TengShaderPartMeta.Destroy;
begin
FreeAndNil(fData);
inherited Destroy;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
class function TengShaderPartMeta.GetTokenName: String;
begin
result := TOKEN_META;
end;

end.


+ 143
- 0
uengShaderPartParameter.pas View File

@@ -0,0 +1,143 @@
unit uengShaderPartParameter;

{$mode objfpc}{$H+}
{$I uengShaderFile.inc}

interface

uses
Classes, SysUtils,
uengShaderPart, uengShaderFileParser;

type
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
TengShaderPartParameter = class(TengShaderPart)
{ Code Loading & Storage }
private
fName: String;
fType: String;
protected
function GetText: String; override;
function ParseIntern(const aArgs: TengParseArgs; const aParams: TengTokenParameterList): String; override;

{ General }
public
property Name: String read fName;
property Typ: String read fType;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
TengShaderPartVar = class(TengShaderPartParameter)
{ Code Loading & Storage }
private
fDefaultValue: String;
protected
function GetText: String; override;
function ParseIntern(const aArgs: TengParseArgs; const aParams: TengTokenParameterList): String; override;

{ General }
public
property DefaultValue: String read fDefaultValue;

{ Class Methods }
public
class function GetTokenName: String; override;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
TengShaderPartVarying = class(TengShaderPartParameter)
{ Class Methods }
public
class function GetTokenName: String; override;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
TengShaderPartUniform = class(TengShaderPartParameter)
{ Class Methods }
public
class function GetTokenName: String; override;
end;

implementation

uses
uengShaderFileConstants, uengShaderFileTypes;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function TengShaderPartParameter.GetText: String;
begin
result := TOKEN_CHAR_BEGIN + GetTokenName + ' ' +
TOKEN_CHAR_QUOTE + fType + TOKEN_CHAR_QUOTE + ' ' +
TOKEN_CHAR_QUOTE + fName + TOKEN_CHAR_QUOTE +
TOKEN_CHAR_END;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function TengShaderPartParameter.ParseIntern(const aArgs: TengParseArgs; const aParams: TengTokenParameterList): String;
begin
if (aParams[0].Name <> GetTokenName) then with aParams[0] do
raise EengInvalidToken.Create(ClassName, Name, Line, Col, Filename);
if (aParams.Count <> 3) then
raise EengInvalidParamterCount.Create(GetTokenName, 3, Line, Col, Filename);

result := '';
fType := aParams[1].Name;
fName := aParams[2].Name;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//TengShaderPartVar/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function TengShaderPartVar.GetText: String;
begin
result := TOKEN_CHAR_BEGIN + GetTokenName + ' ' +
TOKEN_CHAR_QUOTE + fType + TOKEN_CHAR_QUOTE + ' ' +
TOKEN_CHAR_QUOTE + fName + TOKEN_CHAR_QUOTE;
if (fDefaultValue <> '') then
result := result + ' ' + TOKEN_CHAR_QUOTE + fDefaultValue + TOKEN_CHAR_QUOTE;
result := result + TOKEN_CHAR_END;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function TengShaderPartVar.ParseIntern(const aArgs: TengParseArgs; const aParams: TengTokenParameterList): String;
begin
if (aParams[0].Name <> GetTokenName) then with aParams[0] do
raise EengInvalidToken.Create(ClassName, Name, Line, Col, Filename);
if (aParams.Count < 3) or (aParams.Count > 4) then
raise EengInvalidParamterCount.Create(GetTokenName, 3, 4, Line, Col, Filename);

result := '';
fType := aParams[1].Name;
fName := aParams[2].Name;
if (aParams.Count >= 4) then
fDefaultValue := aParams[3].Name
else
fDefaultValue := '';
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
class function TengShaderPartVar.GetTokenName: String;
begin
result := TOKEN_VAR;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//TengShaderPartVarying/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
class function TengShaderPartVarying.GetTokenName: String;
begin
result := TOKEN_VARYING;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//TengShaderPartUniform/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
class function TengShaderPartUniform.GetTokenName: String;
begin
result := TOKEN_UNIFORM;
end;

end.


+ 251
- 0
uengShaderPartProc.pas View File

@@ -0,0 +1,251 @@
unit uengShaderPartProc;

{$mode objfpc}{$H+}
{$I uengShaderFile.inc}

interface

uses
Classes, SysUtils,
uengShaderPart, uengShaderPartScope, uengShaderFileParser

{$IFDEF USE_BITSPACE_UTILS}
, uutlGenerics;
{$ELSE}
, fgl;
{$ENDIF}

type
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
TengShaderPartProcParam = packed record
Typ: String;
Name: String;
end;
TengShaderPartProcParamList = specialize TutlSimpleList<TengShaderPartProcParam>;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
TengShaderPartProc = class(TengShaderPartScope)
{ Code Loading & Storage }
private
fName: String;
fIsInline: Boolean;
fParameters: TengShaderPartProcParamList;
protected
function GetHeaderText: String; virtual;
function GetText: String; override;
function ParseIntern(const aArgs: TengParseArgs; const aParams: TengTokenParameterList): String; override;

{ General }
public
property Name: String read fName;
property IsInline: Boolean read fIsInline;

constructor Create(const aParent: TengShaderPart); override;
destructor Destroy; override;

{ Class Members }
public
class function GetTokenName: String; override;
class procedure Validate(const aArgs: TengParseArgs; const aParent: TengShaderPart); override;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
TengShaderPartMain = class(TengShaderPartProc)
{ Code Loading & Storage }
protected
function GetHeaderText: String; override;
function ParseIntern(const aArgs: TengParseArgs; const aParams: TengTokenParameterList): String; override;

{ General }
public
class function GetTokenName: String; override;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
TengShaderPartFunc = class(TengShaderPartProc)
{ Code Loading & Storage }
private
fReturnType: String;
protected
function GetHeaderText: String; override;
function ParseIntern(const aArgs: TengParseArgs; const aParams: TengTokenParameterList): String; override;

{ Class Methods }
public
class function GetTokenName: String; override;
end;

implementation

uses
uengShaderFileConstants, uengShaderFileTypes, uengShaderFileHelper;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//TengShaderPartProc////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function TengShaderPartProc.GetHeaderText: String;
var
p: TengShaderPartProcParam;
begin
result := TOKEN_CHAR_BEGIN + GetTokenName + ' ' + TOKEN_CHAR_QUOTE + fName + TOKEN_CHAR_QUOTE;
for p in fParameters do begin
result := result + ' ' + TOKEN_CHAR_QUOTE + p.Typ + TOKEN_CHAR_QUOTE +
' ' + TOKEN_CHAR_QUOTE + p.Name + TOKEN_CHAR_QUOTE;
end;
result := result + TOKEN_CHAR_END;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function TengShaderPartProc.GetText: String;
begin
result := GetHeaderText +
inherited GetText +
TOKEN_CHAR_BEGIN + TOKEN_END + TOKEN_CHAR_END;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function TengShaderPartProc.ParseIntern(const aArgs: TengParseArgs; const aParams: TengTokenParameterList): String;
type
TParseArgsState = (pasType, pasName);
var
i: Integer;
state: TParseArgsState;
param: TengShaderPartProcParam;
begin
if (aParams[0].Name <> GetTokenName) then with aParams[0] do
raise EengInvalidToken.Create(ClassName, Name, Line, Col, Filename);
if (aParams.Count < 2) then
raise EengInvalidParamterCount.Create(GetTokenName, 2, -1, Line, Col, Filename);

i := 2;
result := '';
fName := aParams[1].Name;
state := pasType;
fParameters.Clear;
while (i < aParams.Count) do begin
case state of
pasType: begin
if (aParams[i].Name <> TOKEN_INLINE) then begin
param.Typ := aParams[i].Name;
state := pasName;
end else
fIsInline := true;
end;

pasName: begin
if (aParams[i].Name = TOKEN_INLINE) then begin
with aParams[i] do
raise EengInvalidParamter.Create('expected parameter name (found ' + TOKEN_INLINE + ')', Line, Col, Filename);
end else begin
param.Name := aParams[i].Name;
fParameters.Add(param);
state := pasType;
end;
end;
end;
inc(i);
end;
if (state <> pasType) then
raise EengInvalidParamterCount.Create('invalid parameter count in ' + GetTokenName + '(expected multiple of 2)', Line, Col, Filename);
inherited ParseIntern(aArgs, aParams);
result := CheckEndToken(aArgs, self);
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
constructor TengShaderPartProc.Create(const aParent: TengShaderPart);
begin
inherited Create(aParent);
fParameters := TengShaderPartProcParamList.Create(true);
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
destructor TengShaderPartProc.Destroy;
begin
FreeAndNil(fParameters);
inherited Destroy;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
class function TengShaderPartProc.GetTokenName: String;
begin
result := TOKEN_PROC;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
class procedure TengShaderPartProc.Validate(const aArgs: TengParseArgs; const aParent: TengShaderPart);
begin
if (aParent.HasParent(TengShaderPartProc, true)) then with aArgs do
raise EengShaderPart.Create('token ' + GetTokenName + ' is not allowed inside ' +
TOKEN_PROC + ', ' + TOKEN_FUNC + ' or + ' + TOKEN_MAIN, Line, Col, aParent.Filename);
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//TengShaderPartMain////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function TengShaderPartMain.GetHeaderText: String;
begin
result := TOKEN_CHAR_BEGIN + GetTokenName + TOKEN_CHAR_END;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function TengShaderPartMain.ParseIntern(const aArgs: TengParseArgs; const aParams: TengTokenParameterList): String;
var
p: TengTokenParameter;
begin
if (aParams[0].Name <> GetTokenName) then with aParams[0] do
raise EengInvalidToken.Create(ClassName, Name, Line, Col, Filename);
if (aParams.Count <> 1) then
raise EengInvalidParamterCount.Create(GetTokenName, 1, Line, Col, Filename);

result := '';
p.Name := 'main';
p.Quoted := false;
p.Line := Line;
p.Col := Col + Length(GetTokenName);
aParams.Add(p);
inherited ParseIntern(aArgs, aParams);
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
class function TengShaderPartMain.GetTokenName: String;
begin
result := TOKEN_MAIN;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//TengShaderPartFunc////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function TengShaderPartFunc.GetHeaderText: String;
var
p: TengShaderPartProcParam;
begin
result := TOKEN_CHAR_BEGIN + GetTokenName + ' ' +
TOKEN_CHAR_QUOTE + fReturnType + TOKEN_CHAR_QUOTE + ' ' +
TOKEN_CHAR_QUOTE + fName + TOKEN_CHAR_QUOTE;
for p in fParameters do
result := result + ' ' + TOKEN_CHAR_QUOTE + p.Typ + TOKEN_CHAR_QUOTE
+ ' ' + TOKEN_CHAR_QUOTE + p.Name + TOKEN_CHAR_QUOTE;
result := result + TOKEN_CHAR_END;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function TengShaderPartFunc.ParseIntern(const aArgs: TengParseArgs; const aParams: TengTokenParameterList): String;
begin
if (aParams[0].Name <> GetTokenName) then with aParams[0] do
raise EengInvalidToken.Create(ClassName, aParams[0].Name, Line, Col, Filename);
if (aParams.Count < 3) then
raise EengInvalidParamterCount.Create(GetTokenName, 3, Line, Col, Filename);

fReturnType := aParams[1].Name;
aParams.Delete(1);
result := inherited ParseIntern(aArgs, aParams);
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
class function TengShaderPartFunc.GetTokenName: String;
begin
result := TOKEN_FUNC;
end;

end.


+ 20
- 0
uengShaderPartScope.pas View File

@@ -0,0 +1,20 @@
unit uengShaderPartScope;

{$mode objfpc}{$H+}
{$I uengShaderFile.inc}

interface

uses
Classes, SysUtils,
uengShaderPartCntr;

type
TengShaderPartScope = class(TengShaderPartCntr)

end;

implementation

end.


+ 143
- 0
uengShaderPartText.pas View File

@@ -0,0 +1,143 @@
unit uengShaderPartText;

{$mode objfpc}{$H+}
{$I uengShaderFile.inc}

interface

uses
Classes, SysUtils,
uengShaderPart, uengShaderFileParser;

type
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
TengShaderPartText = class(TengShaderPart)
{ Code Loading & Storage }
private
fText: String;
function GetIsEmpty: Boolean;
protected
function GetText: String; override;
function ParseIntern(const aArgs: TengParseArgs; const aParams: TengTokenParameterList): String; override;
public
property Text: String read fText;
property IsEmpty: Boolean read GetIsEmpty;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
TengShaderPartLineBreak = class(TengShaderPart)
{ Code Loading & Storage }
protected
function GetText: String; override;
function ParseIntern(const aArgs: TengParseArgs; const aParams: TengTokenParameterList): String; override;

{ Class Methods }
public
class function GetTokenName: String; override;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
TengShaderPartCommandEnd = class(TengShaderPart)
{ Code Loading & Storage }
private
fToken: String;
protected
function GetText: String; override;
function ParseIntern(const aArgs: TengParseArgs; const aParams: TengTokenParameterList): String; override;

{ Class Methods }
public
class function CheckToken(const aToken: String): Boolean; override;
end;

implementation

uses
uengShaderFileConstants, uengShaderFileTypes;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//TengShaderPartText////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function TengShaderPartText.GetIsEmpty: Boolean;
begin
result := (fText = '');
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function TengShaderPartText.GetText: String;
begin
result := fText;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function TengShaderPartText.ParseIntern(const aArgs: TengParseArgs; const aParams: TengTokenParameterList): String;
begin
fText := '';
result := '';
while not aArgs.EndOfLine do begin
if aArgs.GetTokenPreview(result) then begin
exit;
end else if (aArgs.CurrentChar in COMMAND_END_TOKENS) then begin
result := aArgs.CurrentChar;
exit;
end else begin
fText := fText + aArgs.CurrentChar;
aArgs.NextCol;
end;
end;
result := TOKEN_LINE_BREAK;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//TengShaderPartLineBreak///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function TengShaderPartLineBreak.GetText: String;
begin
result := TOKEN_LINE_BREAK;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function TengShaderPartLineBreak.ParseIntern(const aArgs: TengParseArgs; const aParams: TengTokenParameterList): String;
begin
if not aArgs.EndOfLine then
raise EengInvalidToken.Create(ClassName, '[LineBreak]', Line, Col, Filename);
aArgs.NextLine;
result := '';
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
class function TengShaderPartLineBreak.GetTokenName: String;
begin
result := TOKEN_LINE_BREAK;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//TengShaderPartCommandEnd//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function TengShaderPartCommandEnd.GetText: String;
begin
result := fToken;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function TengShaderPartCommandEnd.ParseIntern(const aArgs: TengParseArgs; const aParams: TengTokenParameterList): String;
begin
result := '';
fToken := aArgs.CurrentChar;
aArgs.NextCol;
end;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
class function TengShaderPartCommandEnd.CheckToken(const aToken: String): Boolean;
var
s: String;
begin
result := true;
for s in COMMAND_END_TOKENS do
if (s = aToken) then
exit;
result := false;
end;

end.


Loading…
Cancel
Save