Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.

281 рядки
9.9 KiB

  1. unit uengShaderFile;
  2. { Package: SpaceEngine
  3. Prefix: eng - ENGine
  4. Beschreibung: stellt Klassen zum laden von Shader-Datein zur Verfügung
  5. beim laden des Codes wird gleichzeitig die Präprozessor-Sprache ausgewertet }
  6. {$mode objfpc}{$H+}
  7. {$I uengShaderFile.inc}
  8. interface
  9. uses
  10. Classes, sysutils,
  11. uengShaderPart, uengShaderPartClass, uengShaderCodeGenerator, uengShaderFileParser, uengShaderFileTypes
  12. {$IFDEF USE_BITSPACE_UTILS}
  13. , uutlSerialization
  14. {$ENDIF}
  15. ;
  16. type
  17. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  18. TengShaderFileLogEvent = procedure(const aSender: TengShaderPart; const aLogLevel: TengShaderPartLogLevel; const aMsg: String) of object;
  19. TengShaderFile = class(TengShaderCodeGenerator)
  20. { Code Loading & Storage }
  21. private
  22. fFilename: String;
  23. fFileReader: IutlFileReader;
  24. fFileWriter: IutlFileWriter;
  25. fClasses: TengShaderPartClassMap;
  26. private
  27. function GetGenerator(const aName: String): TengShaderCodeGenerator;
  28. function GetGeneratorCount: Integer;
  29. function GetGeneratorNames(const aIndex: Integer): String;
  30. procedure UpdateClasses;
  31. protected
  32. function GetFilename: String; override;
  33. function GetFileReader: IengShaderFileReader; override;
  34. function GetFileWriter: IengShaderFileWriter; override;
  35. procedure UpdateProperties; override;
  36. public
  37. procedure LoadFromFile(const aFilename: String; const aFileReader: IengShaderFileReader = nil);
  38. procedure SaveToFile(const aFilename: String; const aFileWriter: IengShaderFileWriter = nil);
  39. { General }
  40. private
  41. fOnLog: TengShaderFileLogEvent;
  42. protected
  43. procedure LogMsgIntern(const aSender: TengShaderPart; const aLogLevel: TengShaderPartLogLevel; const aMsg: String); override;
  44. public
  45. property Generator [const aName: String]: TengShaderCodeGenerator read GetGenerator;
  46. property GeneratorNames[const aIndex: Integer]: String read GetGeneratorNames;
  47. property GeneratorCount: Integer read GetGeneratorCount;
  48. property OnLog: TengShaderFileLogEvent read fOnLog write fOnLog;
  49. procedure Clear; override;
  50. constructor Create(const aParent: TengShaderPart); override;
  51. destructor Destroy; override;
  52. end;
  53. implementation
  54. uses
  55. uengShaderPartInclude, uengShaderPartKeyValuePair;
  56. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  57. //TengShaderFile////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  58. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  59. function TengShaderFile.GetGenerator(const aName: String): TengShaderCodeGenerator;
  60. begin
  61. result := fClasses[aName];
  62. if not Assigned(result) then
  63. result := self;
  64. end;
  65. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  66. function TengShaderFile.GetGeneratorCount: Integer;
  67. begin
  68. result := fClasses.Count+1;
  69. end;
  70. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  71. function TengShaderFile.GetGeneratorNames(const aIndex: Integer): String;
  72. begin
  73. if (aIndex < 0) or (aIndex >= Count) then
  74. raise EengOutOfRange.Create(0, Count-1, aIndex, self);
  75. if (aIndex = 0)
  76. then result := ''
  77. else result := fClasses.Keys[aIndex-1];
  78. end;
  79. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  80. procedure TengShaderFile.UpdateClasses;
  81. procedure AddClass(const aClass: TengShaderPartClass);
  82. var
  83. c: TengShaderPartClass;
  84. s: String;
  85. begin
  86. c := fClasses[aClass.Name];
  87. if Assigned(c) then begin
  88. s := Format('use of duplicate identifier: %s (%s %d:%d)', [aClass.Name, aClass.Filename, aClass.Line + 1, aClass.Col]) + sLineBreak +
  89. 'previously declared here:' + sLineBreak +
  90. Format(' %s %d:%d', [c.Filename, c.Line + 1, c.Col]) + sLineBreak;
  91. LogMsg(llWarning, s);
  92. fClasses[aClass.Name] := aClass;
  93. end else
  94. fClasses.Add(aClass.Name, aClass);
  95. end;
  96. var
  97. sr: TengSearchResults;
  98. p: TengShaderPart;
  99. begin
  100. sr := TengSearchResults.Create([TengShaderPartClass]);
  101. try
  102. Find([sfSearchChildren], sr);
  103. fClasses.Clear;
  104. for p in sr.GetReverseEnumerator do
  105. AddClass(p as TengShaderPartClass);
  106. finally
  107. FreeAndNil(sr);
  108. end;
  109. end;
  110. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  111. function TengShaderFile.GetFilename: String;
  112. begin
  113. result := fFilename;
  114. end;
  115. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  116. function TengShaderFile.GetFileReader: IengShaderFileReader;
  117. begin
  118. result := fFileReader;
  119. if not Assigned(result) and Assigned(Parent) then
  120. result := Parent.FileReader;
  121. end;
  122. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  123. function TengShaderFile.GetFileWriter: IengShaderFileWriter;
  124. begin
  125. result := fFileWriter;
  126. if not Assigned(result) and Assigned(Parent) then
  127. result := Parent.FileWriter;
  128. end;
  129. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  130. procedure TengShaderFile.UpdateProperties;
  131. var
  132. sr: TengSearchResults;
  133. p: TengShaderPart;
  134. begin
  135. inherited UpdateProperties;
  136. sr := TengSearchResults.Create([TengShaderFile]);
  137. try
  138. Find(SEARCH_FLAG_FILE_PROPERTIES, sr);
  139. for p in sr.GetReverseEnumerator do
  140. (p as TengShaderFile).CopyProperties(self);
  141. finally
  142. FreeAndNil(sr);
  143. end;
  144. sr := TengSearchResults.Create([TengShaderPartProperty]);
  145. try
  146. Find(SEARCH_FLAG_FILE_PROPERTIES, sr);
  147. for p in sr.GetReverseEnumerator do
  148. AddProperty(p as TengShaderPartProperty);
  149. finally
  150. FreeAndNil(sr);
  151. end;
  152. end;
  153. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  154. procedure TengShaderFile.LoadFromFile(const aFilename: String; const aFileReader: IengShaderFileReader);
  155. var
  156. args: TengParseArgs;
  157. token: String;
  158. ms: TMemoryStream;
  159. begin
  160. fFileReader := aFileReader;
  161. if not Assigned(fFileReader) then
  162. fFileReader := GetFileReader;
  163. if not Assigned(fFileReader) then
  164. fFileReader := TengShaderFileReader.Create;
  165. ms := TMemoryStream.Create;
  166. try
  167. Clear;
  168. if not fFileReader.LoadStream(aFilename, ms) then
  169. raise EengShaderPart.Create('unable to open file: ' + aFilename, Parent);
  170. ms.Position := 0;
  171. fFilename := aFilename;
  172. args := TengParseArgs.Create(ms, Filename);
  173. try
  174. token := ParseText(args);
  175. if (token <> '') then with args do
  176. raise EengShaderPart.Create('unknown token ''' + token + '''', Line, Col, Filename, self);
  177. if (self = Root) then
  178. UpdateClasses;
  179. finally
  180. FreeAndNil(args);
  181. end;
  182. finally
  183. fFileReader := nil;
  184. end;
  185. end;
  186. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  187. procedure TengShaderFile.SaveToFile(const aFilename: String; const aFileWriter: IengShaderFileWriter);
  188. var
  189. sr: TengSearchResults;
  190. i: Integer;
  191. sl: TStringList;
  192. ms: TMemoryStream;
  193. begin
  194. fFileWriter := aFileWriter;
  195. if not Assigned(fFileWriter) then
  196. fFileWriter := FileWriter;
  197. if not Assigned(fFileWriter) then
  198. fFileWriter := TengShaderFileWriter.Create;
  199. sr := TengSearchResults.Create([TengShaderPartInclude]);
  200. sl := TStringList.Create;
  201. ms := TMemoryStream.Create;
  202. try
  203. Find([sfSearchChildren, sfChildrenOnlyFile], sr);
  204. for i := 0 to sr.Count-1 do
  205. (sr[i] as TengShaderPartInclude).SaveToFile(aFilename, aFileWriter);
  206. sl.Text := Text;
  207. sl.SaveToStream(ms);
  208. ms.Position := 0;
  209. fFileWriter.SaveStream(aFilename, ms);
  210. finally
  211. FreeAndNil(sr);
  212. FreeAndNil(sl);
  213. FreeAndNil(ms);
  214. fFileWriter := nil;
  215. end;
  216. end;
  217. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  218. procedure TengShaderFile.LogMsgIntern(const aSender: TengShaderPart; const aLogLevel: TengShaderPartLogLevel; const aMsg: String);
  219. var
  220. tmp: TengShaderFileLogEvent;
  221. begin
  222. inherited LogMsgIntern(aSender, aLogLevel, aMsg);
  223. tmp := fOnLog;
  224. if Assigned(tmp) then
  225. tmp(aSender, aLogLevel, aMsg);
  226. end;
  227. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  228. procedure TengShaderFile.Clear;
  229. begin
  230. inherited Clear;
  231. fClasses.Clear;
  232. end;
  233. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  234. constructor TengShaderFile.Create(const aParent: TengShaderPart);
  235. begin
  236. inherited Create(aParent);
  237. if not Assigned(fRoot) then
  238. fRoot := self;
  239. fClasses := TengShaderPartClassMap.Create(false);
  240. end;
  241. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  242. destructor TengShaderFile.Destroy;
  243. begin
  244. FreeAndNil(fClasses);
  245. fFileReader := nil;
  246. fFileWriter := nil;
  247. inherited Destroy;
  248. end;
  249. end.