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.

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