Nevar pievienot vairāk kā 25 tēmas Tēmai ir jāsākas ar burtu vai ciparu, tā var saturēt domu zīmes ('-') un var būt līdz 35 simboliem gara.

389 rindas
13 KiB

  1. unit utsOpenGLUtils;
  2. {$IFDEF FPC}
  3. {$mode delphi}{$H+}
  4. {$ENDIF}
  5. interface
  6. uses
  7. Classes, SysUtils,
  8. utsTextSuite, utsTypes;
  9. type
  10. TtsCharRenderRefOpenGL = class(TtsCharRenderRef)
  11. public
  12. TextureID: Integer; // ID of OpenGL texture where the char is stored in
  13. Size: TtsPosition;
  14. TexMat: TtsMatrix4f;
  15. VertMat: TtsMatrix4f;
  16. constructor Create;
  17. end;
  18. PtsTextureUsageItem = ^TtsTextureUsageItem;
  19. TtsTextureUsageItem = packed record
  20. children: array[0..3] of PtsTextureUsageItem;
  21. end;
  22. PtsTextureTreeItem = ^TtsTextureTreeItem;
  23. TtsTextureTreeItem = packed record
  24. value: SmallInt;
  25. children: array[0..1] of PtsTextureTreeItem;
  26. ref: TtsCharRenderRefOpenGL;
  27. end;
  28. PtsFontTexture = ^TtsFontTexture;
  29. TtsFontTexture = packed record
  30. ID: Integer; // OpenGL texture ID
  31. Usage: PtsTextureTreeItem ; // tree of used texture space
  32. Next: PtsFontTexture; // next texture in list
  33. Prev: PtsFontTexture; // previouse texture in list
  34. Size: Integer; // size of this texture
  35. Count: Integer; // number of chars stored in this texture
  36. end;
  37. TtsBaseOpenGL = class(TtsRenderer)
  38. private
  39. fTextureSize: Integer;
  40. fColor: TtsColor4f;
  41. fRenderPos: TtsPosition;
  42. fFirstTexture: PtsFontTexture;
  43. fLastTexture: PtsFontTexture;
  44. procedure FreeTextures(var aTexture: PtsFontTexture);
  45. procedure FreeTextureTreeItem(var aItem: PtsTextureTreeItem);
  46. protected
  47. property Color: TtsColor4f read fColor;
  48. property RenderPos: TtsPosition read fRenderPos;
  49. procedure PushTexture(const aTexture: PtsFontTexture);
  50. function CreateNewTexture: PtsFontTexture; virtual;
  51. procedure FreeTexture(var aTexture: PtsFontTexture); virtual;
  52. procedure UploadTexData(const aCharRef: TtsCharRenderRefOpenGL; const aCharImage: TtsImage; const X, Y: Integer); virtual;
  53. protected
  54. function CreateRenderRef(const aChar: TtsChar; const aCharImage: TtsImage): TtsCharRenderRef; override;
  55. procedure FreeRenderRef(const aCharRef: TtsCharRenderRef); override;
  56. procedure BeginRender; override;
  57. procedure SetDrawPos(const X, Y: Integer); override;
  58. function GetDrawPos: TtsPosition; override;
  59. procedure MoveDrawPos(const X, Y: Integer); override;
  60. procedure SetColor(const aColor: TtsColor4f); override;
  61. public
  62. property TextureSize: Integer read fTextureSize write fTextureSize;
  63. constructor Create(const aContext: TtsContext; const aFormat: TtsFormat);
  64. destructor Destroy; override;
  65. end;
  66. EtsRendererOpenGL = class(EtsRenderer);
  67. implementation
  68. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  69. //TtsCharRenderRefOpenGL////////////////////////////////////////////////////////////////////////////////////////////////
  70. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  71. constructor TtsCharRenderRefOpenGL.Create;
  72. begin
  73. inherited Create;
  74. TextureID := 0;
  75. FillChar(TexMat, SizeOf(TexMat), #0);
  76. FillChar(VertMat, SizeOf(VertMat), #0);
  77. FillChar(Size, SizeOf(Size), #0);
  78. end;
  79. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  80. //TtsBaseOpenGL/////////////////////////////////////////////////////////////////////////////////////////////////////////
  81. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  82. procedure TtsBaseOpenGL.FreeTextures(var aTexture: PtsFontTexture);
  83. begin
  84. if not Assigned(aTexture) then
  85. exit;
  86. FreeTextures(aTexture^.Next);
  87. FreeTexture(aTexture);
  88. end;
  89. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  90. procedure TtsBaseOpenGL.FreeTextureTreeItem(var aItem: PtsTextureTreeItem);
  91. begin
  92. if not Assigned(aItem) then
  93. exit;
  94. FreeTextureTreeItem(aItem^.children[0]);
  95. FreeTextureTreeItem(aItem^.children[1]);
  96. Dispose(aItem);
  97. aItem := nil;
  98. end;
  99. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  100. procedure TtsBaseOpenGL.PushTexture(const aTexture: PtsFontTexture);
  101. begin
  102. aTexture^.Prev := fLastTexture;
  103. if Assigned(fLastTexture) then
  104. fLastTexture^.Next := aTexture
  105. else
  106. fFirstTexture := aTexture;
  107. fLastTexture := aTexture;
  108. end;
  109. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  110. function TtsBaseOpenGL.CreateNewTexture: PtsFontTexture;
  111. begin
  112. result := nil;
  113. end;
  114. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  115. procedure TtsBaseOpenGL.FreeTexture(var aTexture: PtsFontTexture);
  116. begin
  117. if not Assigned(aTexture) then
  118. exit;
  119. FreeTextureTreeItem(aTexture^.Usage);
  120. if Assigned(aTexture^.Prev) then
  121. aTexture^.Prev^.Next := aTexture^.Next;
  122. if Assigned(aTexture^.Next) then
  123. aTexture^.Next^.Prev := aTexture^.Prev;
  124. Dispose(aTexture);
  125. aTexture := nil;
  126. end;
  127. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  128. procedure TtsBaseOpenGL.UploadTexData(const aCharRef: TtsCharRenderRefOpenGL; const aCharImage: TtsImage; const X, Y: Integer);
  129. begin
  130. // DUMMY
  131. end;
  132. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  133. function TtsBaseOpenGL.CreateRenderRef(const aChar: TtsChar; const aCharImage: TtsImage): TtsCharRenderRef;
  134. var
  135. GlyphWidth, GlyphHeight: Integer;
  136. function InsertToTree(const aItem: PtsTextureTreeItem; const X1, Y1, X2, Y2: SmallInt; out X, Y: Integer): PtsTextureTreeItem;
  137. var
  138. w, h: Integer;
  139. begin
  140. result := nil;
  141. w := X2 - X1;
  142. h := Y2 - Y1;
  143. if not Assigned(aItem) or
  144. Assigned(aItem^.ref) or
  145. (w < GlyphWidth) or
  146. (h < GlyphHeight) then
  147. exit;
  148. if (aItem^.value > 0) then begin
  149. result := InsertToTree(aItem^.children[0], X1, Y1, X2, aItem^.value, X, Y);
  150. if not Assigned(result) then
  151. result := InsertToTree(aItem^.children[1], X1, aItem^.value, X2, Y2, X, Y);
  152. end else if (aItem^.value < 0) then begin
  153. result := InsertToTree(aItem^.children[0], X1, Y1, -aItem^.value, Y2, X, Y);
  154. if not Assigned(result) then
  155. result := InsertToTree(aItem^.children[1], -aItem^.value, Y1, X2, Y2, X, Y);
  156. end else if (w = GlyphWidth) and (h = GlyphHeight) then begin
  157. X := X1;
  158. Y := Y1;
  159. result := aItem;
  160. end else begin
  161. new(aItem^.children[0]);
  162. new(aItem^.children[1]);
  163. FillChar(aItem^.children[0]^, SizeOf(aItem^.children[0]^), #0);
  164. FillChar(aItem^.children[1]^, SizeOf(aItem^.children[1]^), #0);
  165. if (w - GlyphWidth) < (h - GlyphHeight) then begin
  166. aItem^.value := Y1 + GlyphHeight;
  167. result := InsertToTree(aItem^.children[0], X1, Y1, X2, aItem^.value, X, Y);
  168. end else begin
  169. aItem^.value := -(X1 + GlyphWidth);
  170. result := InsertToTree(aItem^.children[0], X1, Y1, -aItem^.value, Y2, X, Y)
  171. end;
  172. end;
  173. end;
  174. function AddToTexture(const aTexture: PtsFontTexture): TtsCharRenderRefOpenGL;
  175. var
  176. x, y, wChar, hChar, l, t: Integer;
  177. item: PtsTextureTreeItem;
  178. begin
  179. item := InsertToTree(aTexture^.Usage, 0, 0, aTexture^.Size, aTexture^.Size, x, y);
  180. if not Assigned(item) then
  181. raise EtsRendererOpenGL.Create('unable to add glyph to texture');
  182. item^.ref := TtsCharRenderRefOpenGL.Create;
  183. result := item^.ref;
  184. wChar := aChar.GlyphRect.Right - aChar.GlyphRect.Left;
  185. hChar := aChar.GlyphRect.Bottom - aChar.GlyphRect.Top;
  186. l := aChar.GlyphRect.Left + x;
  187. t := aChar.GlyphRect.Top + y;
  188. result.TextureID := aTexture^.ID;
  189. result.Size := tsPosition(aCharImage.Width, aCharImage.Height);
  190. result.TexMat := tsMatrix4f(
  191. tsVector4f(wChar / aTexture^.Size, 0.0, 0.0, 0.0),
  192. tsVector4f(0.0, hChar / aTexture^.Size, 0.0, 0.0),
  193. tsVector4f(0.0, 0.0, 1.0, 0.0),
  194. tsVector4f(l / aTexture^.Size, t / aTexture^.Size, 0.0, 1.0));
  195. result.VertMat := tsMatrix4f(
  196. tsVector4f(wChar, 0.0, 0.0, 0.0),
  197. tsVector4f(0.0, hChar, 0.0, 0.0),
  198. tsVector4f(0.0, 0.0, 1.0, 0.0),
  199. tsVector4f(aChar.GlyphOrigin.x, -aChar.GlyphOrigin.y, 0.0, 1.0));
  200. UploadTexData(result, aCharImage, x, y);
  201. end;
  202. var
  203. tex: PtsFontTexture;
  204. begin
  205. result := nil;
  206. if aCharImage.IsEmpty then
  207. exit;
  208. GlyphWidth := aCharImage.Width + 1;
  209. GlyphHeight := aCharImage.Height + 1;
  210. // try to add to existing texture
  211. tex := fFirstTexture;
  212. while Assigned(tex) and not Assigned(result) do begin
  213. result := AddToTexture(tex);
  214. tex := tex^.Next;
  215. end;
  216. // create new texture
  217. if not Assigned(result) then begin
  218. if (aCharImage.Width > TextureSize) or (aCharImage.Height > TextureSize) then
  219. raise EtsRendererOpenGL.Create('char is to large to fit into a texture: ' + aChar.CharCode + ' (0x' + IntToHex(Ord(aChar.CharCode), 4) + ')');
  220. tex := CreateNewTexture;
  221. result := AddToTexture(tex);
  222. end;
  223. if not Assigned(result) then
  224. raise EtsRendererOpenGL.Create('unable to creat render reference for char: ' + aChar.CharCode + ' (0x' + IntToHex(Ord(aChar.CharCode), 4) + ')');
  225. end;
  226. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  227. procedure TtsBaseOpenGL.FreeRenderRef(const aCharRef: TtsCharRenderRef);
  228. var
  229. ref: TtsCharRenderRefOpenGL;
  230. tex: PtsFontTexture;
  231. function IsEmtpy(const aItem: PtsTextureTreeItem): Boolean;
  232. begin
  233. result :=
  234. Assigned(aItem) and
  235. not Assigned(aItem^.children[0]) and
  236. not Assigned(aItem^.children[1]) and
  237. not Assigned(aItem^.ref);
  238. end;
  239. function RemoveFromTree(const aItem: PtsTextureTreeItem; const X1, Y1, X2, Y2: Integer): Boolean;
  240. var
  241. w, h: Integer;
  242. begin
  243. w := X2 - X1;
  244. h := Y2 - Y1;
  245. if not Assigned(aItem) or
  246. (w < ref.Size.x) or
  247. (h < ref.Size.y) then
  248. exit;
  249. result := (aItem^.ref = ref);
  250. if not result then begin
  251. if (aItem^.value > 0) then begin
  252. result := result or RemoveFromTree(aItem^.children[0], X1, Y1, X2, aItem^.value);
  253. result := result or RemoveFromTree(aItem^.children[1], X1, aItem^.value, X2, Y2);
  254. end else if (aItem^.value < 0) then begin
  255. result := result or RemoveFromTree(aItem^.children[0], X1, Y1, -aItem^.value, Y2);
  256. result := result or RemoveFromTree(aItem^.children[1], -aItem^.value, Y1, X2, Y2);
  257. end;
  258. end else
  259. aItem^.ref := nil;
  260. if result and
  261. IsEmtpy(aItem^.children[0]) and
  262. IsEmtpy(aItem^.children[1]) then
  263. begin
  264. FreeTextureTreeItem(aItem^.children[0]);
  265. FreeTextureTreeItem(aItem^.children[1]);
  266. FillChar(aItem^, SizeOf(aItem^), #0);
  267. end;
  268. end;
  269. begin
  270. try
  271. if not Assigned(aCharRef) or not (aCharRef is TtsCharRenderRefOpenGL) then
  272. exit;
  273. ref := (aCharRef as TtsCharRenderRefOpenGL);
  274. tex := fFirstTexture;
  275. while Assigned(tex) do begin
  276. if (tex^.ID = ref.TextureID) then begin
  277. if not RemoveFromTree(tex^.Usage, 0, 0, tex^.Size, tex^.Size) then
  278. raise EtsRendererOpenGL.Create('unable to remove render ref from texture');
  279. if IsEmtpy(tex^.Usage) then begin
  280. if (tex = fFirstTexture) then
  281. fFirstTexture := nil;
  282. FreeTexture(tex);
  283. end;
  284. tex := nil;
  285. end else
  286. tex := tex^.Next;
  287. end;
  288. finally
  289. if Assigned(aCharRef) then
  290. aCharRef.Free;
  291. end;
  292. end;
  293. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  294. procedure TtsBaseOpenGL.BeginRender;
  295. begin
  296. inherited BeginRender;
  297. fRenderPos.x := 0;
  298. fRenderPos.y := 0;
  299. end;
  300. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  301. procedure TtsBaseOpenGL.SetDrawPos(const X, Y: Integer);
  302. begin
  303. fRenderPos.x := X;
  304. fRenderPos.y := Y;
  305. end;
  306. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  307. function TtsBaseOpenGL.GetDrawPos: TtsPosition;
  308. begin
  309. result := fRenderPos;
  310. end;
  311. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  312. procedure TtsBaseOpenGL.MoveDrawPos(const X, Y: Integer);
  313. begin
  314. fRenderPos.x := fRenderPos.x + X;
  315. fRenderPos.y := fRenderPos.y + Y;
  316. end;
  317. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  318. procedure TtsBaseOpenGL.SetColor(const aColor: TtsColor4f);
  319. begin
  320. fColor := aColor;
  321. end;
  322. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  323. constructor TtsBaseOpenGL.Create(const aContext: TtsContext; const aFormat: TtsFormat);
  324. begin
  325. inherited Create(aContext, aFormat);
  326. fFirstTexture := nil;
  327. fLastTexture := nil;
  328. fTextureSize := 2048;
  329. fColor := tsColor4f(1, 1, 1, 1);
  330. fRenderPos := tsPosition(0, 0);
  331. end;
  332. destructor TtsBaseOpenGL.Destroy;
  333. begin
  334. FreeTextures(fFirstTexture);
  335. inherited Destroy;
  336. end;
  337. end.