25'ten fazla konu seçemezsiniz Konular bir harf veya rakamla başlamalı, kısa çizgiler ('-') içerebilir ve en fazla 35 karakter uzunluğunda olabilir.

388 satır
13 KiB

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