Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

418 строки
14 KiB

  1. unit utsRendererOpenGLES;
  2. {$mode objfpc}{$H+}
  3. {.$DEFINE DEBUG}
  4. interface
  5. uses
  6. Classes, SysUtils,
  7. utsTextSuite, utsTypes, utsOpenGLUtils, dglOpenGLES;
  8. type
  9. TtsRendererOpenGLES = class(TtsBaseOpenGL)
  10. private
  11. fModelViewMatrix: TtsMatrix4f;
  12. fProjMatrix: TtsMatrix4f;
  13. fShaderProgram: GLuint;
  14. fVBO: GLuint;
  15. fShader: GLuint;
  16. fCharPosLocation: GLint;
  17. fCharTexPosLocation: GLint;
  18. fCharOffsetLocation: GLint;
  19. procedure SetModelViewMatrix(aValue: TtsMatrix4f);
  20. procedure SetProjectionMatrix(aValue: TtsMatrix4f);
  21. procedure SetShaderProgram(aValue: GLuint);
  22. function LoadShader: GLuint;
  23. procedure UpdateUniformProjMat;
  24. procedure UpdateUniformModelMat;
  25. procedure UpdateUniformCharOffset;
  26. protected
  27. function CreateNewTexture: PtsFontTexture; override;
  28. procedure FreeTexture(var aTexture: PtsFontTexture); override;
  29. procedure UploadTexData(const aCharRef: TtsCharRenderRefOpenGL;
  30. const aCharImage: TtsImage; const X, Y: Integer); override;
  31. procedure BeginRender; override;
  32. procedure SetDrawPos(const X, Y: Integer); override;
  33. procedure MoveDrawPos(const X, Y: Integer); override;
  34. procedure SetColor(const aColor: TtsColor4f); override;
  35. procedure Render(const aCharRef: TtsCharRenderRef); override;
  36. public
  37. property ShaderProgram: GLuint read fShaderProgram write SetShaderProgram;
  38. property ProjectionMatrix: TtsMatrix4f read fProjMatrix write SetProjectionMatrix;
  39. property ModelViewMatrix: TtsMatrix4f read fModelViewMatrix write SetModelViewMatrix;
  40. constructor Create(const aContext: TtsContext; const aFormat: TtsFormat);
  41. destructor Destroy; override;
  42. end;
  43. implementation
  44. type
  45. TVertex = packed record
  46. pos: array[0..1] of GLfloat;
  47. tex: array[0..1] of GLfloat;
  48. end;
  49. const
  50. ATTRIB_LOCATION_POSITION = 0;
  51. ATTRIB_LOCATION_TEXCOORD = 1;
  52. ATTRIB_NAME_POSITION = 'inPosition';
  53. ATTRIB_NAME_TEXCOORD = 'inTexCoord';
  54. UNIFORM_NAME_TEXTURE = 'uTexture';
  55. UNIFORM_NAME_MODELVIEWMAT = 'uModelViewMat';
  56. UNIFORM_NAME_PROJMAT = 'uProjMat';
  57. UNIFORM_NAME_CHARTEXPOS = 'uCharTexPos';
  58. UNIFORM_NAME_CHARPOS = 'uCharPos';
  59. UNIFORM_NAME_CHAROFFSET = 'uCharOffset';
  60. VERTEX_SHADER =
  61. 'attribute vec2 inPosition;' +
  62. 'attribute vec2 inTexCoord;' +
  63. 'varying vec2 vTexCoord;' +
  64. 'uniform mat4 uModelViewMat;' +
  65. 'uniform mat4 uProjMat;' +
  66. 'uniform mat4 uCharTexPos;' +
  67. 'uniform mat4 uCharPos;' +
  68. 'uniform ivec2 uCharOffset;' +
  69. 'void main() {' +
  70. ' vec4 pos = uCharPos * vec4(inPosition, 0.0, 1.0);' +
  71. ' pos += vec4(uCharOffset, 0.0, 0.0);' +
  72. ' gl_Position = uProjMat * uModelViewMat * pos;' +
  73. ' vTexCoord = (uCharTexPos * vec4(inTexCoord, 0.0, 1.0)).st;' +
  74. '}';
  75. FRAGMENT_SHADER =
  76. 'uniform sampler2D uTexture;' +
  77. 'varying vec2 vTexCoord;' +
  78. 'void main() {' +
  79. ' gl_FragColor = texture2D(uTexture, vTexCoord);' +
  80. '}';
  81. FORMAT_TYPES: array[TtsFormat] of packed record
  82. InternalFormat: GLenum;
  83. Format: GLenum;
  84. DataFormat: GLenum;
  85. end = (
  86. ( //tsFormatEmpty
  87. InternalFormat: 0;
  88. Format: 0;
  89. DataFormat: 0),
  90. ( //tsFormatRGBA8
  91. InternalFormat: GL_RGBA;
  92. Format: GL_RGBA;
  93. DataFormat: GL_UNSIGNED_BYTE),
  94. ( //tsFormatLumAlpha8
  95. InternalFormat: GL_LUMINANCE_ALPHA;
  96. Format: GL_LUMINANCE_ALPHA;
  97. DataFormat: GL_UNSIGNED_BYTE),
  98. ( //tsFormatAlpha8
  99. InternalFormat: GL_ALPHA;
  100. Format: GL_ALPHA;
  101. DataFormat: GL_UNSIGNED_BYTE),
  102. ( //tsFormatAlpha8
  103. InternalFormat: GL_LUMINANCE;
  104. Format: GL_LUMINANCE;
  105. DataFormat: GL_UNSIGNED_BYTE)
  106. );
  107. VBO_DATA: array[0..3] of TVertex = (
  108. (pos: (0.0, 0.0); tex: (0.0, 0.0)),
  109. (pos: (0.0, 1.0); tex: (0.0, 1.0)),
  110. (pos: (1.0, 0.0); tex: (1.0, 0.0)),
  111. (pos: (1.0, 1.0); tex: (1.0, 1.0))
  112. );
  113. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  114. //TtsRendererOpenGLES///////////////////////////////////////////////////////////////////////////////////////////////////
  115. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  116. procedure TtsRendererOpenGLES.SetModelViewMatrix(aValue: TtsMatrix4f);
  117. begin
  118. fModelViewMatrix := aValue;
  119. UpdateUniformModelMat;
  120. end;
  121. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  122. procedure TtsRendererOpenGLES.SetProjectionMatrix(aValue: TtsMatrix4f);
  123. begin
  124. fProjMatrix := aValue;
  125. UpdateUniformProjMat;
  126. end;
  127. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  128. procedure TtsRendererOpenGLES.SetShaderProgram(aValue: GLuint);
  129. begin
  130. if (fShaderProgram = aValue) then
  131. exit;
  132. fShaderProgram := aValue;
  133. fCharPosLocation := glGetUniformLocation(fShaderProgram, UNIFORM_NAME_CHARPOS);
  134. fCharTexPosLocation := glGetUniformLocation(fShaderProgram, UNIFORM_NAME_CHARTEXPOS);
  135. fCharOffsetLocation := glGetUniformLocation(fShaderProgram, UNIFORM_NAME_CHAROFFSET);
  136. UpdateUniformProjMat;
  137. UpdateUniformModelMat;
  138. UpdateUniformCharOffset;
  139. end;
  140. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  141. function TtsRendererOpenGLES.LoadShader: GLuint;
  142. {$IFDEF DEBUG}
  143. procedure PrintShaderInfo(const aObj: GLuint);
  144. var
  145. msg: PChar;
  146. bLen: GLint;
  147. sLen: GLsizei;
  148. begin
  149. bLen := 0;
  150. glGetShaderiv(aObj, GL_INFO_LOG_LENGTH, @bLen);
  151. if bLen > 1 then begin
  152. GetMem(msg, bLen * SizeOf(Char));
  153. try
  154. glGetShaderInfoLog(aObj, bLen, @sLen, msg);
  155. WriteLn(String(msg));
  156. finally
  157. FreeMem(msg);
  158. end;
  159. end;
  160. end;
  161. procedure PrintProgramInfo(const aObj: GLuint);
  162. var
  163. msg: PChar;
  164. bLen: GLint;
  165. sLen: GLsizei;
  166. begin
  167. bLen := 0;
  168. glGetProgramiv(aObj, GL_INFO_LOG_LENGTH, @bLen);
  169. if bLen > 1 then begin
  170. GetMem(msg, bLen * SizeOf(Char));
  171. try
  172. glGetProgramInfoLog(aObj, bLen, @sLen, msg);
  173. WriteLn(String(msg));
  174. finally
  175. FreeMem(msg);
  176. end;
  177. end;
  178. end;
  179. {$ENDIF}
  180. function CreateObj(const aCode: String; const aType: GLenum): GLuint;
  181. var
  182. code: PAnsiChar;
  183. len: GLint;
  184. begin
  185. result := glCreateShader(aType);
  186. len := Length(aCode);
  187. code := PAnsiChar(aCode);
  188. glShaderSource(result, 1, @code, @len);
  189. glCompileShader(result);
  190. {$IFDEF DEBUG}PrintShaderInfo(result);{$ENDIF}
  191. end;
  192. var
  193. fragObj, vertObj: GLuint;
  194. uLoc: Integer;
  195. begin
  196. result := glCreateProgram();
  197. vertObj := CreateObj(VERTEX_SHADER, GL_VERTEX_SHADER);
  198. fragObj := CreateObj(FRAGMENT_SHADER, GL_FRAGMENT_SHADER);
  199. glAttachShader(result, vertObj);
  200. glAttachShader(result, fragObj);
  201. glLinkProgram(result);
  202. {$IFDEF DEBUG}PrintProgramInfo(result);{$ENDIF}
  203. glBindAttribLocation(result, ATTRIB_LOCATION_POSITION, ATTRIB_NAME_POSITION);
  204. glBindAttribLocation(result, ATTRIB_LOCATION_TEXCOORD, ATTRIB_NAME_TEXCOORD);
  205. uLoc := glGetUniformLocation(result, UNIFORM_NAME_TEXTURE);
  206. if (uLoc >= 0) then begin
  207. glUseProgram(result);
  208. glUniform1i(uLoc, 0);
  209. glUseProgram(0);
  210. end;
  211. end;
  212. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  213. procedure TtsRendererOpenGLES.UpdateUniformProjMat;
  214. var
  215. loc: Integer;
  216. begin
  217. loc := glGetUniformLocation(fShaderProgram, UNIFORM_NAME_PROJMAT);
  218. if (loc >= 0) then begin
  219. glUseProgram(fShaderProgram);
  220. glUniformMatrix4fv(loc, 1, false, @fProjMatrix[0, 0]);
  221. glUseProgram(0);
  222. end;
  223. end;
  224. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  225. procedure TtsRendererOpenGLES.UpdateUniformModelMat;
  226. var
  227. loc: Integer;
  228. begin
  229. loc := glGetUniformLocation(fShaderProgram, UNIFORM_NAME_MODELVIEWMAT);
  230. if (loc >= 0) then begin
  231. glUseProgram(fShaderProgram);
  232. glUniformMatrix4fv(loc, 1, false, @fModelViewMatrix[0, 0]);
  233. glUseProgram(0);
  234. end;
  235. end;
  236. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  237. procedure TtsRendererOpenGLES.UpdateUniformCharOffset;
  238. begin
  239. if (fCharOffsetLocation >= 0) then begin
  240. glUseProgram(fShaderProgram);
  241. glUniform2iv(fCharOffsetLocation, 1, @RenderPos.x);
  242. glUseProgram(0);
  243. end;
  244. end;
  245. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  246. function TtsRendererOpenGLES.CreateNewTexture: PtsFontTexture;
  247. begin
  248. new(result);
  249. try
  250. FillByte(result^, SizeOf(result^), 0);
  251. new(result^.Usage);
  252. FillByte(result^.Usage^, SizeOf(result^.Usage^), 0);
  253. result^.Size := TextureSize;
  254. glGenTextures(1, @result^.ID);
  255. glBindTexture(GL_TEXTURE_2D, result^.ID);
  256. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  257. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  258. glTexImage2D(
  259. GL_TEXTURE_2D,
  260. 0,
  261. FORMAT_TYPES[Format].InternalFormat,
  262. result^.Size,
  263. result^.Size,
  264. 0,
  265. FORMAT_TYPES[Format].Format,
  266. FORMAT_TYPES[Format].DataFormat,
  267. nil);
  268. PushTexture(result);
  269. except
  270. if Assigned(result^.Usage) then
  271. Dispose(result^.Usage);
  272. Dispose(result);
  273. end;
  274. end;
  275. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  276. procedure TtsRendererOpenGLES.FreeTexture(var aTexture: PtsFontTexture);
  277. begin
  278. if Assigned(aTexture) then
  279. glDeleteTextures(1, @aTexture^.ID);
  280. inherited FreeTexture(aTexture);
  281. end;
  282. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  283. procedure TtsRendererOpenGLES.UploadTexData(const aCharRef: TtsCharRenderRefOpenGL; const aCharImage: TtsImage; const X, Y: Integer);
  284. begin
  285. glBindTexture(GL_TEXTURE_2D, aCharRef.TextureID);
  286. glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
  287. glTexSubImage2D(GL_TEXTURE_2D, 0,
  288. x, y, aCharImage.Width, aCharImage.Height,
  289. FORMAT_TYPES[aCharImage.Format].Format,
  290. FORMAT_TYPES[aCharImage.Format].DataFormat,
  291. aCharImage.Data);
  292. end;
  293. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  294. procedure TtsRendererOpenGLES.BeginRender;
  295. begin
  296. inherited BeginRender;
  297. glColor4f(Color.r, Color.g, Color.b, Color.a);
  298. end;
  299. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  300. procedure TtsRendererOpenGLES.SetDrawPos(const X, Y: Integer);
  301. begin
  302. inherited SetDrawPos(X, Y);
  303. UpdateUniformCharOffset;
  304. end;
  305. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  306. procedure TtsRendererOpenGLES.MoveDrawPos(const X, Y: Integer);
  307. begin
  308. inherited MoveDrawPos(X, Y);
  309. UpdateUniformCharOffset;
  310. end;
  311. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  312. procedure TtsRendererOpenGLES.SetColor(const aColor: TtsColor4f);
  313. begin
  314. inherited SetColor(aColor);
  315. glColor4f(Color.r, Color.g, Color.b, Color.a);
  316. end;
  317. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  318. procedure TtsRendererOpenGLES.Render(const aCharRef: TtsCharRenderRef);
  319. var
  320. ref: TtsCharRenderRefOpenGL;
  321. begin
  322. if Assigned(aCharRef) and (aCharRef is TtsCharRenderRefOpenGL) then begin
  323. ref := (aCharRef as TtsCharRenderRefOpenGL);
  324. glBindTexture(GL_TEXTURE_2D, ref.TextureID);
  325. glBindBuffer(GL_ARRAY_BUFFER, fVBO);
  326. glEnableVertexAttribArray(ATTRIB_LOCATION_POSITION);
  327. glVertexAttribPointer(ATTRIB_LOCATION_POSITION, 2, GL_FLOAT, false, SizeOf(TVertex), Pointer(0));
  328. glEnableVertexAttribArray(ATTRIB_LOCATION_TEXCOORD);
  329. glVertexAttribPointer(ATTRIB_LOCATION_TEXCOORD, 2, GL_FLOAT, false, SizeOf(TVertex), Pointer(8));
  330. glUseProgram(fShaderProgram);
  331. if (fCharPosLocation >= 0) then
  332. glUniformMatrix4fv(fCharPosLocation, 1, false, @ref.VertMat);
  333. if (fCharTexPosLocation >= 0) then
  334. glUniformMatrix4fv(fCharTexPosLocation, 1, false, @ref.TexMat);
  335. glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
  336. glUseProgram(0);
  337. glDisableVertexAttribArray(ATTRIB_LOCATION_TEXCOORD);
  338. glDisableVertexAttribArray(ATTRIB_LOCATION_POSITION);
  339. glBindTexture(GL_TEXTURE_2D, 0);
  340. end;
  341. end;
  342. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  343. constructor TtsRendererOpenGLES.Create(const aContext: TtsContext; const aFormat: TtsFormat);
  344. var
  345. viewport: array[0..3] of Integer;
  346. begin
  347. inherited Create(aContext, aFormat);
  348. glGenBuffers(1, @fVBO);
  349. glBindBuffer(GL_ARRAY_BUFFER, fVBO);
  350. glBufferData(GL_ARRAY_BUFFER, SizeOf(TVertex) * Length(VBO_DATA), @VBO_DATA[0].pos[0], GL_STATIC_DRAW);
  351. glBindBuffer(GL_ARRAY_BUFFER, 0);
  352. glGetIntegerv(GL_VIEWPORT, @viewport);
  353. fProjMatrix := tsMatrix4f(
  354. tsVector4f(2 / viewport[2], 0.0, 0.0, 0.0),
  355. tsVector4f( 0.0, -2 / viewport[3], 0.0, 0.0),
  356. tsVector4f( 0.0, 0.0, -0.1, 0.0),
  357. tsVector4f( -1.0, 1.0, 0.0, 1.0));
  358. fModelViewMatrix := TS_MATRIX_IDENTITY;
  359. fShader := LoadShader;
  360. ShaderProgram := fShader;
  361. end;
  362. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  363. destructor TtsRendererOpenGLES.Destroy;
  364. begin
  365. glDeleteBuffers(1, @fVBO);
  366. glDeleteProgram(fShader);
  367. inherited Destroy;
  368. end;
  369. end.