| @@ -9,7 +9,6 @@ | |||
| <Title Value="ShaderFileTests"/> | |||
| <ResourceType Value="res"/> | |||
| <UseXPManifest Value="True"/> | |||
| <Icon Value="0"/> | |||
| </General> | |||
| <i18n> | |||
| <EnableI18N LFM="False"/> | |||
| @@ -39,7 +38,7 @@ | |||
| <PackageName Value="FCL"/> | |||
| </Item3> | |||
| </RequiredPackages> | |||
| <Units Count="27"> | |||
| <Units Count="28"> | |||
| <Unit0> | |||
| <Filename Value="ShaderFileTests.lpr"/> | |||
| <IsPartOfProject Value="True"/> | |||
| @@ -56,14 +55,17 @@ | |||
| <Unit3> | |||
| <Filename Value="..\uengShaderFileTypes.pas"/> | |||
| <IsPartOfProject Value="True"/> | |||
| <UnitName Value="uengShaderFileTypes"/> | |||
| </Unit3> | |||
| <Unit4> | |||
| <Filename Value="..\uengShaderFile.pas"/> | |||
| <IsPartOfProject Value="True"/> | |||
| <UnitName Value="uengShaderFile"/> | |||
| </Unit4> | |||
| <Unit5> | |||
| <Filename Value="..\uengShaderGenerator.pas"/> | |||
| <IsPartOfProject Value="True"/> | |||
| <UnitName Value="uengShaderGenerator"/> | |||
| </Unit5> | |||
| <Unit6> | |||
| <Filename Value="..\uengShaderFileConstants.pas"/> | |||
| @@ -76,6 +78,7 @@ | |||
| <Unit8> | |||
| <Filename Value="..\uengShaderFileHelper.pas"/> | |||
| <IsPartOfProject Value="True"/> | |||
| <UnitName Value="uengShaderFileHelper"/> | |||
| </Unit8> | |||
| <Unit9> | |||
| <Filename Value="..\uengShaderFileParser.pas"/> | |||
| @@ -88,15 +91,16 @@ | |||
| <Unit11> | |||
| <Filename Value="..\uengShaderGeneratorArgs.pas"/> | |||
| <IsPartOfProject Value="True"/> | |||
| <UnitName Value="uengShaderGeneratorArgs"/> | |||
| </Unit11> | |||
| <Unit12> | |||
| <Filename Value="..\uengShaderPartCall.pas"/> | |||
| <IsPartOfProject Value="True"/> | |||
| <UnitName Value="uengShaderPartCall"/> | |||
| </Unit12> | |||
| <Unit13> | |||
| <Filename Value="..\uengShaderPartClass.pas"/> | |||
| <IsPartOfProject Value="True"/> | |||
| <UnitName Value="uengShaderPartClass"/> | |||
| </Unit13> | |||
| <Unit14> | |||
| <Filename Value="..\uengShaderPartCntr.pas"/> | |||
| @@ -121,6 +125,7 @@ | |||
| <Unit19> | |||
| <Filename Value="..\uengShaderPartKeyValuePair.pas"/> | |||
| <IsPartOfProject Value="True"/> | |||
| <UnitName Value="uengShaderPartKeyValuePair"/> | |||
| </Unit19> | |||
| <Unit20> | |||
| <Filename Value="..\uengShaderPartMessage.pas"/> | |||
| @@ -150,6 +155,11 @@ | |||
| <Filename Value="..\uengShaderCodePart.pas"/> | |||
| <IsPartOfProject Value="True"/> | |||
| </Unit26> | |||
| <Unit27> | |||
| <Filename Value="..\uengShaderGeneratorEx.pas"/> | |||
| <IsPartOfProject Value="True"/> | |||
| <UnitName Value="uengShaderGeneratorEx"/> | |||
| </Unit27> | |||
| </Units> | |||
| </ProjectOptions> | |||
| <CompilerOptions> | |||
| @@ -159,7 +169,7 @@ | |||
| <Filename Value="ShaderFileTests"/> | |||
| </Target> | |||
| <SearchPaths> | |||
| <IncludeFiles Value="$(ProjOutDir);.."/> | |||
| <IncludeFiles Value="$(ProjOutDir);..\inc"/> | |||
| <OtherUnitFiles Value="..;..\..\Utils"/> | |||
| <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/> | |||
| </SearchPaths> | |||
| @@ -3,7 +3,7 @@ program ShaderFileTests; | |||
| {$mode objfpc}{$H+} | |||
| uses | |||
| Interfaces, Forms, GuiTestRunner, uShaderFileTestCase; | |||
| Interfaces, Forms, GuiTestRunner, uShaderFileTestCase, uengShaderGeneratorEx; | |||
| {$R *.res} | |||
| @@ -0,0 +1,4 @@ | |||
| {$PROPERTY TestProperty1 '0'} | |||
| {$PROPERTY TestProperty2 'asd'} | |||
| {$PROPERTY TestProperty3 'false'} | |||
| {$PROPERTY TestProperty4} | |||
| @@ -6,7 +6,7 @@ interface | |||
| uses | |||
| Classes, SysUtils, fpcunit, testregistry, | |||
| uengShaderFile, uengShaderGenerator, uengShaderFileTypes; | |||
| uengShaderFile, uengShaderGenerator, uengShaderFileTypes, uengShaderGeneratorEx; | |||
| type | |||
| TShaderFileTestCase = class(TTestCase) | |||
| @@ -57,6 +57,11 @@ type | |||
| procedure OrderOfMainProcClassContent; | |||
| end; | |||
| TTestCase_Generator = class(TShaderFileTestCase) | |||
| published | |||
| procedure DefaultValues; | |||
| end; | |||
| implementation | |||
| uses | |||
| @@ -219,12 +224,61 @@ begin | |||
| DoTest('code_General_OrderOfMainProcClassContent.shdr', 'TestClass', 'result_General_OrderOfMainProcClassContent.shdr'); | |||
| end; | |||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
| //TTestCase_Generator////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
| procedure TTestCase_Generator.DefaultValues; | |||
| var | |||
| shdr: TengShaderFile; | |||
| gen: TengShaderGeneratorEx; | |||
| code: TengShaderCode; | |||
| v: Variant; | |||
| i: Integer; | |||
| begin | |||
| shdr := TengShaderFile.Create; | |||
| code := TengShaderCode.Create; | |||
| try | |||
| shdr.LoadFromFile(ExpandFileName('testfiles\code_Generator_DefaultValues.shdr')); | |||
| for i := 0 to 3 do begin | |||
| gen := TengShaderGeneratorEx.Create(shdr, ''); | |||
| try | |||
| AssertEquals(true, gen.TryGetProperty('TestProperty1', v)); | |||
| AssertEquals(0, v); | |||
| AssertEquals(true, gen.TryGetProperty('TestProperty2', v)); | |||
| AssertEquals('asd', v); | |||
| AssertEquals(true, gen.TryGetProperty('TestProperty3', v)); | |||
| AssertEquals(false, v); | |||
| AssertEquals(true, gen.TryGetProperty('TestProperty4', v)); | |||
| AssertTrue(Unassigned = v); | |||
| AssertEquals(true, gen.TrySetProperty('TestProperty1', 101)); | |||
| AssertEquals(true, gen.TrySetProperty('TestProperty2', 102)); | |||
| AssertEquals(true, gen.TrySetProperty('TestProperty3', 103)); | |||
| AssertEquals(true, gen.TrySetProperty('TestProperty4', 104)); | |||
| gen.Generate(code); | |||
| finally | |||
| FreeAndNil(gen); | |||
| end; | |||
| end; | |||
| finally | |||
| FreeAndNil(code); | |||
| FreeAndNil(shdr); | |||
| end; | |||
| end; | |||
| initialization | |||
| RegisterTest(TTestCase_IfElifElseEnd); | |||
| RegisterTest(TTestCase_FuncProcMain); | |||
| RegisterTest(TTestCase_Include); | |||
| RegisterTest(TTestCase_Class); | |||
| RegisterTest(TTestCase_General); | |||
| RegisterTest(TTestCase_Generator); | |||
| end. | |||
| @@ -50,10 +50,10 @@ type | |||
| protected | |||
| procedure LogMsgIntern(const aSender: TengShaderPart; const aLogLevel: TengShaderPartLogLevel; const aMsg: String); override; | |||
| public | |||
| property Generator [const aName: String]: TengShaderGenerator read GetGenerator; | |||
| property GeneratorNames[const aIndex: Integer]: String read GetGeneratorNames; | |||
| property GeneratorCount: Integer read GetGeneratorCount; | |||
| property OnLog: TengShaderFileLogEvent read fOnLog write fOnLog; | |||
| property Generator [const aName: String]: TengShaderGenerator read GetGenerator; | |||
| property GeneratorNames[const aIndex: Integer]: String read GetGeneratorNames; | |||
| property GeneratorCount: Integer read GetGeneratorCount; | |||
| property OnLog: TengShaderFileLogEvent read fOnLog write fOnLog; | |||
| procedure Clear; override; | |||
| constructor Create; overload; | |||
| @@ -71,9 +71,11 @@ uses | |||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
| function TengShaderFile.GetGenerator(const aName: String): TengShaderGenerator; | |||
| begin | |||
| result := fClasses[aName]; | |||
| if (aName = '') | |||
| then result := self | |||
| else result := fClasses[aName]; | |||
| if not Assigned(result) then | |||
| result := self; | |||
| raise EengUnknownIdentifier.Create(aName, self); | |||
| end; | |||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
| @@ -68,6 +68,7 @@ type | |||
| ); | |||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
| TStringVariantMap = specialize TutlMap<string, variant>; | |||
| TengShaderCode = class(TStringList) | |||
| end; | |||
| @@ -8,13 +8,23 @@ interface | |||
| uses | |||
| Classes, SysUtils, | |||
| uengShaderPart, uengShaderFileTypes, uengShaderFileParser, uengShaderPartScope, | |||
| uengShaderPartKeyValuePair, uengShaderGeneratorArgs; | |||
| uengShaderPartKeyValuePair, uengShaderGeneratorArgs | |||
| {$IFDEF SHADER_FILE_USE_BITSPACE_UTILS} | |||
| , uutlGenerics | |||
| {$ELSE} | |||
| , uengShaderFileGenerics | |||
| {$ENDIF} | |||
| ; | |||
| type | |||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
| TengShaderGenerator = class(TengShaderPartScope) | |||
| { Code Loading & Storage } | |||
| private type | |||
| TNotifyEventList = specialize TutlList<TNotifyEvent>; | |||
| private | |||
| fOnDestroyEvents: TNotifyEventList; | |||
| fPropertyMap: TengShaderPartPropertyMap; | |||
| function GetPropertyByIndex(const aIndex: Integer): Variant; | |||
| @@ -38,6 +48,7 @@ type | |||
| function TryGetProperty(const aName: String; out aValue: Variant): Boolean; | |||
| function TrySetProperty(const aName: String; const aValue: Variant): Boolean; | |||
| procedure ListProperties(const aPropertyNames: TStrings); | |||
| procedure DuplicateProperties(const aMap: TStringVariantMap); | |||
| { Generate Shader Code } | |||
| public | |||
| @@ -45,6 +56,9 @@ type | |||
| { General } | |||
| public | |||
| procedure AddOnDestroyEvent(const aEvent: TNotifyEvent); | |||
| procedure RemoveOnDestroyEvent(const aEvent: TNotifyEvent); | |||
| constructor Create(const aParent: TengShaderPart); override; | |||
| destructor Destroy; override; | |||
| end; | |||
| @@ -107,28 +121,31 @@ procedure TengShaderGenerator.AddProperty(const aProp: TengShaderPartProperty; c | |||
| var | |||
| i: Integer; | |||
| l: TengShaderPartPropertyList; | |||
| p: TengShaderPartProperty; | |||
| s: String; | |||
| begin | |||
| i := -1; | |||
| l := fPropertyMap[aProp.Name]; | |||
| if Assigned(l) then begin | |||
| i := l.IndexOf(aProp); | |||
| if aShowWarning and (i >= 0) then begin | |||
| p := l.Last; | |||
| if (l.IndexOf(aProp) >= 0) then | |||
| exit; | |||
| if aShowWarning and (l.Count > 0) then begin | |||
| s := Format('use of duplicate identifier: %s (%s %d:%d)', [aProp.Name, aProp.Filename, aProp.Line + 1, aProp.Col]) + sLineBreak + | |||
| 'previously declared here:' + sLineBreak + | |||
| Format(' %s %d:%d', [p.Filename, p.Line + 1, p.Col]) + sLineBreak; | |||
| 'previously declared here:' + sLineBreak; | |||
| i := l.Count-1; | |||
| while (i >= 0) do begin | |||
| s := s + Format(' %s %d:%d', [l[i].Filename, l[i].Line + 1, l[i].Col]) + sLineBreak; | |||
| dec(i); | |||
| end; | |||
| LogMsg(llWarning, s); | |||
| end; | |||
| end else begin | |||
| l := TengShaderPartPropertyList.Create; | |||
| fPropertyMap.Add(aProp.Name, l); | |||
| end; | |||
| if (i < 0) then begin | |||
| l.Add(aProp); | |||
| if (aProp.Value <> Unassigned) then | |||
| l.Value := aProp.Value; | |||
| l.Add(aProp); | |||
| if (aProp.DefaultValue <> Unassigned) then begin | |||
| l.DefaultValue := aProp.DefaultValue; | |||
| l.Value := l.DefaultValue; | |||
| end; | |||
| end; | |||
| @@ -188,6 +205,15 @@ begin | |||
| aPropertyNames.Add(s); | |||
| end; | |||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
| procedure TengShaderGenerator.DuplicateProperties(const aMap: TStringVariantMap); | |||
| var | |||
| kvp: TengShaderPartPropertyMap.TKeyValuePair; | |||
| begin | |||
| for kvp in fPropertyMap.KeyValuePairs do | |||
| aMap.Add(kvp.Key, kvp.Value.DefaultValue); | |||
| end; | |||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
| procedure TengShaderGenerator.GenerateCode(const aCode: TengShaderCode); | |||
| var | |||
| @@ -245,17 +271,35 @@ begin | |||
| end; | |||
| end; | |||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
| procedure TengShaderGenerator.AddOnDestroyEvent(const aEvent: TNotifyEvent); | |||
| begin | |||
| fOnDestroyEvents.Add(aEvent); | |||
| end; | |||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
| procedure TengShaderGenerator.RemoveOnDestroyEvent(const aEvent: TNotifyEvent); | |||
| begin | |||
| fOnDestroyEvents.Remove(aEvent); | |||
| end; | |||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
| constructor TengShaderGenerator.Create(const aParent: TengShaderPart); | |||
| begin | |||
| inherited Create(aParent); | |||
| fPropertyMap := TengShaderPartPropertyMap.Create(true); | |||
| fPropertyMap := TengShaderPartPropertyMap.Create(true); | |||
| fOnDestroyEvents := TNotifyEventList.Create(true); | |||
| end; | |||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
| destructor TengShaderGenerator.Destroy; | |||
| var | |||
| e: TNotifyEvent; | |||
| begin | |||
| for e in fOnDestroyEvents do | |||
| e(self); | |||
| FreeAndNil(fPropertyMap); | |||
| FreeAndNil(fOnDestroyEvents); | |||
| inherited Destroy; | |||
| end; | |||
| @@ -0,0 +1,164 @@ | |||
| unit uengShaderGeneratorEx; | |||
| {$mode objfpc}{$H+} | |||
| interface | |||
| uses | |||
| Classes, SysUtils, | |||
| uengShaderFile, uengShaderGenerator, uengShaderFileTypes; | |||
| type | |||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
| { almost the same as TengShaderGenerator, but this is the extended version, that creates a copy of | |||
| all properties. So you can keep more then one gerator configurations at once. It is a little bit slower | |||
| than the normal generator. If you not need multiple configurations at once, use the simple one (TengShaderGenerator) } | |||
| TengShaderGeneratorEx = class(TObject) | |||
| private | |||
| fName: String; | |||
| fGeneratorPart: TengShaderGenerator; | |||
| function GetPropertyByIndex(const aIndex: Integer): Variant; | |||
| function GetPropertyByName(const aName: String): Variant; | |||
| function GetPropertyCount: Integer; | |||
| function GetPropertyNames(const aIndex: Integer): String; | |||
| procedure SetPropertyByIndex(const aIndex: Integer; aValue: Variant); | |||
| procedure SetPropertyByName(const aName: String; aValue: Variant); | |||
| procedure GeneratorPartDestroy(aSender: TObject); | |||
| protected | |||
| fProperties: TStringVariantMap; | |||
| public | |||
| property Name: String read fName write fName; | |||
| property PropertyByName [const aName: String]: Variant read GetPropertyByName write SetPropertyByName; | |||
| property PropertyByIndex[const aIndex: Integer]: Variant read GetPropertyByIndex write SetPropertyByIndex; | |||
| property PropertyNames [const aIndex: Integer]: String read GetPropertyNames; | |||
| property PropertyCount: Integer read GetPropertyCount; | |||
| function TryGetProperty(const aName: String; out aValue: Variant): Boolean; | |||
| function TrySetProperty(const aName: String; const aValue: Variant): Boolean; | |||
| procedure ListProperties(const aPropertyNames: TStrings); | |||
| procedure GenerateCode(const aCode: TengShaderCode); | |||
| constructor Create(const aShaderFile: TengShaderFile; const aName: String); | |||
| destructor Destroy; override; | |||
| end; | |||
| implementation | |||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
| //TengShaderGeneratorEx/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
| function TengShaderGeneratorEx.GetPropertyByIndex(const aIndex: Integer): Variant; | |||
| begin | |||
| result := fProperties.ValueAt[aIndex]; | |||
| end; | |||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
| function TengShaderGeneratorEx.GetPropertyByName(const aName: String): Variant; | |||
| var | |||
| i: Integer; | |||
| begin | |||
| i := fProperties.IndexOf(aName); | |||
| if (i < 0) then | |||
| raise EengUnknownIdentifier.Create(aName, self); | |||
| result := fProperties.ValueAt[i]; | |||
| end; | |||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
| function TengShaderGeneratorEx.GetPropertyCount: Integer; | |||
| begin | |||
| result := fProperties.Count; | |||
| end; | |||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
| function TengShaderGeneratorEx.GetPropertyNames(const aIndex: Integer): String; | |||
| begin | |||
| result := fProperties.Keys[aIndex]; | |||
| end; | |||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
| procedure TengShaderGeneratorEx.SetPropertyByIndex(const aIndex: Integer; aValue: Variant); | |||
| begin | |||
| fProperties.ValueAt[aIndex] := aValue; | |||
| end; | |||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
| procedure TengShaderGeneratorEx.SetPropertyByName(const aName: String; aValue: Variant); | |||
| var | |||
| i: Integer; | |||
| begin | |||
| i := fProperties.IndexOf(aName); | |||
| if (i < 0) then | |||
| raise EengUnknownIdentifier.Create(aName, self); | |||
| fProperties.ValueAt[i] := aValue; | |||
| end; | |||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
| procedure TengShaderGeneratorEx.GeneratorPartDestroy(aSender: TObject); | |||
| begin | |||
| fGeneratorPart := nil; | |||
| end; | |||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
| function TengShaderGeneratorEx.TryGetProperty(const aName: String; out aValue: Variant): Boolean; | |||
| var | |||
| i: Integer; | |||
| begin | |||
| i := fProperties.IndexOf(aName); | |||
| result := (i >= 0); | |||
| if result then | |||
| aValue := fProperties.ValueAt[i]; | |||
| end; | |||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
| function TengShaderGeneratorEx.TrySetProperty(const aName: String; const aValue: Variant): Boolean; | |||
| var | |||
| i: Integer; | |||
| begin | |||
| i := fProperties.IndexOf(aName); | |||
| result := (i >= 0); | |||
| if result then | |||
| fProperties.ValueAt[i] := aValue; | |||
| end; | |||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
| procedure TengShaderGeneratorEx.ListProperties(const aPropertyNames: TStrings); | |||
| var | |||
| s: String; | |||
| begin | |||
| for s in fProperties.Keys do | |||
| aPropertyNames.Add(s); | |||
| end; | |||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
| procedure TengShaderGeneratorEx.GenerateCode(const aCode: TengShaderCode); | |||
| var | |||
| kvp: TStringVariantMap.TKeyValuePair; | |||
| begin | |||
| if not Assigned(fGeneratorPart) then | |||
| EengShaderPartInternal.Create('unable to generate code: generator is not available anymore'); | |||
| for kvp in fProperties.KeyValuePairs do | |||
| fGeneratorPart.TrySetProperty(kvp.Key, kvp.Value); | |||
| end; | |||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
| constructor TengShaderGeneratorEx.Create(const aShaderFile: TengShaderFile; const aName: String); | |||
| begin | |||
| inherited Create; | |||
| fProperties := TStringVariantMap.Create; | |||
| fGeneratorPart := aShaderFile.Generator[aName]; | |||
| fGeneratorPart.DuplicateProperties(fProperties); | |||
| end; | |||
| //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// | |||
| destructor TengShaderGeneratorEx.Destroy; | |||
| begin | |||
| FreeAndNil(fProperties); | |||
| inherited Destroy; | |||
| end; | |||
| end. | |||
| @@ -55,9 +55,13 @@ type | |||
| TengShaderPartPropertyList = class(specialize TutlList<TengShaderPartProperty>) | |||
| private | |||
| fValue: Variant; | |||
| fDefaultValue: Variant; | |||
| public | |||
| property Value: Variant read fValue write fValue; | |||
| property Value: Variant read fValue write fValue; | |||
| property DefaultValue: Variant read fDefaultValue write fDefaultValue; | |||
| procedure ApplyValue; | |||
| constructor Create; | |||
| end; | |||