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.

525 lines
17KB

  1. /*
  2. * TSDGLShader.js
  3. * Keynote HTML Player
  4. *
  5. * Created by Tungwei Cheng
  6. * Copyright (c) 2018-2019 Apple Inc. All rights reserved.
  7. */
  8. // Uniforms
  9. var kTSDGLShaderUniformColor = "Color";
  10. var kTSDGLShaderUniformDuration = "Duration";
  11. var kTSDGLShaderUniformMotionBlurVector = "MotionBlurVector";
  12. var kTSDGLShaderUniformMVPMatrix = "MVPMatrix";
  13. var kTSDGLShaderUniformOpacity = "Opacity";
  14. var kTSDGLShaderUniformParticleTexture = "ParticleTexture";
  15. var kTSDGLShaderUniformPercent = "Percent";
  16. var kTSDGLShaderUniformPreviousMVPMatrix = "PreviousMVPMatrix";
  17. var kTSDGLShaderUniformTexture = "Texture";
  18. var kTSDGLShaderUniformTextureMatrix = "TextureMatrix";
  19. var kTSDGLShaderUniformTextureSize = "TextureSize";
  20. var kTSDGLShaderUniformTexture2 = "Texture2";
  21. var kTSDGLShaderUniformTexture2Matrix = "Texture2Matrix";
  22. var kTSDGLShaderUniformTexture2Size = "Texture2Size";
  23. var kTSDGLShaderUniformVelocityScale = "VelocityScale";
  24. var kTSDGLShaderUniformVelocityTexture = "VelocityTexture";
  25. // Attributes
  26. var kTSDGLShaderAttributeCenter = "Center"; // center point of this particle
  27. var kTSDGLShaderAttributeColor = "Color";
  28. var kTSDGLShaderAttributeLifeSpan = "LifeSpan";
  29. var kTSDGLShaderAttributeNormal = "Normal";
  30. var kTSDGLShaderAttributeParticleTexCoord = "ParticleTexCoord";
  31. var kTSDGLShaderAttributePosition = "Position";
  32. var kTSDGLShaderAttributePreviousPosition = "PreviousPosition";
  33. var kTSDGLShaderAttributeRotation = "Rotation";
  34. var kTSDGLShaderAttributeScale = "Scale";
  35. var kTSDGLShaderAttributeSpeed = "Speed";
  36. var kTSDGLShaderAttributeTexCoord = "TexCoord";
  37. var kTSDGLShaderUniformRotationMax = "RotationMax";
  38. var kTSDGLShaderUniformSpeedMax = "SpeedMax";
  39. var TSDGLShaderQualifierType = {
  40. Unknown: 0, ///< ERROR
  41. Int: 1, // < GLSL type "int"
  42. Float: 2, // < GLSL type "float"
  43. Vec2: 3, // < GLSL type "vec2"
  44. Vec3: 4, // < GLSL type "vec3"
  45. Vec4: 5, // < GLSL type "vec4"
  46. Mat3: 6, // < GLSL type "mat3"
  47. Mat4: 7 // < GLSL type "mat4"
  48. };
  49. function TSDGLShaderQualifierTypeFromGLenum(type) {
  50. var result = TSDGLShaderQualifierType.Unknown;
  51. switch (type) {
  52. case GL_FLOAT:
  53. result = TSDGLShaderQualifierType.Float;
  54. break;
  55. case GL_FLOAT_VEC2:
  56. result = TSDGLShaderQualifierType.Vec2;
  57. break;
  58. case GL_FLOAT_VEC3:
  59. result = TSDGLShaderQualifierType.Vec3;
  60. break;
  61. case GL_FLOAT_VEC4:
  62. result = TSDGLShaderQualifierType.Vec4;
  63. break;
  64. case GL_BOOL:
  65. case GL_SAMPLER_2D:
  66. case GL_INT:
  67. result = TSDGLShaderQualifierType.Int;
  68. break;
  69. case GL_FLOAT_MAT3:
  70. result = TSDGLShaderQualifierType.Mat3;
  71. break;
  72. case GL_FLOAT_MAT4:
  73. result = TSDGLShaderQualifierType.Mat4;
  74. break;
  75. case GL_INT_VEC2:
  76. case GL_INT_VEC3:
  77. case GL_INT_VEC4:
  78. case GL_BOOL_VEC2:
  79. case GL_BOOL_VEC3:
  80. case GL_BOOL_VEC4:
  81. case GL_FLOAT_MAT2:
  82. case GL_SAMPLER_CUBE:
  83. default:
  84. console.log("Unimplemented GLenum type " + type);
  85. break;
  86. }
  87. return result;
  88. }
  89. var TSDGLShader = Class.create({
  90. initialize: function(gl) {
  91. this.gl = gl;
  92. this._uniforms = {};
  93. this.name = "";
  94. this.programObject = null;
  95. this.isActive = false;
  96. this._uniformsNeedingUpdate = [];
  97. },
  98. initWithDefaultTextureShader: function() {
  99. this.initWithShaderFileNames("defaultTexture", "defaultTexture");
  100. this.setGLint(0, kTSDGLShaderUniformTexture);
  101. },
  102. initWithDefaultTextureAndOpacityShader: function() {
  103. this.initWithShaderFileNames("defaultTexture", "defaultTextureAndOpacity");
  104. },
  105. initWithDefaultHorizontalBlurShader: function() {
  106. this.initWithShaderFileNames("horizontalGaussianBlur", "horizontalGaussianBlur");
  107. this.setGLint(0, kTSDGLShaderUniformTexture);
  108. },
  109. initWithDefaultVerticalBlurShader: function() {
  110. this.initWithShaderFileNames("verticalGaussianBlur", "verticalGaussianBlur");
  111. this.setGLint(0, kTSDGLShaderUniformTexture);
  112. },
  113. initWithContentsShader: function() {
  114. this.initWithShaderFileNames("contents", "contents");
  115. },
  116. initWithContentsAndOpacityShader: function() {
  117. this.initWithShaderFileNames("contentsAndOpacity", "contentsAndOpacity");
  118. },
  119. initWithShaderFileNames: function(vertexShaderFileName, fragmentShaderFileName) {
  120. var vertexString = KNWebGLShader[vertexShaderFileName].vertex;
  121. var fragmentString = KNWebGLShader[fragmentShaderFileName].fragment;
  122. this.initWithShaders(vertexString, fragmentString);
  123. },
  124. initWithShaders: function(vertexString, fragmentString) {
  125. var gl = this.gl;
  126. var vertexShader = KNWebGLUtil.loadShader(gl, gl.VERTEX_SHADER, vertexString);
  127. var fragmentShader = KNWebGLUtil.loadShader(gl, gl.FRAGMENT_SHADER, fragmentString);
  128. this.programObject = KNWebGLUtil.createShaderProgram(gl, vertexShader, fragmentShader);
  129. this.p_updateUniformsAndAttributesFromShader();
  130. },
  131. p_updateUniformsAndAttributesFromShader: function() {
  132. var gl = this.gl;
  133. var programObject = this.programObject;
  134. var uniformsCount = -1;
  135. uniformsCount = gl.getProgramParameter(programObject, gl.ACTIVE_UNIFORMS);
  136. for (var i = 0; i < uniformsCount; i++) {
  137. var activeInfo = gl.getActiveUniform(programObject, i);
  138. var name = activeInfo.name;
  139. var type = activeInfo.type;
  140. var size = activeInfo.size;
  141. // Add uniform to cache
  142. var qualifierType = TSDGLShaderQualifierTypeFromGLenum(type);
  143. this.shaderQualifierForUniform(name, qualifierType);
  144. }
  145. // Update attributes
  146. var attributesCount = -1;
  147. attributesCount = gl.getProgramParameter(programObject, gl.ACTIVE_ATTRIBUTES);
  148. for (var i = 0; i < attributesCount; i++) {
  149. var activeInfo = gl.getActiveAttrib(programObject, i);
  150. var name = activeInfo.name;
  151. var type = activeInfo.type;
  152. var size = activeInfo.size;
  153. // Add attribute location to cache
  154. this.locationForAttribute(name);
  155. }
  156. },
  157. shaderQualifierForUniform: function(uniform, qualifierType) {
  158. var gl = this.gl;
  159. var qualifier = this._uniforms[uniform];
  160. if (!qualifier) {
  161. switch (qualifierType) {
  162. case TSDGLShaderQualifierType.Unknown:
  163. console.log("Unknown Shader Qualifier Type!");
  164. break;
  165. case TSDGLShaderQualifierType.Int:
  166. qualifier = new TSDGLShaderQualifierInt(gl, uniform);
  167. break;
  168. case TSDGLShaderQualifierType.Float:
  169. qualifier = new TSDGLShaderQualifierFloat(gl, uniform);
  170. break;
  171. case TSDGLShaderQualifierType.Vec2:
  172. qualifier = new TSDGLShaderQualifierPoint2D(gl, uniform);
  173. break;
  174. case TSDGLShaderQualifierType.Vec3:
  175. qualifier = new TSDGLShaderQualifierPoint3D(gl, uniform);
  176. break;
  177. case TSDGLShaderQualifierType.Vec4:
  178. qualifier = new TSDGLShaderQualifierPoint4D(gl, uniform);
  179. break;
  180. case TSDGLShaderQualifierType.Mat3:
  181. qualifier = new TSDGLShaderQualifierMat3(gl, uniform);
  182. break;
  183. case TSDGLShaderQualifierType.Mat4:
  184. qualifier = new TSDGLShaderQualifierMat4(gl, uniform);
  185. break;
  186. }
  187. qualifier.updateUniformLocationWithShaderProgramObject(this.programObject);
  188. this._uniforms[uniform] = qualifier;
  189. }
  190. return qualifier;
  191. },
  192. setGLint: function(newInt, uniform) {
  193. var qualifier = this.shaderQualifierForUniform(uniform, TSDGLShaderQualifierType.Int);
  194. qualifier.setProposedGLintValue(newInt);
  195. if (qualifier._needsUpdate) {
  196. this._uniformsNeedingUpdate.push(qualifier);
  197. }
  198. this.p_setQualifiersIfNecessary();
  199. },
  200. setGLFloat: function(newFloat, uniform) {
  201. var qualifier = this.shaderQualifierForUniform(uniform, TSDGLShaderQualifierType.Float);
  202. qualifier.setProposedGLfloatValue(newFloat);
  203. if (qualifier._needsUpdate) {
  204. this._uniformsNeedingUpdate.push(qualifier);
  205. }
  206. this.p_setQualifiersIfNecessary();
  207. },
  208. setPoint2D: function(newPoint2D, uniform) {
  209. var qualifier = this.shaderQualifierForUniform(uniform, TSDGLShaderQualifierType.Vec2);
  210. qualifier.setProposedGLPoint2DValue(newPoint2D);
  211. if (qualifier._needsUpdate) {
  212. this._uniformsNeedingUpdate.push(qualifier);
  213. }
  214. this.p_setQualifiersIfNecessary();
  215. },
  216. setMat4WithTransform3D: function(aTransform3D, uniform) {
  217. var qualifier = this.shaderQualifierForUniform(uniform, TSDGLShaderQualifierType.Mat4);
  218. qualifier.setProposedTransform3D(aTransform3D);
  219. if (qualifier._needsUpdate) {
  220. this._uniformsNeedingUpdate.push(qualifier);
  221. }
  222. this.p_setQualifiersIfNecessary();
  223. },
  224. locationForUniform: function(uniform) {
  225. var location;
  226. var shaderQualifier = this._uniforms[uniform];
  227. if (shaderQualifier) {
  228. location = shaderQualifier._uniformLocation;
  229. }
  230. if (!location) {
  231. location = this.gl.getUniformLocation(this.programObject, uniform);
  232. }
  233. return location;
  234. },
  235. locationForAttribute: function(attribute) {
  236. if (!this._attributeLocations) {
  237. this._attributeLocations = {};
  238. }
  239. var location = this._attributeLocations[attribute];
  240. if (location === undefined) {
  241. location = -1;
  242. }
  243. if (location < 0) {
  244. location = this.gl.getAttribLocation(this.programObject, attribute);
  245. this._attributeLocations[attribute] = location;
  246. }
  247. return location;
  248. },
  249. p_setQualifiersIfNecessary: function() {
  250. if (!this.isActive) {
  251. return;
  252. }
  253. if (this._uniformsNeedingUpdate.length === 0) {
  254. return;
  255. }
  256. // Look through all the newly-set qualifiers
  257. for (var i = 0, length = this._uniformsNeedingUpdate.length; i < length; i++) {
  258. var proposedQualifier = this._uniformsNeedingUpdate[i];
  259. if (proposedQualifier._uniformLocation === -1) {
  260. proposedQualifier.updateUniformLocationWithShaderProgramObject(this.programObject);
  261. }
  262. proposedQualifier.setGLUniformWithShader(this.gl, this);
  263. }
  264. this._uniformsNeedingUpdate = [];
  265. },
  266. activate: function() {
  267. var gl = this.gl;
  268. if (!this.isActive) {
  269. gl.useProgram(this.programObject);
  270. this.isActive = true;
  271. }
  272. this.p_setQualifiersIfNecessary();
  273. },
  274. deactivate: function() {
  275. if (this.isActive) {
  276. //gl.useProgram(0);
  277. this.isActive = false;
  278. }
  279. }
  280. });
  281. var TSDGLShaderQualifier = Class.create({
  282. initialize: function(gl, qualifierName) {
  283. this.gl = gl;
  284. this._uniformLocation = -1;
  285. this._needsUpdate = true;
  286. this._name = qualifierName;
  287. },
  288. updateUniformLocationWithShaderProgramObject: function(shaderProgramObject) {
  289. if (this._uniformLocation === -1) {
  290. this._uniformLocation = this.gl.getUniformLocation(shaderProgramObject, this._name);
  291. }
  292. }
  293. });
  294. var TSDGLShaderQualifierInt = Class.create(TSDGLShaderQualifier, {
  295. initialize: function($super, gl, qualifierName) {
  296. this._GLintValue = 0;
  297. this._proposedGLintValue = 0;
  298. $super(gl, qualifierName);
  299. },
  300. setProposedGLintValue: function(proposedGLintValue) {
  301. if (this._proposedGLintValue !== proposedGLintValue) {
  302. this._proposedGLintValue = proposedGLintValue;
  303. this._needsUpdate = true;
  304. }
  305. },
  306. setGLUniformWithShader: function(gl, shader) {
  307. gl.uniform1i(this._uniformLocation, this._proposedGLintValue);
  308. this._GLintValue = this._proposedGLintValue;
  309. this._needsUpdate = false;
  310. }
  311. });
  312. var TSDGLShaderQualifierFloat = Class.create(TSDGLShaderQualifier, {
  313. initialize: function($super, gl, qualifierName) {
  314. this._GLfloatValue = 0;
  315. this._proposedGLfloatValue = 0;
  316. $super(gl, qualifierName);
  317. },
  318. setProposedGLfloatValue: function(proposedGLfloatValue) {
  319. if (this._proposedGLfloatValue !== proposedGLfloatValue) {
  320. this._proposedGLfloatValue = proposedGLfloatValue;
  321. this._needsUpdate = true;
  322. }
  323. },
  324. setGLUniformWithShader: function(gl, shader) {
  325. gl.uniform1f(this._uniformLocation, this._proposedGLfloatValue);
  326. this._GLfloatValue = this._proposedGLfloatValue;
  327. this._needsUpdate = false;
  328. }
  329. });
  330. var TSDGLShaderQualifierPoint2D = Class.create(TSDGLShaderQualifier, {
  331. initialize: function($super, gl, qualifierName) {
  332. this._GLPoint2DValue = {};
  333. this._proposedGLPoint2DValue = {};
  334. $super(gl, qualifierName);
  335. },
  336. setProposedGLPoint2DValue: function(proposedGLPoint2DValue) {
  337. if (!(this._proposedGLPoint2DValue.x === proposedGLPoint2DValue.x && this._proposedGLPoint2DValue.y === proposedGLPoint2DValue.y)) {
  338. this._proposedGLPoint2DValue = proposedGLPoint2DValue;
  339. this._needsUpdate = true;
  340. }
  341. },
  342. setGLUniformWithShader: function(gl, shader) {
  343. gl.uniform2fv(this._uniformLocation, [this._proposedGLPoint2DValue.x, this._proposedGLPoint2DValue.y]);
  344. this._GLPoint2DValue = this._proposedGLPoint2DValue;
  345. this._needsUpdate = false;
  346. }
  347. });
  348. var TSDGLShaderQualifierPoint3D = Class.create(TSDGLShaderQualifier, {
  349. initialize: function($super, gl, qualifierName) {
  350. this._GLPoint3DValue = {};
  351. this._proposedGLPoint3DValue = {};
  352. $super(gl, qualifierName);
  353. },
  354. setProposedGLPoint3DValue: function(proposedGLPoint3DValue) {
  355. if (!(this._proposedGLPoint3DValue.x === proposedGLPoint3DValue.x && this._proposedGLPoint3DValue.y === proposedGLPoint3DValue.y && this._proposedGLPoint3DValue.z === proposedGLPoint3DValue.z)) {
  356. this._proposedGLPoint3DValue = proposedGLPoint3DValue;
  357. this._needsUpdate = true;
  358. }
  359. },
  360. setGLUniformWithShader: function(gl, shader) {
  361. gl.uniform3fv(this._uniformLocation, [this._proposedGLPoint3DValue.x, this._proposedGLPoint3DValue.y, this._proposedGLPoint3DValue.z]);
  362. this._GLPoint3DValue = this._proposedGLPoint3DValue;
  363. this._needsUpdate = false;
  364. }
  365. });
  366. var TSDGLShaderQualifierPoint4D = Class.create(TSDGLShaderQualifier, {
  367. initialize: function($super, gl, qualifierName) {
  368. this._GLPoint4DValue = {};
  369. this._proposedGLPoint4DValue = {};
  370. $super(gl, qualifierName);
  371. },
  372. setProposedGLPoint4DValue: function(proposedGLPoint4DValue) {
  373. if (!(this._proposedGLPoint4DValue.x === proposedGLPoint4DValue.x && this._proposedGLPoint4DValue.y === proposedGLPoint4DValue.y && this._proposedGLPoint4DValue.z === proposedGLPoint4DValue.z && this._proposedGLPoint4DValue.w === proposedGLPoint4DValue.w)) {
  374. this._proposedGLPoint4DValue = proposedGLPoint4DValue;
  375. this._needsUpdate = true;
  376. }
  377. },
  378. setGLUniformWithShader: function(gl, shader) {
  379. gl.uniform4fv(this._uniformLocation, [this._proposedGLPoint4DValue.x, this._proposedGLPoint4DValue.y, this._proposedGLPoint4DValue.z, this._proposedGLPoint4DValue.w]);
  380. this._GLPoint4DValue = this._proposedGLPoint4DValue;
  381. this._needsUpdate = false;
  382. }
  383. });
  384. var TSDGLShaderQualifierMat3 = Class.create(TSDGLShaderQualifier, {
  385. initialize: function($super, gl, qualifierName) {
  386. this._affineTransform = new Float32Array(9) ;
  387. this._proposedAffineTransform = new Float32Array(9);
  388. $super(gl, qualifierName);
  389. },
  390. setProposedAffineTransform: function(proposedAffineTransform) {
  391. if (!CGAffineTransformEqualToTransform(this._proposedAffineTransform, proposedAffineTransform)) {
  392. this._proposedAffineTransform = proposedAffineTransform;
  393. this._needsUpdate = true;
  394. }
  395. },
  396. setGLUniformWithShader: function(gl, shader) {
  397. var mat = [
  398. this._proposedAffineTransform.a, this._proposedAffineTransform.b, 0,
  399. this._proposedAffineTransform.c, this._proposedAffineTransform.d, 0,
  400. this._proposedAffineTransform.tx, this._proposedAffineTransform.ty, 1
  401. ];
  402. gl.uniformMatrix3fv(this._uniformLocation, false, mat);
  403. this._affineTransform = this._proposedAffineTransform;
  404. this._needsUpdate = false;
  405. }
  406. });
  407. var TSDGLShaderQualifierMat4 = Class.create(TSDGLShaderQualifier, {
  408. initialize: function($super, gl, qualifierName) {
  409. this._transform3D = new Float32Array(16);
  410. this._proposedTransform3D = new Float32Array(16);
  411. $super(gl, qualifierName);
  412. },
  413. setProposedTransform3D: function(proposedTransform3D) {
  414. if (!CATransform3DEqualToTransform(this._proposedTransform3D, proposedTransform3D)) {
  415. this._proposedTransform3D = proposedTransform3D;
  416. this._needsUpdate = true;
  417. }
  418. },
  419. setGLUniformWithShader: function(gl, shader) {
  420. gl.uniformMatrix4fv(this._uniformLocation, false, this._proposedTransform3D);
  421. this._transform3D = this._proposedTransform3D;
  422. this._needsUpdate = false;
  423. }
  424. });