You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

430 lines
14 KiB

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