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 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// TengShaderFileLogEvent = procedure(const aSender: TengShaderPart; const aLogLevel: TengShaderPartLogLevel; const aMsg: String) of object; 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; protected function GetFilename: String; override; function GetFileReader: IengShaderFileReader; override; function GetFileWriter: IengShaderFileWriter; override; public procedure LoadFromFile(const aFilename: String; const aFileReader: IengShaderFileReader = nil); procedure SaveToFile(const aFilename: String; const aFileWriter: IengShaderFileWriter = nil); { General } private fOnLog: TengShaderFileLogEvent; protected procedure LogMsgIntern(const aSender: TengShaderPart; const aLogLevel: TengShaderPartLogLevel; const aMsg: String); override; public property Generator [const aName: String]: TengShaderCodeGenerator 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(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; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 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); finally FreeAndNil(args); end; finally fFileReader := nil; end; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// procedure TengShaderFile.SaveToFile(const aFilename: String; const aFileWriter: IengShaderFileWriter); var sr: TengSearchResults; i: Integer; sl: TStringList; ms: TMemoryStream; begin fFileWriter := aFileWriter; if not Assigned(fFileWriter) then fFileWriter := FileWriter; if not Assigned(fFileWriter) then fFileWriter := TengShaderFileWriter.Create; sr := TengSearchResults.Create([TengShaderPartInclude]); sl := TStringList.Create; ms := TMemoryStream.Create; try Find([sfSearchChildren, sfChildrenOnlyFile], sr); for i := 0 to sr.Count-1 do (sr[i] as TengShaderPartInclude).SaveToFile(aFilename, aFileWriter); sl.Text := Text; sl.SaveToStream(ms); ms.Position := 0; fFileWriter.SaveStream(aFilename, ms); finally FreeAndNil(sr); FreeAndNil(sl); FreeAndNil(ms); fFileWriter := nil; end; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// procedure TengShaderFile.LogMsgIntern(const aSender: TengShaderPart; const aLogLevel: TengShaderPartLogLevel; const aMsg: String); var tmp: TengShaderFileLogEvent; begin inherited LogMsgIntern(aSender, aLogLevel, aMsg); tmp := fOnLog; if Assigned(tmp) then tmp(aSender, aLogLevel, aMsg); 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.