AnimatableMask.ts 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475
  1. import { coverRadius, fillRectangle } from "../base/2d";
  2. import { Animator } from "../base/Animator";
  3. import { m4 } from "../base/m4";
  4. import { Disposable, Scene } from "../base/Scene";
  5. import { createProgram, createShader } from "../base/utils";
  6. import { Area, Color } from "./common";
  7. import { FillerData } from "./FillerData"
  8. export class AnimatingArea {
  9. constructor(
  10. readonly area: Area,
  11. readonly x: number,
  12. readonly y: number,
  13. public progress: number,
  14. ) { }
  15. }
  16. export class AnimatableMask implements Disposable {
  17. private vertexShaderCode = /*glsl*/ `
  18. attribute vec2 a_position;
  19. attribute vec2 a_texCoord;
  20. attribute vec4 a_areaId;
  21. attribute vec2 a_center;
  22. attribute float a_progress;
  23. attribute float a_maxRadius;
  24. uniform mat4 u_matrix;
  25. varying vec4 v_areaId;
  26. varying vec2 v_center;
  27. varying float v_progress;
  28. varying float v_maxRadius;
  29. varying vec2 v_texCoord;
  30. varying vec2 v_position;
  31. void main() {
  32. gl_Position = u_matrix * vec4(a_position, 0, 1);
  33. v_areaId = a_areaId;
  34. v_center = a_center;
  35. v_progress = a_progress;
  36. v_maxRadius = a_maxRadius;
  37. v_texCoord = a_texCoord;
  38. v_position = a_position;
  39. }
  40. `;
  41. private fragmentShaderCode = /*glsl*/ `
  42. precision mediump float;
  43. uniform sampler2D u_map;
  44. //uniform sampler2D u_colored;
  45. //uniform sampler2D u_mask;
  46. varying vec4 v_areaId;
  47. varying vec2 v_center;
  48. varying float v_progress;
  49. varying float v_maxRadius;
  50. varying vec2 v_texCoord;
  51. varying vec2 v_position;
  52. void main() {
  53. vec4 map = texture2D(u_map, v_texCoord);
  54. float dist = distance(map, v_areaId);
  55. /*
  56. if(dist < 0.001) {
  57. if(v_progress >= 1.0 ) {
  58. gl_FragColor = vec4(1, 1, 0, 1);
  59. }else{
  60. float dist2 = distance(v_position, v_center);
  61. if(dist2 < v_maxRadius * v_progress) {
  62. gl_FragColor = vec4(1, 1, 0, 1);
  63. }else{
  64. gl_FragColor = vec4(0, 0, 0, 0);
  65. }
  66. }
  67. }else{
  68. gl_FragColor = vec4(0, 0, 0, 0);
  69. }
  70. */
  71. //gl_FragColor = vec4(1, 1, 0, 1);
  72. //gl_FragColor = map;
  73. vec4 colored = vec4(1, 1, 0, 1);
  74. if(dist < 0.001) {
  75. if( v_progress < 1.0 ) {
  76. float dist2 = distance(v_position, v_center);
  77. float r = v_maxRadius * v_progress + 0.001;
  78. if(dist2 < r) {
  79. float f = dist2 / r;
  80. if(f < v_progress) {
  81. gl_FragColor = colored;
  82. }else if(v_progress < 1.0){
  83. float a = (f - 1.0) / (v_progress - 1.0);
  84. gl_FragColor = vec4(colored.xyz, a);
  85. }else{
  86. gl_FragColor = colored;
  87. }
  88. }else {
  89. gl_FragColor = vec4(0,0,0,0);
  90. }
  91. }else{
  92. gl_FragColor = colored;
  93. }
  94. }else{
  95. gl_FragColor = vec4(0, 0, 0, 0);
  96. }
  97. }
  98. `
  99. program: WebGLProgram
  100. aPositionLoc: number
  101. aTexcoordLoc: number
  102. aAreaIdLoc: number
  103. aCenterLoc: number
  104. aProgressLoc: number
  105. aMaxRadiusLoc: number
  106. uMatrixLoc: WebGLUniformLocation
  107. positionBuffer: WebGLBuffer
  108. texCoordBuffer: WebGLBuffer
  109. areaIdBuffer: WebGLBuffer
  110. centerBuffer: WebGLBuffer
  111. progressBuffer: WebGLBuffer
  112. maxRadiusBuffer: WebGLBuffer
  113. dispose(): void {
  114. let gl = this.scene.gl
  115. gl.deleteBuffer(this.positionBuffer)
  116. gl.deleteBuffer(this.texCoordBuffer)
  117. gl.deleteBuffer(this.areaIdBuffer)
  118. gl.deleteBuffer(this.centerBuffer)
  119. gl.deleteBuffer(this.progressBuffer)
  120. gl.deleteBuffer(this.maxRadiusBuffer)
  121. gl.deleteProgram(this.program)
  122. }
  123. positionArray: Float32Array
  124. texCoordArray: Float32Array
  125. areaIdArray: Float32Array
  126. centerArray: Float32Array
  127. progressArray: Float32Array
  128. maxRadiusArray: Float32Array
  129. matrix: m4.Matrix4
  130. texture: WebGLTexture
  131. fb: WebGLFramebuffer
  132. private animatingAreas: Array<AnimatingArea> = []
  133. get width(): number { return this.fillerData.width }
  134. get height(): number { return this.fillerData.height }
  135. maxCount: number
  136. constructor(
  137. private scene: Scene,
  138. private fillerData: FillerData,
  139. ) {
  140. const gl = scene.gl
  141. this.program = createProgram(gl,
  142. createShader(gl, gl.VERTEX_SHADER, this.vertexShaderCode)!,
  143. createShader(gl, gl.FRAGMENT_SHADER, this.fragmentShaderCode)!)!
  144. this.aPositionLoc = gl.getAttribLocation(this.program, "a_position")
  145. this.aTexcoordLoc = gl.getAttribLocation(this.program, "a_texCoord")
  146. this.aAreaIdLoc = gl.getAttribLocation(this.program, "a_areaId")
  147. this.aCenterLoc = gl.getAttribLocation(this.program, "a_center")
  148. this.aProgressLoc = gl.getAttribLocation(this.program, "a_progress")
  149. this.aMaxRadiusLoc = gl.getAttribLocation(this.program, "a_maxRadius")
  150. this.uMatrixLoc = gl.getUniformLocation(this.program, "u_matrix")!
  151. this.maxCount = fillerData.data.maxAreaCountOfGroup
  152. this.positionBuffer = gl.createBuffer()!
  153. this.texCoordBuffer = gl.createBuffer()!
  154. this.areaIdBuffer = gl.createBuffer()!
  155. this.centerBuffer = gl.createBuffer()!
  156. this.progressBuffer = gl.createBuffer()!
  157. this.maxRadiusBuffer = gl.createBuffer()!
  158. this.matrix = m4.projectionNoflipY(fillerData.width, fillerData.height)
  159. this.texture = gl.createTexture()!
  160. gl.bindTexture(gl.TEXTURE_2D, this.texture)
  161. gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, this.fillerData.width, this.fillerData.height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null)
  162. //gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGB, this.fillerData.width, this.fillerData.height, 0, gl.RGB, gl.UNSIGNED_SHORT_5_6_5, null)
  163. gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
  164. gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
  165. gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
  166. gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
  167. this.fb = gl.createFramebuffer()!
  168. gl.bindFramebuffer(gl.FRAMEBUFFER, this.fb)
  169. gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, this.texture, 0)
  170. gl.bindFramebuffer(gl.FRAMEBUFFER, null)
  171. this.positionArray = new Float32Array(this.maxCount * 12)
  172. this.texCoordArray = new Float32Array(this.maxCount * 12)
  173. this.areaIdArray = new Float32Array(this.maxCount * 24)
  174. this.centerArray = new Float32Array(this.maxCount * 12)
  175. this.progressArray = new Float32Array(this.maxCount * 6)
  176. this.maxRadiusArray = new Float32Array(this.maxCount * 6)
  177. }
  178. addArea(area: Area, cx: number, cy: number, duration = 800) {
  179. let aa = new AnimatingArea(area, cx, cy, 0)
  180. let animator = new Animator(duration, () => {
  181. aa.progress = animator.value()
  182. }, () => {
  183. })
  184. this.scene.addAnimator(animator)
  185. this.animatingAreas.push(aa);
  186. }
  187. fillPoint(arr: Float32Array, offset: number, x: number, y: number, count: number) {
  188. for (var i = 0; i < count; i++) {
  189. arr[offset + i * 2] = x
  190. arr[offset + i * 2 + 1] = y
  191. }
  192. }
  193. fillNumber(arr: Float32Array, offset: number, n: number, count: number) {
  194. for (var i = 0; i < count; i++) {
  195. arr[offset + i] = n
  196. }
  197. }
  198. flush() {
  199. // console.log('animationAreas.length=', this.animatingAreas.length)
  200. if (this.animatingAreas.length <= 0) return
  201. var vertexOffset = 0
  202. var colorOffset = 0
  203. var nOffset = 0
  204. const width = this.fillerData.width
  205. const height = this.fillerData.height
  206. for (var i = 0; i < this.animatingAreas.length; i++) {
  207. var aa = this.animatingAreas[i]
  208. var area = aa.area
  209. fillRectangle(this.positionArray, vertexOffset, area.rect.x, area.rect.y, area.rect.width, area.rect.height)
  210. fillRectangle(this.texCoordArray, vertexOffset, area.rect.x / width, area.rect.y / height, area.rect.width / width, area.rect.height / height)
  211. this.fillPoint(this.centerArray, vertexOffset, aa.x, aa.y, 6)
  212. var color = new Color(area.id)
  213. color.fillFloatArray(this.areaIdArray, colorOffset, 6)
  214. var maxRadius = coverRadius(area.rect, aa.x, aa.y)
  215. // console.log('rect=', area.rect, maxRadius, aa.x, aa.y);
  216. //maxRadius =
  217. this.fillNumber(this.progressArray, nOffset, aa.progress, 6)
  218. this.fillNumber(this.maxRadiusArray, nOffset, maxRadius, 6)
  219. vertexOffset += 12
  220. colorOffset += 24
  221. nOffset += 6
  222. }
  223. //console.log('areaIdArray', this.areaIdArray)
  224. const gl = this.scene.gl
  225. gl.bindBuffer(gl.ARRAY_BUFFER, this.positionBuffer)
  226. gl.bufferData(gl.ARRAY_BUFFER, this.positionArray, gl.STATIC_DRAW)
  227. gl.bindBuffer(gl.ARRAY_BUFFER, this.texCoordBuffer)
  228. gl.bufferData(gl.ARRAY_BUFFER, this.texCoordArray, gl.STATIC_DRAW)
  229. gl.bindBuffer(gl.ARRAY_BUFFER, this.areaIdBuffer);
  230. gl.bufferData(gl.ARRAY_BUFFER, this.areaIdArray, gl.STATIC_DRAW)
  231. gl.bindBuffer(gl.ARRAY_BUFFER, this.centerBuffer);
  232. gl.bufferData(gl.ARRAY_BUFFER, this.centerArray, gl.STATIC_DRAW)
  233. gl.bindBuffer(gl.ARRAY_BUFFER, this.progressBuffer);
  234. gl.bufferData(gl.ARRAY_BUFFER, this.progressArray, gl.STATIC_DRAW)
  235. gl.bindBuffer(gl.ARRAY_BUFFER, this.maxRadiusBuffer);
  236. gl.bufferData(gl.ARRAY_BUFFER, this.maxRadiusArray, gl.STATIC_DRAW)
  237. this.draw(this.animatingAreas.length * 6)
  238. this.animatingAreas = this.animatingAreas.filter(aa => aa.progress < 1)
  239. }
  240. private draw(n: number) {
  241. const gl = this.scene.gl;
  242. gl.bindFramebuffer(gl.FRAMEBUFFER, this.fb)
  243. //console.log('fb=', this.progressArray)
  244. gl.useProgram(this.program);
  245. gl.viewport(0, 0, this.fillerData.width, this.fillerData.height)
  246. gl.enableVertexAttribArray(this.aPositionLoc);
  247. gl.bindBuffer(gl.ARRAY_BUFFER, this.positionBuffer);
  248. gl.vertexAttribPointer(this.aPositionLoc, 2, gl.FLOAT, false, 0, 0);
  249. gl.enableVertexAttribArray(this.aTexcoordLoc);
  250. gl.bindBuffer(gl.ARRAY_BUFFER, this.texCoordBuffer);
  251. gl.vertexAttribPointer(this.aTexcoordLoc, 2, gl.FLOAT, false, 0, 0);
  252. gl.enableVertexAttribArray(this.aAreaIdLoc);
  253. gl.bindBuffer(gl.ARRAY_BUFFER, this.areaIdBuffer);
  254. gl.vertexAttribPointer(this.aAreaIdLoc, 4, gl.FLOAT, false, 0, 0);
  255. gl.enableVertexAttribArray(this.aCenterLoc);
  256. gl.bindBuffer(gl.ARRAY_BUFFER, this.centerBuffer);
  257. gl.vertexAttribPointer(this.aCenterLoc, 2, gl.FLOAT, false, 0, 0);
  258. gl.enableVertexAttribArray(this.aProgressLoc);
  259. gl.bindBuffer(gl.ARRAY_BUFFER, this.progressBuffer);
  260. gl.vertexAttribPointer(this.aProgressLoc, 1, gl.FLOAT, false, 0, 0);
  261. gl.enableVertexAttribArray(this.aMaxRadiusLoc);
  262. gl.bindBuffer(gl.ARRAY_BUFFER, this.maxRadiusBuffer);
  263. gl.vertexAttribPointer(this.aMaxRadiusLoc, 1, gl.FLOAT, false, 0, 0);
  264. gl.uniformMatrix4fv(this.uMatrixLoc, false, this.matrix)
  265. gl.activeTexture(gl.TEXTURE0)
  266. gl.bindTexture(gl.TEXTURE_2D, this.fillerData.mapTexure)
  267. gl.drawArrays(gl.TRIANGLES, 0, n)
  268. gl.bindFramebuffer(gl.FRAMEBUFFER, null)
  269. }
  270. // 恢复上次已填色的部分
  271. initTask() {
  272. let taskLisk = this.fillerData.taskList;
  273. const width = this.fillerData.width
  274. const height = this.fillerData.height
  275. for (let task of taskLisk) {
  276. let area = this.fillerData.data.areaHash.get(task);
  277. if (area) {
  278. fillRectangle(this.positionArray, 0, area.rect.x, area.rect.y, area.rect.width, area.rect.height)
  279. fillRectangle(this.texCoordArray, 0, area.rect.x / width, area.rect.y / height, area.rect.width / width, area.rect.height / height)
  280. this.fillPoint(this.centerArray, 0, area.center.x, area.center.y, 6)
  281. var color = new Color(area.id)
  282. color.fillFloatArray(this.areaIdArray, 0, 6)
  283. var maxRadius = coverRadius(area.rect, area.center.x, area.center.y)
  284. // console.log('rect=', area.rect, maxRadius, area.center.x, area.center.y);
  285. this.fillNumber(this.progressArray, 0, 1, 6)
  286. this.fillNumber(this.maxRadiusArray, 0, maxRadius, 6)
  287. const gl = this.scene.gl
  288. gl.bindBuffer(gl.ARRAY_BUFFER, this.positionBuffer)
  289. gl.bufferData(gl.ARRAY_BUFFER, this.positionArray, gl.STATIC_DRAW)
  290. gl.bindBuffer(gl.ARRAY_BUFFER, this.texCoordBuffer)
  291. gl.bufferData(gl.ARRAY_BUFFER, this.texCoordArray, gl.STATIC_DRAW)
  292. gl.bindBuffer(gl.ARRAY_BUFFER, this.areaIdBuffer);
  293. gl.bufferData(gl.ARRAY_BUFFER, this.areaIdArray, gl.STATIC_DRAW)
  294. gl.bindBuffer(gl.ARRAY_BUFFER, this.centerBuffer);
  295. gl.bufferData(gl.ARRAY_BUFFER, this.centerArray, gl.STATIC_DRAW)
  296. gl.bindBuffer(gl.ARRAY_BUFFER, this.progressBuffer);
  297. gl.bufferData(gl.ARRAY_BUFFER, this.progressArray, gl.STATIC_DRAW)
  298. gl.bindBuffer(gl.ARRAY_BUFFER, this.maxRadiusBuffer);
  299. gl.bufferData(gl.ARRAY_BUFFER, this.maxRadiusArray, gl.STATIC_DRAW)
  300. this.draw(6)
  301. }
  302. }
  303. }
  304. }