You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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