Du kan inte välja fler än 25 ämnen Ämnen måste starta med en bokstav eller siffra, kan innehålla bindestreck ('-') och vara max 35 tecken långa.

5642 rader
234 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. Hint: 'USE_VFS' in Projekt-Einstellungen definieren um VFS Support zu aktivieren
  7. 'SHADER_FILE_NO_VFS' in Projekt-Einstellungen um VFS Support für diese Unit zu deaktivieren}
  8. {$mode objfpc}{$H+}
  9. {.$DEFINE EXPRESSION_ADD_BRACKET}
  10. {.$DEFINE DEBUG}
  11. interface
  12. {$IFDEF SHADER_FILE_NO_VFS}
  13. {$UNDEF USE_VFS}
  14. {$ENDIF}
  15. uses
  16. //System
  17. Classes, SysUtils, variants,
  18. //bitSpaceEngine
  19. uutlGenerics, uutlCommon;
  20. type
  21. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  22. //EXPRESSIONS///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  23. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  24. TengShaderPartScope = class;
  25. TengGenCodeArgs = class;
  26. TengExpressionItem = class
  27. protected
  28. fLine: Integer;
  29. fCol: Integer;
  30. fFilename: String;
  31. public
  32. function GetText: String; virtual;
  33. function GetValue(const aScope: TengShaderPartScope; const aGenCodeArgs: TengGenCodeArgs): Variant; virtual;
  34. constructor Create(const aLine, aCol: Integer; const aFilename: String);
  35. end;
  36. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  37. TengExpressionValue = class(TengExpressionItem)
  38. private
  39. fValue: Variant;
  40. public
  41. function GetText: String; override;
  42. function GetValue(const aScope: TengShaderPartScope; const aGenCodeArgs: TengGenCodeArgs): Variant; override;
  43. constructor Create(const aValue: Variant; const aLine, aCol: Integer; const aFilename: String);
  44. end;
  45. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  46. TengExpressionVariable = class(TengExpressionItem)
  47. private
  48. fVariableName: String;
  49. public
  50. function GetText: String; override;
  51. function GetValue(const aScope: TengShaderPartScope; const aGenCodeArgs: TengGenCodeArgs): Variant; override;
  52. constructor Create(const aVariableName: String; const aLine, aCol: Integer; const aFilename: String);
  53. end;
  54. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  55. TengExpressionGroup = class(TengExpressionItem)
  56. private
  57. fChild: TengExpressionItem;
  58. public
  59. property Child: TengExpressionItem read fChild write fChild;
  60. function GetText: String; override;
  61. function GetValue(const aScope: TengShaderPartScope; const aGenCodeArgs: TengGenCodeArgs): Variant; override;
  62. constructor Create(const aChild: TengExpressionItem; const aLine, aCol: Integer; const aFilename: String);
  63. destructor Destroy; override;
  64. end;
  65. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  66. TengExpressionUnaryOperator = (
  67. opBinaryNot, opLogicalNot, opDefined, opSet
  68. );
  69. TengExpressionUnaryOperation = class(TengExpressionItem)
  70. private
  71. fChild: TengExpressionItem;
  72. fUnaryOp: TengExpressionUnaryOperator;
  73. public
  74. property Child: TengExpressionItem read fChild write fChild;
  75. property UnaryOp: TengExpressionUnaryOperator read fUnaryOp;
  76. function GetText: String; override;
  77. function GetValue(const aScope: TengShaderPartScope; const aGenCodeArgs: TengGenCodeArgs): Variant; override;
  78. constructor Create(const aUnaryOp: TengExpressionUnaryOperator; const aLine, aCol: Integer; const aFilename: String);
  79. destructor Destroy; override;
  80. end;
  81. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  82. TengExpressionBinaryOperator = ( //order of elements in this enum is also the weight of the operators
  83. opBinaryOr, opBinaryAnd, opBinaryXor, // binary
  84. opMultiply, opDivide, opAdd, opSubtract, // arithmetic
  85. opLogicalOr, opLogicalAnd, opLogicalXor, // logical
  86. opEquals, opLesser, opGreater, opLEquals, opGEquals, opUnequals // comparison
  87. );
  88. TengExpressionBinaryOperation = class(TengExpressionItem)
  89. private
  90. fFirst: TengExpressionItem;
  91. fSecond: TengExpressionItem;
  92. fBinaryOp: TengExpressionBinaryOperator;
  93. public
  94. property First: TengExpressionItem read fFirst write fFirst;
  95. property Second: TengExpressionItem read fSecond write fSecond;
  96. property BinaryOp: TengExpressionBinaryOperator read fBinaryOp;
  97. function GetText: String; override;
  98. function GetValue(const aScope: TengShaderPartScope; const aGenCodeArgs: TengGenCodeArgs): Variant; override;
  99. constructor Create(const aOperator: TengExpressionBinaryOperator; const aLine, aCol: Integer; const aFilename: String);
  100. destructor Destroy; override;
  101. end;
  102. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  103. //EXCEPTIONS////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  104. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  105. TengShaderPart = class;
  106. CengShaderPart = class of TengShaderPart;
  107. EengShaderPart = class(Exception)
  108. public
  109. Line, Col: Integer;
  110. Filename: String;
  111. constructor Create(const aMsg: String; const aLine, aCol: Integer; const aFilename: String); overload;
  112. end;
  113. EengInvalidParamter = class(EengShaderPart)
  114. constructor Create(const aMsg: String; const aLine, aCol: Integer; const aFilename: String); overload;
  115. end;
  116. EengInvalidIdentifier = class(EengShaderPart)
  117. constructor Create(const aIdentifier: String; const aLine, aCol: Integer; const aFilename: String); overload;
  118. end;
  119. EengEmptyToken = class(EengShaderPart)
  120. constructor Create(const aLine, aCol: Integer; const aFilename: String); overload;
  121. end;
  122. EengInvalidToken = class(EengShaderPart)
  123. constructor Create(const aClassName: String; const aToken: String; const aLine, aCol: Integer; const aFilename: String); overload;
  124. end;
  125. EengInvalidParamterCount = class(EengShaderPart)
  126. constructor Create(const aToken: String; const aLine, aCol: Integer; const aFilename: String); overload;
  127. end;
  128. EengDuplicateIdentifier = class(EengShaderPart)
  129. constructor Create(const aName: String; const aNew, aOld: TengShaderPart); overload;
  130. end;
  131. EengInternal = class(EengShaderPart)
  132. constructor Create(const aMsg: String); overload;
  133. constructor Create(const aMsg: String; const aLine, aCol: Integer; const aFilename: String); overload;
  134. end;
  135. EengUnknownIdentifier = class(EengShaderPart)
  136. constructor Create(const aIdent: String; const aLine, aCol: Integer; const aFilename: String); overload;
  137. end;
  138. EengExpression = class(EengShaderPart);
  139. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  140. //SHADER PARTS//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  141. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  142. TengShaderFile = class;
  143. TengParseArgs = class;
  144. TengTokenParameter = packed record
  145. Name: String;
  146. Quoted: Boolean;
  147. Line: Integer;
  148. Col: Integer;
  149. end;
  150. TengTokenParameterList = specialize TutlSimpleList<TengTokenParameter>;
  151. TengMapDataFlag = (
  152. mdfIfEvaluate, //evaluate if parts and add suitable subtree
  153. mdfIfAll, //do not evaluate if parts and add all subtrees
  154. mdfAddInherited, //add inherited scopes to parent
  155. mdfMapInherited, //map parts of inherited scopes
  156. mdfCurrentScope, //do not map child scopes
  157. mdfChild //is set if current node is not that node the recursion started
  158. );
  159. TengMapDataFlags = set of TengMapDataFlag;
  160. TengShaderPartFlag = (
  161. spfCodeGenVisited //this item was visited by code gen routine
  162. );
  163. TengShaderPartFlags = set of TengShaderPartFlag;
  164. TengShaderPart = class(TutlInterfaceNoRefCount)
  165. { Load & Store Code }
  166. protected type
  167. TengShaderPartEnumerator = class(TObject)
  168. private
  169. fOwner: TengShaderPart;
  170. fPosition: Integer;
  171. function GetCurrent: TengShaderPart;
  172. public
  173. property Current: TengShaderPart read GetCurrent;
  174. function MoveNext: Boolean;
  175. constructor Create(const aOwner: TengShaderPart);
  176. end;
  177. private
  178. fRoot: TengShaderFile;
  179. fParent: TengShaderPart;
  180. fLine: Integer;
  181. fCol: Integer;
  182. protected
  183. function GetCount: Integer; virtual;
  184. function GetChild(const aIndex: Integer): TengShaderPart; virtual;
  185. function GetFilename: String; virtual;
  186. function GetShaderClass: String; virtual;
  187. function GetText: String; virtual;
  188. function ParseTextIntern(const aParseArgs: TengParseArgs; const aParameters: TengTokenParameterList): String; virtual;
  189. function ParseText(const aParseArgs: TengParseArgs): String;
  190. { Generate Shader Code }
  191. private
  192. fFlags: TengShaderPartFlags;
  193. protected
  194. procedure MapData(const aFlags: TengMapDataFlags; const aTypes: array of CengShaderPart); virtual;
  195. procedure GenCodeIntern(const aGenCodeArgs: TengGenCodeArgs); virtual;
  196. procedure ClearGenCode; virtual;
  197. public
  198. property Flags: TengShaderPartFlags read fFlags;
  199. { General }
  200. public
  201. property Root: TengShaderFile read fRoot;
  202. property Line: Integer read fLine;
  203. property Col: Integer read fCol;
  204. property Filename: String read GetFilename;
  205. property ShaderClass: String read GetShaderClass;
  206. property Parent: TengShaderPart read fParent;
  207. property Count: Integer read GetCount;
  208. property Children[const aIndex: Integer]: TengShaderPart read GetChild; default;
  209. property Text: String read GetText;
  210. function HasParentType(const aParentType: CengShaderPart; const aIncludeSelf: Boolean = false): Boolean;
  211. procedure GetParentByType(const aParentType: CengShaderPart; out aPart);
  212. function GetEnumerator: TengShaderPartEnumerator;
  213. constructor Create(const aParent: TengShaderPart); virtual;
  214. public
  215. class function GetTokenName: String; virtual;
  216. class function CheckToken(const aToken: String): Boolean; virtual;
  217. class procedure CheckToken(const aParseArgs: TengParseArgs; const aParent: TengShaderPart); virtual;
  218. end;
  219. TengShaderPartList = specialize TutlList<TengShaderPart>;
  220. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  221. TengShaderPartContainer = class(TengShaderPart)
  222. { Load & Store Code }
  223. private
  224. fChildren: TengShaderPartList;
  225. function HandleToken(var aToken: String; const aParseArgs: TengParseArgs): String;
  226. protected
  227. function GetCount: Integer; override;
  228. function GetChild(const aIndex: Integer): TengShaderPart; override;
  229. function GetText: String; override;
  230. function ParseTextIntern(const aParseArgs: TengParseArgs; const aParameters: TengTokenParameterList): String; override;
  231. { Generate Shader Code }
  232. protected
  233. procedure MapData(const aFlags: TengMapDataFlags; const aTypes: array of CengShaderPart); override;
  234. procedure GenCodeIntern(const aGenCodeArgs: TengGenCodeArgs); override;
  235. procedure ClearGenCode; override;
  236. { General }
  237. public
  238. procedure AddChild(const aChild: TengShaderPart; const aPrepend: Boolean = false);
  239. constructor Create(const aParent: TengShaderPart); override;
  240. destructor Destroy; override;
  241. end;
  242. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  243. TengFindMappedPartFlag = (
  244. // general
  245. ffGlobal, // set current node to root before searching
  246. ffDescending, // depth search starting at current node
  247. ffAscending, // search in parents and grand parents starting at current node
  248. ffLocal, // search in mapped parts of current item (will be reseted when entering next or previous recursion level)
  249. ffFindFirst, // return after finding at least one result
  250. ffVisited, // only search in scopes that are already visited by GenCode
  251. // class data
  252. ffInherited, // search in inherited classes (this is not a new recursion level!)
  253. ffFile, // search in file that belongs to this class (this is not a new recursion level!)
  254. // file GenCodeIntern
  255. ffIgnoreClasses // ignore class parts
  256. );
  257. TengFindMappedPartFlags = set of TengFindMappedPartFlag;
  258. TengShaderPartScope = class(TengShaderPartContainer)
  259. { Generate Shader Code }
  260. private type
  261. TengShaderPartScopeHashSet = specialize TutlHashSet<TengShaderPartScope>;
  262. TengShaderPartMap = specialize TutlMap<string, TengShaderPart>;
  263. private
  264. fInherited: TengShaderPartScopeHashSet;
  265. fChildScopes: TengShaderPartScopeHashSet;
  266. fMappedParts: TengShaderPartMap;
  267. function CheckName(const aName: String; const aShaderPart: TengShaderPart): Boolean;
  268. protected
  269. procedure MapChildScope(const aScope: TengShaderPartScope);
  270. procedure MapInheritedScope(const aScope: TengShaderPartScope);
  271. function MapShaderPart(const aName: String; const aShaderPart: TengShaderPart): Boolean;
  272. procedure FindMappedPart(out aShaderPart; const aName: String; const aFlags: TengFindMappedPartFlags; const aType: CengShaderPart = nil);
  273. procedure FindMappedParts(const aParts: TengShaderPartList; const aName: String; const aFlags: TengFindMappedPartFlags; const aType: CengShaderPart = nil); virtual;
  274. function GetFindPropertyFlags: TengFindMappedPartFlags; virtual;
  275. procedure CheckDuplicate(const aName: String; const aOld, aNew: TengShaderPart); virtual;
  276. procedure MapData(const aFlags: TengMapDataFlags; const aTypes: array of CengShaderPart); override;
  277. procedure GenCodeIntern(const aGenCodeArgs: TengGenCodeArgs); override;
  278. procedure ClearGenCode; override;
  279. procedure ClearMappedData(const aExcludedTypes: array of CengShaderPart); overload;
  280. procedure ClearMappedData; overload;
  281. public
  282. constructor Create(const aParent: TengShaderPart); override;
  283. destructor Destroy; override;
  284. end;
  285. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  286. TengShaderCode = class;
  287. TengShaderPartProperty = class;
  288. TengShaderPartDefine = class;
  289. TengCodeGenerator = class(TengShaderPartScope)
  290. private
  291. function GetProperty(const aName: String): TengShaderPartProperty;
  292. protected
  293. procedure GenerateCode(const aGenCodeArgs: TengGenCodeArgs); virtual;
  294. public
  295. property Properties[const aName: String]: TengShaderPartProperty read GetProperty; default;
  296. function GenerateCode: TengShaderCode;
  297. procedure ListProperties(const aList: TStrings); virtual;
  298. end;
  299. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  300. TengShaderPartClass = class(TengCodeGenerator)
  301. { Load & Store Code }
  302. private
  303. fName: String;
  304. fExtends: TStringList;
  305. function GetExtendCount: Integer;
  306. function GetExtends(const aIndex: Integer): String;
  307. protected
  308. function GetText: String; override;
  309. function GetShaderClass: String; override;
  310. function ParseTextIntern(const aParseArgs: TengParseArgs; const aParameters: TengTokenParameterList): String; override;
  311. public
  312. property Name: String read fName;
  313. property ExtendCount: Integer read GetExtendCount;
  314. property Extends[const aIndex: Integer]: String read GetExtends;
  315. { Generate Shader Code }
  316. protected
  317. procedure CheckDuplicate(const aName: String; const aOld, aNew: TengShaderPart); override;
  318. function GetFindPropertyFlags: TengFindMappedPartFlags; override;
  319. procedure GenCodeIntern(const aGenCodeArgs: TengGenCodeArgs); override;
  320. procedure GenerateCode(const aGenCodeArgs: TengGenCodeArgs); override;
  321. public
  322. procedure FindMappedParts(const aParts: TengShaderPartList; const aName: String; const aFlags: TengFindMappedPartFlags; const aType: CengShaderPart = nil); override;
  323. procedure MapData(const aFlags: TengMapDataFlags; const aTypes: array of CengShaderPart); override;
  324. { General }
  325. public
  326. constructor Create(const aParent: TengShaderPart); override;
  327. destructor Destroy; override;
  328. public
  329. class function GetTokenName: String; override;
  330. class procedure CheckToken(const aParseArgs: TengParseArgs; const aParent: TengShaderPart); override;
  331. end;
  332. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  333. TengShaderFile = class(TengCodeGenerator)
  334. { Load & Store Code }
  335. private
  336. fFilename: String;
  337. protected
  338. function GetFilename: String; override;
  339. public
  340. property Filename: String read fFilename;
  341. procedure LoadFromFile(const aFilename: String);
  342. procedure SaveToFile(const aFilename: String);
  343. procedure LoadFromStream(const aStream: TStream; const aFilename: String);
  344. procedure SaveToStream(const aStream: TStream);
  345. { Generate Shader Code }
  346. private type
  347. TengShaderPartClassMap = specialize TutlMap<string, TengShaderPartClass>;
  348. private
  349. fClasses: TengShaderPartClassMap;
  350. function GetGenerator(const aName: String): TengCodeGenerator;
  351. protected
  352. function GetFindPropertyFlags: TengFindMappedPartFlags; override;
  353. procedure MapData(const aFlags: TengMapDataFlags; const aTypes: array of CengShaderPart); override;
  354. function GetClass(const aName: String): TengShaderPartClass;
  355. procedure AddClass(const aClass: TengShaderPartClass);
  356. procedure GenerateCode(const aGenCodeArgs: TengGenCodeArgs); override;
  357. public
  358. { be carefull with the returned object, it will be destroyed
  359. when the shaderfile is cleared, reloaded or destroyed }
  360. property Generator[const aName: String]: TengCodeGenerator read GetGenerator;
  361. procedure ListGenerators(const aList: TStrings);
  362. { General }
  363. public
  364. procedure Clear;
  365. constructor Create(const aParent: TengShaderPart); override; overload;
  366. constructor Create; overload;
  367. destructor Destroy; override;
  368. end;
  369. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  370. TengShaderPartInclude = class(TengShaderPart)
  371. { Load & Store Code }
  372. private
  373. fShaderFile: TengShaderFile;
  374. fIncludeFile: String;
  375. fAbsoluteFile: String;
  376. protected
  377. function GetCount: Integer; override;
  378. function GetChild(const aIndex: Integer): TengShaderPart; override;
  379. function GetText: String; override;
  380. function ParseTextIntern(const aParseArgs: TengParseArgs; const aParameters: TengTokenParameterList): String; override;
  381. { Generate Code }
  382. private
  383. procedure CheckShaderFile;
  384. protected
  385. procedure MapData(const aFlags: TengMapDataFlags; const aTypes: array of CengShaderPart); override;
  386. procedure GenCodeIntern(const aGenCodeArgs: TengGenCodeArgs); override;
  387. { General }
  388. public
  389. property IncludeFile: String read fIncludeFile;
  390. constructor Create(const aParent: TengShaderPart); override;
  391. destructor Destroy; override;
  392. public
  393. class function GetTokenName: String; override;
  394. end;
  395. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  396. TengShaderPartComment = class(TengShaderPart)
  397. private
  398. fText: String;
  399. protected
  400. function GetText: String; override;
  401. function ParseTextIntern(const aParseArgs: TengParseArgs; const aParameters: TengTokenParameterList): String; override;
  402. public
  403. class function GetTokenName: String; override;
  404. end;
  405. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  406. TengShaderPartInherited = class(TengShaderPart)
  407. { Load & Store Code }
  408. private
  409. fInheritedName: String;
  410. fParameters: TStringList;
  411. protected
  412. function GetText: String; override;
  413. function ParseTextIntern(const aParseArgs: TengParseArgs; const aParameters: TengTokenParameterList): String; override;
  414. { Generate Shader Code }
  415. protected
  416. procedure GenCodeIntern(const aGenCodeArgs: TengGenCodeArgs); override;
  417. { General }
  418. public
  419. constructor Create(const aParent: TengShaderPart); override;
  420. destructor Destroy; override;
  421. public
  422. class function GetTokenName: String; override;
  423. class procedure CheckToken(const aParseArgs: TengParseArgs; const aParent: TengShaderPart); override;
  424. end;
  425. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  426. TengMetaType = (metaNormal, metaVersion, metaExtension, metaLayout);
  427. IengMetaData = interface(IUnknown)
  428. ['{8064AB43-4A82-4E77-BE46-E222827522FF}']
  429. function GetValues(const aIndex: Integer): String;
  430. function GetCount: Integer;
  431. function GetMetaType: TengMetaType;
  432. function GetName: String;
  433. property MetaType: TengMetaType read GetMetaType;
  434. property Name: String read GetName;
  435. property Count: Integer read GetCount;
  436. property Values[const aIndex: Integer]: String read GetValues; default;
  437. end;
  438. TengMetaData = class(TInterfacedObject, IengMetaData)
  439. private
  440. fMetaType: TengMetaType;
  441. fName: String;
  442. fValues: TStringList;
  443. function GetValues(const aIndex: Integer): String;
  444. function GetCount: Integer;
  445. function GetMetaType: TengMetaType;
  446. function GetName: String;
  447. public
  448. property MetaType: TengMetaType read GetMetaType;
  449. property Name: String read GetName;
  450. property Count: Integer read GetCount;
  451. property Values[const aIndex: Integer]: String read GetValues; default;
  452. procedure AddValue(const aValue: String);
  453. constructor Create(const aName: String; const aType: TengMetaType);
  454. destructor Destroy; override;
  455. end;
  456. TengShaderPartMeta = class(TengShaderPart)
  457. private
  458. fMetaData: IengMetaData;
  459. protected
  460. function GetText: String; override;
  461. function ParseTextIntern(const aParseArgs: TengParseArgs; const aParameters: TengTokenParameterList): String; override;
  462. procedure GenCodeIntern(const aGenCodeArgs: TengGenCodeArgs); override;
  463. public
  464. property Data: IengMetaData read fMetaData;
  465. public
  466. destructor Destroy; override;
  467. public
  468. class function GetTokenName: String; override;
  469. end;
  470. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  471. TengShaderPartKeyValuePair = class(TengShaderPart)
  472. { Load & Store Code }
  473. protected
  474. fName: String;
  475. fValue: Variant;
  476. fValueName: String;
  477. function GetText: String; override;
  478. function ParseTextIntern(const aParseArgs: TengParseArgs; const aParameters: TengTokenParameterList): String; override;
  479. public
  480. property Name: String read fName;
  481. property Value: Variant read fValue;
  482. constructor CreateValue(const aParent: TengShaderPart; const aName: String; const aValue: Variant);
  483. constructor CreateName(const aParent: TengShaderPart; const aName, aValueName: String);
  484. { Generate Code }
  485. protected
  486. procedure GenCodeIntern(const aGenCodeArgs: TengGenCodeArgs); override;
  487. end;
  488. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  489. TengShaderPartProperty = class(TengShaderPartKeyValuePair)
  490. public
  491. property Value: Variant read fValue write fValue;
  492. procedure MapData(const aFlags: TengMapDataFlags; const aTypes: array of CengShaderPart); override;
  493. public
  494. class function GetTokenName: String; override;
  495. end;
  496. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  497. TengShaderPartDefine = class(TengShaderPartKeyValuePair)
  498. protected
  499. function ParseTextIntern(const aParseArgs: TengParseArgs; const aParameters: TengTokenParameterList): String; override;
  500. procedure MapData(const aFlags: TengMapDataFlags; const aTypes: array of CengShaderPart); override;
  501. public
  502. class function GetTokenName: String; override;
  503. end;
  504. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  505. TengShaderPartCodeProperty = class(TengShaderPart)
  506. { Load & Store Code }
  507. protected
  508. fName: String;
  509. fType: String;
  510. function GetText: String; override;
  511. function ParseTextIntern(const aParseArgs: TengParseArgs; const aParameters: TengTokenParameterList): String; override;
  512. { Generate Code }
  513. protected
  514. property Name: String read fName;
  515. property PropType: String read fType;
  516. function IsEquals(const aCodeProp: TengShaderPartCodeProperty): Boolean; virtual;
  517. procedure MapData(const aFlags: TengMapDataFlags; const aTypes: array of CengShaderPart); override;
  518. procedure GenCodeIntern(const aGenCodeArgs: TengGenCodeArgs); override;
  519. end;
  520. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  521. TengShaderPartVar = class(TengShaderPartCodeProperty)
  522. { Load & Store Cde }
  523. private
  524. fDefault: String;
  525. protected
  526. function GetText: String; override;
  527. function ParseTextIntern(const aParseArgs: TengParseArgs; const aParameters: TengTokenParameterList): String; override;
  528. { Generate Shader Code }
  529. protected
  530. function IsEquals(const aCodeProp: TengShaderPartCodeProperty): Boolean; override;
  531. procedure GenCodeIntern(const aGenCodeArgs: TengGenCodeArgs); override;
  532. { General }
  533. public
  534. class function GetTokenName: String; override;
  535. end;
  536. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  537. TengShaderPartVarying = class(TengShaderPartCodeProperty)
  538. { Generate Shader Code }
  539. protected
  540. procedure GenCodeIntern(const aGenCodeArgs: TengGenCodeArgs); override;
  541. { General }
  542. public
  543. class function GetTokenName: String; override;
  544. end;
  545. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  546. TengShaderPartUniform = class(TengShaderPartCodeProperty)
  547. { Generate Shader Code }
  548. protected
  549. procedure GenCodeIntern(const aGenCodeArgs: TengGenCodeArgs); override;
  550. { General }
  551. public
  552. class function GetTokenName: String; override;
  553. end;
  554. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  555. TengShaderPartCall = class(TengShaderPart)
  556. { Load & Store Code }
  557. private
  558. fName: String;
  559. fParameters: TStringList;
  560. protected
  561. function GetText: String; override;
  562. function ParseTextIntern(const aParseArgs: TengParseArgs; const aParameters: TengTokenParameterList): String; override;
  563. { Generate Shader Code }
  564. protected
  565. procedure GenCodeIntern(const aGenCodeArgs: TengGenCodeArgs); override;
  566. { General }
  567. public
  568. constructor Create(const aParent: TengShaderPart); override;
  569. destructor Destroy; override;
  570. public
  571. class function GetTokenName: String; override;
  572. end;
  573. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  574. TengShaderPartProcParam = packed record
  575. Typ: String;
  576. Name: String;
  577. end;
  578. TengShaderPartProcParamList = specialize TutlSimpleList<TengShaderPartProcParam>;
  579. TengShaderPartProc = class(TengShaderPartScope)
  580. { Load & Store Code }
  581. private
  582. fName: String;
  583. fIsInline: Boolean;
  584. fParameters: TengShaderPartProcParamList;
  585. protected
  586. function GetHeaderText: String; virtual;
  587. function GetText: String; override;
  588. function ParseTextIntern(const aParseArgs: TengParseArgs; const aParameters: TengTokenParameterList): String; override;
  589. { Generate Shader Code }
  590. protected
  591. function GenHeaderCode: String; virtual;
  592. procedure GenInlineCode(const aGenCodeArgs: TengGenCodeArgs; const aAddToken: Boolean = true); virtual;
  593. procedure GenCodeIntern(const aGenCodeArgs: TengGenCodeArgs); override;
  594. procedure MapData(const aFlags: TengMapDataFlags; const aTypes: array of CengShaderPart); override;
  595. { General }
  596. public
  597. property Name: String read fName;
  598. property IsInline: Boolean read fIsInline;
  599. constructor Create(const aParent: TengShaderPart); override;
  600. destructor Destroy; override;
  601. public
  602. class function GetTokenName: String; override;
  603. class procedure CheckToken(const aParseArgs: TengParseArgs; const aParent: TengShaderPart); override;
  604. end;
  605. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  606. TengShaderPartMain = class(TengShaderPartProc)
  607. { Save & Store Code }
  608. protected
  609. function GetHeaderText: String; override;
  610. function ParseTextIntern(const aParseArgs: TengParseArgs; const aParameters: TengTokenParameterList): String; override;
  611. { Generate Code }
  612. protected
  613. function GenHeaderCode: String; override;
  614. { General }
  615. public
  616. class function GetTokenName: String; override;
  617. end;
  618. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  619. TengShaderPartFunc = class(TengShaderPartProc)
  620. { Save & Store Code }
  621. private
  622. fReturnType: String;
  623. protected
  624. function GetHeaderText: String; override;
  625. function ParseTextIntern(const aParseArgs: TengParseArgs; const aParameters: TengTokenParameterList): String; override;
  626. public
  627. property ReturnType: String read fReturnType;
  628. { Generate Code }
  629. protected
  630. procedure GenInlineCode(const aGenCodeArgs: TengGenCodeArgs; const aAddToken: Boolean = true); override;
  631. function GenHeaderCode: String; override;
  632. { General }
  633. public
  634. class function GetTokenName: String; override;
  635. class procedure CheckToken(const aParseArgs: TengParseArgs; const aParent: TengShaderPart); override;
  636. end;
  637. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  638. TengShaderPartIf = class(TengShaderPart)
  639. { Load & Store Code }
  640. private
  641. fExpression: TengExpressionItem;
  642. fIfPart: TengShaderPart;
  643. fElsePart: TengShaderPart;
  644. function ParseExpression(const aParameters: TengTokenParameterList; aIndex: Integer): TengExpressionItem;
  645. protected
  646. function GetCount: Integer; override;
  647. function GetChild(const aIndex: Integer): TengShaderPart; override;
  648. function GetText: String; override;
  649. function ParseTextIntern(const aParseArgs: TengParseArgs; const aParameters: TengTokenParameterList): String; override;
  650. function HandleToken(const aToken: String; const aParseArgs: TengParseArgs): String;
  651. function HandleEndToken(const aToken: String; const aParseArgs: TengParseArgs): String; virtual;
  652. { Generate Shader Code }
  653. protected
  654. procedure MapData(const aFlags: TengMapDataFlags; const aTypes: array of CengShaderPart); override;
  655. procedure GenCodeIntern(const aGenCodeArgs: TengGenCodeArgs); override;
  656. { General }
  657. public
  658. destructor Destroy; override;
  659. public
  660. class function GetTokenName: String; override;
  661. end;
  662. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  663. TengShaderPartElIf = class(TengShaderPartIf)
  664. protected
  665. function GetText: String; override;
  666. function HandleEndToken(const aToken: String; const aParseArgs: TengParseArgs): String; override;
  667. public
  668. class function GetTokenName: String; override;
  669. end;
  670. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  671. TengShaderPartElse = class(TengShaderPartContainer)
  672. protected
  673. function GetText: String; override;
  674. public
  675. class function GetTokenName: String; override;
  676. end;
  677. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  678. TengShaderPartEcho = class(TengShaderPart)
  679. { Load & Store Code }
  680. private
  681. fName: String;
  682. protected
  683. function GetText: String; override;
  684. function ParseTextIntern(const aParseArgs: TengParseArgs; const aParameters: TengTokenParameterList): String; override;
  685. { Generate Shader Code }
  686. protected
  687. procedure GenCodeIntern(const aGenCodeArgs: TengGenCodeArgs); override;
  688. { General }
  689. public
  690. class function GetTokenName: String; override;
  691. end;
  692. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  693. TengShaderPartMessage = class(TengShaderPart)
  694. private
  695. fMessage: String;
  696. protected
  697. function GetText: String; override;
  698. function ParseTextIntern(const aParseArgs: TengParseArgs; const aParameters: TengTokenParameterList): String; override;
  699. public
  700. class function GetTokenName: String; override;
  701. end;
  702. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  703. TengShaderPartWarning = class(TengShaderPartMessage)
  704. public
  705. class function GetTokenName: String; override;
  706. end;
  707. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  708. TengShaderPartError = class(TengShaderPartMessage)
  709. protected
  710. procedure GenCodeIntern(const aGenCodeArgs: TengGenCodeArgs); override;
  711. public
  712. class function GetTokenName: String; override;
  713. end;
  714. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  715. TengShaderPartCode = class(TengShaderPart)
  716. { Load & Store Code }
  717. private
  718. fCode: String;
  719. protected
  720. function GetText: String; override;
  721. function ParseTextIntern(const aParseArgs: TengParseArgs; const aParameters: TengTokenParameterList): String; override;
  722. public
  723. property Code: String read fCode;
  724. { Generate Shader Code }
  725. protected
  726. procedure GenCodeIntern(const aGenCodeArgs: TengGenCodeArgs); override;
  727. end;
  728. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  729. TengShaderPartLineBreak = class(TengShaderPart)
  730. { Load & Store Code }
  731. protected
  732. function GetText: String; override;
  733. function ParseTextIntern(const aParseArgs: TengParseArgs; const aParameters: TengTokenParameterList): String; override;
  734. { Generate Shader Code }
  735. protected
  736. procedure GenCodeIntern(const aGenCodeArgs: TengGenCodeArgs); override;
  737. { General }
  738. public
  739. class function GetTokenName: String; override;
  740. end;
  741. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  742. TengShaderPartCommandEnd = class(TengShaderPart)
  743. { Load & Store Code }
  744. private
  745. fToken: String;
  746. protected
  747. function GetText: String; override;
  748. function ParseTextIntern(const aParseArgs: TengParseArgs; const aParameters: TengTokenParameterList): String; override;
  749. { Generate Shader Code }
  750. protected
  751. procedure GenCodeIntern(const aGenCodeArgs: TengGenCodeArgs); override;
  752. { General }
  753. public
  754. class function CheckToken(const aToken: String): Boolean; override;
  755. end;
  756. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  757. //HELPER////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  758. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  759. TengShaderCode = class(TStringList)
  760. private type
  761. TMetaList = specialize TutlList<IengMetaData>;
  762. private
  763. function GetMeta(const aIndex: Integer): IengMetaData;
  764. function GetMetaCount: Integer;
  765. protected
  766. fMetaList: TMetaList;
  767. public
  768. property Meta[const aIndex: Integer]: IengMetaData read GetMeta;
  769. property MetaCount: Integer read GetMetaCount;
  770. constructor Create;
  771. destructor Destroy; override;
  772. end;
  773. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  774. TengShaderCodeIntern = class(TengShaderCode)
  775. public
  776. property MetaList: TMetaList read fMetaList;
  777. procedure AddMeta(const aMeta: IengMetaData);
  778. end;
  779. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  780. TengParseArgs = class
  781. private
  782. fCode: TStringList;
  783. fLineLength: Integer;
  784. fLineCount: Integer;
  785. fCurrentLine: String;
  786. fCurrentChar: Char;
  787. fCol: Integer;
  788. fLine: Integer;
  789. fOwner: TengShaderFile;
  790. procedure SetCol(const aValue: Integer);
  791. procedure SetLine(const aValue: Integer);
  792. function GetEndOfLine: Boolean;
  793. function GetEndOfFile: Boolean;
  794. function GetCode: TStrings;
  795. public
  796. property Code: TStrings read GetCode;
  797. property LineLength: Integer read fLineLength;
  798. property LineCount: Integer read fLineCount;
  799. property CurrentLine: String read fCurrentLine;
  800. property CurrentChar: Char read fCurrentChar;
  801. property EndOfLine: Boolean read GetEndOfLine;
  802. property EndOfFile: Boolean read GetEndOfFile;
  803. property Col: Integer read fCol write SetCol;
  804. property Line: Integer read fLine write SetLine;
  805. procedure IncCol;
  806. procedure IncLine;
  807. function ParseParameters(const aParameters: TengTokenParameterList): Boolean;
  808. procedure LoadCode(const aStream: TStream);
  809. constructor Create(const aOwner: TengShaderFile);
  810. destructor Destroy; override;
  811. end;
  812. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  813. TengGenCodeFlag = (
  814. gcfGenProcedure, // generate shader code for procedure or function
  815. gcfGenProcInline, // generate inline shader code for procedure or function
  816. gcfGenProcCall, // generate procedure call
  817. gcfGenCodeProp // generate shader code for code properties (e.g. Var, Varying, Uniform)
  818. );
  819. TengGenCodeFlags = set of TengGenCodeFlag;
  820. TengGenCodeArgs = class(TObject)
  821. private type
  822. TCodeItem = class
  823. public
  824. function GetText: String; virtual;
  825. function IsEmpty: Boolean;
  826. end;
  827. TCodeItemStart = class(TCodeItem)
  828. function GetText: String; override;
  829. end;
  830. TCodeItemText = class(TCodeItem)
  831. public
  832. Text: String;
  833. function GetText: String; override;
  834. constructor Create(const aText: String);
  835. end;
  836. TCodeItemLineBreak = class(TCodeItem)
  837. public
  838. function GetText: String; override;
  839. end;
  840. TCodeItemCommandEnd = class(TCodeItem)
  841. public
  842. Token: String;
  843. function GetText: String; override;
  844. constructor Create(const aToken: String);
  845. end;
  846. TTokenType = (ttBegin, ttEnd, ttSingle);
  847. TCodeItemToken = class(TCodeItem)
  848. public
  849. TokenType: TTokenType;
  850. Level: Integer;
  851. constructor Create(const aTokenType: TTokenType; const aLevel: Integer = -1);
  852. end;
  853. TCodeItemList = specialize TutlList<TCodeItem>;
  854. TCodeStackItem = class
  855. private type
  856. TFlag = (cfIgnoreNextSemicolon);
  857. TFlags = set of TFlag;
  858. private
  859. fFlags: TFlags;
  860. fItems: TCodeItemList;
  861. function GetEmpty: Boolean;
  862. public
  863. property Items: TCodeItemList read fItems;
  864. property Empty: Boolean read GetEmpty;
  865. {$IFDEF DEBUG}
  866. function GetDebugText: String;
  867. {$ENDIF}
  868. function GetText: String;
  869. procedure SplitCurrentCommand(const aItem: TCodeStackItem);
  870. function Merge(const aItem: TCodeStackItem; aIndex: Integer): Integer;
  871. procedure AddText(const aText: String);
  872. procedure AddCommandEnd(const aToken: String = '');
  873. procedure AddToken(const aTokenType: TTokenType; const aLevel: Integer = -1);
  874. procedure AddLineEnd;
  875. function GetMinLineOffset: Integer;
  876. procedure IgnoreNextSemicolon;
  877. procedure ReplaceIdents(const aOld, aNew: TStrings);
  878. procedure ReplaceReturns(const aItem: TCodeStackItem; const aRetType, aFuncName: String; const aCntr: Integer);
  879. constructor Create;
  880. destructor Destroy; override;
  881. end;
  882. TProcWrapper = class
  883. public
  884. Proc: TengShaderPartProc;
  885. Code: TCodeStackItem;
  886. constructor Create;
  887. destructor Destroy; override;
  888. end;
  889. TCodeStack = specialize TutlList<TCodeStackItem>;
  890. TProcParamStack = specialize TutlList<TStrings>;
  891. TGenCodeFlagsStack = specialize TutlList<TengGenCodeFlags>;
  892. TProcedureList = specialize TutlList<TProcWrapper>;
  893. TCodePropertyMap = specialize TutlMap<string, TengShaderPartCodeProperty>;
  894. public type
  895. TPopCodeFlag = (
  896. pcfAppend,
  897. pcfPrepend,
  898. pcfAddEmptyLine
  899. );
  900. TPopCodeFlags = set of TPopCodeFlag;
  901. private
  902. fMaxPropNameLen: Integer;
  903. fRoot: TengShaderPartScope;
  904. fFlags: TGenCodeFlagsStack;
  905. fProcParams: TProcParamStack;
  906. fProcedures: TProcedureList;
  907. fProperties: TCodePropertyMap;
  908. fCode: TCodeStack;
  909. fCommands: TCodeStack;
  910. fShaderCode: TengShaderCodeIntern;
  911. fInlineRetCounter: Integer;
  912. function GetFlags: TengGenCodeFlags;
  913. function GetText: String;
  914. function GetCode: TCodeStackItem;
  915. function GetProcParams: TStrings;
  916. public
  917. property Root: TengShaderPartScope read fRoot;
  918. property Flags: TengGenCodeFlags read GetFlags;
  919. property Code: TCodeStackItem read GetCode;
  920. property ProcParams: TStrings read GetProcParams;
  921. property MaxPropNameLen: Integer read fMaxPropNameLen;
  922. procedure PushCode;
  923. procedure InsertCode(const aCodeStackItem: TCodeStackItem);
  924. function PushCurrentCommand: TCodeStackItem;
  925. procedure PushFlags(const aFlags: TengGenCodeFlags);
  926. procedure PushProcParams(const aParams: TStrings);
  927. procedure PopCode(const aFlags: TPopCodeFlags = [pcfAppend]);
  928. function ExtractCode: TCodeStackItem;
  929. procedure PopCurrentCommand(const aRetType, aFuncName: String);
  930. procedure PopFlags;
  931. procedure PopProcParams;
  932. procedure AddProcedure(const aProc: TengShaderPartProc);
  933. procedure AddCodeProperty(const aProp: TengShaderPartCodeProperty);
  934. procedure AddMeta(const aMeta: IengMetaData);
  935. function HasCodeProperty(const aName: String): Boolean;
  936. procedure GenProcedureCode(const aAppend: Boolean = false);
  937. procedure GenCodePropertyCode(const aTypes: array of CengShaderPart);
  938. procedure GenMetaCode;
  939. constructor Create(const aShaderCode: TengShaderCodeIntern; const aRoot: TengShaderPartScope);
  940. destructor Destroy; override;
  941. end;
  942. function TrySetProperty(const aGenerator: TengCodeGenerator; const aName: String; const aValue: Variant): Boolean;
  943. {$IFDEF DEBUG}
  944. procedure SaveAsXMindXml(const aShaderPart: TengShaderPart; const aDirectory: String);
  945. {$ENDIF}
  946. implementation
  947. uses
  948. uutlExceptions, FileUtil, RegExpr, Math{$IFDEF USE_VFS}, uvfsManager{$ENDIF};
  949. const
  950. PRECOMPILER_STATEMENT_BEGIN = '{';
  951. PRECOMPILER_STATEMENT_END = '}';
  952. PRECOMPILER_QUOTE_CHAR = '''';
  953. TOKEN_IDENTIFIER = '$';
  954. TOKEN_COMMAND_END = ';';
  955. TOKEN_SCOPE_BEGIN = '{';
  956. TOKEN_SCOPE_END = '}';
  957. TOKEN_LINE_BREAK = sLineBreak;
  958. COMMENT_IDENTIFIER = '.';
  959. TOKEN_CLASS = TOKEN_IDENTIFIER + 'CLASS'; //{$CLASS PhongLight $EXTENDS Normal Glow}
  960. TOKEN_EXTENDS = TOKEN_IDENTIFIER + 'EXTENDS';
  961. TOKEN_INHERITED = TOKEN_IDENTIFIER + 'INHERITED'; //{$INHERITED} {$INHERITED BaseClass}
  962. TOKEN_INCLUDE = TOKEN_IDENTIFIER + 'INCLUDE'; //{$INCLUDE 'Normal.frag'}
  963. TOKEN_META = TOKEN_IDENTIFIER + 'META'; //{$META 'Fuu' 'Bar'}
  964. TOKEN_VERSION = TOKEN_IDENTIFIER + 'VERSION'; //{$META $VERSION 'version'}
  965. TOKEN_EXTENSION = TOKEN_IDENTIFIER + 'EXTENSION'; //{$META $EXTENSION 'GL_ARB_geometry_shader4' 'enable'}
  966. TOKEN_LAYOUT = TOKEN_IDENTIFIER + 'LAYOUT'; //{$META $LAYOUT '(line_strip, max_vertices = 6) out'}
  967. TOKEN_PROPERTY = TOKEN_IDENTIFIER + 'PROPERTY'; //{$PROPERTY InvertRoughmap 'false'}
  968. TOKEN_DEFINE = TOKEN_IDENTIFIER + 'DEFINE'; //{$DEFINE RENDER_FACE_FRONT '0'}
  969. TOKEN_ECHO = TOKEN_IDENTIFIER + 'ECHO'; //{$ECHO InvertRoughmap}
  970. TOKEN_VAR = TOKEN_IDENTIFIER + 'VAR'; //{$VAR 'float' 'refractivity' '0.0'}
  971. TOKEN_VARYING = TOKEN_IDENTIFIER + 'VARYING'; //{$VARYING 'vec3' 'vVertex'}
  972. TOKEN_UNIFORM = TOKEN_IDENTIFIER + 'UNIFORM'; //{$UNIFORM 'sampler2D' 'uShadowMap'}
  973. TOKEN_CALL = TOKEN_IDENTIFIER + 'CALL'; //{$CALL CalcLight}
  974. TOKEN_PROC = TOKEN_IDENTIFIER + 'PROC'; //{$PROC CalcLight} Code... {$END}
  975. TOKEN_FUNC = TOKEN_IDENTIFIER + 'FUNC'; //{$FUND 'float' 'ShadowPoisson' 'vec2' 'shadowMapST' 'float' 'receiver'} Code... {$END}
  976. TOKEN_MAIN = TOKEN_IDENTIFIER + 'MAIN';
  977. TOKEN_INLINE = TOKEN_IDENTIFIER + 'INLINE'; //{$PROC CalcLight $INLINE} Code... {$END}
  978. TOKEN_IF = TOKEN_IDENTIFIER + 'IF'; //{$IF PhongLight = '0'} Code ... {$END}
  979. TOKEN_ELIF = TOKEN_IDENTIFIER + 'ELIF';
  980. TOKEN_ELSE = TOKEN_IDENTIFIER + 'ELSE';
  981. TOKEN_END = TOKEN_IDENTIFIER + 'END';
  982. TOKEN_MESSAGE = TOKEN_IDENTIFIER + 'MESSAGE'; //{$MESSAGE 'message'}
  983. TOKEN_WARNING = TOKEN_IDENTIFIER + 'WARNING'; //{$WARNING 'message'}
  984. TOKEN_ERROR = TOKEN_IDENTIFIER + 'ERROR'; //{$ERROR 'message'}
  985. TOKEN_OP_LOGICAL_NOT = TOKEN_IDENTIFIER + 'NOT'; //{$IF $NOT test}
  986. TOKEN_OP_LOGICAL_OR = TOKEN_IDENTIFIER + 'OR'; //{$IF test1 $OR test2}
  987. TOKEN_OP_LOGICAL_AND = TOKEN_IDENTIFIER + 'AND'; //{$IF test1 $AND test2}
  988. TOKEN_OP_LOGICAL_XOR = TOKEN_IDENTIFIER + 'XOR'; //{$IF test1 $XOR test2}
  989. TOKEN_OP_DEFINED = TOKEN_IDENTIFIER + 'DEFINED'; //{$IF $DEFINED test2}
  990. TOKEN_OP_SET = TOKEN_IDENTIFIER + 'SET'; //{$IF $SET vVertex}
  991. TOKEN_OP_ADD = '+'; //{$IF test1 + test2}
  992. TOKEN_OP_SUBTRACT = '-'; //{$IF test1 - test2}
  993. TOKEN_OP_MULTIPLY = '*'; //{$IF test1 * test2}
  994. TOKEN_OP_DIVIDE = '/'; //{$IF test1 / test2}
  995. TOKEN_OP_EQUALS = '='; //{$IF test1 = test2}
  996. TOKEN_OP_LESSER = '<'; //{$IF test1 < test2}
  997. TOKEN_OP_GREATER = '>'; //{$IF test1 > test2}
  998. TOKEN_OP_LEQUALS = '<='; //{$IF test1 <= test2}
  999. TOKEN_OP_GEQUALS = '>='; //{$IF test1 >= test2}
  1000. TOKEN_OP_UNEQUALS = '<>'; //{$IF test1 <> test2}
  1001. TOKEN_OP_BINARY_OR = '|'; //{$IF test1 | test2}
  1002. TOKEN_OP_BINARY_AND = '&'; //{$IF test1 & test2}
  1003. TOKEN_OP_BINARY_XOR = '^'; //{$IF test1 ^ test2}
  1004. TOKEN_OP_BINARY_NOT = '!'; //{$IF !test1}
  1005. TOKEN_OP_GROUP_BEGIN = '('; //{$IF (test1 $OR test2) >= '0'}
  1006. TOKEN_OP_GROUP_END = ')';
  1007. WHITESPACES = [' ', #9];
  1008. VALID_IDENT_CHARS = ['A'..'Z', 'a'..'z', '0'..'9', '_'];
  1009. VALID_TOKEN_CHARS = ['$'] + VALID_IDENT_CHARS;
  1010. TOKEN_SPLIT_CHARS = [' ', #9, TOKEN_OP_GROUP_BEGIN, TOKEN_OP_GROUP_END];
  1011. LAYOUT_MIN_VERSION = 150;
  1012. VERSION_EXTRA_COMPAT = 'compatibility'; //{$META $VERSION 'compatibility'}
  1013. EXPRESSION_UNARY_OPERATIONS: array[TengExpressionUnaryOperator] of String = (
  1014. TOKEN_OP_BINARY_NOT, //opBinaryNot
  1015. TOKEN_OP_LOGICAL_NOT, //opLogicalNot
  1016. TOKEN_OP_DEFINED, //opDefined
  1017. TOKEN_OP_SET //opSet
  1018. );
  1019. EXPRESSION_BINARY_OPERATIONS: array[TengExpressionBinaryOperator] of String = (
  1020. TOKEN_OP_BINARY_OR, //opBinaryOr
  1021. TOKEN_OP_BINARY_AND, //opBinaryAnd
  1022. TOKEN_OP_BINARY_XOR, //opBinaryXor
  1023. TOKEN_OP_MULTIPLY, //opMultiply
  1024. TOKEN_OP_DIVIDE, //opDivide
  1025. TOKEN_OP_ADD, //opAdd
  1026. TOKEN_OP_SUBTRACT, //opSubtract
  1027. TOKEN_OP_LOGICAL_OR, //opLogicalOr
  1028. TOKEN_OP_LOGICAL_AND, //opLogicalAnd
  1029. TOKEN_OP_LOGICAL_XOR, //opLogicalXor
  1030. TOKEN_OP_EQUALS, //opEquals
  1031. TOKEN_OP_LESSER, //opLesser
  1032. TOKEN_OP_GREATER, //opGreater
  1033. TOKEN_OP_LEQUALS, //opLEquals
  1034. TOKEN_OP_GEQUALS, //opGEquals
  1035. TOKEN_OP_UNEQUALS //opUnequals,
  1036. );
  1037. TOKEN_CLASSES: array[0..20] of CengShaderPart = (
  1038. TengShaderPartProperty,
  1039. TengShaderPartClass,
  1040. TengShaderPartDefine,
  1041. TengShaderPartError,
  1042. TengShaderPartIf,
  1043. TengShaderPartInclude,
  1044. TengShaderPartMessage,
  1045. TengShaderPartMeta,
  1046. TengShaderPartCall,
  1047. TengShaderPartProc,
  1048. TengShaderPartFunc,
  1049. TengShaderPartMain,
  1050. TengShaderPartInherited,
  1051. TengShaderPartUniform,
  1052. TengShaderPartVar,
  1053. TengShaderPartVarying,
  1054. TengShaderPartWarning,
  1055. TengShaderPartLineBreak,
  1056. TengShaderPartCommandEnd,
  1057. TengShaderPartComment,
  1058. TengShaderPartEcho);
  1059. COMMAND_END_TOKENS = [TOKEN_COMMAND_END, TOKEN_SCOPE_BEGIN, TOKEN_SCOPE_END];
  1060. FIND_OVERWRITTEN_FLAGS: TengFindMappedPartFlags = [ffLocal, ffInherited]; // search all ShaderParts in current and inherited scopes
  1061. FIND_INHERITED_FLAGS: TengFindMappedPartFlags = [ffInherited]; // search in inherited scropes only
  1062. FIND_IN_SCOPE_FLAGS: TengFindMappedPartFlags = [ffLocal, ffAscending, ffInherited, ffFile]; // search in current, all parent, all interhited scopes and in file the scope
  1063. FIND_GLOBAL: TengFindMappedPartFlags = [ffGlobal, ffLocal]; // search in root file only (for defines that are set from the program)
  1064. GEN_CODE_FIND_FLAGS: TengFindMappedPartFlags = [ffLocal, ffAscending, ffInherited, ffFile, ffVisited]; // search in current, all parent, all inherited scopes and in file scope, but search only in already visited scopes
  1065. FIND_PROPERTY_FLAGS: TengFindMappedPartFlags = [ffLocal, ffDescending, ffInherited]; // search in current, all inherited and all child scopes
  1066. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1067. {$IFDEF DEBUG}
  1068. function MakeDebugStr(const aItems: TengGenCodeArgs.TCodeItemList; const aFilename: String): String;
  1069. var
  1070. i: TengGenCodeArgs.TCodeItem;
  1071. fs: TFileStream;
  1072. begin
  1073. fs := TFileStream.Create(aFilename, fmCreate);
  1074. try
  1075. result := '';
  1076. for i in aItems do begin
  1077. result := result + i.ClassName;
  1078. result := result + '(';
  1079. if (i is TengGenCodeArgs.TCodeItemLineBreak) then
  1080. result := result + 'LB)' + sLineBreak + sLineBreak
  1081. else
  1082. result := result + i.GetText + ')' + sLineBreak;
  1083. end;
  1084. fs.Write(result[1], Length(result));
  1085. finally
  1086. FreeAndNil(fs);
  1087. end;
  1088. end;
  1089. {$ENDIF}
  1090. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1091. function TrySetProperty(const aGenerator: TengCodeGenerator; const aName: String; const aValue: Variant): Boolean;
  1092. var
  1093. prop: TengShaderPartProperty;
  1094. begin
  1095. prop := aGenerator.Properties[aName];
  1096. result := Assigned(prop);
  1097. if result then
  1098. prop.Value := aValue;
  1099. end;
  1100. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1101. function IsValidIdentifier(const aIdent: String): Boolean;
  1102. var
  1103. i, len: Integer;
  1104. begin
  1105. len := Length(aIdent);
  1106. result := false;
  1107. for i := 1 to len do
  1108. if not (aIdent[i] in VALID_IDENT_CHARS) then
  1109. exit;
  1110. result := true;
  1111. end;
  1112. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1113. function CheckEndToken(const aParseArgs: TengParseArgs; const aShaderPart: TengShaderPart): String;
  1114. var
  1115. oldLine, oldCol: Integer;
  1116. param: TengTokenParameterList;
  1117. begin
  1118. param := TengTokenParameterList.Create;
  1119. try
  1120. oldLine := aParseArgs.Line;
  1121. oldCol := aParseArgs.Col;
  1122. if not aParseArgs.ParseParameters(param) then
  1123. raise EengInvalidToken.Create('expected ' + TOKEN_END, oldLine, oldCol, aShaderPart.Filename);
  1124. if (param[0].Name <> TOKEN_END) then
  1125. raise EengInvalidToken.Create(aShaderPart.ClassName, param[0].Name, oldLine, oldCol, aShaderPart.Filename);
  1126. if (param.Count <> 1) then
  1127. raise EengInvalidParamterCount.Create(TOKEN_END, oldLine, oldCol, aShaderPart.Filename);
  1128. result := '';
  1129. finally
  1130. FreeAndNil(param);
  1131. end;
  1132. end;
  1133. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1134. function CheckType(const aShaderPart: TengShaderPart; const aTypes: array of CengShaderPart): Boolean;
  1135. var
  1136. t: CengShaderPart;
  1137. begin
  1138. result := true;
  1139. for t in aTypes do
  1140. if (aShaderPart is t) then
  1141. exit;
  1142. result := (Length(aTypes) = 0);
  1143. end;
  1144. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1145. function CheckParentScope(const aShaderPart: TengShaderPart): TengShaderPartScope;
  1146. begin
  1147. aShaderPart.GetParentType(TengShaderPartScope, result);
  1148. if not Assigned(result) then
  1149. raise EengInternal.Create('this part has no container parent');
  1150. end;
  1151. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1152. //TengExpressionItem////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1153. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1154. function TengExpressionItem.GetText: String;
  1155. begin
  1156. result := '';
  1157. end;
  1158. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1159. function TengExpressionItem.GetValue(const aScope: TengShaderPartScope; const aGenCodeArgs: TengGenCodeArgs): Variant;
  1160. begin
  1161. result := Unassigned;
  1162. end;
  1163. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1164. constructor TengExpressionItem.Create(const aLine, aCol: Integer; const aFilename: String);
  1165. begin
  1166. inherited Create;
  1167. fLine := aLine;
  1168. fCol := aCol;
  1169. fFilename := aFilename;
  1170. end;
  1171. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1172. //TengExpressionItemSingle//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1173. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1174. function TengExpressionValue.GetText: String;
  1175. begin
  1176. result := '''' + fValue + '''';
  1177. end;
  1178. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1179. function TengExpressionValue.GetValue(const aScope: TengShaderPartScope; const aGenCodeArgs: TengGenCodeArgs): Variant;
  1180. begin
  1181. result := fValue;
  1182. end;
  1183. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1184. constructor TengExpressionValue.Create(const aValue: Variant; const aLine, aCol: Integer; const aFilename: String);
  1185. begin
  1186. inherited Create(aLine, aCol, aFilename);
  1187. fValue := aValue;
  1188. end;
  1189. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1190. //TengExpressionVariable////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1191. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1192. function TengExpressionVariable.GetText: String;
  1193. begin
  1194. result := fVariableName;
  1195. end;
  1196. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1197. function TengExpressionVariable.GetValue(const aScope: TengShaderPartScope; const aGenCodeArgs: TengGenCodeArgs): Variant;
  1198. var
  1199. p: TengShaderPart;
  1200. begin
  1201. aScope.FindMappedPart(p, fVariableName, FIND_IN_SCOPE_FLAGS);
  1202. if not Assigned(p) then begin
  1203. aScope.FindMappedPart(p, fVariableName, FIND_GLOBAL);
  1204. if not Assigned(p) then
  1205. raise EengUnknownIdentifier.Create(fVariableName, fLine, fCol, fFilename)
  1206. end
  1207. else if not (p is TengShaderPartProperty) and not (p is TengShaderPartDefine) then
  1208. raise EengInvalidParamter.Create('unexpected type, expected ' +
  1209. TengShaderPartProperty.GetTokenName + ' or ' +
  1210. TengShaderPartDefine.GetTokenName,
  1211. fLine, fCol, fFilename)
  1212. else
  1213. result := (p as TengShaderPartKeyValuePair).Value;
  1214. end;
  1215. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1216. constructor TengExpressionVariable.Create(const aVariableName: String; const aLine, aCol: Integer; const aFilename: String);
  1217. begin
  1218. inherited Create(aLine, aCol, aFilename);
  1219. fVariableName := aVariableName;
  1220. end;
  1221. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1222. //TengExpressionGroup///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1223. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1224. function TengExpressionGroup.GetText: String;
  1225. begin
  1226. if Assigned(fChild) then
  1227. result := TOKEN_OP_GROUP_BEGIN + fChild.GetText + TOKEN_OP_GROUP_END
  1228. else
  1229. result := '';
  1230. end;
  1231. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1232. function TengExpressionGroup.GetValue(const aScope: TengShaderPartScope; const aGenCodeArgs: TengGenCodeArgs): Variant;
  1233. begin
  1234. result := fChild.GetValue(aScope, aGenCodeArgs);
  1235. end;
  1236. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1237. constructor TengExpressionGroup.Create(const aChild: TengExpressionItem; const aLine, aCol: Integer; const aFilename: String);
  1238. begin
  1239. inherited Create(aLine, aCol, aFilename);
  1240. fChild := aChild;
  1241. end;
  1242. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1243. destructor TengExpressionGroup.Destroy;
  1244. begin
  1245. FreeAndNil(fChild);
  1246. inherited Destroy;
  1247. end;
  1248. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1249. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1250. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1251. function TengExpressionUnaryOperation.GetText: String;
  1252. begin
  1253. if not Assigned(fChild) then
  1254. EengExpression.Create('no child assigned');
  1255. result :=
  1256. {$IFDEF EXPRESSION_ADD_BRACKET}TOKEN_OP_GROUP_BEGIN +{$ENDIF}
  1257. EXPRESSION_UNARY_OPERATIONS[fUnaryOp] + ' ' + fChild.GetText
  1258. {$IFDEF EXPRESSION_ADD_BRACKET} + TOKEN_OP_GROUP_END{$ENDIF};
  1259. end;
  1260. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1261. function TengExpressionUnaryOperation.GetValue(const aScope: TengShaderPartScope; const aGenCodeArgs: TengGenCodeArgs): Variant;
  1262. var
  1263. p: TengShaderPart;
  1264. v: Variant;
  1265. begin
  1266. try
  1267. case fUnaryOp of
  1268. opBinaryNot: begin
  1269. v := fChild.GetValue(aScope, aGenCodeArgs);
  1270. result := not Integer(v);
  1271. end;
  1272. opLogicalNot: begin
  1273. v := fChild.GetValue(aScope, aGenCodeArgs);
  1274. result := not Boolean(v);
  1275. end;
  1276. opDefined: begin
  1277. v := (fChild as TengExpressionVariable).fVariableName;
  1278. if not (fChild is TengExpressionVariable) then
  1279. raise EengInternal.Create('child is not a variable', fLine, fCol, fFilename);
  1280. aScope.FindMappedPart(p, (fChild as TengExpressionVariable).fVariableName, FIND_IN_SCOPE_FLAGS);
  1281. result := Assigned(p);
  1282. if result and (not (p is TengShaderPartProperty) or not (p is TengShaderPartDefine)) then with fChild do
  1283. raise EengInvalidParamter.Create('unexpected type, expected ' +
  1284. TengShaderPartProperty.GetTokenName + ' or ' +
  1285. TengShaderPartDefine.GetTokenName,
  1286. fLine, fCol, fFilename);
  1287. end;
  1288. opSet: begin
  1289. if Assigned(aGenCodeArgs) then begin
  1290. if not (fChild is TengExpressionVariable) then
  1291. raise EengInternal.Create('child is not a variable', fLine, fCol, fFilename);
  1292. result := aGenCodeArgs.HasCodeProperty((fChild as TengExpressionVariable).fVariableName);
  1293. end else
  1294. result := false;
  1295. end
  1296. else
  1297. result := inherited GetValue(aScope, aGenCodeArgs);
  1298. end;
  1299. except
  1300. on ex: Exception do
  1301. raise EengInvalidParamter.Create(ex.Message + ' ("' + GetText + '" ==> "' + EXPRESSION_UNARY_OPERATIONS[fUnaryOp] + ' ' + v + '")', fLine, fCol, fFilename);
  1302. end;
  1303. end;
  1304. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1305. constructor TengExpressionUnaryOperation.Create(const aUnaryOp: TengExpressionUnaryOperator; const aLine, aCol: Integer; const aFilename: String);
  1306. begin
  1307. inherited Create(aLine, aCol, aFilename);
  1308. fUnaryOp := aUnaryOp;
  1309. fChild := nil;
  1310. end;
  1311. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1312. destructor TengExpressionUnaryOperation.Destroy;
  1313. begin
  1314. FreeAndNil(fChild);
  1315. inherited Destroy;
  1316. end;
  1317. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1318. //TengExpressionBinaryOperation///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1319. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1320. function TengExpressionBinaryOperation.GetText: String;
  1321. begin
  1322. if not Assigned(fFirst) or not Assigned(fSecond) then
  1323. raise EengExpression.Create('first or second item not assigned');
  1324. result :=
  1325. {$IFDEF EXPRESSION_ADD_BRACKET}TOKEN_OP_GROUP_BEGIN +{$ENDIF}
  1326. fFirst.GetText + ' ' + EXPRESSION_BINARY_OPERATIONS[fBinaryOp] + ' ' + fSecond.GetText
  1327. {$IFDEF EXPRESSION_ADD_BRACKET} + TOKEN_OP_GROUP_END{$ENDIF};
  1328. end;
  1329. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1330. function TengExpressionBinaryOperation.GetValue(const aScope: TengShaderPartScope; const aGenCodeArgs: TengGenCodeArgs): Variant;
  1331. var
  1332. v1, v2: Variant;
  1333. begin
  1334. v1 := fFirst.GetValue(aScope, aGenCodeArgs);
  1335. v2 := fSecond.GetValue(aScope, aGenCodeArgs);
  1336. try
  1337. case fBinaryOp of
  1338. opBinaryOr: result := (Integer(v1) or Integer(v2));
  1339. opBinaryAnd: result := (Integer(v1) and Integer(v2));
  1340. opBinaryXor: result := (Integer(v1) xor Integer(v2));
  1341. opMultiply: result := (v1 * v2);
  1342. opDivide: result := (v1 / v2);
  1343. opAdd: result := (v1 + v2);
  1344. opSubtract: result := (v1 - v2);
  1345. opLogicalOr: result := (Boolean(v1) or Boolean(v2));
  1346. opLogicalAnd: result := (Boolean(v1) and Boolean(v2));
  1347. opLogicalXor: result := (Boolean(v1) xor Boolean(v2));
  1348. opEquals: result := (v1 = v2);
  1349. opLesser: result := (v1 < v2);
  1350. opGreater: result := (v1 > v2);
  1351. opLEquals: result := (v1 <= v2);
  1352. opGEquals: result := (v1 >= v2);
  1353. opUnequals: result := (v1 <> v2);
  1354. end;
  1355. except
  1356. on ex: Exception do
  1357. raise EengInvalidParamter.Create(ex.Message + ' ("' + GetText + '" ==> "' + v1 + ' ' + EXPRESSION_BINARY_OPERATIONS[fBinaryOp] + ' ' + v2 + '")', fLine, fCol, fFilename);
  1358. end;
  1359. end;
  1360. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1361. constructor TengExpressionBinaryOperation.Create(const aOperator: TengExpressionBinaryOperator; const aLine, aCol: Integer; const aFilename: String);
  1362. begin
  1363. inherited Create(aLine, aCol, aFilename);
  1364. fBinaryOp := aOperator;
  1365. fFirst := nil;
  1366. fSecond := nil;
  1367. end;
  1368. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1369. destructor TengExpressionBinaryOperation.Destroy;
  1370. begin
  1371. FreeAndNil(fFirst);
  1372. FreeAndNil(fSecond);
  1373. inherited Destroy;
  1374. end;
  1375. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1376. //EengShaderPart////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1377. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1378. constructor EengShaderPart.Create(const aMsg: String; const aLine, aCol: Integer; const aFilename: String);
  1379. begin
  1380. inherited Create(aMsg + format(' (file: %s; line: %d; col: %d)', [ExtractFileName(aFilename), aLine+1, aCol]));
  1381. Line := aLine;
  1382. Col := aCol;
  1383. Filename := aFilename;
  1384. end;
  1385. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1386. //EengInvalidParamter///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1387. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1388. constructor EengInvalidParamter.Create(const aMsg: String; const aLine, aCol: Integer; const aFilename: String);
  1389. begin
  1390. inherited Create('invalid parameter: ' + aMsg, aLine, aCol, aFilename);
  1391. end;
  1392. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1393. //EengInvalidIdentifier/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1394. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1395. constructor EengInvalidIdentifier.Create(const aIdentifier: String; const aLine, aCol: Integer; const aFilename: String);
  1396. begin
  1397. inherited Create('invalid identifier: ' + aIdentifier, aLine, aCol, aFilename);
  1398. end;
  1399. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1400. //EengEmptyToken////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1401. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1402. constructor EengEmptyToken.Create(const aLine, aCol: Integer; const aFilename: String);
  1403. begin
  1404. inherited Create('empty token', aLine, aCol, aFilename);
  1405. end;
  1406. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1407. //EengInvalidToken//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1408. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1409. constructor EengInvalidToken.Create(const aClassName: String; const aToken: String; const aLine, aCol: Integer; const aFilename: String);
  1410. begin
  1411. inherited Create('invalid token: ' + aClassName + ' <> '+ aToken, aLine, aCol, aFilename);
  1412. end;
  1413. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1414. //EengInvalidParamterCount//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1415. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1416. constructor EengInvalidParamterCount.Create(const aToken: String; const aLine, aCol: Integer; const aFilename: String);
  1417. begin
  1418. inherited Create('invalid parameter count in ' + aToken, aLine, aCol, aFilename);
  1419. end;
  1420. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1421. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1422. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1423. constructor EengDuplicateIdentifier.Create(const aName: String; const aNew, aOld: TengShaderPart);
  1424. begin
  1425. inherited Create(format('duplicate identifier: %s (previously declared here: %s %d:%d)',
  1426. [aName, aOld.Filename, aOld.Line, aOld.Col]), aNew.Line, aNew.Col, aNew.Filename);
  1427. end;
  1428. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1429. //EengInternal//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1430. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1431. constructor EengInternal.Create(const aMsg: String);
  1432. begin
  1433. inherited Create(aMsg);
  1434. end;
  1435. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1436. constructor EengInternal.Create(const aMsg: String; const aLine, aCol: Integer; const aFilename: String);
  1437. begin
  1438. inherited Create(aMsg, aLine, aCol, aFilename);
  1439. end;
  1440. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1441. //EengUnknownIdentifier/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1442. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1443. constructor EengUnknownIdentifier.Create(const aIdent: String; const aLine, aCol: Integer; const aFilename: String);
  1444. begin
  1445. inherited Create('unknown identifier: ' + aIdent, aLine, aCol, aFilename);
  1446. end;
  1447. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1448. //TengShaderPart.TengShaderPartEnumerator///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1449. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1450. function TengShaderPart.TengShaderPartEnumerator.GetCurrent: TengShaderPart;
  1451. begin
  1452. result := fOwner[fPosition];
  1453. end;
  1454. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1455. function TengShaderPart.TengShaderPartEnumerator.MoveNext: Boolean;
  1456. begin
  1457. inc(fPosition);
  1458. result := (fPosition < fOwner.Count);
  1459. end;
  1460. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1461. constructor TengShaderPart.TengShaderPartEnumerator.Create(const aOwner: TengShaderPart);
  1462. begin
  1463. inherited Create;
  1464. fOwner := aOwner;
  1465. fPosition := -1;
  1466. end;
  1467. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1468. //TengShaderPart////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1469. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1470. function TengShaderPart.GetCount: Integer;
  1471. begin
  1472. result := 0;
  1473. end;
  1474. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1475. function TengShaderPart.{%H-}GetChild(const aIndex: Integer): TengShaderPart;
  1476. begin
  1477. raise EengShaderPart.Create('this part does not have any children');
  1478. end;
  1479. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1480. function TengShaderPart.GetFilename: String;
  1481. begin
  1482. if Assigned(fParent) then
  1483. result := fParent.Filename
  1484. else
  1485. result := '';
  1486. end;
  1487. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1488. function TengShaderPart.GetShaderClass: String;
  1489. begin
  1490. if Assigned(fParent) then
  1491. result := fParent.ShaderClass
  1492. else
  1493. result := '';
  1494. end;
  1495. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1496. function TengShaderPart.GetText: String;
  1497. begin
  1498. result := ''; //DUMMY
  1499. end;
  1500. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1501. function TengShaderPart.ParseTextIntern(const aParseArgs: TengParseArgs; const aParameters: TengTokenParameterList): String;
  1502. begin
  1503. result := ''; //DUMMY
  1504. end;
  1505. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1506. function TengShaderPart.ParseText(const aParseArgs: TengParseArgs): String;
  1507. var
  1508. param: TengTokenParameterList;
  1509. begin
  1510. param := TengTokenParameterList.Create;
  1511. try
  1512. fCol := aParseArgs.Col;
  1513. fLine := aParseArgs.Line;
  1514. if (GetTokenName <> '') then
  1515. aParseArgs.ParseParameters(param);
  1516. result := ParseTextIntern(aParseArgs, param);
  1517. finally
  1518. FreeAndNil(param);
  1519. end;
  1520. end;
  1521. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1522. procedure TengShaderPart.MapData(const aFlags: TengMapDataFlags; const aTypes: array of CengShaderPart);
  1523. begin
  1524. //DUMMY
  1525. end;
  1526. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1527. procedure TengShaderPart.GenCodeIntern(const aGenCodeArgs: TengGenCodeArgs);
  1528. begin
  1529. fFlags := fFlags + [spfCodeGenVisited];
  1530. end;
  1531. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1532. procedure TengShaderPart.ClearGenCode;
  1533. begin
  1534. fFlags := fFlags - [spfCodeGenVisited];
  1535. end;
  1536. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1537. function TengShaderPart.HasParentType(const aParentType: CengShaderPart; const aIncludeSelf: Boolean): Boolean;
  1538. var
  1539. p: TengShaderPart;
  1540. begin
  1541. result := aIncludeSelf and (self is aParentType);
  1542. if not result then begin
  1543. GetParentType(aParentType, p);
  1544. result := Assigned(p);
  1545. end;
  1546. end;
  1547. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1548. function TengShaderPart.ParentOrSelfHasType(const aParentType: CengShaderPart): Boolean;
  1549. begin
  1550. result := (self is aParentType) or ParentHasType(aParentType);
  1551. end;
  1552. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1553. procedure TengShaderPart.GetParentByType(const aParentType: CengShaderPart; out aPart);
  1554. begin
  1555. if (fParent is aParentType) then
  1556. TengShaderPart(aPart) := fParent
  1557. else if Assigned(fParent) then
  1558. fParent.GetParentType(aParentType, aPart)
  1559. else
  1560. TengShaderPart(aPart) := nil;
  1561. end;
  1562. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1563. function TengShaderPart.GetEnumerator: TengShaderPartEnumerator;
  1564. begin
  1565. result := TengShaderPartEnumerator.Create(self);
  1566. end;
  1567. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1568. constructor TengShaderPart.Create(const aParent: TengShaderPart);
  1569. begin
  1570. inherited Create;
  1571. fParent := aParent;
  1572. if Assigned(fParent) then
  1573. fRoot := aParent.Root
  1574. else
  1575. fRoot := nil;
  1576. end;
  1577. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1578. class function TengShaderPart.GetTokenName: String;
  1579. begin
  1580. result := '';
  1581. end;
  1582. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1583. class function TengShaderPart.CheckToken(const aToken: String): Boolean;
  1584. begin
  1585. result := (aToken = GetTokenName);
  1586. end;
  1587. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1588. class procedure TengShaderPart.CheckToken(const aParseArgs: TengParseArgs; const aParent: TengShaderPart);
  1589. begin
  1590. //DUMMY
  1591. end;
  1592. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1593. //TengShaderPartContainer///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1594. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1595. function TengShaderPartContainer.HandleToken(var aToken: String; const aParseArgs: TengParseArgs): String;
  1596. var
  1597. obj: TengShaderPart;
  1598. c: CengShaderPart;
  1599. begin
  1600. obj := nil;
  1601. for c in TOKEN_CLASSES do
  1602. if c.CheckToken(aToken) then begin
  1603. c.CheckToken(aParseArgs, self);
  1604. obj := c.Create(self);
  1605. fChildren.Add(obj);
  1606. break;
  1607. end;
  1608. if Assigned(obj) then
  1609. result := obj.ParseText(aParseArgs)
  1610. else
  1611. result := aToken;
  1612. end;
  1613. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1614. function TengShaderPartContainer.GetCount: Integer;
  1615. begin
  1616. result := fChildren.Count;
  1617. end;
  1618. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1619. function TengShaderPartContainer.GetChild(const aIndex: Integer): TengShaderPart;
  1620. begin
  1621. result := fChildren[aIndex];
  1622. end;
  1623. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1624. function TengShaderPartContainer.GetText: String;
  1625. var
  1626. p: TengShaderPart;
  1627. begin
  1628. result := '';
  1629. for p in self do
  1630. result := result + p.Text;
  1631. end;
  1632. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1633. function TengShaderPartContainer.ParseTextIntern(const aParseArgs: TengParseArgs; const aParameters: TengTokenParameterList): String;
  1634. var
  1635. codeObj: TengShaderPartCode;
  1636. begin
  1637. fChildren.Clear;
  1638. while not aParseArgs.EndOfFile do begin
  1639. codeObj := TengShaderPartCode.Create(self);
  1640. try
  1641. result := codeObj.ParseText(aParseArgs);
  1642. if (codeObj.Code <> '') then
  1643. AddChild(codeObj)
  1644. else
  1645. FreeAndNil(codeObj);
  1646. except
  1647. FreeAndNil(codeObj);
  1648. raise;
  1649. end;
  1650. if (result <> '') then begin
  1651. result := HandleToken(result, aParseArgs);
  1652. if (result <> '') then
  1653. break;
  1654. end;
  1655. end;
  1656. end;
  1657. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1658. procedure TengShaderPartContainer.MapData(const aFlags: TengMapDataFlags; const aTypes: array of CengShaderPart);
  1659. var
  1660. p: TengShaderPart;
  1661. begin
  1662. inherited MapData(aFlags, aTypes);
  1663. for p in fChildren do
  1664. p.MapData(aFlags, aTypes);
  1665. end;
  1666. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1667. procedure TengShaderPartContainer.GenCodeIntern(const aGenCodeArgs: TengGenCodeArgs);
  1668. var
  1669. p: TengShaderPart;
  1670. begin
  1671. inherited GenCodeIntern(aGenCodeArgs);
  1672. for p in fChildren do
  1673. if not (p is TengShaderPartClass) then
  1674. p.GenCodeIntern(aGenCodeArgs);
  1675. end;
  1676. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1677. procedure TengShaderPartContainer.ClearGenCode;
  1678. var
  1679. p: TengShaderPart;
  1680. begin
  1681. inherited ClearGenCode;
  1682. for p in fChildren do
  1683. p.ClearGenCode;
  1684. end;
  1685. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1686. procedure TengShaderPartContainer.AddChild(const aChild: TengShaderPart; const aPrepend: Boolean);
  1687. begin
  1688. if aPrepend then
  1689. fChildren.PushFirst(aChild)
  1690. else
  1691. fChildren.PushLast(aChild);
  1692. end;
  1693. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1694. constructor TengShaderPartContainer.Create(const aParent: TengShaderPart);
  1695. begin
  1696. inherited Create(aParent);
  1697. fChildren := TengShaderPartList.Create(true);
  1698. end;
  1699. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1700. destructor TengShaderPartContainer.Destroy;
  1701. begin
  1702. FreeAndNil(fChildren);
  1703. inherited Destroy;
  1704. end;
  1705. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1706. //TengShaderPartScope///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1707. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1708. function TengShaderPartScope.CheckName(const aName: String; const aShaderPart: TengShaderPart): Boolean;
  1709. var
  1710. old: TengShaderPart;
  1711. begin
  1712. result := false;
  1713. // check properties (global)
  1714. FindMappedPart(old, aName, [ffGlobal, ffLocal, ffDescending], TengShaderPartProperty);
  1715. if Assigned(old) then begin
  1716. if (old <> aShaderPart) then
  1717. raise EengDuplicateIdentifier.Create(aName, aShaderPart, old)
  1718. else
  1719. exit;
  1720. end;
  1721. // check all others
  1722. FindMappedPart(old, aName, FIND_IN_SCOPE_FLAGS);
  1723. if Assigned(old) then begin
  1724. if (old <> aShaderPart) then
  1725. CheckDuplicate(aName, old, aShaderPart)
  1726. else
  1727. exit;
  1728. end;
  1729. result := true;
  1730. end;
  1731. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1732. procedure TengShaderPartScope.MapChildScope(const aScope: TengShaderPartScope);
  1733. begin
  1734. if (CheckParentScope(aScope) <> self) then
  1735. raise EengInternal.Create('container is not a direct child of this container');
  1736. if not fChildScopes.Contains(aScope) then
  1737. fChildScopes.Add(aScope);
  1738. end;
  1739. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1740. procedure TengShaderPartScope.MapInheritedScope(const aScope: TengShaderPartScope);
  1741. begin
  1742. if not fInherited.Contains(aScope) then
  1743. fInherited.Add(aScope);
  1744. end;
  1745. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1746. function TengShaderPartScope.MapShaderPart(const aName: String; const aShaderPart: TengShaderPart): Boolean;
  1747. begin
  1748. if (CheckParentScope(aShaderPart) <> self) then
  1749. raise EengInternal.Create('shader part does not belong to this container');
  1750. result := CheckName(aName, aShaderPart);
  1751. if result then
  1752. fMappedParts.Add(aName, aShaderPart);
  1753. end;
  1754. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1755. procedure TengShaderPartScope.FindMappedPart(out aShaderPart; const aName: String; const aFlags: TengFindMappedPartFlags; const aType: CengShaderPart);
  1756. var
  1757. list: TengShaderPartList;
  1758. begin
  1759. TengShaderPart(aShaderPart) := nil;
  1760. list := TengShaderPartList.Create(false);
  1761. try
  1762. FindMappedParts(list, aName, aFlags + [ffFindFirst], aType);
  1763. if (list.Count > 0) then
  1764. TengShaderPart(aShaderPart) := list[0];
  1765. finally
  1766. FreeAndNil(list);
  1767. end;
  1768. end;
  1769. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1770. procedure TengShaderPartScope.FindMappedParts(const aParts: TengShaderPartList; const aName: String; const aFlags: TengFindMappedPartFlags; const aType: CengShaderPart);
  1771. procedure AddPart(const aShaderPart: TengShaderPart);
  1772. begin
  1773. if Assigned(aShaderPart) and
  1774. (not Assigned(aType) or (aShaderPart is aType)) and
  1775. (aParts.IndexOf(aShaderPart) < 0) then
  1776. aParts.Add(aShaderPart);
  1777. end;
  1778. var
  1779. s: TengShaderPartScope;
  1780. p: TengShaderPart;
  1781. begin
  1782. if (ffFindFirst in aFlags) and (aParts.Count > 0) then
  1783. exit;
  1784. if not (ffGlobal in aFlags) then begin
  1785. // local
  1786. if (ffLocal in aFlags) then begin
  1787. if (aName <> '') then
  1788. AddPart(fMappedParts[aName])
  1789. else
  1790. for p in fMappedParts do
  1791. AddPart(p);
  1792. end;
  1793. // descending
  1794. if (ffDescending in aFlags) then
  1795. for s in fChildScopes do
  1796. s.FindMappedParts(aParts, aName, aFlags + [ffLocal], aType);
  1797. // ascending
  1798. if (ffAscending in aFlags) then begin
  1799. GetParentType(TengShaderPartScope, s);
  1800. if Assigned(s) and s.fChildScopes.Contains(self) then
  1801. s.FindMappedParts(aParts, aName, aFlags + [ffLocal], aType);
  1802. end;
  1803. // search in inherited scopes
  1804. if (ffInherited in aFlags) then
  1805. for s in fInherited do
  1806. s.FindMappedParts(aParts, aName, aFlags + [ffLocal], aType);
  1807. end else
  1808. fRoot.FindMappedParts(aParts, aName, aFlags - [ffGlobal], aType);
  1809. end;
  1810. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1811. function TengShaderPartScope.GetFindPropertyFlags: TengFindMappedPartFlags;
  1812. begin
  1813. result := FIND_PROPERTY_FLAGS;
  1814. end;
  1815. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1816. procedure TengShaderPartScope.CheckDuplicate(const aName: String; const aOld, aNew: TengShaderPart);
  1817. begin
  1818. raise EengDuplicateIdentifier.Create(aName, aNew, aOld);
  1819. end;
  1820. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1821. procedure TengShaderPartScope.MapData(const aFlags: TengMapDataFlags; const aTypes: array of CengShaderPart);
  1822. var
  1823. s: TengShaderPartScope;
  1824. p: TengShaderPart;
  1825. begin
  1826. if (mdfCurrentScope in aFlags) and (mdfChild in aFlags) then
  1827. exit;
  1828. GetParentType(TengShaderPartScope, s);
  1829. if Assigned(s) then
  1830. s.MapChildScope(self);
  1831. for p in fChildren do
  1832. p.MapData(aFlags + [mdfChild], aTypes);
  1833. if (mdfMapInherited in aFlags) then
  1834. for s in fInherited do
  1835. s.MapData(aFlags, aTypes);
  1836. end;
  1837. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1838. procedure TengShaderPartScope.GenCodeIntern(const aGenCodeArgs: TengGenCodeArgs);
  1839. begin
  1840. MapData([mdfMapInherited, mdfCurrentScope, mdfIfEvaluate], []);
  1841. inherited GenCodeIntern(aGenCodeArgs);
  1842. end;
  1843. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1844. procedure TengShaderPartScope.ClearGenCode;
  1845. var
  1846. p: TengShaderPartScope;
  1847. begin
  1848. inherited ClearGenCode;
  1849. for p in fInherited do
  1850. p.ClearGenCode;
  1851. end;
  1852. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1853. procedure TengShaderPartScope.ClearMappedData(const aExcludedTypes: array of CengShaderPart);
  1854. var
  1855. s: TengShaderPartScope;
  1856. i: Integer;
  1857. begin
  1858. for s in fChildScopes do
  1859. s.ClearMappedData(aExcludedTypes);
  1860. for s in fInherited do
  1861. s.ClearMappedData(aExcludedTypes);
  1862. for i := fMappedParts.Count-1 downto 0 do
  1863. if not CheckType(fMappedParts.ValueAt[i], aExcludedTypes) then
  1864. fMappedParts.DeleteAt(i);
  1865. end;
  1866. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1867. procedure TengShaderPartScope.ClearMappedData;
  1868. var
  1869. s: TengShaderPartScope;
  1870. begin
  1871. for s in fChildScopes do
  1872. s.ClearMappedData;
  1873. fChildScopes.Clear;
  1874. for s in fInherited do
  1875. s.ClearMappedData;
  1876. fInherited.Clear;
  1877. fMappedParts.Clear;
  1878. end;
  1879. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1880. constructor TengShaderPartScope.Create(const aParent: TengShaderPart);
  1881. begin
  1882. inherited Create(aParent);
  1883. fInherited := TengShaderPartScopeHashSet.Create(false);
  1884. fChildScopes := TengShaderPartScopeHashSet.Create(false);
  1885. fMappedParts := TengShaderPartMap.Create(false);
  1886. end;
  1887. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1888. destructor TengShaderPartScope.Destroy;
  1889. begin
  1890. FreeAndNil(fMappedParts);
  1891. FreeAndNil(fChildScopes);
  1892. FreeAndNil(fInherited);
  1893. inherited Destroy;
  1894. end;
  1895. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1896. //TengCodeGenerator/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1897. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1898. function TengCodeGenerator.GetProperty(const aName: String): TengShaderPartProperty;
  1899. begin
  1900. FindMappedPart(result, aName, GetFindPropertyFlags, TengShaderPartProperty);
  1901. end;
  1902. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1903. procedure TengCodeGenerator.GenerateCode(const aGenCodeArgs: TengGenCodeArgs);
  1904. begin
  1905. //DUMMY
  1906. end;
  1907. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1908. function TengCodeGenerator.GenerateCode: TengShaderCode;
  1909. var
  1910. args: TengGenCodeArgs;
  1911. begin
  1912. result := TengShaderCodeIntern.Create;
  1913. args := TengGenCodeArgs.Create((result as TengShaderCodeIntern), self);
  1914. try
  1915. ClearGenCode;
  1916. ClearMappedData([TengShaderPartProperty]);
  1917. GenCodeIntern(args);
  1918. args.PushCode;
  1919. try
  1920. GenerateCode(args);
  1921. args.GenProcedureCode;
  1922. finally
  1923. args.PopCode;
  1924. end;
  1925. args.GenCodePropertyCode([TengShaderPartVar]);
  1926. args.GenCodePropertyCode([TengShaderPartVarying]);
  1927. args.GenCodePropertyCode([TengShaderPartUniform]);
  1928. args.GenMetaCode;
  1929. finally
  1930. FreeAndNil(args);
  1931. end;
  1932. end;
  1933. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1934. procedure TengCodeGenerator.ListProperties(const aList: TStrings);
  1935. var
  1936. list: TengShaderPartList;
  1937. p: TengShaderPart;
  1938. begin
  1939. list := TengShaderPartList.Create(false);
  1940. try
  1941. FindMappedParts(list, '', GetFindPropertyFlags, TengShaderPartProperty);
  1942. for p in list do
  1943. aList.Add((p as TengShaderPartProperty).Name);
  1944. finally
  1945. FreeAndNil(list);
  1946. end;
  1947. end;
  1948. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1949. //TengShaderPartClass///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1950. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1951. function TengShaderPartClass.GetExtendCount: Integer;
  1952. begin
  1953. result := fExtends.Count;
  1954. end;
  1955. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1956. function TengShaderPartClass.GetExtends(const aIndex: Integer): String;
  1957. begin
  1958. if (aIndex >= 0) and (aIndex < fExtends.Count) then
  1959. result := fExtends[aIndex]
  1960. else
  1961. raise EOutOfRange.Create(aIndex, 0, fExtends.Count-1);
  1962. end;
  1963. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1964. function TengShaderPartClass.GetText: String;
  1965. var
  1966. s: String;
  1967. begin
  1968. result := PRECOMPILER_STATEMENT_BEGIN + GetTokenName + ' ' + fName;
  1969. if (fExtends.Count > 0) then begin
  1970. result := result + ' ' + TOKEN_EXTENDS;
  1971. for s in fExtends do
  1972. result := result + ' ' + s;
  1973. end;
  1974. result := result + PRECOMPILER_STATEMENT_END +
  1975. inherited GetText +
  1976. PRECOMPILER_STATEMENT_BEGIN + TOKEN_END + PRECOMPILER_STATEMENT_END;
  1977. end;
  1978. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1979. function TengShaderPartClass.GetShaderClass: String;
  1980. begin
  1981. result := fName;
  1982. end;
  1983. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1984. function TengShaderPartClass.ParseTextIntern(const aParseArgs: TengParseArgs; const aParameters: TengTokenParameterList): String;
  1985. var
  1986. i: Integer;
  1987. begin
  1988. if (aParameters[0].Name <> GetTokenName) then
  1989. raise EengInvalidToken.Create(ClassName, aParameters[0].Name, Line, Col, Filename);
  1990. if (aParameters.Count < 2) then
  1991. raise EengInvalidParamterCount.Create(GetTokenName, Line, Col, Filename);
  1992. fName := aParameters[1].Name;
  1993. if not IsValidIdentifier(fName) then
  1994. raise EengShaderPart.Create('invalid name: ' + fName, Line, Col, GetFilename);
  1995. if (aParameters.Count > 2) then begin
  1996. if (aParameters.Count < 4) then
  1997. raise EengInvalidParamterCount.Create(GetTokenName, Line, Col, Filename);
  1998. if (aParameters[2].Name <> TOKEN_EXTENDS) then
  1999. raise EengInvalidParamter.Create(aParameters[2].Name + ' (expected ' + TOKEN_EXTENDS + ')', Line, Col, Filename);
  2000. fExtends.Clear;
  2001. for i := 3 to aParameters.Count-1 do
  2002. fExtends.Add(aParameters[i].Name);
  2003. end;
  2004. fRoot.AddClass(self);
  2005. inherited ParseTextIntern(aParseArgs, aParameters);
  2006. result := CheckEndToken(aParseArgs, self);
  2007. end;
  2008. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2009. procedure TengShaderPartClass.CheckDuplicate(const aName: String; const aOld, aNew: TengShaderPart);
  2010. function IsInherited(const aRoot: TengShaderPartScope; const aClass: TengShaderPartClass): Boolean;
  2011. var
  2012. p: TengShaderPartScope;
  2013. begin
  2014. result := true;
  2015. for p in fInherited do
  2016. if (p is TengShaderPartClass) and ((p = aClass) or IsInherited(p, aClass)) then
  2017. exit;
  2018. result := false;
  2019. end;
  2020. function CompareParam(const p1, p2: TengShaderPartProcParam): Boolean;
  2021. begin
  2022. result := (p1.Name = p2.Name) and (p1.Typ = p2.Typ);
  2023. end;
  2024. var
  2025. i: Integer;
  2026. o, n: TengShaderPartProc;
  2027. c: TengShaderPartClass;
  2028. begin
  2029. if (aOld is TengShaderPartProc) and (aNew is TengShaderPartProc) then begin
  2030. o := (aOld as TengShaderPartProc);
  2031. n := (aNew as TengShaderPartProc);
  2032. o.GetParentType(TengShaderPartClass, c);
  2033. if (o.fParameters.Count <> n.fParameters.Count) then
  2034. raise EengInvalidParamterCount.Create('method must have the same parameters as the overwritten one', n.Line, n.Col, n.Filename);
  2035. for i := 0 to o.fParameters.Count-1 do
  2036. if not CompareParam(n.fParameters[i], o.fParameters[i]) then
  2037. raise EengInvalidParamter.Create('parameters must have the same name and type as the overwritten one', n.Line, n.Col, n.Filename);
  2038. if (o.ClassName <> n.ClassName) then
  2039. raise EengInvalidToken.Create('method must be the same type as the overwritten one', n.Line, n.Col, n.Filename);
  2040. if (o is TengShaderPartFunc) and ((o as TengShaderPartFunc).ReturnType <> (n as TengShaderPartFunc).ReturnType) then
  2041. raise EengInvalidParamter.Create('return type must be the same as the overwritten one', n.Line, n.Col, n.Filename);
  2042. end else
  2043. inherited CheckDuplicate(aName, aOld, aNew);
  2044. end;
  2045. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2046. function TengShaderPartClass.GetFindPropertyFlags: TengFindMappedPartFlags;
  2047. begin
  2048. result := inherited GetFindPropertyFlags + [ffFile];
  2049. end;
  2050. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2051. procedure TengShaderPartClass.GenCodeIntern(const aGenCodeArgs: TengGenCodeArgs);
  2052. var
  2053. p: TengShaderPartScope;
  2054. begin
  2055. for p in fInherited do
  2056. p.GenCodeIntern(aGenCodeArgs);
  2057. aGenCodeArgs.Code.AddToken(ttBegin);
  2058. try
  2059. inherited GenCodeIntern(aGenCodeArgs);
  2060. finally
  2061. aGenCodeArgs.Code.AddToken(ttEnd);
  2062. end;
  2063. end;
  2064. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2065. procedure TengShaderPartClass.GenerateCode(const aGenCodeArgs: TengGenCodeArgs);
  2066. var
  2067. main: TengShaderPartMain;
  2068. begin
  2069. FindMappedPart(main, '', FIND_IN_SCOPE_FLAGS, TengShaderPartMain);
  2070. if not Assigned(main) then
  2071. raise EengInternal.Create('no main routine found');
  2072. aGenCodeArgs.PushFlags([gcfGenProcedure]);
  2073. try
  2074. main.GenCodeIntern(aGenCodeArgs);
  2075. finally
  2076. aGenCodeArgs.PopFlags;
  2077. end;
  2078. end;
  2079. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2080. procedure TengShaderPartClass.FindMappedParts(const aParts: TengShaderPartList; const aName: String; const aFlags: TengFindMappedPartFlags; const aType: CengShaderPart);
  2081. var
  2082. f: TengShaderFile;
  2083. begin
  2084. if (ffIgnoreClasses in aFlags) or
  2085. ((ffFindFirst in aFlags) and (aParts.Count > 0)) then
  2086. exit;
  2087. // search in file
  2088. if not (ffGlobal in aFlags) and (ffFile in aFlags) then begin
  2089. GetParentType(TengShaderFile, f);
  2090. if not Assigned(f) then
  2091. EengInternal.Create('unable to find file object');
  2092. f.FindMappedParts(aParts, aName, aFlags + [ffIgnoreClasses], aType);
  2093. end;
  2094. inherited FindMappedParts(aParts, aName, aFlags, aType);
  2095. end;
  2096. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2097. procedure TengShaderPartClass.MapData(const aFlags: TengMapDataFlags; const aTypes: array of CengShaderPart);
  2098. var
  2099. s: String;
  2100. sc: TengShaderPartScope;
  2101. begin
  2102. if (mdfAddInherited in aFlags) then begin
  2103. for s in fExtends do begin
  2104. sc := fRoot.GetClass(s);
  2105. if not Assigned(sc) then
  2106. raise EengUnknownIdentifier.Create(s, Line, Col, Filename);
  2107. MapInheritedScope(sc);
  2108. end;
  2109. end;
  2110. inherited MapData(aFlags, aTypes);
  2111. end;
  2112. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2113. constructor TengShaderPartClass.Create(const aParent: TengShaderPart);
  2114. begin
  2115. inherited Create(aParent);
  2116. fExtends := TStringList.Create;
  2117. end;
  2118. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2119. destructor TengShaderPartClass.Destroy;
  2120. begin
  2121. FreeAndNil(fExtends);
  2122. inherited Destroy;
  2123. end;
  2124. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2125. class function TengShaderPartClass.GetTokenName: String;
  2126. begin
  2127. result := TOKEN_CLASS;
  2128. end;
  2129. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2130. class procedure TengShaderPartClass.CheckToken(const aParseArgs: TengParseArgs; const aParent: TengShaderPart);
  2131. procedure RaiseEx(const aToken: String);
  2132. begin
  2133. with aParseArgs do
  2134. raise EengShaderPart.Create('token ' + GetTokenName + ' is not allowed in ' + aToken, Line, Col, aParent.Filename);
  2135. end;
  2136. begin
  2137. if (aParent is TengShaderPartClass) or aParent.ParentHasType(TengShaderPartClass) then
  2138. RaiseEx(TengShaderPartClass.GetTokenName);
  2139. if (aParent is TengShaderPartIf) or aParent.ParentHasType(TengShaderPartIf) then
  2140. RaiseEx(TengShaderPartIf.GetTokenName);
  2141. if (aParent is TengShaderPartElse) or aParent.ParentHasType(TengShaderPartElse) then
  2142. RaiseEx(TengShaderPartElse.GetTokenName);
  2143. if (aParent is TengShaderPartElIf) or aParent.ParentHasType(TengShaderPartElIf) then
  2144. RaiseEx(TengShaderPartElIf.GetTokenName);
  2145. end;
  2146. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2147. //TengShaderFile////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2148. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2149. function TengShaderFile.GetFilename: String;
  2150. begin
  2151. result := fFilename;
  2152. end;
  2153. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2154. procedure TengShaderFile.LoadFromFile(const aFilename: String);
  2155. var
  2156. s: TStream;
  2157. {$IFDEF USE_VFS}sHandle: IStreamHandle;{$ENDIF}
  2158. function GetStream(out aStream: TStream): Boolean;
  2159. begin
  2160. {$IFDEF USE_VFS}
  2161. result := vfsManager.ReadFile(aFilename, sHandle);
  2162. if result then
  2163. aStream := sHandle.GetStream
  2164. else
  2165. aStream := nil;;
  2166. {$ELSE}
  2167. result := true;
  2168. aStream := TFileStream.Create(aFilename, fmOpenRead);
  2169. {$ENDIF}
  2170. end;
  2171. procedure FreeStream(var aStream: TStream);
  2172. begin
  2173. {$IFDEF USE_VFS}
  2174. aStream := nil;
  2175. sHandle := nil;
  2176. {$ELSE}
  2177. FreeAndNil(aStream);
  2178. {$ENDIF}
  2179. end;
  2180. begin
  2181. if not {$IFDEF USE_VFS}vfsManager.{$ENDIF}FileExists(aFilename) then
  2182. if Assigned(fParent) then with fParent do
  2183. raise EengShaderPart.Create('file does not exist: ' + aFilename, Line, Col, Filename)
  2184. else
  2185. raise EengShaderPart.Create('file does not exist: ' + aFilename);
  2186. if GetStream(s) then begin
  2187. try
  2188. LoadFromStream(s, aFilename);
  2189. finally
  2190. FreeStream(s);
  2191. end;
  2192. end;
  2193. end;
  2194. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2195. procedure TengShaderFile.SaveToFile(const aFilename: String);
  2196. var
  2197. s: TStream;
  2198. {$IFDEF USE_VFS}sHandle: IStreamHandle;{$ENDIF}
  2199. function GetStream(out aStream: TStream): Boolean;
  2200. begin
  2201. {$IFDEF USE_VFS}
  2202. result := vfsManager.CreateFile(aFilename, sHandle);
  2203. if result then
  2204. aStream := sHandle.GetStream
  2205. else
  2206. aStream := nil;;
  2207. {$ELSE}
  2208. result := true;
  2209. aStream := TFileStream.Create(aFilename, fmCreate);
  2210. {$ENDIF}
  2211. end;
  2212. procedure FreeStream(var aStream: TStream);
  2213. begin
  2214. {$IFDEF USE_VFS}
  2215. aStream := nil;
  2216. sHandle := nil;
  2217. {$ELSE}
  2218. FreeAndNil(aStream);
  2219. {$ENDIF}
  2220. end;
  2221. begin
  2222. fFilename := aFilename;
  2223. if GetStream(s) then begin
  2224. try
  2225. SaveToStream(s);
  2226. finally
  2227. FreeStream(s);
  2228. end;
  2229. end;
  2230. end;
  2231. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2232. procedure TengShaderFile.LoadFromStream(const aStream: TStream; const aFilename: String);
  2233. var
  2234. token: String;
  2235. args: TengParseArgs;
  2236. begin
  2237. fFilename := aFilename;
  2238. Clear;
  2239. args := TengParseArgs.Create(self);
  2240. try
  2241. args.LoadCode(aStream);
  2242. token := ParseText(args);
  2243. if (token <> '') then
  2244. raise EengShaderPart.Create('unknown token ''' + token + '''', args.Line, args.Col, Filename);
  2245. finally
  2246. FreeAndNil(args);
  2247. end;
  2248. end;
  2249. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2250. procedure TengShaderFile.SaveToStream(const aStream: TStream);
  2251. var
  2252. sl: TStringList;
  2253. begin
  2254. sl := TStringList.Create;
  2255. try
  2256. sl.Text := Text;
  2257. sl.SaveToStream(aStream);
  2258. finally
  2259. FreeAndNil(sl);
  2260. end;
  2261. end;
  2262. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2263. function TengShaderFile.GetGenerator(const aName: String): TengCodeGenerator;
  2264. begin
  2265. ClearMappedData;
  2266. MapData([], [TengShaderPartDefine]);
  2267. MapData([mdfIfAll, mdfAddInherited], [TengShaderPartProperty]);
  2268. if (aName <> '') then
  2269. result := fClasses[aName]
  2270. else
  2271. result := self;
  2272. end;
  2273. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2274. function TengShaderFile.GetFindPropertyFlags: TengFindMappedPartFlags;
  2275. begin
  2276. result := inherited GetFindPropertyFlags + [ffIgnoreClasses];
  2277. end;
  2278. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2279. procedure TengShaderFile.MapData(const aFlags: TengMapDataFlags; const aTypes: array of CengShaderPart);
  2280. var
  2281. s: TengShaderPartScope;
  2282. p: TengShaderPart;
  2283. begin
  2284. // do not call inherited or included files will map themself as child to this file-scope,
  2285. // but files are all inherited to each other
  2286. if (mdfCurrentScope in aFlags) and (mdfChild in aFlags) then
  2287. exit;
  2288. if (mdfAddInherited in aFlags) then begin
  2289. GetParentType(TengShaderPartScope, s);
  2290. if Assigned(s) then begin
  2291. if(s is TengShaderFile) then
  2292. s.MapInheritedScope(self)
  2293. else
  2294. s.MapChildScope(self);
  2295. end;
  2296. end;
  2297. for p in fChildren do
  2298. p.MapData(aFlags + [mdfChild], aTypes);
  2299. if (mdfMapInherited in aFlags) then
  2300. for s in fInherited do
  2301. s.MapData(aFlags, aTypes);
  2302. end;
  2303. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2304. function TengShaderFile.GetClass(const aName: String): TengShaderPartClass;
  2305. begin
  2306. result := fClasses[aName];
  2307. end;
  2308. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2309. procedure TengShaderFile.AddClass(const aClass: TengShaderPartClass);
  2310. var
  2311. c: TengShaderPartClass;
  2312. begin
  2313. c := fClasses[aClass.Name];
  2314. if not Assigned(c) then
  2315. fClasses.Add(aClass.Name, aClass)
  2316. else if (c <> aClass) then
  2317. raise EengInternal.Create('name is already registred for other class data object: ' + aClass.Name);
  2318. end;
  2319. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2320. procedure TengShaderFile.GenerateCode(const aGenCodeArgs: TengGenCodeArgs);
  2321. var
  2322. main: TengShaderPartMain;
  2323. begin
  2324. FindMappedPart(main, '', FIND_IN_SCOPE_FLAGS, TengShaderPartMain);
  2325. if Assigned(main) then begin
  2326. aGenCodeArgs.PushFlags([gcfGenProcedure]);
  2327. try
  2328. main.GenCodeIntern(aGenCodeArgs);
  2329. finally
  2330. aGenCodeArgs.PopFlags;
  2331. end;
  2332. end;
  2333. end;
  2334. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2335. procedure TengShaderFile.ListGenerators(const aList: TStrings);
  2336. var
  2337. s: String;
  2338. begin
  2339. ClearMappedData;
  2340. MapData([], [TengShaderPartDefine]);
  2341. MapData([mdfIfAll, mdfAddInherited], [TengShaderPartProperty]);
  2342. for s in fClasses.Keys do
  2343. aList.Add(s);
  2344. end;
  2345. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2346. procedure TengShaderFile.Clear;
  2347. begin
  2348. ClearMappedData;
  2349. ClearGenCode;
  2350. fClasses.Clear;
  2351. fChildren.Clear;
  2352. end;
  2353. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2354. constructor TengShaderFile.Create(const aParent: TengShaderPart);
  2355. begin
  2356. inherited Create(aParent);
  2357. fClasses := TengShaderPartClassMap.Create(false);
  2358. if not Assigned(fRoot) then
  2359. fRoot := self;
  2360. end;
  2361. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2362. constructor TengShaderFile.Create;
  2363. begin
  2364. Create(nil);
  2365. end;
  2366. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2367. destructor TengShaderFile.Destroy;
  2368. begin
  2369. FreeAndNil(fClasses);
  2370. inherited Destroy;
  2371. end;
  2372. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2373. //TengShaderPartInclude/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2374. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2375. function TengShaderPartInclude.GetCount: Integer;
  2376. begin
  2377. if Assigned(fShaderFile) then
  2378. result := 1
  2379. else
  2380. result := 0;
  2381. end;
  2382. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2383. function TengShaderPartInclude.GetChild(const aIndex: Integer): TengShaderPart;
  2384. begin
  2385. if Assigned(fShaderFile) then
  2386. result := fShaderFile
  2387. else
  2388. raise EOutOfRange.Create(aIndex, 0, -1);
  2389. end;
  2390. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2391. function TengShaderPartInclude.GetText: String;
  2392. begin
  2393. result := PRECOMPILER_STATEMENT_BEGIN + GetTokenName + ' ''' + fIncludeFile + '''' + PRECOMPILER_STATEMENT_END;
  2394. end;
  2395. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2396. function TengShaderPartInclude.ParseTextIntern(const aParseArgs: TengParseArgs; const aParameters: TengTokenParameterList): String;
  2397. begin
  2398. if (aParameters[0].Name <> GetTokenName) then
  2399. raise EengInvalidToken.Create(ClassName, aParameters[0].Name, Line, Col, Filename);
  2400. if (aParameters.Count <> 2) then
  2401. raise EengInvalidParamterCount.Create(GetTokenName, Line, Col, Filename);
  2402. fIncludeFile := aParameters[1].Name;
  2403. fAbsoluteFile := CreateAbsolutePath(fIncludeFile, ExtractFilePath(Filename));
  2404. result := '';
  2405. end;
  2406. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2407. procedure TengShaderPartInclude.CheckShaderFile;
  2408. begin
  2409. if not Assigned(fShaderFile) then
  2410. fShaderFile := TengShaderFile.Create(self);
  2411. if (fShaderFile.Filename <> fAbsoluteFile) then
  2412. fShaderFile.LoadFromFile(fAbsoluteFile);
  2413. end;
  2414. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2415. procedure TengShaderPartInclude.MapData(const aFlags: TengMapDataFlags; const aTypes: array of CengShaderPart);
  2416. begin
  2417. inherited MapData(aFlags, aTypes);
  2418. CheckShaderFile;
  2419. fShaderFile.MapData(aFlags, aTypes);
  2420. end;
  2421. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2422. procedure TengShaderPartInclude.GenCodeIntern(const aGenCodeArgs: TengGenCodeArgs);
  2423. begin
  2424. inherited GenCodeIntern(aGenCodeArgs);
  2425. CheckShaderFile;
  2426. aGenCodeArgs.Code.AddToken(ttBegin);
  2427. try
  2428. aGenCodeArgs.Code.AddToken(ttSingle);
  2429. aGenCodeArgs.Code.AddLineEnd;
  2430. fShaderFile.GenCodeIntern(aGenCodeArgs);
  2431. finally
  2432. aGenCodeArgs.Code.AddToken(ttEnd);
  2433. end;
  2434. end;
  2435. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2436. constructor TengShaderPartInclude.Create(const aParent: TengShaderPart);
  2437. begin
  2438. inherited Create(aParent);
  2439. fShaderFile := nil;
  2440. end;
  2441. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2442. destructor TengShaderPartInclude.Destroy;
  2443. begin
  2444. FreeAndNil(fShaderFile);
  2445. inherited Destroy;
  2446. end;
  2447. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2448. class function TengShaderPartInclude.GetTokenName: String;
  2449. begin
  2450. result := TOKEN_INCLUDE;
  2451. end;
  2452. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2453. //TengShaderPartComment/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2454. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2455. function TengShaderPartComment.GetText: String;
  2456. begin
  2457. result := PRECOMPILER_STATEMENT_BEGIN + GetTokenName + fText + PRECOMPILER_STATEMENT_END;
  2458. end;
  2459. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2460. function TengShaderPartComment.ParseTextIntern(const aParseArgs: TengParseArgs; const aParameters: TengTokenParameterList): String;
  2461. begin
  2462. if (aParameters[0].Name <> GetTokenName) then
  2463. raise EengInvalidToken.Create(ClassName, aParameters[0].Name, Line, Col, Filename);
  2464. if (aParameters.Count <> 2) then
  2465. raise EengInvalidParamterCount.Create(GetTokenName, Line, Col, Filename);
  2466. fText := aParameters[1].Name;
  2467. result := '';
  2468. end;
  2469. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2470. class function TengShaderPartComment.GetTokenName: String;
  2471. begin
  2472. result := COMMENT_IDENTIFIER;
  2473. end;
  2474. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2475. //TengShaderPartInherited///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2476. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2477. function TengShaderPartInherited.GetText: String;
  2478. begin
  2479. result := PRECOMPILER_STATEMENT_BEGIN + GetTokenName;
  2480. if (fInheritedName <> '') then
  2481. result := ' ' + fInheritedName;
  2482. result := result + PRECOMPILER_STATEMENT_END;
  2483. end;
  2484. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2485. function TengShaderPartInherited.ParseTextIntern(const aParseArgs: TengParseArgs; const aParameters: TengTokenParameterList): String;
  2486. var
  2487. i: Integer;
  2488. begin
  2489. if (aParameters[0].Name <> GetTokenName) then
  2490. raise EengInvalidToken.Create(ClassName, aParameters[0].Name, Line, Col, Filename);
  2491. if (aParameters.Count < 1) then
  2492. raise EengInvalidParamterCount.Create(GetTokenName, Line, Col, Filename);
  2493. fParameters.Clear;
  2494. if (aParameters.Count >= 2) then begin
  2495. if not IsValidIdentifier(aParameters[1].Name) and (aParameters[1].Name <> TOKEN_MAIN) then
  2496. raise EengInvalidIdentifier.Create(aParameters[1].Name, Line, Col, Filename);
  2497. fInheritedName := aParameters[1].Name;
  2498. for i := 2 to aParameters.Count-1 do
  2499. fParameters.Add(aParameters[i].Name);
  2500. end else
  2501. fInheritedName := '';
  2502. result := '';
  2503. end;
  2504. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2505. procedure TengShaderPartInherited.GenCodeIntern(const aGenCodeArgs: TengGenCodeArgs);
  2506. function FindProc(const aParentProc: TengShaderPartProc): TengShaderPartProc;
  2507. var
  2508. c: TengShaderPartClass;
  2509. p: TengShaderPart;
  2510. s: TengShaderPartScope;
  2511. procs: TengShaderPartList;
  2512. begin
  2513. procs := TengShaderPartList.Create(false);
  2514. try
  2515. s := CheckParentScope(aParentProc);
  2516. if not (s is TengShaderPartClass) then
  2517. raise EengInternal.Create('parent scope of method with inherited token must be a class', Line, Col, Filename);
  2518. s.FindMappedParts(procs, aParentProc.Name, FIND_INHERITED_FLAGS, TengShaderPartProc);
  2519. if (fInheritedName <> '') then begin
  2520. for p in procs do begin
  2521. result := (p as TengShaderPartProc);
  2522. result.GetParentType(TengShaderPartClass, c);
  2523. if not Assigned(c) then
  2524. raise EengInternal.Create('inherited method without class', Line, Col, Filename);
  2525. if (c.Name = fInheritedName) then
  2526. exit;
  2527. end;
  2528. raise EengInvalidIdentifier.Create('could not find inherited method: ' + aParentProc.Name, Line, Col, Filename)
  2529. end else if (procs.Count > 1) then
  2530. raise EengInvalidParamterCount.Create(GetTokenName + ' is ambiguous: specify inherited class')
  2531. else if (procs.Count <= 0) then
  2532. raise EengInvalidIdentifier.Create('could not find inherited method: ' + aParentProc.Name, Line, Col, Filename)
  2533. else
  2534. result := (procs[0] as TengShaderPartProc);
  2535. finally
  2536. FreeAndNil(procs);
  2537. end;
  2538. end;
  2539. procedure GenCode(const aProc: TengShaderPartProc; const aParams: TStrings);
  2540. begin
  2541. aGenCodeArgs.PushFlags(aGenCodeArgs.Flags + [gcfGenProcInline]);
  2542. aGenCodeArgs.PushProcParams(aParams);
  2543. try
  2544. aProc.GenCodeIntern(aGenCodeArgs);
  2545. finally
  2546. aGenCodeArgs.PopProcParams;
  2547. aGenCodeArgs.PopFlags;
  2548. end;
  2549. end;
  2550. var
  2551. proc: TengShaderPartProc;
  2552. params: TStringList;
  2553. p: TengShaderPartProcParam;
  2554. begin
  2555. inherited GenCodeIntern(aGenCodeArgs);
  2556. GetParentType(TengShaderPartProc, proc);
  2557. if not Assigned(proc) then
  2558. raise EengInternal.Create('inherited without parent procedure', Line, Col, Filename);
  2559. proc := FindProc(proc);
  2560. if (fParameters.Count > 0) then begin
  2561. if (fParameters.Count <> proc.fParameters.Count) then
  2562. raise EengInvalidParamterCount.Create(proc.Name + ' expects ' + IntToStr(proc.fParameters.Count) + ' parameter', Line, Col, Filename);
  2563. GenCode(proc, fParameters);
  2564. end else begin
  2565. params := TStringList.Create;
  2566. try
  2567. for p in proc.fParameters do
  2568. params.Add(p.Name);
  2569. GenCode(proc, params);
  2570. finally
  2571. FreeAndNil(params);
  2572. end;
  2573. end;
  2574. end;
  2575. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2576. constructor TengShaderPartInherited.Create(const aParent: TengShaderPart);
  2577. begin
  2578. inherited Create(aParent);
  2579. fParameters := TStringList.Create;
  2580. end;
  2581. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2582. destructor TengShaderPartInherited.Destroy;
  2583. begin
  2584. FreeAndNil(fParameters);
  2585. inherited Destroy;
  2586. end;
  2587. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2588. class function TengShaderPartInherited.GetTokenName: String;
  2589. begin
  2590. result := TOKEN_INHERITED;
  2591. end;
  2592. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2593. class procedure TengShaderPartInherited.CheckToken(const aParseArgs: TengParseArgs; const aParent: TengShaderPart);
  2594. begin
  2595. inherited CheckToken(aParseArgs, aParent);
  2596. if not ((aParent is TengShaderPartProc) or aParent.ParentHasType(TengShaderPartProc)) or
  2597. not (aParent.ParentHasType(TengShaderPartClass)) then
  2598. with aParseArgs do
  2599. raise EengShaderPart.Create(GetTokenName + ' is not allowed outside of a function or procedure', Line, Col, aParent.GetFilename);
  2600. end;
  2601. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2602. //TengMetaData//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2603. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2604. function TengMetaData.GetCount: Integer;
  2605. begin
  2606. result := fValues.Count;
  2607. end;
  2608. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2609. function TengMetaData.GetMetaType: TengMetaType;
  2610. begin
  2611. result := fMetaType;
  2612. end;
  2613. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2614. function TengMetaData.GetName: String;
  2615. begin
  2616. result := fName;
  2617. end;
  2618. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2619. function TengMetaData.GetValues(const aIndex: Integer): String;
  2620. begin
  2621. result := fValues[aIndex];
  2622. end;
  2623. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2624. procedure TengMetaData.AddValue(const aValue: String);
  2625. begin
  2626. fValues.Add(aValue);
  2627. end;
  2628. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2629. constructor TengMetaData.Create(const aName: String; const aType: TengMetaType);
  2630. begin
  2631. inherited Create;
  2632. fName := aName;
  2633. fMetaType := aType;
  2634. fValues := TStringList.Create;
  2635. end;
  2636. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2637. destructor TengMetaData.Destroy;
  2638. begin
  2639. FreeAndNil(fValues);
  2640. inherited Destroy;
  2641. end;
  2642. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2643. //TengShaderPartMeta////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2644. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2645. function TengShaderPartMeta.GetText: String;
  2646. var
  2647. i: Integer;
  2648. begin
  2649. result := PRECOMPILER_STATEMENT_BEGIN + GetTokenName + ' ' + fMetaData.Name;
  2650. for i := 0 to fMetaData.Count-1 do
  2651. result := result + ' ' + fMetaData[i];
  2652. result := result + PRECOMPILER_STATEMENT_END;
  2653. end;
  2654. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2655. function TengShaderPartMeta.ParseTextIntern(const aParseArgs: TengParseArgs; const aParameters: TengTokenParameterList): String;
  2656. var
  2657. i: Integer;
  2658. t: TengMetaType;
  2659. d: TengMetaData;
  2660. n: String;
  2661. begin
  2662. if (aParameters[0].Name <> GetTokenName) then
  2663. raise EengInvalidToken.Create(ClassName, aParameters[0].Name, Line, Col, Filename);
  2664. if (aParameters.Count < 2) then
  2665. raise EengInvalidParamterCount.Create(GetTokenName, Line, Col, Filename);
  2666. result := '';
  2667. n := aParameters[1].Name;
  2668. {.$VERSION}
  2669. if (n = TOKEN_VERSION) then begin
  2670. t := metaVersion;
  2671. if (aParameters.Count >= 3) and (aParameters.Count <= 4) then
  2672. if (aParameters.Count = 3) then begin
  2673. if (aParameters[2].Name <> VERSION_EXTRA_COMPAT) and not TryStrToInt(aParameters[2].Name, i) then
  2674. raise EengInvalidParamter.Create('version must be an number or "' + VERSION_EXTRA_COMPAT + '"', Line, Col, Filename);
  2675. end else if (aParameters.Count = 4) then begin
  2676. if (aParameters[2].Name <> VERSION_EXTRA_COMPAT) and not TryStrToInt(aParameters[2].Name, i) then
  2677. raise EengInvalidParamter.Create('version must be an number or "' + VERSION_EXTRA_COMPAT + '"', Line, Col, Filename);
  2678. if (aParameters[3].Name <> VERSION_EXTRA_COMPAT) then
  2679. raise EengInvalidParamter.Create('only "' + VERSION_EXTRA_COMPAT + '" is alowed as second parameter', Line, Col, Filename);
  2680. end else
  2681. raise EengInvalidParamterCount.Create(GetTokenName, Line, Col, Filename);
  2682. {.$EXTENSION}
  2683. end else if (n = TOKEN_EXTENSION) then begin
  2684. t := metaExtension;
  2685. if (aParameters.Count <> 4) then
  2686. raise EengInvalidParamterCount.Create(GetTokenName, Line, Col, Filename);
  2687. {.$LAYOUT}
  2688. end else if (n = TOKEN_LAYOUT) then begin
  2689. t := metaLayout;
  2690. if (aParameters.Count <> 3) then
  2691. raise EengInvalidParamterCount.Create(GetTokenName, Line, Col, Filename);
  2692. {.VALUES}
  2693. end else
  2694. t := metaNormal;
  2695. d := TengMetaData.Create(n, t);
  2696. for i := 2 to aParameters.Count-1 do
  2697. d.AddValue(aParameters[i].Name);
  2698. fMetaData := d;
  2699. end;
  2700. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2701. procedure TengShaderPartMeta.GenCodeIntern(const aGenCodeArgs: TengGenCodeArgs);
  2702. begin
  2703. inherited GenCodeIntern(aGenCodeArgs);
  2704. aGenCodeArgs.AddMeta(fMetaData);
  2705. end;
  2706. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2707. destructor TengShaderPartMeta.Destroy;
  2708. begin
  2709. fMetaData := nil;
  2710. inherited Destroy;
  2711. end;
  2712. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2713. class function TengShaderPartMeta.GetTokenName: String;
  2714. begin
  2715. result := TOKEN_META;
  2716. end;
  2717. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2718. //TengShaderPartKeyValuePair////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2719. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2720. function TengShaderPartKeyValuePair.GetText: String;
  2721. begin
  2722. result := PRECOMPILER_STATEMENT_BEGIN + GetTokenName + ' ' + fName;
  2723. if (fValueName <> '') then
  2724. result := result + ' ' + fValueName
  2725. else if (fValue <> Unassigned) then
  2726. result := result + ' ''' + String(fValue) + '''';
  2727. result := result + PRECOMPILER_STATEMENT_END;
  2728. end;
  2729. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2730. function TengShaderPartKeyValuePair.ParseTextIntern(const aParseArgs: TengParseArgs; const aParameters: TengTokenParameterList): String;
  2731. begin
  2732. if (aParameters[0].Name <> GetTokenName) then
  2733. raise EengInvalidToken.Create(ClassName, GetTokenName, Line, Col, Filename);
  2734. if (aParameters.Count < 2) or (aParameters.Count > 3) then
  2735. raise EengInvalidParamterCount.Create(GetTokenName, Line, Col, Filename);
  2736. result := '';
  2737. fName := aParameters[1].Name;
  2738. if not IsValidIdentifier(fName) then
  2739. raise EengInvalidIdentifier.Create(fName, Line, Col, Filename);
  2740. if (aParameters.Count >= 3) then
  2741. if aParameters[2].Quoted then begin
  2742. fValue := aParameters[2].Name;
  2743. fValueName := '';
  2744. end else begin
  2745. fValue := Unassigned;
  2746. fValueName := aParameters[2].Name;
  2747. end
  2748. else begin
  2749. fValue := Unassigned;
  2750. fValueName := '';
  2751. end;
  2752. end;
  2753. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2754. constructor TengShaderPartKeyValuePair.CreateValue(const aParent: TengShaderPart; const aName: String; const aValue: Variant);
  2755. begin
  2756. inherited Create(aParent);
  2757. fName := aName;
  2758. fValue := aValue;
  2759. fValueName := '';
  2760. end;
  2761. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2762. constructor TengShaderPartKeyValuePair.CreateName(const aParent: TengShaderPart; const aName, aValueName: String);
  2763. begin
  2764. inherited Create(aParent);
  2765. fName := aName;
  2766. fValue := Unassigned;
  2767. fValueName := aValueName;
  2768. end;
  2769. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2770. procedure TengShaderPartKeyValuePair.GenCodeIntern(const aGenCodeArgs: TengGenCodeArgs);
  2771. begin
  2772. inherited GenCodeIntern(aGenCodeArgs);
  2773. aGenCodeArgs.Code.AddToken(ttSingle);
  2774. end;
  2775. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2776. //TengShaderPartProperty//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2777. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2778. procedure TengShaderPartProperty.MapData(const aFlags: TengMapDataFlags; const aTypes: array of CengShaderPart);
  2779. var
  2780. p: TengShaderPart;
  2781. s: TengShaderPartScope;
  2782. begin
  2783. inherited MapData(aFlags, aTypes);
  2784. if CheckType(self, aTypes) then begin
  2785. s := CheckParentScope(self);
  2786. if s.MapShaderPart(Name, self) and (fValueName <> '') then begin
  2787. s.FindMappedPart(p, fValueName, FIND_IN_SCOPE_FLAGS);
  2788. if not Assigned(p) then
  2789. raise EengUnknownIdentifier.Create(fValueName, Line, Col, Filename)
  2790. else if not (p is TengShaderPartDefine) then
  2791. raise EengInvalidParamter.Create('invalid type, expected ' + TengShaderPartDefine.GetTokenName, Line, Col, Filename)
  2792. else
  2793. fValue := (p as TengShaderPartDefine).Value;
  2794. end;
  2795. end;
  2796. end;
  2797. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2798. class function TengShaderPartProperty.GetTokenName: String;
  2799. begin
  2800. result := TOKEN_PROPERTY;
  2801. end;
  2802. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2803. //TengShaderPartDefine//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2804. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2805. function TengShaderPartDefine.ParseTextIntern(const aParseArgs: TengParseArgs; const aParameters: TengTokenParameterList): String;
  2806. begin
  2807. if (aParameters.Count <> 3) then
  2808. raise EengInvalidParamterCount.Create(GetTokenName, Line, Col, GetFilename);
  2809. result := inherited ParseTextIntern(aParseArgs, aParameters);
  2810. if (fValueName <> '') then
  2811. fValue := fValueName;
  2812. end;
  2813. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2814. procedure TengShaderPartDefine.MapData(const aFlags: TengMapDataFlags; const aTypes: array of CengShaderPart);
  2815. begin
  2816. if CheckType(self, aTypes) then
  2817. CheckParentScope(self).MapShaderPart(Name, self);
  2818. end;
  2819. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2820. class function TengShaderPartDefine.GetTokenName: String;
  2821. begin
  2822. result := TOKEN_DEFINE;
  2823. end;
  2824. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2825. //TengShaderPartCodeProperty////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2826. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2827. function TengShaderPartCodeProperty.GetText: String;
  2828. begin
  2829. result := PRECOMPILER_STATEMENT_BEGIN + GetTokenName + ' ''' + fType + ''' ''' + fName + '''' + PRECOMPILER_STATEMENT_END;
  2830. end;
  2831. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2832. function TengShaderPartCodeProperty.ParseTextIntern(const aParseArgs: TengParseArgs; const aParameters: TengTokenParameterList): String;
  2833. begin
  2834. if (aParameters[0].Name <> GetTokenName) then
  2835. raise EengInvalidToken.Create(ClassName, aParameters[0].Name, Line, Col, Filename);
  2836. if (aParameters.Count <> 3) then
  2837. raise EengInvalidParamterCount.Create(GetTokenName, Line, Col, Filename);
  2838. result := '';
  2839. fType := aParameters[1].Name;
  2840. fName := aParameters[2].Name;
  2841. end;
  2842. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2843. function TengShaderPartCodeProperty.IsEquals(const aCodeProp: TengShaderPartCodeProperty): Boolean;
  2844. begin
  2845. result :=
  2846. (ClassName = aCodeProp.ClassName) and
  2847. (fName = aCodeProp.fName) and
  2848. (fType = aCodeProp.fType);
  2849. end;
  2850. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2851. procedure TengShaderPartCodeProperty.MapData(const aFlags: TengMapDataFlags; const aTypes: array of CengShaderPart);
  2852. begin
  2853. if CheckType(self, aTypes) then
  2854. CheckParentScope(self).MapShaderPart(fName, self);
  2855. end;
  2856. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2857. procedure TengShaderPartCodeProperty.GenCodeIntern(const aGenCodeArgs: TengGenCodeArgs);
  2858. begin
  2859. inherited GenCodeIntern(aGenCodeArgs);
  2860. if not (gcfGenCodeProp in aGenCodeArgs.Flags) then begin
  2861. aGenCodeArgs.AddCodeProperty(self);
  2862. aGenCodeArgs.Code.AddToken(ttSingle);
  2863. end;
  2864. end;
  2865. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2866. //TengShaderPartVar/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2867. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2868. function TengShaderPartVar.GetText: String;
  2869. begin
  2870. result := PRECOMPILER_STATEMENT_BEGIN + GetTokenName + ' ''' + fType + ''' ''' + fName + '''';
  2871. if (fDefault <> Unassigned) then
  2872. result := result + ' ''' + fDefault + '''';
  2873. result := result + PRECOMPILER_STATEMENT_END;
  2874. end;
  2875. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2876. function TengShaderPartVar.ParseTextIntern(const aParseArgs: TengParseArgs; const aParameters: TengTokenParameterList): String;
  2877. begin
  2878. if (aParameters[0].Name <> GetTokenName) then
  2879. raise EengInvalidToken.Create(ClassName, aParameters[0].Name, Line, Col, Filename);
  2880. if (aParameters.Count < 3) or (aParameters.Count > 4) then
  2881. raise EengInvalidParamterCount.Create(GetTokenName, Line, Col, Filename);
  2882. result := '';
  2883. fType := aParameters[1].Name;
  2884. fName := aParameters[2].Name;
  2885. if (aParameters.Count >= 4) then
  2886. fDefault := aParameters[3].Name
  2887. else
  2888. fDefault := Unassigned;
  2889. end;
  2890. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2891. function TengShaderPartVar.IsEquals(const aCodeProp: TengShaderPartCodeProperty): Boolean;
  2892. begin
  2893. result := inherited IsEquals(aCodeProp);
  2894. if result and ((aCodeProp as TengShaderPartVar).fDefault <> '') and (fDefault <> '') then
  2895. result := ((aCodeProp as TengShaderPartVar).fDefault = fDefault);
  2896. end;
  2897. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2898. procedure TengShaderPartVar.GenCodeIntern(const aGenCodeArgs: TengGenCodeArgs);
  2899. begin
  2900. inherited GenCodeIntern(aGenCodeArgs);
  2901. if (gcfGenCodeProp in aGenCodeArgs.Flags) then begin
  2902. aGenCodeArgs.Code.AddText(Format('%'+IntToStr(aGenCodeArgs.MaxPropNameLen)+'s %s', [fType, fName]));
  2903. if (fDefault <> '') then
  2904. aGenCodeArgs.Code.AddText(' = ' + fDefault);
  2905. aGenCodeArgs.Code.AddText(';');
  2906. end;
  2907. end;
  2908. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2909. class function TengShaderPartVar.GetTokenName: String;
  2910. begin
  2911. result := TOKEN_VAR;
  2912. end;
  2913. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2914. //TengShaderPartVarying/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2915. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2916. procedure TengShaderPartVarying.GenCodeIntern(const aGenCodeArgs: TengGenCodeArgs);
  2917. begin
  2918. inherited GenCodeIntern(aGenCodeArgs);
  2919. if (gcfGenCodeProp in aGenCodeArgs.Flags) then
  2920. aGenCodeArgs.Code.AddText(Format('varying %'+IntToStr(aGenCodeArgs.MaxPropNameLen)+'s %s;', [fType, fName]));
  2921. end;
  2922. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2923. class function TengShaderPartVarying.GetTokenName: String;
  2924. begin
  2925. result := TOKEN_VARYING;
  2926. end;
  2927. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2928. //TengShaderPartUniform/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2929. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2930. procedure TengShaderPartUniform.GenCodeIntern(const aGenCodeArgs: TengGenCodeArgs);
  2931. begin
  2932. inherited GenCodeIntern(aGenCodeArgs);
  2933. if (gcfGenCodeProp in aGenCodeArgs.Flags) then
  2934. aGenCodeArgs.Code.AddText(Format('uniform %'+IntToStr(aGenCodeArgs.MaxPropNameLen)+'s %s;', [fType, fName]));
  2935. end;
  2936. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2937. class function TengShaderPartUniform.GetTokenName: String;
  2938. begin
  2939. result := TOKEN_UNIFORM;
  2940. end;
  2941. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2942. //TengShaderPartCall////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2943. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2944. function TengShaderPartCall.GetText: String;
  2945. var
  2946. i: Integer;
  2947. begin
  2948. result := PRECOMPILER_STATEMENT_BEGIN + GetTokenName + ' ' + fName;
  2949. for i := 0 to fParameters.Count-1 do
  2950. if (PtrInt(fParameters.Objects[i]) <> 0) then
  2951. result := result + ' ''' + fParameters[i] + ''''
  2952. else
  2953. result := result + ' ' + fParameters[i];
  2954. result := result + PRECOMPILER_STATEMENT_END;
  2955. end;
  2956. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2957. function TengShaderPartCall.ParseTextIntern(const aParseArgs: TengParseArgs; const aParameters: TengTokenParameterList): String;
  2958. var
  2959. i: Integer;
  2960. begin
  2961. if (aParameters[0].Name <> GetTokenName) then
  2962. raise EengInvalidToken.Create(ClassName, aParameters[0].Name, Line, Col, Filename);
  2963. if (aParameters.Count < 2) then
  2964. raise EengInvalidParamterCount.Create(GetTokenName, Line, Col, Filename);
  2965. fParameters.Clear;
  2966. result := '';
  2967. fName := aParameters[1].Name;
  2968. if not IsValidIdentifier(fName) then
  2969. raise EengShaderPart.Create('invalid name: ' + fName, Line, Col, GetFilename);
  2970. for i := 2 to aParameters.Count-1 do
  2971. fParameters.AddObject(aParameters[i].Name, TObject(PtrInt(aParameters[i].Quoted)));
  2972. end;
  2973. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2974. procedure TengShaderPartCall.GenCodeIntern(const aGenCodeArgs: TengGenCodeArgs);
  2975. var
  2976. p: TengShaderPartProc;
  2977. begin
  2978. aGenCodeArgs.Root.FindMappedPart(p, fName, FIND_OVERWRITTEN_FLAGS, TengShaderPartProc);
  2979. if not Assigned(p) then
  2980. CheckParentScope(self).FindMappedPart(p, fName, GEN_CODE_FIND_FLAGS, TengShaderPartProc);
  2981. if not Assigned(p) then
  2982. raise EengUnknownIdentifier.Create(fName, Line, Col, Filename);
  2983. if not (p is TengShaderPartProc) then
  2984. raise EengInvalidParamter.Create('Expected ' + TengShaderPartFunc.GetTokenName + ' or ' + TengShaderPartProc.GetTokenName, Line, Col, Filename);
  2985. if ((p as TengShaderPartProc).fParameters.Count <> fParameters.Count) then
  2986. raise EengInvalidParamterCount.Create(fName + ' expects ' + IntToStr((p as TengShaderPartProc).fParameters.Count) + ' parameter', Line, Col, Filename);
  2987. aGenCodeArgs.PushProcParams(fParameters);
  2988. aGenCodeArgs.PushFlags(aGenCodeArgs.Flags - [gcfGenProcedure, gcfGenProcInline] + [gcfGenProcCall]);
  2989. try
  2990. p.GenCodeIntern(aGenCodeArgs);
  2991. finally
  2992. aGenCodeArgs.PopProcParams;
  2993. aGenCodeArgs.PopFlags;
  2994. end;
  2995. inherited GenCodeIntern(aGenCodeArgs);
  2996. end;
  2997. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2998. constructor TengShaderPartCall.Create(const aParent: TengShaderPart);
  2999. begin
  3000. inherited Create(aParent);
  3001. fParameters := TStringList.Create;
  3002. end;
  3003. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  3004. destructor TengShaderPartCall.Destroy;
  3005. begin
  3006. FreeAndNil(fParameters);
  3007. inherited Destroy;
  3008. end;
  3009. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  3010. class function TengShaderPartCall.GetTokenName: String;
  3011. begin
  3012. result := TOKEN_CALL;
  3013. end;
  3014. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  3015. //TengShaderPartProc////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  3016. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  3017. function TengShaderPartProc.GetHeaderText: String;
  3018. var
  3019. p: TengShaderPartProcParam;
  3020. begin
  3021. result := PRECOMPILER_STATEMENT_BEGIN + GetTokenName + ' ''' + fName + '''';
  3022. for p in fParameters do
  3023. result := result + ' ''' + p.Typ + ''' ''' + p.Name + '''';
  3024. result := result + PRECOMPILER_STATEMENT_END;
  3025. end;
  3026. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  3027. function TengShaderPartProc.GetText: String;
  3028. begin
  3029. result := GetHeaderText +
  3030. inherited GetText +
  3031. PRECOMPILER_STATEMENT_BEGIN + TOKEN_END + PRECOMPILER_STATEMENT_END;
  3032. end;
  3033. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  3034. function TengShaderPartProc.ParseTextIntern(const aParseArgs: TengParseArgs; const aParameters: TengTokenParameterList): String;
  3035. type
  3036. TParseArgsState = (pasType, pasName);
  3037. var
  3038. i: Integer;
  3039. state: TParseArgsState;
  3040. param: TengShaderPartProcParam;
  3041. begin
  3042. if (aParameters[0].Name <> GetTokenName) then
  3043. raise EengInvalidToken.Create(ClassName, aParameters[0].Name, Line, Col, Filename);
  3044. if (aParameters.Count < 2) then
  3045. raise EengInvalidParamterCount.Create(GetTokenName, Line, Col, Filename);
  3046. result := '';
  3047. fName := aParameters[1].Name;
  3048. state := pasType;
  3049. fParameters.Clear;
  3050. i := 2;
  3051. while (i < aParameters.Count) do begin
  3052. case state of
  3053. pasType: begin
  3054. if (aParameters[i].Name = TOKEN_INLINE) then begin
  3055. fIsInline := true;
  3056. end else begin
  3057. param.Typ := aParameters[i].Name;
  3058. state := pasName;
  3059. end;
  3060. end;
  3061. pasName: begin
  3062. if (aParameters[i].Name = TOKEN_INLINE) then begin
  3063. raise EengInvalidParamter.Create('expected parameter name, found ' + TOKEN_INLINE, aParameters[i].Line, aParameters[i].Col, Filename);
  3064. end else begin
  3065. param.Name := aParameters[i].Name;
  3066. fParameters.Add(param);
  3067. state := pasType;
  3068. end;
  3069. end;
  3070. end;
  3071. inc(i);
  3072. end;
  3073. if (state <> pasType) then
  3074. raise EengInvalidParamterCount.Create(GetTokenName, Line, Col, Filename);
  3075. inherited ParseTextIntern(aParseArgs, aParameters);
  3076. result := CheckEndToken(aParseArgs, self);
  3077. end;
  3078. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  3079. function TengShaderPartProc.GenHeaderCode: String;
  3080. var
  3081. p: TengShaderPartProcParam;
  3082. begin
  3083. result := '';
  3084. for p in fParameters do begin
  3085. if (result <> '') then
  3086. result := result + ', ';
  3087. result := result + p.Typ + ' ' + p.Name;
  3088. end;
  3089. if (result = '') then
  3090. result := 'void';
  3091. result := 'void ' + fName + '(' + result + ')';
  3092. end;
  3093. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  3094. procedure TengShaderPartProc.GenInlineCode(const aGenCodeArgs: TengGenCodeArgs; const aAddToken: Boolean);
  3095. var
  3096. old, new: TStringList;
  3097. p: TengShaderPartProcParam;
  3098. rx: TRegExpr;
  3099. s: String;
  3100. begin
  3101. aGenCodeArgs.PushCode;
  3102. if aAddToken then
  3103. aGenCodeArgs.Code.AddToken(ttBegin);
  3104. try
  3105. inherited GenCodeIntern(aGenCodeArgs);
  3106. old := TStringList.Create;
  3107. new := TStringList.Create;
  3108. rx := TRegExpr.Create;
  3109. try
  3110. //prepare old parameter
  3111. for p in fParameters do
  3112. old.Add(p.Name);
  3113. //prepare new parameter
  3114. rx.Expression := '[^A-z0-9_]+';
  3115. for s in aGenCodeArgs.ProcParams do
  3116. if (rx.Exec(s)) then
  3117. new.Add('(' + s + ')')
  3118. else
  3119. new.Add(s);
  3120. //replace parameter
  3121. aGenCodeArgs.Code.ReplaceIdents(old, new);
  3122. finally
  3123. FreeAndNil(rx);
  3124. FreeAndNil(old);
  3125. FreeAndNil(new);
  3126. end;
  3127. finally
  3128. if aAddToken then
  3129. aGenCodeArgs.Code.AddToken(ttEnd);
  3130. aGenCodeArgs.PopCode;
  3131. end;
  3132. end;
  3133. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  3134. procedure TengShaderPartProc.GenCodeIntern(const aGenCodeArgs: TengGenCodeArgs);
  3135. var
  3136. s, params: String;
  3137. begin
  3138. // generate inline code
  3139. if (aGenCodeArgs.Flags * [gcfGenProcCall, gcfGenProcedure] <> []) and
  3140. ((gcfGenProcInline in aGenCodeArgs.Flags) or fIsInline) then
  3141. begin
  3142. GenInlineCode(aGenCodeArgs);
  3143. if (ClassType = TengShaderPartProc) then
  3144. aGenCodeArgs.Code.IgnoreNextSemicolon;
  3145. // generate code
  3146. end else if (gcfGenProcedure in aGenCodeArgs.Flags) then begin
  3147. aGenCodeArgs.Code.AddLineEnd;
  3148. aGenCodeArgs.Code.AddText(GenHeaderCode);
  3149. aGenCodeArgs.Code.AddLineEnd;
  3150. aGenCodeArgs.Code.AddText('{');
  3151. aGenCodeArgs.Code.AddLineEnd;
  3152. aGenCodeArgs.Code.AddToken(ttBegin);
  3153. aGenCodeArgs.Code.AddCommandEnd();
  3154. try
  3155. inherited GenCodeIntern(aGenCodeArgs);
  3156. finally
  3157. aGenCodeArgs.Code.AddText('}');
  3158. aGenCodeArgs.Code.AddToken(ttEnd);
  3159. aGenCodeArgs.Code.AddCommandEnd();
  3160. aGenCodeArgs.Code.AddLineEnd;
  3161. end;
  3162. // generate call
  3163. end else if (gcfGenProcCall in aGenCodeArgs.Flags) then begin
  3164. params := '';
  3165. for s in aGenCodeArgs.ProcParams do begin
  3166. if (params <> '') then
  3167. params := params + ', ';
  3168. params := params + s;
  3169. end;
  3170. aGenCodeArgs.Code.AddText(fName + '(' + params + ')');
  3171. aGenCodeArgs.AddProcedure(self);
  3172. end;
  3173. end;
  3174. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  3175. procedure TengShaderPartProc.MapData(const aFlags: TengMapDataFlags; const aTypes: array of CengShaderPart);
  3176. begin
  3177. if CheckType(self, aTypes) then begin
  3178. with CheckParentScope(self) do begin
  3179. MapShaderPart(fName, self); // Procs are named shader parts
  3180. MapChildScope(self); // and also Child Scopes
  3181. end;
  3182. end;
  3183. end;
  3184. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  3185. constructor TengShaderPartProc.Create(const aParent: TengShaderPart);
  3186. begin
  3187. inherited Create(aParent);
  3188. fParameters := TengShaderPartProcParamList.Create(true);
  3189. end;
  3190. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  3191. destructor TengShaderPartProc.Destroy;
  3192. begin
  3193. FreeAndNil(fParameters);
  3194. inherited Destroy;
  3195. end;
  3196. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  3197. class function TengShaderPartProc.GetTokenName: String;
  3198. begin
  3199. result := TOKEN_PROC;
  3200. end;
  3201. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  3202. class procedure TengShaderPartProc.CheckToken(const aParseArgs: TengParseArgs; const aParent: TengShaderPart);
  3203. begin
  3204. if (aParent is TengShaderPartProc) or (aParent.ParentHasType(TengShaderPartProc)) then
  3205. with aParseArgs do
  3206. raise EengShaderPart.Create('token ' + GetTokenName + ' is not allowed in procedure or function', Line, Col, aParent.Filename);
  3207. end;
  3208. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  3209. //TengShaderPartMain////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  3210. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  3211. function TengShaderPartMain.GetHeaderText: String;
  3212. begin
  3213. result := PRECOMPILER_STATEMENT_BEGIN + GetTokenName + PRECOMPILER_STATEMENT_END;
  3214. end;
  3215. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  3216. function TengShaderPartMain.ParseTextIntern(const aParseArgs: TengParseArgs; const aParameters: TengTokenParameterList): String;
  3217. var
  3218. p: TengTokenParameter;
  3219. begin
  3220. if (aParameters[0].Name <> GetTokenName) then
  3221. raise EengInvalidToken.Create(ClassName, aParameters[0].Name, Line, Col, Filename);
  3222. if (aParameters.Count <> 1) then
  3223. raise EengInvalidParamterCount.Create(GetTokenName, Line, Col, Filename);
  3224. result := '';
  3225. p.Name := 'main';
  3226. p.Quoted := false;
  3227. aParameters.Add(p);
  3228. inherited ParseTextIntern(aParseArgs, aParameters);
  3229. end;
  3230. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  3231. function TengShaderPartMain.GenHeaderCode: String;
  3232. begin
  3233. result := 'void main(void)';
  3234. end;
  3235. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  3236. class function TengShaderPartMain.GetTokenName: String;
  3237. begin
  3238. result := TOKEN_MAIN;
  3239. end;
  3240. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  3241. //TengShaderPartFunc////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  3242. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  3243. function TengShaderPartFunc.GetHeaderText: String;
  3244. var
  3245. p: TengShaderPartProcParam;
  3246. begin
  3247. result := PRECOMPILER_STATEMENT_BEGIN + GetTokenName + ' ''' + fReturnType + ''' ''' + fName + '''';
  3248. for p in fParameters do
  3249. result := result + ' ''' + p.Typ + ''' ''' + p.Name + '''';
  3250. result := result + PRECOMPILER_STATEMENT_END;
  3251. end;
  3252. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  3253. function TengShaderPartFunc.ParseTextIntern(const aParseArgs: TengParseArgs; const aParameters: TengTokenParameterList): String;
  3254. begin
  3255. if (aParameters[0].Name <> GetTokenName) then
  3256. raise EengInvalidToken.Create(ClassName, aParameters[0].Name, Line, Col, Filename);
  3257. if (aParameters.Count < 3) then
  3258. raise EengInvalidParamterCount.Create(GetTokenName, Line, Col, Filename);
  3259. fReturnType := aParameters[1].Name;
  3260. aParameters.Delete(1);
  3261. result := inherited ParseTextIntern(aParseArgs, aParameters);
  3262. end;
  3263. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  3264. procedure TengShaderPartFunc.GenInlineCode(const aGenCodeArgs: TengGenCodeArgs; const aAddToken: Boolean);
  3265. var
  3266. o: Integer;
  3267. begin
  3268. o := aGenCodeArgs.PushCurrentCommand.GetMinLineOffset;
  3269. aGenCodeArgs.PushCode;
  3270. aGenCodeArgs.Code.AddLineEnd;
  3271. aGenCodeArgs.Code.AddToken(ttBegin, o);
  3272. try
  3273. inherited GenInlineCode(aGenCodeArgs, false);
  3274. finally
  3275. aGenCodeArgs.PopCurrentCommand(fReturnType, fName);
  3276. aGenCodeArgs.Code.AddToken(ttEnd);
  3277. aGenCodeArgs.PopCode;
  3278. end;
  3279. end;
  3280. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  3281. function TengShaderPartFunc.GenHeaderCode: String;
  3282. var
  3283. p: TengShaderPartProcParam;
  3284. begin
  3285. result := '';
  3286. for p in fParameters do begin
  3287. if (result <> '') then
  3288. result := result + ', ';
  3289. result := result + p.Typ + ' ' + p.Name;
  3290. end;
  3291. if (result = '') then
  3292. result := 'void';
  3293. result := fReturnType + ' ' + fName + '(' + result + ')';
  3294. end;
  3295. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  3296. class function TengShaderPartFunc.GetTokenName: String;
  3297. begin
  3298. result := TOKEN_FUNC;
  3299. end;
  3300. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  3301. class procedure TengShaderPartFunc.CheckToken(const aParseArgs: TengParseArgs; const aParent: TengShaderPart);
  3302. begin
  3303. if (aParent is TengShaderPartFunc) or (aParent.ParentHasType(TengShaderPartFunc)) then
  3304. with aParseArgs do
  3305. raise EengShaderPart.Create('token ' + GetTokenName + ' is not allowed in function', Line, Col, aParent.Filename);
  3306. end;
  3307. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  3308. //TengShaderPartIf//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  3309. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  3310. function TengShaderPartIf.ParseExpression(const aParameters: TengTokenParameterList; aIndex: Integer): TengExpressionItem;
  3311. type
  3312. TExpectedParam = (exVariable, exValue, exGroupBegin, exGroupEnd, exUnaryOperation, exBinaryOperation);
  3313. TExpectedParams = set of TExpectedParam;
  3314. TExpressionItemStack = specialize TutlList<TengExpressionItem>;
  3315. var
  3316. param: TengTokenParameter;
  3317. function NextParam: Boolean;
  3318. begin
  3319. inc(aIndex);
  3320. result := (aIndex < aParameters.Count);
  3321. if result then
  3322. param := aParameters[aIndex];
  3323. end;
  3324. function IsUnaryOperation(const aParam: String; out aOperator: TengExpressionUnaryOperator): Boolean;
  3325. begin
  3326. result := true;
  3327. for aOperator in TengExpressionUnaryOperator do
  3328. if (aParam = EXPRESSION_UNARY_OPERATIONS[aOperator]) then
  3329. exit;
  3330. result := false;
  3331. end;
  3332. function IsBinaryOperation(const aParam: String; out aOperator: TengExpressionBinaryOperator): Boolean;
  3333. begin
  3334. result := true;
  3335. for aOperator in TengExpressionBinaryOperator do
  3336. if (aParam = EXPRESSION_BINARY_OPERATIONS[aOperator]) then
  3337. exit;
  3338. result := false;
  3339. end;
  3340. procedure MergeItems(const aStack: TExpressionItemStack; const aNew: TengExpressionItem);
  3341. var
  3342. itm: TengExpressionItem;
  3343. begin
  3344. if (aStack.Count > 0) then begin
  3345. itm := aStack.Last;
  3346. if (itm is TengExpressionBinaryOperation) then begin
  3347. if (aNew is TengExpressionBinaryOperation) then begin
  3348. //both are binary operators, new is weaker then existing
  3349. if ((aNew as TengExpressionBinaryOperation).BinaryOp < (itm as TengExpressionBinaryOperation).BinaryOp) then begin
  3350. aStack.PopLast;
  3351. (aNew as TengExpressionBinaryOperation).First := itm;
  3352. aStack.PushLast(aNew);
  3353. //both are binary operators, new is stronger than existing
  3354. end else begin
  3355. if not Assigned((itm as TengExpressionBinaryOperation).Second) then
  3356. raise EengExpression.Create('inconsistent state', param.Line, param.Col, Filename);
  3357. (aNew as TengExpressionBinaryOperation).First := (itm as TengExpressionBinaryOperation).Second;
  3358. (itm as TengExpressionBinaryOperation).Second := aNew;
  3359. aStack.PushLast(aNew);
  3360. end;
  3361. //existing is binary operator, new is normal
  3362. end else begin
  3363. if Assigned((itm as TengExpressionBinaryOperation).Second) then
  3364. raise EengExpression.Create('inconsistent state', param.Line, param.Col, Filename);
  3365. (itm as TengExpressionBinaryOperation).Second := aNew;
  3366. while (aStack.Count > 1) do
  3367. aStack.PopLast; //remove all but first
  3368. end;
  3369. end else begin
  3370. //existing is normal item, new is binary operation
  3371. if (aNew is TengExpressionBinaryOperation) then begin
  3372. aStack.PopLast;
  3373. (aNew as TengExpressionBinaryOperation).First := itm;
  3374. aStack.PushLast(aNew);
  3375. //existing is unary operation, new is normal item or unary operation
  3376. end else if (itm is TengExpressionUnaryOperation) then begin
  3377. if Assigned((itm as TengExpressionUnaryOperation).Child) then
  3378. raise EengExpression.Create('inconsistent state', param.Line, param.Col, Filename);
  3379. (itm as TengExpressionUnaryOperation).Child := aNew;
  3380. if not (aNew is TengExpressionUnaryOperation) then begin
  3381. while (aStack.Count > 1) do
  3382. aStack.PopLast; //remove all but first
  3383. end else
  3384. aStack.PushLast(aNew);
  3385. //existing and new are both normal items
  3386. end else begin
  3387. raise EengExpression.Create('inconsistent state', param.Line, param.Col, Filename);
  3388. end;
  3389. end;
  3390. end else
  3391. aStack.PushLast(aNew);
  3392. end;
  3393. function BuildTree(const aDepth: Integer = 0): TengExpressionItem;
  3394. var
  3395. uOp: TengExpressionUnaryOperator;
  3396. bOp: TengExpressionBinaryOperator;
  3397. expected: TExpectedParams;
  3398. stack: TExpressionItemStack;
  3399. begin
  3400. expected := [exVariable, exValue, exGroupBegin, exUnaryOperation];
  3401. result := nil;
  3402. stack := TExpressionItemStack.Create(false);
  3403. try try
  3404. repeat
  3405. //GroupBegin
  3406. if (param.Name = TOKEN_OP_GROUP_BEGIN) then begin
  3407. if not (exGroupBegin in expected) then
  3408. raise EengExpression.Create('unexpected ''' + TOKEN_OP_GROUP_BEGIN + '''', param.Line, param.Col, Filename);
  3409. if not NextParam then
  3410. raise EengExpression.Create('unexpected end', Line, Col, Filename);
  3411. MergeItems(stack, TengExpressionGroup.Create(BuildTree(aDepth + 1), param.Line, param.Col, Filename));
  3412. if (param.Name <> TOKEN_OP_GROUP_END) then
  3413. raise EengExpression.Create('missing ''' + TOKEN_OP_GROUP_END + '''', param.Line, param.Col, Filename);
  3414. expected := [exBinaryOperation, exGroupEnd];
  3415. //GroupEnd
  3416. end else if (param.Name = TOKEN_OP_GROUP_END) then begin
  3417. if not (exGroupEnd in expected) or (aDepth = 0) then
  3418. raise EengExpression.Create('unexpected ''' + TOKEN_OP_GROUP_END + '''', param.Line, param.Col, Filename);
  3419. exit;
  3420. //UnaryOperation
  3421. end else if IsUnaryOperation(param.Name, uOp) then begin
  3422. if not (exUnaryOperation in expected) then
  3423. raise EengExpression.Create('unexpected operator: ' + param.Name, param.Line, param.Col, Filename);
  3424. MergeItems(stack, TengExpressionUnaryOperation.Create(uOp, param.Line, param.Col, Filename));
  3425. expected := [exVariable];
  3426. if (uOp <> opDefined) then
  3427. expected := expected + [exValue, exGroupBegin, exUnaryOperation]
  3428. //BinaryOperation
  3429. end else if IsBinaryOperation(param.Name, bOp) then begin
  3430. if not (exBinaryOperation in expected) then
  3431. raise EengExpression.Create('unexpected operator: ' + param.Name, param.Line, param.Col, Filename);
  3432. MergeItems(stack, TengExpressionBinaryOperation.Create(bOp, param.Line, param.Col, Filename));
  3433. expected := [exVariable, exValue, exGroupBegin, exUnaryOperation];
  3434. //Value
  3435. end else if param.Quoted and IsValidIdentifier(param.Name) then begin
  3436. if not (exValue in expected) then
  3437. raise EengExpression.Create('unexpected value: ' + param.Name, param.Line, param.Col, Filename);
  3438. MergeItems(stack, TengExpressionValue.Create(param.Name, param.Line, param.Col, Filename));
  3439. expected := [exGroupEnd, exBinaryOperation];
  3440. //Variable
  3441. end else if IsValidIdentifier(param.Name) then begin
  3442. if not (exVariable in expected) then
  3443. raise EengExpression.Create('unexpected variable: ' + param.Name, param.Line, param.Col, Filename);
  3444. MergeItems(stack, TengExpressionVariable.Create(param.Name, param.Line, param.Col, Filename));
  3445. expected := [exGroupEnd, exBinaryOperation];
  3446. //Unknown
  3447. end else
  3448. raise EengExpression.Create('invalid parameter: ' + param.Name, param.Line, param.Col, Filename);
  3449. until not NextParam;
  3450. except
  3451. if (stack.Count > 0) then begin
  3452. stack[0].Free;
  3453. stack[0] := nil;
  3454. end;
  3455. raise;
  3456. end;
  3457. finally
  3458. if (stack.Count > 0) then
  3459. result := stack[0];
  3460. FreeAndNil(stack);
  3461. end;
  3462. end;
  3463. begin
  3464. if (aIndex >= aParameters.Count) then
  3465. raise EengExpression.Create('invalid parameter count in expression', Line, Col, Filename);
  3466. dec(aIndex);
  3467. NextParam;
  3468. result := BuildTree;
  3469. end;
  3470. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  3471. function TengShaderPartIf.GetCount: Integer;
  3472. begin
  3473. result := 1;
  3474. if Assigned(fElsePart) then
  3475. inc(result);
  3476. end;
  3477. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  3478. function TengShaderPartIf.GetChild(const aIndex: Integer): TengShaderPart;
  3479. begin
  3480. if (aIndex >= 0) and (aIndex < Count) then begin
  3481. case aIndex of
  3482. 0: result := fIfPart;
  3483. 1: result := fElsePart;
  3484. end;
  3485. end else
  3486. raise EOutOfRange.Create(aIndex, 0, Count-1);
  3487. end;
  3488. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  3489. function TengShaderPartIf.GetText: String;
  3490. begin
  3491. result := PRECOMPILER_STATEMENT_BEGIN + GetTokenName + ' ' + fExpression.GetText + PRECOMPILER_STATEMENT_END + fIfPart.Text;
  3492. if Assigned(fElsePart) then
  3493. result := result + fElsePart.Text;
  3494. result := result + PRECOMPILER_STATEMENT_BEGIN + TOKEN_END + PRECOMPILER_STATEMENT_END;
  3495. end;
  3496. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  3497. function TengShaderPartIf.ParseTextIntern(const aParseArgs: TengParseArgs; const aParameters: TengTokenParameterList): String;
  3498. begin
  3499. if (aParameters[0].Name <> GetTokenName) then
  3500. raise EengInvalidToken.Create(ClassName, aParameters[0].Name, Line, Col, Filename);
  3501. if (aParameters.Count < 2) then
  3502. raise EengInvalidParamterCount.Create(GetTokenName, Line, Col, Filename);
  3503. fExpression := ParseExpression(aParameters, 1);
  3504. fIfPart := TengShaderPartContainer.Create(self);
  3505. result := fIfPart.ParseText(aParseArgs);
  3506. result := HandleToken(result, aParseArgs);
  3507. end;
  3508. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  3509. function TengShaderPartIf.HandleToken(const aToken: String; const aParseArgs: TengParseArgs): String;
  3510. begin
  3511. result := aToken;
  3512. if (result = TengShaderPartElse.GetTokenName) then begin
  3513. fElsePart := TengShaderPartElse.Create(self);
  3514. result := fElsePart.ParseText(aParseArgs);
  3515. end else if (result = TengShaderPartElIf.GetTokenName) then begin
  3516. fElsePart := TengShaderPartElIf.Create(self);
  3517. result := fElsePart.ParseText(aParseArgs);
  3518. end;
  3519. result := HandleEndToken(result, aParseArgs);
  3520. end;
  3521. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  3522. function TengShaderPartIf.HandleEndToken(const aToken: String; const aParseArgs: TengParseArgs): String;
  3523. begin
  3524. result := CheckEndToken(aParseArgs, self);
  3525. end;
  3526. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  3527. procedure TengShaderPartIf.MapData(const aFlags: TengMapDataFlags; const aTypes: array of CengShaderPart);
  3528. begin
  3529. inherited MapData(aFlags, aTypes);
  3530. //map all
  3531. if (mdfIfAll in aFlags) then begin
  3532. if Assigned(fIfPart) then
  3533. fIfPart.MapData(aFlags, aTypes);
  3534. if Assigned(fElsePart) then
  3535. fElsePart.MapData(aFlags, aTypes);
  3536. // evaluete and map suitable
  3537. end else if (mdfIfEvaluate in aFlags) then begin
  3538. if fExpression.GetValue(CheckParentScope(self), nil) then begin
  3539. if Assigned(fIfPart) then
  3540. fIfPart.MapData(aFlags, aTypes);
  3541. end else begin
  3542. if Assigned(fElsePart) then
  3543. fElsePart.MapData(aFlags, aTypes);
  3544. end;
  3545. end;
  3546. end;
  3547. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  3548. procedure TengShaderPartIf.GenCodeIntern(const aGenCodeArgs: TengGenCodeArgs);
  3549. var
  3550. p: TengShaderPart;
  3551. b: Boolean;
  3552. begin
  3553. inherited GenCodeIntern(aGenCodeArgs);
  3554. b := fExpression.GetValue(CheckParentScope(self), aGenCodeArgs);
  3555. if b then
  3556. p := fIfPart
  3557. else
  3558. p := fElsePart;
  3559. aGenCodeArgs.Code.AddToken(ttBegin); // IF ...
  3560. try
  3561. if Assigned(p) then
  3562. p.GenCodeIntern(aGenCodeArgs);
  3563. finally
  3564. aGenCodeArgs.Code.AddToken(ttEnd); // ... END
  3565. end;
  3566. end;
  3567. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  3568. destructor TengShaderPartIf.Destroy;
  3569. begin
  3570. FreeAndNil(fExpression);
  3571. FreeAndNil(fIfPart);
  3572. FreeAndNil(fElsePart);
  3573. inherited Destroy;
  3574. end;
  3575. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  3576. class function TengShaderPartIf.GetTokenName: String;
  3577. begin
  3578. result := TOKEN_IF;
  3579. end;
  3580. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  3581. //TengShaderPartElIf////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  3582. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  3583. function TengShaderPartElIf.GetText: String;
  3584. begin
  3585. result := PRECOMPILER_STATEMENT_BEGIN + GetTokenName + PRECOMPILER_STATEMENT_END + fIfPart.Text;
  3586. if Assigned(fElsePart) then
  3587. result := result + fElsePart.Text;
  3588. end;
  3589. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  3590. function TengShaderPartElIf.HandleEndToken(const aToken: String; const aParseArgs: TengParseArgs): String;
  3591. begin
  3592. result := aToken;
  3593. if (result <> TOKEN_END) then
  3594. raise EengInvalidToken.Create(ClassName, result, aParseArgs.Line, aParseArgs.Col, Filename);
  3595. end;
  3596. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  3597. class function TengShaderPartElIf.GetTokenName: String;
  3598. begin
  3599. result := TOKEN_ELIF;
  3600. end;
  3601. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  3602. //TengShaderPartElse////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  3603. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  3604. function TengShaderPartElse.GetText: String;
  3605. begin
  3606. result := PRECOMPILER_STATEMENT_BEGIN + GetTokenName + PRECOMPILER_STATEMENT_END + inherited GetText;
  3607. end;
  3608. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  3609. class function TengShaderPartElse.GetTokenName: String;
  3610. begin
  3611. result := TOKEN_ELSE;
  3612. end;
  3613. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  3614. //TengShaderPartEcho////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  3615. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  3616. function TengShaderPartEcho.GetText: String;
  3617. begin
  3618. result := PRECOMPILER_STATEMENT_BEGIN + GetTokenName + ' ' + fName + PRECOMPILER_STATEMENT_END;
  3619. end;
  3620. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  3621. function TengShaderPartEcho.ParseTextIntern(const aParseArgs: TengParseArgs; const aParameters: TengTokenParameterList): String;
  3622. begin
  3623. if (aParameters[0].Name <> GetTokenName) then
  3624. raise EengInvalidToken.Create(ClassName, aParameters[0].Name, Line, Col, Filename);
  3625. if (aParameters.Count <> 2) then
  3626. raise EengInvalidParamterCount.Create(GetTokenName, Line, Col, Filename);
  3627. result := '';
  3628. fName := aParameters[1].Name;
  3629. if not IsValidIdentifier(fName) then
  3630. raise EengShaderPart.Create('invalid name: ' + fName, Line, Col, GetFilename);
  3631. end;
  3632. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  3633. procedure TengShaderPartEcho.GenCodeIntern(const aGenCodeArgs: TengGenCodeArgs);
  3634. var
  3635. p: TengShaderPart;
  3636. begin
  3637. CheckParentScope(self).FindMappedPart(p, fName, GEN_CODE_FIND_FLAGS);
  3638. if not Assigned(p) then
  3639. raise EengUnknownIdentifier.Create(fName, Line, Col, Filename);
  3640. if not (p is TengShaderPartKeyValuePair) then
  3641. raise EengInvalidParamter.Create('Expected ' + TengShaderPartDefine.GetTokenName + ' or ' + TengShaderPartProperty.GetTokenName, Line, Col, Filename);
  3642. aGenCodeArgs.Code.AddText((p as TengShaderPartKeyValuePair).Value);
  3643. inherited GenCodeIntern(aGenCodeArgs);
  3644. end;
  3645. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  3646. class function TengShaderPartEcho.GetTokenName: String;
  3647. begin
  3648. result := TOKEN_ECHO;
  3649. end;
  3650. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  3651. //TengShaderPartMessage/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  3652. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  3653. function TengShaderPartMessage.GetText: String;
  3654. begin
  3655. result := PRECOMPILER_STATEMENT_BEGIN + GetTokenName + ' ''' + fMessage + '''' + PRECOMPILER_STATEMENT_END;
  3656. end;
  3657. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  3658. function TengShaderPartMessage.ParseTextIntern(const aParseArgs: TengParseArgs; const aParameters: TengTokenParameterList): String;
  3659. begin
  3660. if (aParameters[0].Name <> GetTokenName) then
  3661. raise EengInvalidToken.Create(ClassName, aParameters[0].Name, Line, Col, Filename);
  3662. if (aParameters.Count <> 2) then
  3663. raise EengInvalidParamterCount.Create(GetTokenName, Line, Col, Filename);
  3664. result := '';
  3665. fMessage := aParameters[1].Name;
  3666. end;
  3667. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  3668. class function TengShaderPartMessage.GetTokenName: String;
  3669. begin
  3670. result := TOKEN_MESSAGE;
  3671. end;
  3672. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  3673. //TengShaderPartWarning/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  3674. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  3675. class function TengShaderPartWarning.GetTokenName: String;
  3676. begin
  3677. result := TOKEN_WARNING;
  3678. end;
  3679. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  3680. //TengShaderPartError///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  3681. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  3682. procedure TengShaderPartError.GenCodeIntern(const aGenCodeArgs: TengGenCodeArgs);
  3683. begin
  3684. inherited GenCodeIntern(aGenCodeArgs);
  3685. raise EengShaderPart.Create(fMessage, Line, Col, Filename);
  3686. end;
  3687. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  3688. class function TengShaderPartError.GetTokenName: String;
  3689. begin
  3690. result := TOKEN_ERROR;
  3691. end;
  3692. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  3693. //TengShaderPartCode////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  3694. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  3695. function TengShaderPartCode.GetText: String;
  3696. begin
  3697. result := fCode;
  3698. end;
  3699. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  3700. function TengShaderPartCode.ParseTextIntern(const aParseArgs: TengParseArgs; const aParameters: TengTokenParameterList): String;
  3701. function CheckToken: Boolean;
  3702. begin
  3703. with aParseArgs do
  3704. result :=
  3705. (CurrentChar = PRECOMPILER_STATEMENT_BEGIN) and
  3706. (Col < LineLength) and
  3707. (CurrentLine[Col + 1] in [TOKEN_IDENTIFIER, COMMENT_IDENTIFIER]);
  3708. end;
  3709. function FindToken: String;
  3710. var
  3711. c: Integer;
  3712. begin
  3713. with aParseArgs do
  3714. if (CurrentChar = TOKEN_COMMAND_END) then
  3715. result := TOKEN_COMMAND_END
  3716. else if (Col < LineLength) then begin
  3717. c := Col + 1;
  3718. case CurrentLine[c] of
  3719. TOKEN_IDENTIFIER: begin
  3720. result := TOKEN_IDENTIFIER;
  3721. inc(c);
  3722. while (c <= LineLength) and (CurrentLine[c] in VALID_TOKEN_CHARS) do begin
  3723. result := result + CurrentLine[c];
  3724. inc(c);
  3725. end;
  3726. result := Trim(result);
  3727. if (result = TOKEN_IDENTIFIER) then
  3728. raise EengShaderPart.Create('empty token', Line, Col, Filename);
  3729. end;
  3730. //skip comment
  3731. COMMENT_IDENTIFIER:
  3732. result := COMMENT_IDENTIFIER;
  3733. end;
  3734. end else begin
  3735. result := '';
  3736. aParseArgs.IncCol;
  3737. end;
  3738. end;
  3739. begin
  3740. fCode := '';
  3741. while not aParseArgs.EndOfLine do begin
  3742. if CheckToken then begin
  3743. result := FindToken;
  3744. if (result <> '') then
  3745. exit;
  3746. end else if (aParseArgs.CurrentChar in COMMAND_END_TOKENS) then begin
  3747. result := aParseArgs.CurrentChar;
  3748. exit;
  3749. end else begin
  3750. fCode := fCode + aParseArgs.CurrentChar;
  3751. aParseArgs.IncCol;
  3752. end;
  3753. end;
  3754. result := TOKEN_LINE_BREAK;
  3755. end;
  3756. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  3757. procedure TengShaderPartCode.GenCodeIntern(const aGenCodeArgs: TengGenCodeArgs);
  3758. begin
  3759. inherited GenCodeIntern(aGenCodeArgs);
  3760. aGenCodeArgs.Code.AddText(fCode);
  3761. end;
  3762. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  3763. //TengShaderPartLineBreak///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  3764. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  3765. function TengShaderPartLineBreak.GetText: String;
  3766. begin
  3767. result := GetTokenName;
  3768. end;
  3769. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  3770. function TengShaderPartLineBreak.ParseTextIntern(const aParseArgs: TengParseArgs; const aParameters: TengTokenParameterList): String;
  3771. begin
  3772. if not aParseArgs.EndOfLine then
  3773. raise EengShaderPart.Create('TengShaderPartLineBreak but not end of line', aParseArgs.Line, aParseArgs.Col, Filename);
  3774. aParseArgs.IncLine;
  3775. result := '';
  3776. end;
  3777. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  3778. procedure TengShaderPartLineBreak.GenCodeIntern(const aGenCodeArgs: TengGenCodeArgs);
  3779. begin
  3780. inherited GenCodeIntern(aGenCodeArgs);
  3781. aGenCodeArgs.Code.AddLineEnd;
  3782. end;
  3783. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  3784. class function TengShaderPartLineBreak.GetTokenName: String;
  3785. begin
  3786. result := TOKEN_LINE_BREAK;
  3787. end;
  3788. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  3789. //TengShaderPartCommandEnd//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  3790. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  3791. function TengShaderPartCommandEnd.GetText: String;
  3792. begin
  3793. result := fToken;
  3794. end;
  3795. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  3796. function TengShaderPartCommandEnd.ParseTextIntern(const aParseArgs: TengParseArgs; const aParameters: TengTokenParameterList): String;
  3797. begin
  3798. result := '';
  3799. fToken := aParseArgs.CurrentChar;
  3800. aParseArgs.IncCol;
  3801. end;
  3802. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  3803. procedure TengShaderPartCommandEnd.GenCodeIntern(const aGenCodeArgs: TengGenCodeArgs);
  3804. begin
  3805. inherited GenCodeIntern(aGenCodeArgs);
  3806. aGenCodeArgs.Code.AddCommandEnd(fToken);
  3807. end;
  3808. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  3809. class function TengShaderPartCommandEnd.CheckToken(const aToken: String): Boolean;
  3810. var
  3811. s: String;
  3812. begin
  3813. result := true;
  3814. for s in COMMAND_END_TOKENS do
  3815. if (s = aToken) then
  3816. exit;
  3817. result := false;
  3818. end;
  3819. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  3820. //TengShaderCode////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  3821. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  3822. function TengShaderCode.GetMeta(const aIndex: Integer): IengMetaData;
  3823. begin
  3824. result := fMetaList[aIndex];
  3825. end;
  3826. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  3827. function TengShaderCode.GetMetaCount: Integer;
  3828. begin
  3829. result := fMetaList.Count;
  3830. end;
  3831. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  3832. constructor TengShaderCode.Create;
  3833. begin
  3834. inherited Create;
  3835. fMetaList := TMetaList.Create;
  3836. end;
  3837. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  3838. destructor TengShaderCode.Destroy;
  3839. begin
  3840. FreeAndNil(fMetaList);
  3841. inherited Destroy;
  3842. end;
  3843. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  3844. //TengShaderCodeIntern//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  3845. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  3846. procedure TengShaderCodeIntern.AddMeta(const aMeta: IengMetaData);
  3847. begin
  3848. fMetaList.Add(aMeta);
  3849. end;
  3850. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  3851. //TengParseArgs/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  3852. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  3853. procedure TengParseArgs.SetCol(const aValue: Integer);
  3854. begin
  3855. fCol := aValue;
  3856. if not EndOfLine then
  3857. fCurrentChar := fCurrentLine[fCol]
  3858. else
  3859. fCurrentChar := #0;
  3860. end;
  3861. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  3862. procedure TengParseArgs.SetLine(const aValue: Integer);
  3863. begin
  3864. fLine := aValue;
  3865. if not EndOfFile then begin
  3866. fCurrentLine := fCode[fLine];
  3867. fLineLength := Length(fCurrentLine);
  3868. end else begin
  3869. fCurrentLine := '';
  3870. fLineLength := -1;
  3871. end;
  3872. Col := 1;
  3873. end;
  3874. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  3875. function TengParseArgs.GetEndOfFile: Boolean;
  3876. begin
  3877. result := (fLine >= fLineCount);
  3878. end;
  3879. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  3880. function TengParseArgs.GetEndOfLine: Boolean;
  3881. begin
  3882. result := (fCol > fLineLength);
  3883. end;
  3884. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  3885. function TengParseArgs.GetCode: TStrings;
  3886. begin
  3887. result := fCode;
  3888. end;
  3889. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  3890. procedure TengParseArgs.IncCol;
  3891. begin
  3892. Col := Col + 1;
  3893. end;
  3894. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  3895. procedure TengParseArgs.IncLine;
  3896. begin
  3897. Line := Line + 1;
  3898. end;
  3899. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  3900. function TengParseArgs.ParseParameters(const aParameters: TengTokenParameterList): Boolean;
  3901. type
  3902. TCharType = (ctUnknown, ctValidTokenChar, ctInvalidTokenChar, ctWhiteSpace);
  3903. var
  3904. s: String;
  3905. charType: TCharType;
  3906. pLine, pCol: Integer;
  3907. isComment: Boolean;
  3908. procedure AddPart(const aTrimAndCheck: Boolean = true);
  3909. var
  3910. len: Integer;
  3911. p: TengTokenParameter;
  3912. begin
  3913. if aTrimAndCheck then
  3914. s := Trim(s);
  3915. if not aTrimAndCheck or (s <> '')then begin
  3916. len := Length(s);
  3917. if aTrimAndCheck and ((s[1] = PRECOMPILER_QUOTE_CHAR) or (s[len] = PRECOMPILER_QUOTE_CHAR)) then begin
  3918. if not (s[1] = PRECOMPILER_QUOTE_CHAR) then
  3919. raise EengShaderPart.Create('missing leading quote char', Line, Col, fOwner.Filename);
  3920. if not (s[len] = PRECOMPILER_QUOTE_CHAR) then
  3921. raise EengShaderPart.Create('missing trailing quote char', Line, Col, fOwner.Filename);
  3922. delete(s, len, 1);
  3923. delete(s, 1, 1);
  3924. p.Quoted := true;
  3925. end else
  3926. p.Quoted := false;
  3927. p.Name := s;
  3928. p.Line := pLine;
  3929. p.Col := pCol;
  3930. aParameters.Add(p);
  3931. end;
  3932. s := '';
  3933. pLine := Line;
  3934. pCol := Col;
  3935. charType := ctUnknown;
  3936. end;
  3937. var
  3938. quote, inToken, commentTokenAdded: Boolean;
  3939. lOld, cOld: Integer;
  3940. begin
  3941. result := false;
  3942. aParameters.Clear;
  3943. if (CurrentChar <> PRECOMPILER_STATEMENT_BEGIN) or
  3944. (Col + 1 > LineLength) or
  3945. ( (CurrentLine[Col + 1] <> TOKEN_IDENTIFIER) and
  3946. (CurrentLine[Col + 1] <> COMMENT_IDENTIFIER)) then
  3947. exit;
  3948. result := true;
  3949. quote := false;
  3950. inToken := false;
  3951. isComment := CurrentLine[Col + 1] = COMMENT_IDENTIFIER;
  3952. commentTokenAdded := false;
  3953. s := '';
  3954. charType := ctUnknown;
  3955. lOld := Line;
  3956. cOld := Col;
  3957. AddPart; //initialize
  3958. while not EndOfFile do begin
  3959. while not EndOfLine do begin
  3960. case CurrentChar of
  3961. PRECOMPILER_STATEMENT_BEGIN: begin
  3962. if quote then
  3963. s := s + PRECOMPILER_STATEMENT_BEGIN
  3964. else if not inToken then
  3965. inToken := true
  3966. else
  3967. EengShaderPart.Create('invalid char in token');
  3968. end;
  3969. PRECOMPILER_STATEMENT_END: begin
  3970. if not quote then begin
  3971. AddPart(not isComment);
  3972. IncCol;
  3973. if (aParameters.Count <= 0) or (aParameters[0].Name = TOKEN_IDENTIFIER) then
  3974. raise EengEmptyToken.Create(lOld, cOld, fOwner.Filename);
  3975. exit;
  3976. end else
  3977. s := s + CurrentChar;
  3978. end;
  3979. PRECOMPILER_QUOTE_CHAR: begin
  3980. if not quote and not isComment then
  3981. AddPart;
  3982. s := s + PRECOMPILER_QUOTE_CHAR;
  3983. quote := not quote;
  3984. if not quote and not isComment then
  3985. AddPart;
  3986. end;
  3987. COMMENT_IDENTIFIER: begin
  3988. s := s + COMMENT_IDENTIFIER;
  3989. if isComment and not commentTokenAdded then begin
  3990. commentTokenAdded := true;
  3991. AddPart(false);
  3992. end;
  3993. end;
  3994. else
  3995. if not quote and not isComment then begin
  3996. if (CurrentChar in TOKEN_SPLIT_CHARS) then begin
  3997. AddPart;
  3998. end else if (CurrentChar in VALID_TOKEN_CHARS) then begin
  3999. if (charType <> ctValidTokenChar) then
  4000. AddPart;
  4001. charType := ctValidTokenChar;
  4002. end else begin
  4003. if (charType <> ctInvalidTokenChar) then
  4004. AddPart;
  4005. charType := ctInvalidTokenChar;
  4006. end;
  4007. end;
  4008. s := s + CurrentChar;
  4009. end;
  4010. IncCol;
  4011. end;
  4012. s := s + sLineBreak;
  4013. IncLine;
  4014. end;
  4015. raise EengShaderPart.Create('incomplete token', lOld, cOld, fOwner.Filename);
  4016. end;
  4017. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  4018. procedure TengParseArgs.LoadCode(const aStream: TStream);
  4019. begin
  4020. fCode.LoadFromStream(aStream);
  4021. fLineCount := fCode.Count;
  4022. Line := 0;
  4023. end;
  4024. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  4025. constructor TengParseArgs.Create(const aOwner: TengShaderFile);
  4026. begin
  4027. inherited Create;
  4028. fOwner := aOwner;
  4029. fCode := TStringList.Create;
  4030. fLineCount := fCode.Count;
  4031. Line := 0;
  4032. end;
  4033. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  4034. destructor TengParseArgs.Destroy;
  4035. begin
  4036. FreeAndNil(fCode);
  4037. inherited Destroy;
  4038. end;
  4039. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  4040. //TengGenCodeArgs.TCodeItem/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  4041. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  4042. function TengGenCodeArgs.TCodeItem.GetText: String;
  4043. begin
  4044. result := '';
  4045. end;
  4046. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  4047. function TengGenCodeArgs.TCodeItem.IsEmpty: Boolean;
  4048. begin
  4049. result := (Trim(GetText) = '');
  4050. end;
  4051. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  4052. //TengGenCodeArgs.TCodeItemStart////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  4053. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  4054. function TengGenCodeArgs.TCodeItemStart.GetText: String;
  4055. begin
  4056. result := '';
  4057. end;
  4058. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  4059. //TengGenCodeArgs.TCodeItemText/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  4060. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  4061. function TengGenCodeArgs.TCodeItemText.GetText: String;
  4062. begin
  4063. result := Text;
  4064. end;
  4065. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  4066. constructor TengGenCodeArgs.TCodeItemText.Create(const aText: String);
  4067. begin
  4068. inherited Create;
  4069. Text := aText;
  4070. end;
  4071. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  4072. //TCodeItemLineBreak.TCodeItemLineBreak/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  4073. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  4074. function TengGenCodeArgs.TCodeItemLineBreak.GetText: String;
  4075. begin
  4076. result := sLineBreak;
  4077. end;
  4078. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  4079. //TengGenCodeArgs.TCodeItemCommandEnd///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  4080. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  4081. function TengGenCodeArgs.TCodeItemCommandEnd.GetText: String;
  4082. begin
  4083. result := Token;
  4084. end;
  4085. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  4086. constructor TengGenCodeArgs.TCodeItemCommandEnd.Create(const aToken: String);
  4087. begin
  4088. inherited Create;
  4089. Token := aToken;
  4090. end;
  4091. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  4092. //TengGenCodeArgs.TCodeItemToken////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  4093. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  4094. constructor TengGenCodeArgs.TCodeItemToken.Create(const aTokenType: TTokenType; const aLevel: Integer);
  4095. begin
  4096. inherited Create;
  4097. TokenType := aTokenType;
  4098. Level := aLevel;
  4099. end;
  4100. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  4101. //TengGenCodeArgs.TCodeStackItem////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  4102. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  4103. function TengGenCodeArgs.TCodeStackItem.GetEmpty: Boolean;
  4104. begin
  4105. result := (fItems.Count = 0) or
  4106. ((fItems.Count = 1) and (fItems[0] is TCodeItemStart));
  4107. end;
  4108. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  4109. {$IFDEF DEBUG}
  4110. function TengGenCodeArgs.TCodeStackItem.GetDebugText: String;
  4111. var
  4112. ci: TCodeItem;
  4113. begin
  4114. result := '';
  4115. for ci in fItems do
  4116. if (ci is TCodeItemToken) then with (ci as TCodeItemToken) do begin
  4117. case TokenType of
  4118. ttBegin: result := result + '$B';
  4119. ttEnd: result := result + '$E';
  4120. ttSingle: result := result + '$S';
  4121. end;
  4122. if (Level >= 0) then
  4123. result := result + IntToStr(Level);
  4124. end else if (ci is TCodeItemCommandEnd) then with (ci as TCodeItemCommandEnd) do begin
  4125. result := result + '$C("' + ci.GetText + '")';
  4126. end else
  4127. result := result + ci.GetText;
  4128. end;
  4129. {$ENDIF}
  4130. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  4131. function TengGenCodeArgs.TCodeStackItem.GetText: String;
  4132. type
  4133. TGenFlag = (
  4134. gfToken, // current line has a token in it
  4135. gfTokenSingle, // current line has a single token in it
  4136. gfPrevEmpty, // previouse line was empty
  4137. gfAddToPrevLine, // trim left current line and add to prev line if not empty
  4138. gfAddNextLine // trim left next line and add to current line if not empty
  4139. );
  4140. TGenFlags = set of TGenFlag;
  4141. var
  4142. i: Integer;
  4143. line: String;
  4144. sl: TStringList;
  4145. f: TGenFlags;
  4146. function GetStrOffset(const aStr: String): Integer;
  4147. var
  4148. len: Integer;
  4149. begin
  4150. result := 0;
  4151. len := Length(aStr);
  4152. while (result < len) and (aStr[result+1] in WHITESPACES) do
  4153. inc(result);
  4154. end;
  4155. function GetOffset(const aItem: TCodeItemToken): Integer;
  4156. begin
  4157. result := aItem.Level;
  4158. if (result < 0) then
  4159. result := GetStrOffset(line);
  4160. end;
  4161. function GetMinOffset(aStartIndex: Integer): Integer;
  4162. begin
  4163. if (Trim(line) <> '') then
  4164. result := GetStrOffset(line)
  4165. else
  4166. result := High(Integer);
  4167. while (aStartIndex < sl.Count) do begin
  4168. if (Trim(sl[aStartIndex]) <> '') then
  4169. result := Min(result, GetStrOffset(sl[aStartIndex]));
  4170. inc(aStartIndex);
  4171. end;
  4172. if (result >= High(Integer)) then
  4173. result := -1;
  4174. end;
  4175. function TrimLeftLen(const aStr: String; aLen: Integer): String;
  4176. var
  4177. i, len: Integer;
  4178. begin
  4179. i := 1;
  4180. len := Length(aStr);
  4181. while (i <= len) and (aStr[i] in WHITESPACES) and (aLen > 0) do begin
  4182. inc(i);
  4183. dec(aLen);
  4184. end;
  4185. result := Copy(aStr, i, len - i + 1);
  4186. end;
  4187. function PrepareStr(const aStr: String; const aOffset: Integer): String;
  4188. begin
  4189. if (aOffset < 0) then
  4190. result := StringOfChar(' ', -aOffset) + aStr
  4191. else
  4192. result := TrimLeftLen(aStr, aOffset);
  4193. end;
  4194. procedure IndentBlock(aStartIndex: Integer; const aOffset: Integer);
  4195. var
  4196. o: Integer;
  4197. begin
  4198. o := GetMinOffset(aStartIndex);
  4199. if (o < 0) then
  4200. exit;
  4201. o := o - aOffset;
  4202. if (o = 0) then
  4203. exit;
  4204. while (aStartIndex < sl.Count) do begin
  4205. sl[aStartIndex] := PrepareStr(sl[aStartIndex], o);
  4206. inc(aStartIndex);
  4207. end;
  4208. line := PrepareStr(line, o);
  4209. end;
  4210. procedure ProgressBlock(const aOffset: Integer);
  4211. var
  4212. item: TCodeItem;
  4213. s: String;
  4214. lineIndex: Integer;
  4215. begin
  4216. lineIndex := sl.Count; //start at next line
  4217. while (i < fItems.Count) do begin
  4218. item := fItems[i];
  4219. inc(i);
  4220. // LineBreak
  4221. if (item is TCodeItemLineBreak) then begin
  4222. if (Trim(line) = '') then begin
  4223. if (f * [gfToken, gfPrevEmpty] = []) then begin
  4224. sl.Add(line);
  4225. Include(f, gfPrevEmpty);
  4226. end;
  4227. if not (gfTokenSingle in f) then
  4228. Exclude(f, gfAddToPrevLine);
  4229. end else begin
  4230. if not (gfAddToPrevLine in f) then begin
  4231. sl.Add(line);
  4232. Exclude(f, gfPrevEmpty);
  4233. end else if (sl.Count > 0) then
  4234. sl[sl.Count-1] := sl[sl.Count-1] + TrimLeft(line)
  4235. else
  4236. sl.Add(line);
  4237. Exclude(f, gfAddToPrevLine);
  4238. end;
  4239. Exclude(f, gfToken);
  4240. Exclude(f, gfTokenSingle);
  4241. if (gfAddNextLine in f) then
  4242. f := f + [gfAddToPrevLine] - [gfAddNextLine];
  4243. line := '';
  4244. // Token
  4245. end else if (item is TCodeItemToken) then with (item as TCodeItemToken) do begin
  4246. Include(f, gfToken);
  4247. case TokenType of
  4248. ttBegin: begin
  4249. if (Trim(line) <> '') then
  4250. Include(f, gfAddNextLine);
  4251. Include(f, gfPrevEmpty);
  4252. ProgressBlock(GetOffset(item as TCodeItemToken));
  4253. end;
  4254. ttEnd: begin
  4255. if (Trim(line) = '') then
  4256. Include(f, gfAddToPrevLine);
  4257. IndentBlock(lineIndex, aOffset);
  4258. exit;
  4259. end;
  4260. ttSingle: begin
  4261. Include(f, gfTokenSingle);
  4262. end;
  4263. end;
  4264. // other
  4265. end else begin
  4266. s := item.GetText;;
  4267. if (gfAddNextLine in f) and (Trim(s) <> '') then
  4268. Exclude(f, gfAddNextLine);
  4269. line := line + s;
  4270. end;
  4271. end;
  4272. end;
  4273. procedure TrimList;
  4274. begin
  4275. while (sl.Count > 0) and (Trim(sl[0]) = '') do
  4276. sl.Delete(0);
  4277. while (sl.Count > 0) and (Trim(sl[sl.Count-1]) = '') do
  4278. sl.Delete(sl.Count-1);
  4279. end;
  4280. begin
  4281. sl := TStringList.Create;
  4282. try
  4283. {$IFDEF DEBUG}
  4284. sl.Text := GetDebugText;
  4285. sl.SaveToFile('dbg');
  4286. sl.Clear;
  4287. {$ENDIF}
  4288. i := 0;
  4289. line := '';
  4290. f := [gfPrevEmpty];
  4291. ProgressBlock(0);
  4292. TrimList;
  4293. result := sl.Text;
  4294. finally
  4295. FreeAndNil(sl);
  4296. end;
  4297. end;
  4298. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  4299. procedure TengGenCodeArgs.TCodeStackItem.SplitCurrentCommand(const aItem: TCodeStackItem);
  4300. var
  4301. HasCode: Boolean;
  4302. ci: TCodeItem;
  4303. function IsEndToken(const ci: TCodeItem): Boolean;
  4304. begin
  4305. result := (ci is TCodeItemToken) and ((ci as TCodeItemToken).TokenType = ttEnd)
  4306. end;
  4307. begin
  4308. fItems.OwnsObjects := false;
  4309. aItem.fItems.OwnsObjects := false;
  4310. try
  4311. //move all items before TCodeItemCommandEnd to aItem
  4312. while (fItems.Count > 1) and not (fItems[fItems.Count-1] is TCodeItemCommandEnd) do begin
  4313. ci := fItems.PopLast;
  4314. if (trim(ci.GetText) <> '') then
  4315. HasCode := true;
  4316. if IsEndToken(ci) then
  4317. HasCode := false;
  4318. aItem.fItems.Insert(1, ci);
  4319. end;
  4320. // if ther is no code between last CommandEnd and Last End-Token, move back to last end Token
  4321. if not HasCode then begin
  4322. while not IsEndToken(aItem.fItems[1]) do begin
  4323. fItems.PushLast(aItem.fItems[1]);
  4324. aItem.fItems.Delete(1);
  4325. end;
  4326. fItems.PushLast(aItem.fItems[1]);
  4327. aItem.fItems.Delete(1);
  4328. end;
  4329. finally
  4330. aItem.fItems.OwnsObjects := true;
  4331. fItems.OwnsObjects := true;
  4332. end;
  4333. end;
  4334. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  4335. function TengGenCodeArgs.TCodeStackItem.Merge(const aItem: TCodeStackItem; aIndex: Integer): Integer;
  4336. begin
  4337. if (aIndex <= 0) then
  4338. aIndex := 1; // do not go below start item
  4339. result := aIndex + aItem.fItems.Count - 1;
  4340. aItem.fItems.OwnsObjects := false;
  4341. try
  4342. while (aItem.fItems.Count > 1) do begin
  4343. fItems.Insert(aIndex, aItem.fItems[aItem.fItems.Count-1]);
  4344. aItem.fItems.Delete(aItem.fItems.Count-1);
  4345. end;
  4346. finally
  4347. aItem.fItems.OwnsObjects := true;
  4348. end;
  4349. end;
  4350. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  4351. procedure TengGenCodeArgs.TCodeStackItem.AddText(const aText: String);
  4352. begin
  4353. fItems.Add(TCodeItemText.Create(aText));
  4354. if (Trim(aText) <> '') then
  4355. Exclude(fFlags, cfIgnoreNextSemicolon);
  4356. end;
  4357. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  4358. procedure TengGenCodeArgs.TCodeStackItem.AddCommandEnd(const aToken: String);
  4359. begin
  4360. if (cfIgnoreNextSemicolon in fFlags) then begin
  4361. if (aToken <> '') then
  4362. Exclude(fFlags, cfIgnoreNextSemicolon);
  4363. if (aToken = ';') then
  4364. exit;
  4365. end;
  4366. fItems.Add(TCodeItemCommandEnd.Create(aToken));
  4367. end;
  4368. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  4369. procedure TengGenCodeArgs.TCodeStackItem.AddToken(const aTokenType: TTokenType; const aLevel: Integer);
  4370. begin
  4371. fItems.Add(TCodeItemToken.Create(aTokenType, aLevel));
  4372. end;
  4373. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  4374. procedure TengGenCodeArgs.TCodeStackItem.AddLineEnd;
  4375. begin
  4376. fItems.Add(TCodeItemLineBreak.Create);
  4377. end;
  4378. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  4379. function TengGenCodeArgs.TCodeStackItem.GetMinLineOffset: Integer;
  4380. procedure CalcOffset(const aLine: String);
  4381. var i, len: Integer;
  4382. begin
  4383. if (Trim(aLine) = '') then
  4384. exit;
  4385. len := Length(aLine);
  4386. i := 1;
  4387. while (i <= len) and (aLine[i] in WHITESPACES) do
  4388. inc(i);
  4389. if (i < result) then
  4390. result := i-1;
  4391. end;
  4392. var
  4393. item: TCodeItem;
  4394. line: String;
  4395. begin
  4396. result := High(Integer);
  4397. line := '';
  4398. for item in fItems do begin
  4399. if (item is TCodeItemLineBreak) then begin
  4400. CalcOffset(line);
  4401. line := '';
  4402. end else
  4403. line := line + item.GetText;
  4404. end;
  4405. CalcOffset(line);
  4406. if (result = High(Integer)) then
  4407. result := -1;
  4408. end;
  4409. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  4410. procedure TengGenCodeArgs.TCodeStackItem.IgnoreNextSemicolon;
  4411. begin
  4412. Include(fFlags, cfIgnoreNextSemicolon);
  4413. end;
  4414. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  4415. procedure TengGenCodeArgs.TCodeStackItem.ReplaceIdents(const aOld, aNew: TStrings);
  4416. var
  4417. rx: TRegExpr;
  4418. i: Integer;
  4419. itm: TCodeItem;
  4420. begin
  4421. if (aOld.Count <> aNew.Count) then
  4422. raise EengInternal.Create('old and new idents must have the same size');
  4423. rx := TRegExpr.Create;
  4424. try
  4425. for i := 0 to aOld.Count-1 do begin
  4426. rx.Expression := '([^A-z0-9_]+|^)' + aOld[i] + '([^A-z0-9_]+|$)';
  4427. for itm in fItems do
  4428. if (itm is TCodeItemText) then
  4429. with (itm as TCodeItemText) do
  4430. Text := rx.Replace(Text, '$1' + aNew[i] + '$2', true);
  4431. end;
  4432. finally
  4433. FreeAndNil(rx);
  4434. end;
  4435. end;
  4436. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  4437. procedure TengGenCodeArgs.TCodeStackItem.ReplaceReturns(const aItem: TCodeStackItem; const aRetType, aFuncName: String; const aCntr: Integer);
  4438. var
  4439. s: String;
  4440. i, j, retCount, first, firstOffset: Integer;
  4441. item: TCodeItem;
  4442. rx: TRegExpr;
  4443. begin
  4444. rx := TRegExpr.Create;
  4445. try
  4446. rx.Expression := '([^A-z0-9_]+|^)return([^A-z0-9_]+|$)';
  4447. //find number of "return" in code and first item with not only whitespaces
  4448. retCount := 0;
  4449. first := 0;
  4450. for i := 0 to fItems.Count-1 do begin
  4451. item := fItems[i];
  4452. s := item.GetText;
  4453. if (item is TCodeItemText) and (Trim(s) <> '') and (first = 0) then begin
  4454. first := i;
  4455. firstOffset := Length(s) - Length(TrimLeft(s));
  4456. end;
  4457. if (rx.Exec(s)) then
  4458. inc(retCount);
  4459. end;
  4460. //more than one return
  4461. if (retCount > 1) then begin
  4462. //TrimEnd;
  4463. s := aFuncName + Format('_ret%.3d', [aCntr]);
  4464. fItems.Insert(first, TCodeItemText.Create(StringOfChar(' ', firstOffset) + aRetType + ' ' + s));
  4465. fItems.Insert(first + 1, TCodeItemCommandEnd.Create(';'));
  4466. fItems.Insert(first + 2, TCodeItemLineBreak.Create);
  4467. for item in fItems do
  4468. if (item is TCodeItemText) then
  4469. with (item as TCodeItemText) do
  4470. Text := rx.Replace(Text, '$1' + s + ' =$2', true);
  4471. Merge(aItem, fItems.Count);
  4472. AddText(s);
  4473. // only one return
  4474. end else begin
  4475. i := fItems.Count-1;
  4476. while (i > 0) do begin
  4477. item := fItems[i];
  4478. if (item is TCodeItemText) then
  4479. with (item as TCodeItemText) do begin
  4480. if (rx.Exec(Text)) then begin
  4481. // replace
  4482. fItems.Insert(i, TCodeItemText.Create(rx.Match[1]));
  4483. Text := rx.Replace(Text, '(', true);
  4484. // replace last CommandEnd with ')'
  4485. j := fItems.Count-1;
  4486. while (j > i) and not (fItems[j] is TCodeItemCommandEnd) do
  4487. dec(j);
  4488. if (j > i) then begin
  4489. fItems.Delete(j);
  4490. fItems.Insert(j, TCodeItemText.Create(')'));
  4491. fItems.Insert(j+1, TCodeItemToken.Create(ttEnd));
  4492. end;
  4493. // merge
  4494. i := fItems.IndexOf(item);
  4495. fItems.Insert(i, TCodeItemToken.Create(ttBegin));
  4496. inc(i);
  4497. i := Merge(aItem, i);
  4498. exit;
  4499. end;
  4500. end;
  4501. dec(i);
  4502. end;
  4503. raise EengInternal.Create('no return found in current code');
  4504. end;
  4505. finally
  4506. FreeAndNil(rx);
  4507. end;
  4508. end;
  4509. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  4510. constructor TengGenCodeArgs.TCodeStackItem.Create;
  4511. begin
  4512. inherited Create;
  4513. fItems := TCodeItemList.Create(true);
  4514. fItems.Add(TCodeItemStart.Create);
  4515. end;
  4516. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  4517. destructor TengGenCodeArgs.TCodeStackItem.Destroy;
  4518. begin
  4519. FreeAndNil(fItems);
  4520. inherited Destroy;
  4521. end;
  4522. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  4523. //TengGenCodeArgs.TProcWrapper//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  4524. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  4525. constructor TengGenCodeArgs.TProcWrapper.Create;
  4526. begin
  4527. Proc := nil;
  4528. Code := nil;
  4529. end;
  4530. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  4531. destructor TengGenCodeArgs.TProcWrapper.Destroy;
  4532. begin
  4533. FreeAndNil(Code);
  4534. Proc := nil;
  4535. inherited Destroy;
  4536. end;
  4537. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  4538. //TengGenCodeArgs///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  4539. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  4540. function TengGenCodeArgs.GetFlags: TengGenCodeFlags;
  4541. begin
  4542. if (fFlags.Count > 0) then
  4543. result := fFlags.Last
  4544. else
  4545. result := [];
  4546. end;
  4547. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  4548. function TengGenCodeArgs.GetText: String;
  4549. begin
  4550. result := fCode.Last.GetText;
  4551. end;
  4552. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  4553. function TengGenCodeArgs.GetCode: TCodeStackItem;
  4554. begin
  4555. result := fCode.Last;
  4556. end;
  4557. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  4558. function TengGenCodeArgs.GetProcParams: TStrings;
  4559. begin
  4560. result := fProcParams.Last;
  4561. end;
  4562. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  4563. procedure TengGenCodeArgs.PushCode;
  4564. begin
  4565. fCode.PushLast(TCodeStackItem.Create);
  4566. end;
  4567. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  4568. procedure TengGenCodeArgs.InsertCode(const aCodeStackItem: TCodeStackItem);
  4569. begin
  4570. fCode.PushLast(aCodeStackItem);
  4571. end;
  4572. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  4573. function TengGenCodeArgs.PushCurrentCommand: TCodeStackItem;
  4574. begin
  4575. result := TCodeStackItem.Create;
  4576. fCommands.PushLast(result);
  4577. Code.SplitCurrentCommand(result);
  4578. end;
  4579. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  4580. procedure TengGenCodeArgs.PushFlags(const aFlags: TengGenCodeFlags);
  4581. begin
  4582. fFlags.PushLast(aFlags);
  4583. end;
  4584. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  4585. procedure TengGenCodeArgs.PushProcParams(const aParams: TStrings);
  4586. begin
  4587. fProcParams.PushLast(aParams);
  4588. end;
  4589. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  4590. procedure TengGenCodeArgs.PopCode(const aFlags: TPopCodeFlags);
  4591. var
  4592. csi: TCodeStackItem;
  4593. begin
  4594. csi := fCode.PopLast(false);
  4595. try
  4596. if not csi.Empty and (aFlags * [pcfAppend, pcfPrepend] <> []) then begin
  4597. if (pcfPrepend in aFlags) then begin
  4598. if (pcfAddEmptyLine in aFlags) then
  4599. csi.AddLineEnd;
  4600. Code.Merge(csi, 1);
  4601. end else begin
  4602. if (pcfAddEmptyLine in aFlags) then
  4603. Code.AddLineEnd;
  4604. Code.Merge(csi, Code.Items.Count);
  4605. end;
  4606. end;
  4607. finally
  4608. FreeAndNil(csi);
  4609. end;
  4610. end;
  4611. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  4612. function TengGenCodeArgs.ExtractCode: TCodeStackItem;
  4613. begin
  4614. result := fCode.PopLast(false);
  4615. end;
  4616. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  4617. procedure TengGenCodeArgs.PopCurrentCommand(const aRetType, aFuncName: String);
  4618. var
  4619. csi: TCodeStackItem;
  4620. begin
  4621. csi := fCommands.PopLast(false);
  4622. try
  4623. Code.ReplaceReturns(csi, aRetType, aFuncName, fInlineRetCounter);
  4624. inc(fInlineRetCounter);
  4625. finally
  4626. FreeAndNil(csi);
  4627. end;
  4628. end;
  4629. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  4630. procedure TengGenCodeArgs.PopFlags;
  4631. begin
  4632. fFlags.PopLast(true);
  4633. end;
  4634. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  4635. procedure TengGenCodeArgs.PopProcParams;
  4636. begin
  4637. fProcParams.PopLast;
  4638. end;
  4639. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  4640. procedure TengGenCodeArgs.AddProcedure(const aProc: TengShaderPartProc);
  4641. function FindProc(const aName: String): TProcWrapper;
  4642. begin
  4643. for result in fProcedures do
  4644. if (result.Proc.Name = aName) then
  4645. exit;
  4646. result := nil;
  4647. end;
  4648. var
  4649. w: TProcWrapper;
  4650. begin
  4651. w := FindProc(aProc.Name);
  4652. if Assigned(w) then begin
  4653. if (aProc <> w.Proc) then
  4654. raise EengDuplicateIdentifier.Create(w.Proc.Name, aProc, w.Proc);
  4655. exit;
  4656. end;
  4657. w := TProcWrapper.Create;
  4658. w.Proc := aProc;
  4659. fProcedures.Add(w);
  4660. PushCode; // push current code
  4661. PushFlags(Flags + [gcfGenProcedure]);
  4662. try
  4663. w.Proc.GenCodeIntern(self);
  4664. finally
  4665. w.Code := ExtractCode; // pop procedure code and store it in wrapper
  4666. PopFlags;
  4667. end;
  4668. end;
  4669. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  4670. procedure TengGenCodeArgs.AddCodeProperty(const aProp: TengShaderPartCodeProperty);
  4671. var
  4672. p: TengShaderPartCodeProperty;
  4673. begin
  4674. p := fProperties[aProp.Name];
  4675. if Assigned(p) then begin
  4676. if not p.IsEquals(aProp) then
  4677. raise EengDuplicateIdentifier.Create(p.Name, aProp, p);
  4678. exit;
  4679. end;
  4680. fProperties.Add(aProp.Name, aProp);
  4681. end;
  4682. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  4683. procedure TengGenCodeArgs.AddMeta(const aMeta: IengMetaData);
  4684. begin
  4685. fShaderCode.AddMeta(aMeta);
  4686. end;
  4687. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  4688. function TengGenCodeArgs.HasCodeProperty(const aName: String): Boolean;
  4689. begin
  4690. result := fProperties.Contains(aName);
  4691. end;
  4692. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  4693. procedure TengGenCodeArgs.GenProcedureCode(const aAppend: Boolean);
  4694. var
  4695. w: TProcWrapper;
  4696. begin
  4697. for w in fProcedures do begin
  4698. if not Assigned(w.Code) then
  4699. continue;
  4700. InsertCode(w.Code); // push stored code ...
  4701. w.Code := nil;
  4702. PopCode([pcfPrepend, pcfAddEmptyLine]); // and pop it back to the code tree (this will merge the code)
  4703. end;
  4704. end;
  4705. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  4706. procedure TengGenCodeArgs.GenCodePropertyCode(const aTypes: array of CengShaderPart);
  4707. var
  4708. p: TengShaderPartCodeProperty;
  4709. m: TCodePropertyMap;
  4710. begin
  4711. PushCode;
  4712. PushFlags(Flags + [gcfGenCodeProp]);
  4713. m := TCodePropertyMap.Create(false);
  4714. try
  4715. fMaxPropNameLen := 0;
  4716. for p in fProperties do
  4717. if CheckType(p, aTypes) then begin
  4718. fMaxPropNameLen := Max(fMaxPropNameLen, Length(p.PropType));
  4719. m.Add(p.PropType+p.Name, p);
  4720. end;
  4721. for p in m do begin
  4722. p.GenCodeIntern(self);
  4723. Code.AddLineEnd;
  4724. end;
  4725. finally
  4726. FreeAndNil(m);
  4727. PopCode([pcfPrepend, pcfAddEmptyLine]);
  4728. PopFlags;
  4729. end;
  4730. end;
  4731. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  4732. procedure TengGenCodeArgs.GenMetaCode;
  4733. var
  4734. m: IengMetaData;
  4735. s: String;
  4736. vCompat: Boolean;
  4737. vMax: Integer;
  4738. layouts: TStringList;
  4739. begin
  4740. vCompat := false;
  4741. vMax := 0;
  4742. PushCode;
  4743. layouts := TStringList.Create;
  4744. try
  4745. for m in fShaderCode.MetaList do begin
  4746. case m.MetaType of
  4747. metaVersion: begin
  4748. if (m.Values[0] = VERSION_EXTRA_COMPAT) then
  4749. vCompat := true
  4750. else
  4751. vMax := Max(vMax, StrToInt(m.Values[0]));
  4752. if (m.Count > 1) and (m.Values[1] = VERSION_EXTRA_COMPAT) then
  4753. vCompat := true;
  4754. end;
  4755. metaExtension: begin
  4756. Code.AddText(format('#extension %s : %s', [m.Values[0], m.Values[1]]));
  4757. Code.AddLineEnd;
  4758. end;
  4759. metaLayout: begin
  4760. layouts.Add(format('layout%s;', [m.Values[0]]));
  4761. end;
  4762. end;
  4763. end;
  4764. if (vMax >= LAYOUT_MIN_VERSION) then
  4765. for s in layouts do begin
  4766. Code.AddText(s);
  4767. Code.AddLineEnd;
  4768. end;
  4769. if (vMax > 0) then begin
  4770. PushCode;
  4771. try
  4772. Code.AddText('#version ' + IntToStr(vMax));
  4773. if vCompat then
  4774. Code.AddText(' ' + VERSION_EXTRA_COMPAT);
  4775. Code.AddLineEnd;
  4776. finally
  4777. PopCode([pcfPrepend]);
  4778. end;
  4779. end;
  4780. finally
  4781. PopCode([pcfPrepend, pcfAddEmptyLine]);
  4782. FreeAndNil(layouts);
  4783. end;
  4784. end;
  4785. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  4786. constructor TengGenCodeArgs.Create(const aShaderCode: TengShaderCodeIntern; const aRoot: TengShaderPartScope);
  4787. begin
  4788. inherited Create;
  4789. fRoot := aRoot;
  4790. fProcedures := TProcedureList.Create(true);
  4791. fProperties := TCodePropertyMap.Create(false);
  4792. fFlags := TGenCodeFlagsStack.Create(true);
  4793. fCode := TCodeStack.Create(true);
  4794. fCommands := TCodeStack.Create(true);
  4795. fProcParams := TProcParamStack.Create(false);
  4796. fShaderCode := aShaderCode;
  4797. PushCode;
  4798. end;
  4799. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  4800. destructor TengGenCodeArgs.Destroy;
  4801. begin
  4802. fShaderCode.Text := GetText;
  4803. FreeAndNil(fProcParams);
  4804. FreeAndNil(fCommands);
  4805. FreeAndNil(fCode);
  4806. FreeAndNil(fFlags);
  4807. FreeAndNil(fProperties);
  4808. FreeAndNil(fProcedures);
  4809. inherited Destroy;
  4810. end;
  4811. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  4812. //DEBUG/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  4813. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  4814. {$IFDEF DEBUG}
  4815. procedure SaveAsXMindXml(const aShaderPart: TengShaderPart; const aDirectory: String);
  4816. var
  4817. linkStr: String;
  4818. function Escape(const aText: String): String;
  4819. begin
  4820. result := StringReplace(aText, '''', '' { &apos; }, [rfReplaceAll]);
  4821. result := StringReplace(result, '"', '&quot;', [rfReplaceAll]);
  4822. result := StringReplace(result, '&', '&amp;', [rfReplaceAll]);
  4823. result := StringReplace(result, '<', '&lt;', [rfReplaceAll]);
  4824. result := StringReplace(result, '>', '&gt;', [rfReplaceAll]);
  4825. end;
  4826. function MakeID(const aItem: TengShaderPart): String;
  4827. begin
  4828. result := Format('%p', [Pointer(aItem)]);
  4829. end;
  4830. function GetTitle(const aItem: TengShaderPart): String;
  4831. var
  4832. i: Integer;
  4833. s: String;
  4834. begin
  4835. // TengShaderPartIf
  4836. if (aItem.Parent is TengShaderPartIf) then begin
  4837. if (aItem.Parent.Children[0] = aItem) then
  4838. result := '- TRUE -'
  4839. else if (aItem.Parent.Count > 1) and (aItem.Parent.Children[1] = aItem) then
  4840. result := '- FALSE -'
  4841. else
  4842. result := '- UNKNOWN -';
  4843. // TengShaderPartClass
  4844. end else if (aItem is TengShaderPartClass) then
  4845. result := aItem.GetTokenName + ' ' + (aItem as TengShaderPartClass).Name
  4846. // TengShaderPartInclude
  4847. else if (aItem is TengShaderPartInclude) then
  4848. result := aItem.GetTokenName
  4849. // TengShaderFile
  4850. else if (aItem is TengShaderFile) then
  4851. result := ExtractFileName((aItem as TengShaderFile).Filename)
  4852. // TengShaderPartProperty
  4853. else if (aItem is TengShaderPartProperty) then with (aItem as TengShaderPartProperty) do
  4854. result := aItem.GetTokenName + ' ' + Name
  4855. // TengShaderPartCodeProperty
  4856. else if (aItem is TengShaderPartCodeProperty) then with (aItem as TengShaderPartCodeProperty) do
  4857. result := aItem.GetTokenName + ' ' + fType + ' ' + fName
  4858. // TengShaderPartCall
  4859. else if (aItem is TengShaderPartCall) then with (aItem as TengShaderPartCall) do
  4860. result := aItem.GetTokenName + ' ' + fName
  4861. // TengShaderPartProc
  4862. else if (aItem is TengShaderPartProc) then with (aItem as TengShaderPartProc) do
  4863. result := aItem.GetTokenName + ' ' + fName
  4864. // TengShaderPartMeta
  4865. else if (aItem is TengShaderPartMeta) then with (aItem as TengShaderPartMeta) do begin
  4866. result := aItem.GetTokenName + ' ' + fMetaData.Name;
  4867. for i := 0 to fMetaData.Count-1 do
  4868. result := result + ' ' + fMetaData[i];
  4869. // TengShaderPartMeta
  4870. end else if (aItem is TengShaderPartIf) then with (aItem as TengShaderPartIf) do
  4871. result := aItem.GetTokenName + ' ' + fExpression.GetText
  4872. // TengShaderPartEcho
  4873. else if (aItem is TengShaderPartEcho) then with (aItem as TengShaderPartEcho) do
  4874. result := aItem.GetTokenName + ' ' + fName
  4875. // TengShaderPartMessage
  4876. else if (aItem is TengShaderPartMessage) then with (aItem as TengShaderPartMessage) do
  4877. result := aItem.GetTokenName + ' ' + fMessage
  4878. else if (aItem is TengShaderPartInherited) then with (aItem as TengShaderPartInherited) do begin
  4879. result := aItem.GetTokenName + ' ' + fInheritedName;
  4880. for s in fParameters do
  4881. result := ' ' + s;
  4882. end else
  4883. result := 'TODO: ' + aItem.GetTokenName;
  4884. result := Escape(result);
  4885. end;
  4886. function GetDesc(const aItem: TengShaderPart): String;
  4887. begin
  4888. result := ''; //'<notes><plain>Your Description Here</plain></notes>';
  4889. end;
  4890. function MakeLinks(const aItem: TengShaderPartScope): String;
  4891. var
  4892. p: TengShaderPart;
  4893. begin
  4894. result := '';
  4895. for p in aItem.fInherited do // red
  4896. result := result + '<relationship end1="' + MakeID(aItem) + '" end2="' + MakeID(p) + '" style-id="1c2250lh1o9dug5bqnmfjqjj2h" timestamp="1407953246105"><control-points><control-point index="0"></control-point><control-point index="1"><position svg:x="-150" svg:y="0"/></control-point></control-points></relationship>';
  4897. for p in aItem.fChildScopes do // green
  4898. result := result + '<relationship end1="' + MakeID(aItem) + '" end2="' + MakeID(p) + '" style-id="kjafgighq039598z56afioh565" timestamp="1407953246105"><control-points><control-point index="0"></control-point><control-point index="1"><position svg:x="-150" svg:y="0"/></control-point></control-points></relationship>';
  4899. for p in aItem.fMappedParts do // blue
  4900. result := result + '<relationship end1="' + MakeID(aItem) + '" end2="' + MakeID(p) + '" style-id="akjbq3589715ljkbg09uath6pa" timestamp="1407953246105"><control-points><control-point index="0"></control-point><control-point index="1"><position svg:x="-150" svg:y="0"/></control-point></control-points></relationship>';
  4901. end;
  4902. function CreateCodeItem(var aCode: String): String;
  4903. var
  4904. sl: TStringList;
  4905. begin
  4906. sl := TStringList.Create;
  4907. try
  4908. sl.Text := aCode;
  4909. while (sl.Count > 0) and (Trim(sl[0]) = '') do
  4910. sl.Delete(0);
  4911. while (sl.Count > 0) and (Trim(sl[sl.Count-1]) = '') do
  4912. sl.Delete(sl.Count-1);
  4913. if (sl.Count > 0) then
  4914. result := '<topic timestamp="1407871141500" style-id="7dh2otp9bqp93n80sk589g5916"><title>- CODE -</title>' +
  4915. '<notes><plain>' + Escape(sl.Text) + '</plain></notes></topic>'
  4916. else
  4917. result := '';
  4918. aCode := '';
  4919. finally
  4920. FreeAndNil(sl);
  4921. end;
  4922. end;
  4923. function DoItem(const aItem: TengShaderPart; const aIsRoot: Boolean = false): String;
  4924. var
  4925. p: TengShaderPart;
  4926. code: String;
  4927. begin
  4928. code := '';
  4929. result := '<topic id="' + MakeID(aItem) + '" style-id="7dh2otp9bqp93n80sk589g5916" timestamp="1407871141500"';
  4930. if (aIsRoot) then
  4931. result := result + ' structure-class="org.xmind.ui.logic.right"';
  4932. result := result + '><title>' + GetTitle(aItem) + '</title>' + GetDesc(aItem);
  4933. if (aItem is TengShaderPartScope) then
  4934. linkStr := linkStr + MakeLinks(aItem as TengShaderPartScope);
  4935. if (aItem.Count > 0) then begin
  4936. result := result + '<children><topics type="attached">';
  4937. for p in aItem do begin
  4938. if (p is TengShaderPartCode) then
  4939. code := code + (p as TengShaderPartCode).Text
  4940. else if (p is TengShaderPartCommandEnd) then
  4941. code := code + (p as TengShaderPartCommandEnd).fToken
  4942. else if (p is TengShaderPartLineBreak) then
  4943. code := code + (p as TengShaderPartLineBreak).Text
  4944. else
  4945. result := result + CreateCodeItem(code) + DoItem(p);
  4946. end;
  4947. result := result + CreateCodeItem(code) + '</topics></children>';
  4948. end;
  4949. result := result + '</topic>';
  4950. end;
  4951. var
  4952. fs: TFileStream;
  4953. s: String;
  4954. len: Integer;
  4955. begin
  4956. linkStr := '';
  4957. s := '<?xml version="1.0" encoding="UTF-8" standalone="no"?><xmap-content xmlns="urn:xmind:xmap:xmlns:content:2.0" xmlns:fo="http://www.w3.org/1999/XSL/Format" xmlns:svg="http://www.w3.org/2000/svg" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:xlink="http://www.w3.org/1999/xlink" timestamp="1407871228304" version="2.0"><sheet id="2e1sqd3f443tanv8s665jo6r9u" timestamp="1407871228304">' +
  4958. DoItem(aShaderPart, true) + '<title>glslPreCompiler Code Tree</title>';
  4959. if (linkStr <> '') then
  4960. s := s + '<relationships>' + linkStr + '</relationships>';
  4961. s := s + '</sheet></xmap-content>';
  4962. len := Length(s);
  4963. if (len > 0) then begin
  4964. fs := TFileStream.Create(IncludeTrailingPathDelimiter(aDirectory) + 'content.xml', fmCreate);
  4965. try
  4966. fs.Write(s[1], len);
  4967. finally
  4968. FreeAndNil(fs);
  4969. end;
  4970. s := '<?xml version="1.0" encoding="UTF-8" standalone="no"?><xmap-styles xmlns="urn:xmind:xmap:xmlns:style:2.0" xmlns:fo="http://www.w3.org/1999/XSL/Format" xmlns:svg="http://www.w3.org/2000/svg" version="2.0"><styles>' +
  4971. '<style id="7dh2otp9bqp93n80sk589g5916" type="topic"><topic-properties fo:font-family="Calibri" fo:font-size="10pt" line-class="org.xmind.branchConnection.elbow" shape-class="org.xmind.topicShape.roundedRect"/></style>' +
  4972. '<style id="1c2250lh1o9dug5bqnmfjqjj2h" type="relationship"><relationship-properties line-color="#FF0000" /></style>' +
  4973. '<style id="kjafgighq039598z56afioh565" type="relationship"><relationship-properties line-color="#00FF00" /></style>' +
  4974. '<style id="akjbq3589715ljkbg09uath6pa" type="relationship"><relationship-properties line-color="#0000FF" /></style>' +
  4975. '</styles></xmap-styles>';
  4976. len := Length(s);
  4977. fs := TFileStream.Create(IncludeTrailingPathDelimiter(aDirectory) + 'styles.xml', fmCreate);
  4978. try
  4979. fs.Write(s[1], len);
  4980. finally
  4981. FreeAndNil(fs);
  4982. end;
  4983. end;
  4984. end;
  4985. {$ENDIF}
  4986. end.