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.

434 lines
16 KiB

  1. unit uengShaderPartProc;
  2. {$mode objfpc}{$H+}
  3. {$I uengShaderFile.inc}
  4. interface
  5. uses
  6. Classes, SysUtils,
  7. uengShaderPart, uengShaderPartScope, uengShaderFileParser, uengShaderGeneratorArgs
  8. {$IFDEF SHADER_FILE_USE_BITSPACE_UTILS}
  9. , uutlGenerics;
  10. {$ELSE}
  11. , fgl;
  12. {$ENDIF}
  13. type
  14. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  15. TengShaderPartProcParam = packed record
  16. Typ: String;
  17. Name: String;
  18. end;
  19. TengShaderPartProcParamList = specialize TutlSimpleList<TengShaderPartProcParam>;
  20. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  21. TengShaderPartProc = class(TengShaderPartScope)
  22. { Code Loading & Storage }
  23. private
  24. fName: String;
  25. fIsInline: Boolean;
  26. fParameters: TengShaderPartProcParamList;
  27. function GetParameter(const aIndex: Integer): TengShaderPartProcParam;
  28. function GetParameterCount: Integer;
  29. protected
  30. function GetHeaderText: String; virtual;
  31. function GetText: String; override;
  32. function ParseIntern(const aArgs: TengParseArgs; const aParams: TengTokenParameterList): String; override;
  33. { Code Generation }
  34. protected
  35. function GenerateHeaderCode(const aArgs: TengShaderGeneratorArgs): String; virtual;
  36. procedure GenerateInlineCode(const aArgs: TengShaderGeneratorArgs); virtual;
  37. public
  38. procedure GenerateCodeIntern(const aArgs: TengShaderGeneratorArgs); override;
  39. { General }
  40. public
  41. property Name: String read fName;
  42. property IsInline: Boolean read fIsInline;
  43. property ParameterCount: Integer read GetParameterCount;
  44. property Parameters[const aIndex: Integer]: TengShaderPartProcParam read GetParameter;
  45. constructor Create(const aParent: TengShaderPart); override;
  46. destructor Destroy; override;
  47. { Class Members }
  48. public
  49. class function GetTokenName: String; override;
  50. end;
  51. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  52. TengShaderPartMain = class(TengShaderPartProc)
  53. { Code Loading & Storage }
  54. protected
  55. function GetHeaderText: String; override;
  56. function ParseIntern(const aArgs: TengParseArgs; const aParams: TengTokenParameterList): String; override;
  57. { Code Generation }
  58. protected
  59. function GenerateHeaderCode(const aArgs: TengShaderGeneratorArgs): String; override;
  60. { General }
  61. public
  62. class function GetTokenName: String; override;
  63. end;
  64. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  65. TengShaderPartFunc = class(TengShaderPartProc)
  66. { Code Loading & Storage }
  67. private
  68. fReturnType: String;
  69. protected
  70. function GetHeaderText: String; override;
  71. function ParseIntern(const aArgs: TengParseArgs; const aParams: TengTokenParameterList): String; override;
  72. { Code Generation }
  73. protected
  74. function GenerateHeaderCode(const aArgs: TengShaderGeneratorArgs): String; override;
  75. procedure GenerateInlineCode(const aArgs: TengShaderGeneratorArgs); override;
  76. { Class Methods }
  77. public
  78. class function GetTokenName: String; override;
  79. end;
  80. implementation
  81. uses
  82. RegExpr,
  83. uengShaderFileConstants, uengShaderFileTypes, uengShaderFileHelper, uengShaderPartClass;
  84. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  85. //TengShaderPartProc////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  86. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  87. function TengShaderPartProc.GetParameter(const aIndex: Integer): TengShaderPartProcParam;
  88. begin
  89. result := fParameters[aIndex];
  90. end;
  91. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  92. function TengShaderPartProc.GetParameterCount: Integer;
  93. begin
  94. result := fParameters.Count;
  95. end;
  96. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  97. function TengShaderPartProc.GetHeaderText: String;
  98. var
  99. p: TengShaderPartProcParam;
  100. begin
  101. result := TOKEN_CHAR_BEGIN + GetTokenName + ' ' + TOKEN_CHAR_QUOTE + fName + TOKEN_CHAR_QUOTE;
  102. for p in fParameters do begin
  103. result := result + ' ' + TOKEN_CHAR_QUOTE + p.Typ + TOKEN_CHAR_QUOTE +
  104. ' ' + TOKEN_CHAR_QUOTE + p.Name + TOKEN_CHAR_QUOTE;
  105. end;
  106. result := result + TOKEN_CHAR_END;
  107. end;
  108. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  109. function TengShaderPartProc.GetText: String;
  110. begin
  111. result := GetHeaderText +
  112. inherited GetText +
  113. TOKEN_CHAR_BEGIN + TOKEN_END + TOKEN_CHAR_END;
  114. end;
  115. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  116. function TengShaderPartProc.ParseIntern(const aArgs: TengParseArgs; const aParams: TengTokenParameterList): String;
  117. type
  118. TParseArgsState = (pasType, pasName);
  119. var
  120. i: Integer;
  121. state: TParseArgsState;
  122. param: TengShaderPartProcParam;
  123. begin
  124. if (aParams[0].Name <> GetTokenName) then with aParams[0] do
  125. raise EengInvalidToken.Create(ClassName, Name, Line, Col, Filename, self);
  126. if (aParams.Count < 2) then
  127. raise EengInvalidParamterCount.Create(GetTokenName, 2, -1, self);
  128. i := 2;
  129. result := '';
  130. fName := aParams[1].Name;
  131. state := pasType;
  132. fParameters.Clear;
  133. while (i < aParams.Count) do begin
  134. case state of
  135. pasType: begin
  136. if (aParams[i].Name <> TOKEN_INLINE) then begin
  137. param.Typ := aParams[i].Name;
  138. state := pasName;
  139. end else
  140. fIsInline := true;
  141. end;
  142. pasName: begin
  143. if (aParams[i].Name = TOKEN_INLINE) then begin
  144. with aParams[i] do
  145. raise EengInvalidParamter.Create('expected parameter name (found ' + TOKEN_INLINE + ')', Line, Col, Filename, self);
  146. end else begin
  147. param.Name := aParams[i].Name;
  148. fParameters.Add(param);
  149. state := pasType;
  150. end;
  151. end;
  152. end;
  153. inc(i);
  154. end;
  155. if (state <> pasType) then
  156. raise EengInvalidParamterCount.Create('invalid parameter count in ' + GetTokenName + '(expected multiple of 2)', self);
  157. result := inherited ParseIntern(aArgs, aParams);
  158. result := CheckEndToken(result, aArgs, self);
  159. end;
  160. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  161. function TengShaderPartProc.GenerateHeaderCode(const aArgs: TengShaderGeneratorArgs): String;
  162. var
  163. p: TengShaderPartProcParam;
  164. c: TengShaderPartClass;
  165. begin
  166. result := '';
  167. for p in fParameters do begin
  168. if (result <> '') then
  169. result := result + ', ';
  170. result := result + p.Typ + ' ' + p.Name;
  171. end;
  172. if (result = '') then
  173. result := 'void';
  174. if GetParent(TengShaderPartClass, c)
  175. then result := 'void ' + c.Name + '_' + fName + '(' + result + ')'
  176. else result := 'void ' + fName + '(' + result + ')';
  177. end;
  178. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  179. procedure TengShaderPartProc.GenerateInlineCode(const aArgs: TengShaderGeneratorArgs);
  180. var
  181. p: TengShaderPartProcParam;
  182. old, new: TStringList;
  183. rx: TRegExpr;
  184. s: String;
  185. begin
  186. aArgs.PushCode;
  187. rx := TRegExpr.Create;
  188. old := TStringList.Create;
  189. new := TStringList.Create;
  190. try
  191. inherited GenerateCodeIntern(aArgs);
  192. // prepare old parameters
  193. for p in fParameters do
  194. old.Add(p.Name);
  195. // prepate new paramaters
  196. rx.Expression := '[^A-z0-9_]+';
  197. for s in aArgs.ProcParams do begin
  198. if rx.Exec(s)
  199. then new.Add('(' + s + ')')
  200. else new.Add(s);
  201. end;
  202. // replace parameters
  203. aArgs.ReplaceIdents(old, new);
  204. finally
  205. FreeAndNil(rx);
  206. FreeAndNil(old);
  207. FreeAndNil(new);
  208. aArgs.PopCode([pcfAppend]);
  209. end;
  210. end;
  211. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  212. procedure TengShaderPartProc.GenerateCodeIntern(const aArgs: TengShaderGeneratorArgs);
  213. var
  214. s, params: String;
  215. c: TengShaderPartClass;
  216. begin
  217. // generate inline code
  218. if (aArgs.Flags * [gfGenerateProcedureCall, gfGenerateProcedureCode] <> []) and
  219. ((gfGenerateInlineCode in aArgs.Flags) or fIsInline) then
  220. begin
  221. GenerateInlineCode(aArgs);
  222. if (GetTokenName = TOKEN_PROC) then
  223. aArgs.IgnoreNextCommandEnd;
  224. // generate code
  225. end else if (gfGenerateProcedureCode in aArgs.Flags) then begin
  226. aArgs
  227. .AddLineBreak
  228. .AddText(GenerateHeaderCode(aArgs))
  229. .AddLineBreak
  230. .AddCommandEnd('{')
  231. .AddLineBreak
  232. .BeginBlock(4);
  233. try
  234. inherited GenerateCodeIntern(aArgs);
  235. finally
  236. aArgs
  237. .EndBlock
  238. .AddCommandEnd('}')
  239. .AddLineBreak;
  240. end;
  241. // generate call
  242. end else if (gfGenerateProcedureCall in aArgs.Flags) then begin
  243. params := '';
  244. for s in aArgs.ProcParams do begin
  245. if (params <> '') then
  246. params := params + ', ';
  247. params := params + s;
  248. end;
  249. if GetParent(TengShaderPartClass, c)
  250. then aArgs.AddText(c.Name + '_' + fName + '(' + params + ')')
  251. else aArgs.AddText(fName + '(' + params + ')');
  252. aArgs.AddProcedure(self);
  253. end;
  254. end;
  255. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  256. constructor TengShaderPartProc.Create(const aParent: TengShaderPart);
  257. begin
  258. inherited Create(aParent);
  259. fParameters := TengShaderPartProcParamList.Create(true);
  260. end;
  261. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  262. destructor TengShaderPartProc.Destroy;
  263. begin
  264. FreeAndNil(fParameters);
  265. inherited Destroy;
  266. end;
  267. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  268. class function TengShaderPartProc.GetTokenName: String;
  269. begin
  270. result := TOKEN_PROC;
  271. end;
  272. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  273. //TengShaderPartMain////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  274. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  275. function TengShaderPartMain.GetHeaderText: String;
  276. begin
  277. result := TOKEN_CHAR_BEGIN + GetTokenName + TOKEN_CHAR_END;
  278. end;
  279. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  280. function TengShaderPartMain.ParseIntern(const aArgs: TengParseArgs; const aParams: TengTokenParameterList): String;
  281. var
  282. p: TengTokenParameter;
  283. begin
  284. if (aParams[0].Name <> GetTokenName) then with aParams[0] do
  285. raise EengInvalidToken.Create(ClassName, Name, Line, Col, Filename, self);
  286. if (aParams.Count <> 1) then
  287. raise EengInvalidParamterCount.Create(GetTokenName, 1, self);
  288. result := '';
  289. p.Name := 'main';
  290. p.Quoted := false;
  291. p.Line := Line;
  292. p.Col := Col + Length(GetTokenName);
  293. aParams.Add(p);
  294. inherited ParseIntern(aArgs, aParams);
  295. end;
  296. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  297. function TengShaderPartMain.GenerateHeaderCode(const aArgs: TengShaderGeneratorArgs): String;
  298. var
  299. c: TengShaderPartClass;
  300. begin
  301. if not (gfGenerateProcedureMain in aArgs.Flags) and GetParent(TengShaderPartClass, c)
  302. then result := 'void ' + c.Name + '_main(void)'
  303. else result := 'void main(void)';
  304. end;
  305. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  306. class function TengShaderPartMain.GetTokenName: String;
  307. begin
  308. result := TOKEN_MAIN;
  309. end;
  310. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  311. //TengShaderPartFunc////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  312. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  313. function TengShaderPartFunc.GetHeaderText: String;
  314. var
  315. p: TengShaderPartProcParam;
  316. begin
  317. result := TOKEN_CHAR_BEGIN + GetTokenName + ' ' +
  318. TOKEN_CHAR_QUOTE + fReturnType + TOKEN_CHAR_QUOTE + ' ' +
  319. TOKEN_CHAR_QUOTE + fName + TOKEN_CHAR_QUOTE;
  320. for p in fParameters do
  321. result := result + ' ' + TOKEN_CHAR_QUOTE + p.Typ + TOKEN_CHAR_QUOTE
  322. + ' ' + TOKEN_CHAR_QUOTE + p.Name + TOKEN_CHAR_QUOTE;
  323. result := result + TOKEN_CHAR_END;
  324. end;
  325. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  326. function TengShaderPartFunc.ParseIntern(const aArgs: TengParseArgs; const aParams: TengTokenParameterList): String;
  327. begin
  328. if (aParams[0].Name <> GetTokenName) then with aParams[0] do
  329. raise EengInvalidToken.Create(ClassName, aParams[0].Name, Line, Col, Filename, self);
  330. if (aParams.Count < 3) then
  331. raise EengInvalidParamterCount.Create(GetTokenName, 3, self);
  332. fReturnType := aParams[1].Name;
  333. aParams.Delete(1);
  334. result := inherited ParseIntern(aArgs, aParams);
  335. end;
  336. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  337. function TengShaderPartFunc.GenerateHeaderCode(const aArgs: TengShaderGeneratorArgs): String;
  338. var
  339. p: TengShaderPartProcParam;
  340. c: TengShaderPartClass;
  341. begin
  342. result := '';
  343. for p in fParameters do begin
  344. if (result <> '') then
  345. result := result + ', ';
  346. result := result + p.Typ + ' ' + p.Name;
  347. end;
  348. if (result = '') then
  349. result := 'void';
  350. if GetParent(TengShaderPartClass, c)
  351. then result := fReturnType + ' ' + c.Name + '_' + fName + '(' + result + ')'
  352. else result := fReturnType + ' ' + fName + '(' + result + ')';
  353. end;
  354. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  355. procedure TengShaderPartFunc.GenerateInlineCode(const aArgs: TengShaderGeneratorArgs);
  356. var
  357. csi: TengShaderGeneratorArgs.TCodeStackItem;
  358. indent: Integer;
  359. begin
  360. csi := TengShaderGeneratorArgs.TCodeStackItem.Create;
  361. try
  362. indent := aArgs.ExtractCurrentCommand(csi);
  363. aArgs
  364. .PushCode
  365. .BeginBlock;
  366. try
  367. inherited GenerateInlineCode(aArgs);
  368. finally
  369. aArgs
  370. .EndBlock
  371. .AddText(StringOfChar(' ', indent))
  372. .ReplaceReturns(csi, fReturnType, fName)
  373. .PopCode([pcfAppend]);
  374. end;
  375. finally
  376. FreeAndNil(csi);
  377. end;
  378. end;
  379. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  380. class function TengShaderPartFunc.GetTokenName: String;
  381. begin
  382. result := TOKEN_FUNC;
  383. end;
  384. end.