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.

307 lines
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. if (aName = '')
  64. then result := self
  65. else result := fClasses[aName];
  66. if not Assigned(result) then
  67. raise EengUnknownIdentifier.Create(aName, self);
  68. end;
  69. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  70. function TengShaderFile.GetGeneratorCount: Integer;
  71. begin
  72. result := fClasses.Count+1;
  73. end;
  74. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  75. function TengShaderFile.GetGeneratorNames(const aIndex: Integer): String;
  76. begin
  77. if (aIndex < 0) or (aIndex >= GeneratorCount) then
  78. raise EengOutOfRange.Create(0, GeneratorCount-1, aIndex, self);
  79. if (aIndex = 0)
  80. then result := ''
  81. else result := fClasses.Keys[aIndex-1];
  82. end;
  83. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  84. procedure TengShaderFile.UpdateClasses;
  85. procedure AddClass(const aClass: TengShaderPartClass);
  86. var
  87. c: TengShaderPartClass;
  88. s: String;
  89. begin
  90. c := fClasses[aClass.Name];
  91. if Assigned(c) and (c <> aClass) then begin
  92. s := Format('use of duplicate identifier: %s (%s %d:%d)', [aClass.Name, aClass.Filename, aClass.Line + 1, aClass.Col]) + sLineBreak +
  93. 'previously declared here:' + sLineBreak +
  94. Format(' %s %d:%d', [c.Filename, c.Line + 1, c.Col]) + sLineBreak;
  95. LogMsg(llWarning, s);
  96. fClasses[aClass.Name] := aClass;
  97. end else if (c <> aClass) then
  98. fClasses.Add(aClass.Name, aClass);
  99. end;
  100. var
  101. sr: TengSearchResults;
  102. walker: TengSearchWalker;
  103. p: TengShaderPart;
  104. begin
  105. sr := TengSearchResults.Create;
  106. walker := TengSearchWalker.Create(sr);
  107. try
  108. walker.ResultTypes := CengShaderPartArr.Create(TengShaderPartClass);
  109. walker.SearchFlags := [sfSearchChildren];
  110. walker.Run(self);
  111. fClasses.Clear;
  112. for p in sr do
  113. AddClass(p as TengShaderPartClass);
  114. finally
  115. FreeAndNil(walker);
  116. FreeAndNil(sr);
  117. end;
  118. end;
  119. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  120. function TengShaderFile.GetFilename: String;
  121. begin
  122. result := fFilename;
  123. end;
  124. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  125. function TengShaderFile.GetFileReader: IengShaderFileReader;
  126. begin
  127. result := fFileReader;
  128. if not Assigned(result) and Assigned(Parent) then
  129. result := Parent.FileReader;
  130. end;
  131. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  132. function TengShaderFile.GetFileWriter: IengShaderFileWriter;
  133. begin
  134. result := fFileWriter;
  135. if not Assigned(result) and Assigned(Parent) then
  136. result := Parent.FileWriter;
  137. end;
  138. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  139. procedure TengShaderFile.UpdateProperties;
  140. var
  141. sr: TengSearchResults;
  142. walker: TengSearchWalker;
  143. p: TengShaderPart;
  144. begin
  145. inherited UpdateProperties;
  146. sr := TengSearchResults.Create;
  147. walker := TengSearchWalker.Create(sr);
  148. try
  149. walker.Owner := self;
  150. walker.SearchFlags := [sfSearchChildren, sfIgnoreOwner];
  151. walker.ResultTypes := CengShaderPartArr.Create(TengShaderFile);
  152. walker.ChildrenDoNotLeave := CengShaderPartArr.Create(TengShaderGenerator);
  153. walker.Run(self);
  154. for p in sr do
  155. (p as TengShaderFile).CopyProperties(self);
  156. walker.ResultTypes := CengShaderPartArr.Create(TengShaderPartProperty);
  157. sr.Clear;
  158. walker.Run(self);
  159. for p in sr do
  160. AddProperty(p as TengShaderPartProperty);
  161. finally
  162. FreeAndNil(walker);
  163. FreeAndNil(sr);
  164. end;
  165. end;
  166. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  167. procedure TengShaderFile.LoadFromFile(const aFilename: String; const aFileReader: IengShaderFileReader);
  168. var
  169. args: TengParseArgs;
  170. token: String;
  171. ms: TMemoryStream;
  172. begin
  173. fFileReader := aFileReader;
  174. if not Assigned(fFileReader) then
  175. fFileReader := GetFileReader;
  176. if not Assigned(fFileReader) then
  177. fFileReader := TengShaderFileReader.Create;
  178. ms := TMemoryStream.Create;
  179. try
  180. Clear;
  181. if not fFileReader.LoadStream(aFilename, ms) then
  182. raise EengShaderPart.Create('unable to open file: ' + aFilename, Parent);
  183. ms.Position := 0;
  184. fFilename := aFilename;
  185. args := TengParseArgs.Create(ms, Filename);
  186. try
  187. token := ParseText(args);
  188. if (token <> '') then with args do
  189. raise EengShaderPart.Create('unknown token ''' + token + '''', Line, Col, Filename, self);
  190. if (self = Root) then
  191. UpdateClasses;
  192. finally
  193. FreeAndNil(args);
  194. end;
  195. finally
  196. FreeAndNil(ms);
  197. fFileReader := nil;
  198. end;
  199. end;
  200. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  201. procedure TengShaderFile.SaveToFile(const aFilename: String; const aFileWriter: IengShaderFileWriter);
  202. var
  203. i: Integer;
  204. sr: TengSearchResults;
  205. sl: TStringList;
  206. ms: TMemoryStream;
  207. walker: TengSearchWalker;
  208. begin
  209. fFileWriter := aFileWriter;
  210. if not Assigned(fFileWriter) then
  211. fFileWriter := FileWriter;
  212. if not Assigned(fFileWriter) then
  213. fFileWriter := TengShaderFileWriter.Create;
  214. sr := TengSearchResults.Create;
  215. sl := TStringList.Create;
  216. ms := TMemoryStream.Create;
  217. walker := TengSearchWalker.Create(sr);
  218. try
  219. walker.SearchFlags := [sfSearchChildren];
  220. walker.ChildrenDoNotLeave := CengShaderPartArr.Create(TengShaderFile);
  221. walker.ResultTypes := CengShaderPartArr.Create(TengShaderPartInclude);
  222. walker.Run(self);
  223. for i := 0 to sr.Count-1 do
  224. (sr[i] as TengShaderPartInclude).SaveToFile(aFilename, aFileWriter);
  225. sl.Text := Text;
  226. sl.SaveToStream(ms);
  227. ms.Position := 0;
  228. fFileWriter.SaveStream(aFilename, ms);
  229. finally
  230. FreeAndNil(walker);
  231. FreeAndNil(sr);
  232. FreeAndNil(sl);
  233. FreeAndNil(ms);
  234. fFileWriter := nil;
  235. end;
  236. end;
  237. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  238. procedure TengShaderFile.LogMsgIntern(const aSender: TengShaderPart; const aLogLevel: TengShaderPartLogLevel; const aMsg: String);
  239. var
  240. tmp: TengShaderFileLogEvent;
  241. begin
  242. inherited LogMsgIntern(aSender, aLogLevel, aMsg);
  243. tmp := fOnLog;
  244. if Assigned(tmp) then
  245. tmp(aSender, aLogLevel, aMsg);
  246. end;
  247. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  248. procedure TengShaderFile.Clear;
  249. begin
  250. inherited Clear;
  251. fClasses.Clear;
  252. end;
  253. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  254. constructor TengShaderFile.Create;
  255. begin
  256. Create(nil);
  257. end;
  258. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  259. constructor TengShaderFile.Create(const aParent: TengShaderPart);
  260. begin
  261. inherited Create(aParent);
  262. if not Assigned(fRoot) then
  263. fRoot := self;
  264. fClasses := TengShaderPartClassMap.Create(false);
  265. end;
  266. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  267. destructor TengShaderFile.Destroy;
  268. begin
  269. FreeAndNil(fClasses);
  270. inherited Destroy;
  271. fFileReader := nil;
  272. fFileWriter := nil;
  273. end;
  274. end.