Non puoi selezionare più di 25 argomenti Gli argomenti devono iniziare con una lettera o un numero, possono includere trattini ('-') e possono essere lunghi fino a 35 caratteri.

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