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, uengShaderPart, uengShaderPartClass, uengShaderCodeGenerator, uengShaderFileParser, uengShaderFileTypes {$IFDEF USE_BITSPACE_UTILS} , uutlSerialization {$ENDIF} ; type //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// TengShaderFile = class(TengShaderCodeGenerator) { Code Loading & Storage } private fFilename: String; fFileReader: IutlFileReader; fFileWriter: IutlFileWriter; fClasses: TengShaderPartClassMap; private function GetGenerator(const aName: String): TengShaderCodeGenerator; function GetGeneratorCount: Integer; function GetGeneratorNames(const aIndex: Integer): String; procedure UpdateClasses; protected function GetFilename: String; override; function GetFileReader: IengShaderFileReader; override; function GetFileWriter: IengShaderFileWriter; override; { General } public property Generator [const aName: String]: TengShaderCodeGenerator read GetGenerator; property GeneratorNames[const aIndex: Integer]: String read GetGeneratorNames; property GeneratorCount: Integer read GetGeneratorCount; procedure LoadFromFile(const aFilename: String; const aFileReader: IengShaderFileReader = nil); procedure SaveToFile(const aFilename: String; const aFileWriter: IengShaderFileWriter = nil); procedure Clear; override; constructor Create(const aParent: TengShaderPart); override; destructor Destroy; override; end; implementation uses uengShaderPartInclude; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //TengShaderFile//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function TengShaderFile.GetGenerator(const aName: String): TengShaderCodeGenerator; begin result := fClasses[aName]; if not Assigned(result) then result := self; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function TengShaderFile.GetGeneratorCount: Integer; begin result := fClasses.Count+1; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function TengShaderFile.GetGeneratorNames(const aIndex: Integer): String; begin if (aIndex < 0) or (aIndex >= Count) then raise EengOutOfRange.Create(0, Count-1, aIndex, self); if (aIndex = 0) then result := '' else result := fClasses.Keys[aIndex-1]; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// procedure TengShaderFile.UpdateClasses; var l: TengShaderPart.TSearchResults; p: TengShaderPart; new, old: TengShaderPartClass; begin l := TengShaderPart.TSearchResults.Create; try fClasses.Clear; FindAll([sfSearchChildren], [TengShaderPartClass], l); for p in l do begin new := (p as TengShaderPartClass); old := fClasses[new.Name]; if Assigned(old) then raise EengDuplicateIdentifier.Create(new.Name, new, old, self); fClasses.Add(new.Name, new); end; finally FreeAndNil(l); end; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 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.LoadFromFile(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, Parent); ms.Position := 0; fFilename := aFilename; args := TengParseArgs.Create(ms, Filename); try token := ParseText(args); if (token <> '') then with args do raise EengShaderPart.Create('unknown token ''' + token + '''', Line, Col, Filename, self); if (Root = self) then UpdateClasses; finally FreeAndNil(args); end; finally fFileReader := nil; end; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// procedure TengShaderFile.SaveToFile(const aFilename: String; const aFileWriter: IengShaderFileWriter); var l: TengShaderPart.TSearchResults; i: Integer; sl: TStringList; ms: TMemoryStream; begin fFileWriter := aFileWriter; if not Assigned(fFileWriter) then fFileWriter := FileWriter; if not Assigned(fFileWriter) then fFileWriter := TengShaderFileWriter.Create; l := TengShaderPart.TSearchResults.Create; sl := TStringList.Create; ms := TMemoryStream.Create; try FindAll([sfSearchChildren, sfCurrentFileOnly], [TengShaderPartInclude], l); for i := 0 to l.Count-1 do (l[i] as TengShaderPartInclude).SaveToFile(aFilename, aFileWriter); sl.Text := Text; sl.SaveToStream(ms); ms.Position := 0; fFileWriter.SaveStream(aFilename, ms); finally FreeAndNil(l); FreeAndNil(sl); FreeAndNil(ms); fFileWriter := nil; end; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// procedure TengShaderFile.Clear; begin inherited Clear; fClasses.Clear; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// constructor TengShaderFile.Create(const aParent: TengShaderPart); begin inherited Create(aParent); if not Assigned(fRoot) then fRoot := self; fClasses := TengShaderPartClassMap.Create(false); end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// destructor TengShaderFile.Destroy; begin FreeAndNil(fClasses); fFileReader := nil; fFileWriter := nil; inherited Destroy; end; end.