Nie możesz wybrać więcej, niż 25 tematów Tematy muszą się zaczynać od litery lub cyfry, mogą zawierać myślniki ('-') i mogą mieć do 35 znaków.

383 wiersze
13 KiB

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