library libShaderFile; {$mode objfpc}{$H+} uses SysUtils, variants, Classes, uengShaderFile, uengShaderGeneratorEx, uengShaderPart, uengShaderFileGenerics, uengShaderFileTypes; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //external types and contstants///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// const {%H-}LSF_LOGLEVEL_DEBUG = llDebug; {%H-}LSF_LOGLEVEL_INFO = llInfo; {%H-}LSF_LOGLEVEL_WARNING = llWarning; {%H-}LSF_LOGLEVEL_ERROR = llError; LSF_ERR_NONE = $00000000; LSF_ERR_NOT_INIT = $00000001; LSF_ERR_INVALID_HANDLE_SHADER_FILE = $00000010; LSF_ERR_INVALID_HANDLE_SHADER_GENERATOR = $00000011; LSF_ERR_INVALID_HANDLE_STREAM = $00000012; LSF_ERR_INVALID_GENERATOR_NAME = $00000020; LSF_ERR_INVALID_PROPERTY_INDEX = $00000021; LSF_ERR_INVALID_PROPERTY_NAME = $00000022; LSF_ERR_GENERATOR_NOT_ASSIGNED_TO_FILE = $00000023; LSF_ERR_UNKNOWN_IDENTFIFIER = $00001000; LSF_ERR_DUPLICATE_IDENTIFIER = $00001001; LSF_ERR_OUT_OF_RANGE = $00001002; LSF_ERR_INVALID_IDENTIFIER = $00001003; LSF_ERR_INVALID_PARAMTER_COUNT = $00001004; LSF_ERR_INVALID_PARAMTER = $00001005; LSF_ERR_UNEXPECTED_TOKEN = $00001006; LSF_ERR_INVALID_TOKEN = $00001007; LSF_ERR_EXPRESSION_INTERNAL = $00001008; LSF_ERR_EXPRESSION = $00001009; LSF_ERR_SHADER_PART_INTERNAL = $0000100A; LSF_ERR_SHADER_PART = $0000100B; LSF_ERR_UNKNOWN = $FFFFFFFF; {%H-}LSF_SEEK_BEG = soBeginning; {%H-}LSF_SEEK_CUR = soCurrent; {%H-}LSF_SEEK_END = soEnd; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// type TlsfErrorCode = Cardinal; TlsfLogLevel = Cardinal; TlsfSeekOrigin = Cardinal; TlsfShaderFileHandle = Pointer; TlsfShaderGeneratorHandle = Pointer; TlsfStreamHandle = Pointer; TlsfShaderFileLogEvent = procedure(const aLogLevel: TlsfLogLevel; const aMsg: PAnsiChar; const aUserArgs: Pointer); stdcall; TlsfSaveDataCallback = procedure(const aFilename: PAnsiChar; const aHandle: TlsfStreamHandle; const aUserArgs: Pointer); stdcall; TlsfLoadDataCallback = function(const aFilename: PAnsiChar; const aHandle: TlsfStreamHandle; const aUserArgs: Pointer): Boolean; stdcall; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //internal types and contstants///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// type TShaderFile = class; TShaderGenerator = class; TShaderGeneratorHandleHashSet = specialize TutlHashSet; TShaderGeneratorHashSet = specialize TutlHashSet; TStreamHashSet = specialize TutlHashSet; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// TShaderGenerator = class(TengShaderGeneratorEx) private fOwner: TShaderFile; fPropertyNames: String; fPropertyValue: String; fGeneratedCode: String; public property Owner: TShaderFile read fOwner; property PropertyNames: String read fPropertyNames; function GetProperty(const aIndex: Integer): PAnsiChar; function GetProperty(const aName: String): PAnsiChar; function SetProperty(const aIndex: Integer; const aValue: PAnsiChar): TlsfErrorCode; function SetProperty(const aName: String; const aValue: PAnsiChar): TlsfErrorCode; function GenerateCode: PAnsiChar; constructor Create(const aOwner: TShaderFile; const aName: String); end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// TShaderFile = class(TengShaderFile) private fLogUserArgs: Pointer; fLogCallback: TlsfShaderFileLogEvent; fGenerators: TShaderGeneratorHashSet; fGeneratorNames: String; protected procedure LogMsgIntern(const aSender: TengShaderPart; const aLogLevel: TengShaderPartLogLevel; const aMsg: String); override; public property LogCallback: TlsfShaderFileLogEvent read fLogCallback write fLogCallback; property LogUserArgs: Pointer read fLogUserArgs write fLogUserArgs; property GeneratorNames: String read fGeneratorNames; procedure LoadFromFile(const aFilename: String; const aFileReader: IengShaderFileReader = nil); reintroduce; function CreateGenerator(const aName: String): TShaderGenerator; function DestroyGenerator(const aGenerator: TShaderGenerator): TlsfErrorCode; constructor Create; overload; destructor Destroy; override; end; TShaderFileHashSet = specialize TutlHashSet; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// TFileWriterProxy = class(TInterfacedObject, IengShaderFileWriter) private fUserArgs: Pointer; fCallback: TlsfSaveDataCallback; public procedure SaveStream(const aFilename: String; const aStream: TStream); constructor Create(const aCallback: TlsfSaveDataCallback; const aUserArgs: Pointer); end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// TFileReaderProxy = class(TInterfacedObject, IengShaderFileReader) private fUserArgs: Pointer; fCallback: TlsfLoadDataCallback; public function LoadStream(const aFilename: String; const aStream: TStream): Boolean; constructor Create(const aCallback: TlsfLoadDataCallback; const aUserArgs: Pointer); end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// var ShaderFiles: TShaderFileHashSet = nil; ShaderGenerators: TShaderGeneratorHandleHashSet = nil; Streams: TStreamHashSet = nil; LastErrorCode: TlsfErrorCode = LSF_ERR_NONE; LastErrorMsg: String = ''; LastErrorTrace: String = ''; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //Misc (not exportet)/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// procedure SetLastError(const aErrorCode: TlsfErrorCode; const aMsg: String); begin LastErrorCode := aErrorCode; LastErrorMsg := aMsg; LastErrorTrace := ''; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// procedure SetLastError(const aException: Exception); begin if (aException is EengUnknownIdentifier) then LastErrorCode := LSF_ERR_UNKNOWN_IDENTFIFIER else if (aException is EengDuplicateIdentifier) then LastErrorCode := LSF_ERR_DUPLICATE_IDENTIFIER else if (aException is EengOutOfRange) then LastErrorCode := LSF_ERR_OUT_OF_RANGE else if (aException is EengInvalidIdentifier) then LastErrorCode := LSF_ERR_INVALID_IDENTIFIER else if (aException is EengInvalidParamterCount) then LastErrorCode := LSF_ERR_INVALID_PARAMTER_COUNT else if (aException is EengInvalidParamter) then LastErrorCode := LSF_ERR_INVALID_PARAMTER else if (aException is EengUnexpectedToken) then LastErrorCode := LSF_ERR_UNEXPECTED_TOKEN else if (aException is EengInvalidToken) then LastErrorCode := LSF_ERR_INVALID_TOKEN else if (aException is EengExpressionInternal) then LastErrorCode := LSF_ERR_EXPRESSION_INTERNAL else if (aException is EengExpression) then LastErrorCode := LSF_ERR_EXPRESSION else if (aException is EengShaderPartInternal) then LastErrorCode := LSF_ERR_SHADER_PART_INTERNAL else if (aException is EengShaderPart ) then LastErrorCode := LSF_ERR_SHADER_PART else LastErrorCode := LSF_ERR_UNKNOWN; if (aException is EengShaderPart) then LastErrorTrace := (aException as EengShaderPart).PrintTrace else LastErrorTrace := ''; LastErrorMsg := aException.Message; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function CheckIfInitialized: Boolean; begin result := Assigned(ShaderFiles); if not result then SetLastError(LSf_ERR_NOT_INIT, 'libShaderFile has not been initialized. call lsf_init before using any other methods.'); end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function CheckShaderFileHandle(const aHandle: TlsfShaderFileHandle): Boolean; begin result := CheckIfInitialized; if result then begin result := ShaderFiles.Contains(TShaderFile(aHandle)); if not result then SetLastError(LSF_ERR_INVALID_HANDLE_SHADER_FILE, Format('0x%x is not a valid shader file handle', [{%H-}PtrUInt(aHandle)])); end; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function CheckShaderGeneratorHandle(const aHandle: TlsfShaderGeneratorHandle): Boolean; begin result := CheckIfInitialized; if result then begin result := ShaderGenerators.Contains(TShaderGenerator(aHandle)); if not result then SetLastError(LSF_ERR_INVALID_HANDLE_SHADER_GENERATOR, Format('0x%x is not a valid shader generator handle', [{%H-}PtrUInt(aHandle)])); end; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function CheckStreamHandle(const aHandle: TlsfStreamHandle): Boolean; begin result := CheckIfInitialized; if result then begin result := Streams.Contains(TStream(aHandle)); if not result then SetLastError(LSF_ERR_INVALID_HANDLE_STREAM, Format('0x%x is not a valid stream handle', [{%H-}PtrUInt(aHandle)])); end; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //ShaderFile//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function lsf_ShaderFile_create: TlsfShaderFileHandle; stdcall; var sf: TShaderFile; begin try result := nil; if not CheckIfInitialized then exit; sf := TShaderFile.Create; ShaderFiles.Add(sf); result := sf; except on e: Exception do begin SetLastError(e); result := nil; end; end; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function lsf_ShaderFile_setLogCallback(const aHandle: TlsfShaderFileHandle; const aCallback: TlsfShaderFileLogEvent; const aUserArgs: Pointer): TlsfErrorCode; stdcall; begin try result := LSF_ERR_NONE; if CheckShaderFileHandle(aHandle) then with TShaderFile(aHandle) do begin LogCallback := aCallback; LogUserArgs := aUserArgs; end else result := LastErrorCode; except on e: Exception do begin SetLastError(e); result := LastErrorCode; end; end; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function lsf_ShaderFile_loadFromFile(const aHandle: TlsfShaderFileHandle; const aFilename: PAnsiChar): TlsfErrorCode; stdcall; begin try result := LSF_ERR_NONE; if not CheckShaderFileHandle(aHandle) then result := LastErrorCode else TShaderFile(aHandle).LoadFromFile(aFilename); except on e: Exception do begin SetLastError(e); result := LastErrorCode; end; end; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function lsf_ShaderFile_loadFromFunc(const aHandle: TlsfShaderFileHandle; const aFilename: PAnsiChar; const aCallback: TlsfLoadDataCallback; const aUserArgs: Pointer): TlsfErrorCode; stdcall; begin try result := LSF_ERR_NONE; if not CheckShaderFileHandle(aHandle) then result := LastErrorCode else TShaderFile(aHandle).LoadFromFile(aFilename, TFileReaderProxy.Create(aCallback, aUserArgs)); except on e: Exception do begin SetLastError(e); result := LastErrorCode; end; end; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function lsf_ShaderFile_saveToFile(const aHandle: TlsfShaderFileHandle; const aFilename: PAnsiChar): TlsfErrorCode; stdcall; begin try result := LSF_ERR_NONE; if not CheckShaderFileHandle(aHandle) then result := LastErrorCode else TShaderFile(aHandle).SaveToFile(aFilename); except on e: Exception do begin SetLastError(e); result := LastErrorCode; end; end; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function lsf_ShaderFile_saveToFunc(const aHandle: TlsfShaderFileHandle; const aFilename: PAnsiChar; const aCallback: TlsfSaveDataCallback; const aUserArgs: Pointer): TlsfErrorCode; stdcall; begin try result := LSF_ERR_NONE; if not CheckShaderFileHandle(aHandle) then result := LastErrorCode else TShaderFile(aHandle).SaveToFile(aFilename, TFileWriterProxy.Create(aCallback, aUserArgs)); except on e: Exception do begin SetLastError(e); result := LastErrorCode; end; end; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function lsf_ShaderFile_getGeneratorNames(const aHandle: TlsfShaderFileHandle): PAnsiChar; stdcall; begin try if not CheckShaderFileHandle(aHandle) then result := nil else result := PAnsiChar(TShaderFile(aHandle).GeneratorNames); except on e: Exception do begin SetLastError(e); result := nil; end; end; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function lsf_ShaderFile_destroy(const aHandle: TlsfShaderFileHandle): TlsfErrorCode; stdcall; begin try result := LSF_ERR_NONE; if not CheckShaderFileHandle(aHandle) then result := LastErrorCode else ShaderFiles.Remove(TShaderFile(aHandle)); except on e: Exception do begin SetLastError(e); result := LastErrorCode; end; end; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //Generator///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function lsf_Generator_create(const aHandle: TlsfShaderFileHandle; const aName: PAnsiChar): TlsfShaderGeneratorHandle; stdcall; begin try if not CheckShaderFileHandle(aHandle) then result := nil else result := TShaderFile(aHandle).CreateGenerator(string(aName)); except on e: Exception do begin SetLastError(e); result := nil; end; end; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function lsf_Generator_getPropertyNames(const aHandle: TlsfShaderGeneratorHandle): PAnsiChar; stdcall; begin try if not CheckShaderGeneratorHandle(aHandle) then result := nil else result := PAnsiChar(TShaderGenerator(aHandle).PropertyNames); except on e: Exception do begin SetLastError(e); result := nil; end; end; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function lsf_Generator_getProperty(const aHandle: TlsfShaderGeneratorHandle; const aIndex: Integer): PAnsiChar; stdcall; begin try if not CheckShaderGeneratorHandle(aHandle) then result := nil else result := TShaderGenerator(aHandle).GetProperty(aIndex); except on e: Exception do begin SetLastError(e); result := nil; end; end; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function lsf_Generator_getPropertyByName(const aHandle: TlsfShaderGeneratorHandle; const aName: PAnsiChar): PAnsiChar; stdcall; begin try if not CheckShaderGeneratorHandle(aHandle) then result := nil else result := TShaderGenerator(aHandle).GetProperty(aName); except on e: Exception do begin SetLastError(e); result := nil; end; end; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function lsf_Generator_setProperty(const aHandle: TlsfShaderGeneratorHandle; const aIndex: Integer; const aValue: PAnsiChar): TlsfErrorCode; stdcall; begin try if not CheckShaderGeneratorHandle(aHandle) then result := LastErrorCode else result := TShaderGenerator(aHandle).SetProperty(aIndex, aValue); except on e: Exception do begin SetLastError(e); result := LastErrorCode; end; end; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function lsf_Generator_setPropertyByName(const aHandle: TlsfShaderGeneratorHandle; const aName, aValue: PAnsiChar): TlsfErrorCode; stdcall; begin try if not CheckShaderGeneratorHandle(aHandle) then result := LastErrorCode else result := TShaderGenerator(aHandle).SetProperty(aName, aValue); except on e: Exception do begin SetLastError(e); result := LastErrorCode; end; end; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function lsf_Generator_generateCode(const aHandle: TlsfShaderGeneratorHandle): PAnsiChar; stdcall; begin try if not CheckShaderGeneratorHandle(aHandle) then result := nil else result := TShaderGenerator(aHandle).GenerateCode; except on e: Exception do begin SetLastError(e); result := nil; end; end; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function lsf_Generator_destroy(const aHandle: TlsfShaderGeneratorHandle): TlsfErrorCode; stdcall; var sg: TShaderGenerator; sf: TShaderFile; begin try result := LSF_ERR_NONE; if CheckShaderGeneratorHandle(aHandle) then begin sg := TShaderGenerator(aHandle); sf := sg.Owner; sf.DestroyGenerator(sg); end else result := LastErrorCode; except on e: Exception do begin SetLastError(e); result := LastErrorCode; end; end; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //Stream//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function lsf_Stream_getSize(const aHandle: TlsfStreamHandle): Integer; stdcall; begin try if CheckStreamHandle(aHandle) then result := TStream(aHandle).Size else result := -1; except on e: Exception do begin SetLastError(e); result := LastErrorCode; end; end; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function lsf_Stream_setSize(const aHandle: TlsfStreamHandle; const aSize: Integer): TlsfErrorCode; stdcall; begin try if CheckStreamHandle(aHandle) then TStream(aHandle).Size := aSize else result := LastErrorCode; except on e: Exception do begin SetLastError(e); result := LastErrorCode; end; end; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function lsf_Stream_seek(const aHandle: TlsfStreamHandle; const aOffset: Integer; const aOrigin: TlsfSeekOrigin): Integer; stdcall; begin try if CheckStreamHandle(aHandle) then result := TStream(aHandle).Seek(aOrigin, aOrigin) else result := -1; except on e: Exception do begin SetLastError(e); result := LastErrorCode; end; end; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function lsf_Stream_read(const aHandle: TlsfStreamHandle; const aBuffer: Pointer; const aSize: Integer): Integer; stdcall; begin try if CheckStreamHandle(aHandle) then result := TStream(aHandle).Read(aBuffer^, aSize) else result := -1; except on e: Exception do begin SetLastError(e); result := LastErrorCode; end; end; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function lsf_Stream_write(const aHandle: TlsfStreamHandle; const aBuffer: Pointer; const aSize: Integer): Integer; stdcall; begin try if CheckStreamHandle(aHandle) then result := TStream(aHandle).Write(aBuffer^, aSize) else result := -1; except on e: Exception do begin SetLastError(e); result := LastErrorCode; end; end; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //Global//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function lsf_init: TlsfErrorCode; stdcall; begin try result := LSF_ERR_NONE; ShaderFiles := TShaderFileHashSet.Create(true); ShaderGenerators := TShaderGeneratorHandleHashSet.Create(true); Streams := TStreamHashSet.Create(false); except on e: Exception do begin SetLastError(e); result := LastErrorCode; end; end; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function lsf_getLastErrorCode: TlsfErrorCode; stdcall; begin result := LastErrorCode; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function lsf_getLastErrorMsg: PAnsiChar; stdcall; begin result := PAnsiChar(LastErrorMsg); end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function lsf_getLastErrorTrace: PAnsiChar; stdcall; begin result := PAnsiChar(LastErrorTrace); end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function lsf_finish: TlsfErrorCode; stdcall; begin try result := LSF_ERR_NONE; FreeAndNil(Streams); FreeAndNil(ShaderGenerators); FreeAndNil(ShaderFiles); except on e: Exception do begin SetLastError(e); result := LastErrorCode; end; end; end; exports lsf_ShaderFile_create, lsf_ShaderFile_setLogCallback, lsf_ShaderFile_loadFromFile, lsf_ShaderFile_loadFromFunc, lsf_ShaderFile_saveToFile, lsf_ShaderFile_saveToFunc, lsf_ShaderFile_getGeneratorNames, lsf_ShaderFile_destroy, lsf_Generator_create, lsf_Generator_getPropertyNames, lsf_Generator_getProperty, lsf_Generator_getPropertyByName, lsf_Generator_setProperty, lsf_Generator_setPropertyByName, lsf_Generator_generateCode, lsf_Generator_destroy, lsf_Stream_getSize, lsf_Stream_setSize, lsf_Stream_seek, lsf_Stream_read, lsf_Stream_write, lsf_init, lsf_getLastErrorCode, lsf_getLastErrorMsg, lsf_getLastErrorTrace, lsf_finish; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //TShaderGenerator////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function TShaderGenerator.GetProperty(const aIndex: Integer): PAnsiChar; begin result := nil; if (aIndex < 0) or (aIndex >= fProperties.Count) then begin SetLastError(LSF_ERR_INVALID_PROPERTY_INDEX, Format('index (%d) out of range (%d:%d)', [aIndex, 0, fProperties.Count-1])); exit; end; fPropertyValue := fProperties.ValueAt[aIndex]; result := PAnsiChar(fPropertyValue); end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function TShaderGenerator.GetProperty(const aName: String): PAnsiChar; var i: Integer; begin result := nil; i := fProperties.IndexOf(aName); if (i >= 0) then result := GetProperty(i) else SetLastError(LSF_ERR_INVALID_PROPERTY_NAME, Format('%s is not a valid/known property name', [aName])); end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function TShaderGenerator.SetProperty(const aIndex: Integer; const aValue: PAnsiChar): TlsfErrorCode; begin result := LSF_ERR_NONE; if (aIndex < 0) or (aIndex >= fProperties.Count) then begin SetLastError(LSF_ERR_INVALID_PROPERTY_INDEX, Format('index (%d) out of range (%d:%d)', [aIndex, 0, fProperties.Count-1])); result := LastErrorCode; end; fProperties.ValueAt[aIndex] := string(aValue); end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function TShaderGenerator.SetProperty(const aName: String; const aValue: PAnsiChar): TlsfErrorCode; var i: Integer; begin i := fProperties.IndexOf(aName); if (i < 0) then begin SetLastError(LSF_ERR_INVALID_PROPERTY_NAME, Format('%s is not a valid/known property name', [aName])); result := LastErrorCode; end else result := SetProperty(i, aValue) end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function TShaderGenerator.GenerateCode: PAnsiChar; var kvp: TStringVariantMap.TKeyValuePair; c: TengShaderCode; begin for kvp in fProperties.KeyValuePairs do PropertyByName[kvp.Key] := kvp.Value; c := TengShaderCode.Create; try inherited GenerateCode(c); fGeneratedCode := c.Text; result := PAnsiChar(fGeneratedCode); finally FreeAndNil(c); end; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// constructor TShaderGenerator.Create(const aOwner: TShaderFile; const aName: String); var s: String; begin inherited Create(aOwner, aName); fOwner := aOwner; fPropertyNames := ''; for s in fProperties.Keys do fPropertyNames := fPropertyNames + s + sLineBreak; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //TShaderFile/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// procedure TShaderFile.LogMsgIntern(const aSender: TengShaderPart; const aLogLevel: TengShaderPartLogLevel; const aMsg: String); var tmp: TlsfShaderFileLogEvent; begin inherited LogMsgIntern(aSender, aLogLevel, aMsg); tmp := fLogCallback; if Assigned(tmp) then tmp(Cardinal(aLogLevel), PAnsiChar(aMsg), fLogUserArgs); end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// procedure TShaderFile.LoadFromFile(const aFilename: String; const aFileReader: IengShaderFileReader); var i: Integer; begin inherited LoadFromFile(aFilename, aFileReader); fGeneratorNames := ''; for i := 0 to GeneratorCount-1 do fGeneratorNames := fGeneratorNames + inherited GeneratorNames[i] + sLineBreak; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function TShaderFile.CreateGenerator(const aName: String): TShaderGenerator; function CheckName: Boolean; var i: Integer; begin result := true; for i := 0 to GeneratorCount-1 do if (inherited GeneratorNames[i] = aName) then exit; result := false; end; begin result := nil; if not CheckName then begin SetLastError(LSF_ERR_INVALID_GENERATOR_NAME, 'a generator with the name ''' + aName + ''' does not exist'); exit; end; result := TShaderGenerator.Create(self, aName); fGenerators.Add(result); ShaderGenerators.Add(result); end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function TShaderFile.DestroyGenerator(const aGenerator: TShaderGenerator): TlsfErrorCode; begin if Assigned(ShaderGenerators) then ShaderGenerators.Remove(aGenerator); if not fGenerators.Remove(aGenerator) then begin SetLastError(LSF_ERR_GENERATOR_NOT_ASSIGNED_TO_FILE, 'the passed generator handle is not owned by any file'); result := LastErrorCode; end else result := LSF_ERR_NONE; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// constructor TShaderFile.Create; begin inherited Create; fGenerators := TShaderGeneratorHashSet.Create(true); end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// destructor TShaderFile.Destroy; begin FreeAndNil(fGenerators); inherited Destroy; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //TFileWriterProxy////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// procedure TFileWriterProxy.SaveStream(const aFilename: String; const aStream: TStream); begin Streams.Add(aStream); try fCallback(PAnsiChar(aFilename), TlsfStreamHandle(aStream), fUserArgs); finally Streams.Remove(aStream); end; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// constructor TFileWriterProxy.Create(const aCallback: TlsfSaveDataCallback; const aUserArgs: Pointer); begin inherited Create; fCallback := aCallback; fUserArgs := aUserArgs; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //TFileReaderProxy////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// function TFileReaderProxy.LoadStream(const aFilename: String; const aStream: TStream): Boolean; begin Streams.Add(aStream); try result := fCallback(PAnsiChar(aFilename), TlsfStreamHandle(aStream), fUserArgs); finally Streams.Remove(aStream); end; end; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// constructor TFileReaderProxy.Create(const aCallback: TlsfLoadDataCallback; const aUserArgs: Pointer); begin inherited Create; fCallback := aCallback; fUserArgs := aUserArgs; end; end.