GLUtils.pas 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
  1. unit GLUtils;
  2. interface
  3. uses
  4. BrowserConsole, Web, WebGL, JS;
  5. type
  6. TShader = class
  7. public
  8. constructor Create (context: TJSWebGLRenderingContext; vertexShaderSource, fragmentShaderSource: string);
  9. procedure Compile;
  10. procedure Link;
  11. procedure Use;
  12. function GetAttribLocation (name: string): GLint;
  13. procedure BindAttribLocation (index: GLuint; name: string);
  14. procedure SetUniformMat4 (name: string; value: TJSFloat32List);
  15. private
  16. gl: TJSWebGLRenderingContext;
  17. vertexShader: TJSWebGLShader;
  18. fragmentShader: TJSWebGLShader;
  19. programID: TJSWebGLProgram;
  20. function CreateShader (theType: GLenum; source: string): TJSWebGLShader;
  21. end;
  22. implementation
  23. procedure Fatal (messageString: string); overload;
  24. begin
  25. writeln('*** FATAL: ', messageString);
  26. exit;
  27. end;
  28. // TODO: toll free bridge to FPC strings
  29. procedure Fatal (messageString: TJSString); overload;
  30. begin
  31. writeln('*** FATAL: ', messageString);
  32. exit;
  33. end;
  34. procedure GLFatal (gl: TJSWebGLRenderingContext; messageString: string = 'Fatal OpenGL error');
  35. var
  36. error: integer;
  37. begin
  38. error := gl.getError();
  39. if error <> gl.NO_ERROR then
  40. begin
  41. // TODO: case doesn't work?
  42. //case error of
  43. // gl.INVALID_VALUE:
  44. // messageString := messageString+' (GL_INVALID_VALUE)';
  45. // gl.INVALID_OPERATION:
  46. // messageString := messageString+' (GL_INVALID_OPERATION)';
  47. // gl.INVALID_ENUM:
  48. // messageString := messageString+' (GL_INVALID_ENUM)';
  49. // otherwise
  50. // messageString := messageString+' '+IntToStr(error);
  51. //end;
  52. // TODO: IntoStr doesn't work? cast to string or TJSString doesn't work either
  53. //messageString := messageString+' '+IntToStr(error);
  54. Fatal(messageString);
  55. end;
  56. end;
  57. procedure TShader.SetUniformMat4 (name: string; value: TJSFloat32List);
  58. var
  59. location: TJSWebGLUniformLocation;
  60. begin
  61. location := gl.getUniformLocation(programID, name);
  62. //writeln(name, ' = ', location, ' => ', value);
  63. GLFatal(gl, 'gl.getUniformLocation');
  64. gl.uniformMatrix4fv(location, false, value);
  65. GLFatal(gl, 'gl.uniformMatrix4fv');
  66. end;
  67. function TShader.GetAttribLocation (name: string): GLint;
  68. begin
  69. result := gl.getAttribLocation(programID, name);
  70. end;
  71. procedure TShader.BindAttribLocation (index: GLuint; name: string);
  72. begin
  73. gl.bindAttribLocation(programID, index, name);
  74. //GLFatal('glBindAttribLocation '+IntToStr(index)+':'+name);
  75. end;
  76. constructor TShader.Create (context: TJSWebGLRenderingContext; vertexShaderSource, fragmentShaderSource: string);
  77. begin
  78. gl := context;
  79. vertexShader := CreateShader(gl.VERTEX_SHADER, vertexShaderSource);
  80. fragmentShader := CreateShader(gl.FRAGMENT_SHADER, fragmentShaderSource);
  81. end;
  82. function TShader.CreateShader(theType: GLenum; source: string): TJSWebGLShader;
  83. var
  84. shader: TJSWebGLShader;
  85. begin
  86. shader := gl.createShader(theType);
  87. if shader = nil then
  88. Fatal('create shader failed');
  89. gl.shaderSource(shader, source);
  90. gl.compileShader(shader);
  91. if gl.getShaderParameter(shader, gl.COMPILE_STATUS) then
  92. begin
  93. //writeln('loaded shader ', theType);
  94. exit(shader);
  95. end
  96. else
  97. begin
  98. Fatal(gl.getShaderInfoLog(shader));
  99. //gl.deleteShader(shader);
  100. end;
  101. end;
  102. procedure TShader.Compile;
  103. begin
  104. programID := gl.createProgram;
  105. gl.attachShader(programID, vertexShader);
  106. gl.attachShader(programID, fragmentShader);
  107. end;
  108. procedure TShader.Link;
  109. begin
  110. gl.linkProgram(programID);
  111. if not gl.getProgramParameter(programID, gl.LINK_STATUS) then
  112. begin
  113. Fatal(gl.getProgramInfoLog(programID));
  114. //gl.deleteProgram(programID);
  115. end;
  116. end;
  117. procedure TShader.Use;
  118. begin
  119. gl.useProgram(programID);
  120. end;
  121. end.