From ac9d8ff44f79e6b67cd01a5e52448cad0dfd9646 Mon Sep 17 00:00:00 2001 From: Felipe Alfonso Date: Wed, 1 Mar 2017 18:08:10 -0300 Subject: [PATCH] Fill canvas rendering on WebGL for Graphics GO --- v3/src/gameobjects/graphics/Commands.js | 3 +- v3/src/gameobjects/graphics/Graphics.js | 21 +- .../graphics/GraphicsCanvasRenderer.js | 13 - .../graphics/GraphicsWebGLRenderer.js | 288 ++++++++++++++++++ v3/src/gameobjects/graphics/earcut.js | 1 + .../webgl/batches/shape/FragmentShader.js | 3 +- .../webgl/batches/shape/ShapeBatch.js | 18 +- .../webgl/batches/shape/VertexShader.js | 11 +- v3/src/renderer/webgl/batches/shape/const.js | 7 +- 9 files changed, 329 insertions(+), 36 deletions(-) create mode 100644 v3/src/gameobjects/graphics/earcut.js diff --git a/v3/src/gameobjects/graphics/Commands.js b/v3/src/gameobjects/graphics/Commands.js index 8c8631e2e..b2ecc0532 100644 --- a/v3/src/gameobjects/graphics/Commands.js +++ b/v3/src/gameobjects/graphics/Commands.js @@ -10,5 +10,6 @@ module.exports = { STROKE_CIRCLE: 8, STROKE_RECT: 9, FILL_PATH: 10, - STROKE_PATH: 11 + STROKE_PATH: 11, + FILL_STYLE: 12 }; diff --git a/v3/src/gameobjects/graphics/Graphics.js b/v3/src/gameobjects/graphics/Graphics.js index d83fe8226..78d5afd2b 100644 --- a/v3/src/gameobjects/graphics/Graphics.js +++ b/v3/src/gameobjects/graphics/Graphics.js @@ -3,6 +3,7 @@ var GameObject = require('../GameObject'); var Components = require('../../components'); var Render = require('./GraphicsRender'); var Commands = require('./Commands'); +var PI2 = 2 * Math.PI; var Graphics = new Class({ @@ -78,32 +79,32 @@ var Graphics = new Class({ fillCircle: function (x, y, radius) { - this.commandBuffer.push( - Commands.DRAW_CIRCLE, - x, y, radius - ); + this.beginPath(); + this.arc(x, y, radius, 0, PI2); + this.fillPath(); + this.closePath(); }, fillRect: function (x, y, width, height) { this.commandBuffer.push( - Commands.DRAW_RECT, + Commands.FILL_RECT, x, y, width, height ); }, strokeCircle: function (x, y, radius) { - this.commandBuffer.push( - Commands.DRAW_CIRCLE, - x, y, radius - ); + this.beginPath(); + this.arc(x, y, radius, 0, PI2); + this.strokePath(); + this.closePath(); }, strokeRect: function (x, y, width, height) { this.commandBuffer.push( - Commands.DRAW_RECT, + Commands.STROKE_RECT, x, y, width, height ); }, diff --git a/v3/src/gameobjects/graphics/GraphicsCanvasRenderer.js b/v3/src/gameobjects/graphics/GraphicsCanvasRenderer.js index 51530aa5f..c07d0c2e6 100644 --- a/v3/src/gameobjects/graphics/GraphicsCanvasRenderer.js +++ b/v3/src/gameobjects/graphics/GraphicsCanvasRenderer.js @@ -103,19 +103,6 @@ var GraphicsCanvasRenderer = function (renderer, src, interpolationPercentage, c ctx.lineWidth = lineWidth; ctx.stroke(); break; - case Commands.FILL_CIRCLE: - ctx.beginPath(); - ctx.arc( - commandBuffer[index + 1], - commandBuffer[index + 2], - commandBuffer[index + 3], - 0, - PI2 - ); - ctx.fill(); - ctx.closePath(); - index += 3; - break; case Commands.FILL_RECT: ctx.fillRect( commandBuffer[index + 1], diff --git a/v3/src/gameobjects/graphics/GraphicsWebGLRenderer.js b/v3/src/gameobjects/graphics/GraphicsWebGLRenderer.js index 767d61cde..43d8bd017 100644 --- a/v3/src/gameobjects/graphics/GraphicsWebGLRenderer.js +++ b/v3/src/gameobjects/graphics/GraphicsWebGLRenderer.js @@ -1,9 +1,297 @@ +var Commands = require('./Commands'); +var Earcut = require('./earcut'); +var pathArray = []; +var cos = Math.cos; +var sin = Math.sin; + + +var Point = function (x, y) +{ + this.x = x; + this.y = y; +}; + +var Path = function (x, y) +{ + this.points = []; + this.points.push(new Point(x, y)); +}; + +var lerp = function (norm, min, max) +{ + return (max - min) * norm + min; +}; + var GraphicsWebGLRenderer = function (renderer, src, interpolationPercentage, camera) { if (this.renderMask !== this.renderFlags) { return; } + var shapeBatch = renderer.shapeBatch; + var vertexDataBuffer = shapeBatch.vertexDataBuffer; + var vertexBufferF32 = vertexDataBuffer.floatView; + var vertexBufferU32 = vertexDataBuffer.uintView; + var vertexOffset = 0; + var cameraScrollX = camera.scrollX; + var cameraScrollY = camera.scrollY; + var srcX = src.x; + var srcY = src.y; + var srcScaleX = src.scaleX; + var srcScaleY = src.scaleY; + var srcRotation = src.rotation; + var commandBuffer = src.commandBuffer; + var value; + var lineAlpha = 1.0; + var fillAlpha = 1.0; + var lineColor = 0; + var fillColor = 0; + var lineWidth = 1.0; + var cameraMatrix = camera.matrix.matrix; + var a = cameraMatrix[0]; + var b = cameraMatrix[1]; + var c = cameraMatrix[2]; + var d = cameraMatrix[3]; + var e = cameraMatrix[4]; + var f = cameraMatrix[5]; + var lastPath = null; + var iteration = 0; + var iterStep = 0.01; + var tx = 0; + var ty = 0; + var ta = 0; + var x, y, radius, startAngle, endAngle, anticlockwise; + var width, height, txw, tyh; + var vertexCount = shapeBatch.vertexCount; + var polygon = []; + var x0, y0, x1, y1, x2, y2; + var tx0, ty0, tx1, ty1, tx2, ty2; + var v0, v1, v2; + var polygonIndex; + var path; + var pathLength; + var point; + + renderer.setBatch(shapeBatch, null); + + for (var cmdIndex = 0, cmdLength = commandBuffer.length; cmdIndex < cmdLength; ++cmdIndex) + { + var cmd = commandBuffer[cmdIndex]; + + switch(cmd) + { + case Commands.ARC: + x = commandBuffer[cmdIndex + 1]; + y = commandBuffer[cmdIndex + 2]; + radius = commandBuffer[cmdIndex + 3]; + startAngle = commandBuffer[cmdIndex + 4]; + endAngle = commandBuffer[cmdIndex + 5]; + anticlockwise = commandBuffer[cmdIndex + 6]; + + while (iteration < 1) { + ta = lerp(iteration, startAngle, endAngle); + tx = x + cos(ta) * radius; + ty = y + sin(ta) * radius; + if (iteration === 0) { + lastPath = new Path(tx, ty); + pathArray.push(lastPath); + } else { + lastPath.points.push(new Point(tx, ty)); + } + iteration += iterStep; + } + + cmdIndex += 6; + break; + case Commands.LINE_STYLE: + lineWidth = commandBuffer[cmdIndex + 1]; + lineColor = commandBuffer[cmdIndex + 2] + lineAlpha = commandBuffer[cmdIndex + 3]; + cmdIndex += 3; + break; + case Commands.FILL_STYLE: + fillColor = commandBuffer[cmdIndex + 1]; + fillAlpha = commandBuffer[cmdIndex + 2]; + cmdIndex += 2; + break; + case Commands.BEGIN_PATH: + pathArray.length = 0; + break; + case Commands.CLOSE_PATH: + if (lastPath !== null && lastPath.points.length > 0) { + var firstPoint = lastPath.points[0]; + var lastPoint = lastPath.points[lastPath.points.length - 1]; + lastPath.points.push(firstPoint); + lastPath = new Path(x, y); + pathArray.push(lastPath); + } + break; + case Commands.FILL_PATH: + for (var pathArrayIndex = 0, pathArrayLength = pathArray.length; pathArrayIndex < pathArrayLength; ++pathArrayIndex) + { + path = pathArray[pathArrayIndex].points; + pathLength = path.length; + for (var pathIndex = 0; pathIndex < pathLength; ++pathIndex) + { + point = path[pathIndex]; + polygon.push(point.x, point.y); + } + polygonIndex = Earcut(polygon); + for (var index = 0, length = polygonIndex.length; index < length; index += 3) + { + v0 = polygonIndex[index + 0] * 2; + v1 = polygonIndex[index + 1] * 2; + v2 = polygonIndex[index + 2] * 2; + vertexOffset = vertexDataBuffer.allocate(9 * 3); + vertexCount += 3; + + x0 = polygon[v0 + 0] - cameraScrollX; + y0 = polygon[v0 + 1] - cameraScrollY; + x1 = polygon[v1 + 0] - cameraScrollX; + y1 = polygon[v1 + 1] - cameraScrollY; + x2 = polygon[v2 + 0] - cameraScrollX; + y2 = polygon[v2 + 1] - cameraScrollY; + + tx0 = x0 * a + y0 * c + e; + ty0 = x0 * b + y0 * d + f; + tx1 = x1 * a + y1 * c + e; + ty1 = x1 * b + y1 * d + f; + tx2 = x2 * a + y2 * c + e; + ty2 = x2 * b + y2 * d + f; + + vertexBufferF32[vertexOffset++] = tx0; + vertexBufferF32[vertexOffset++] = ty0; + vertexBufferU32[vertexOffset++] = fillColor; + vertexBufferF32[vertexOffset++] = fillAlpha; + vertexBufferF32[vertexOffset++] = srcX; + vertexBufferF32[vertexOffset++] = srcY; + vertexBufferF32[vertexOffset++] = srcScaleX; + vertexBufferF32[vertexOffset++] = srcScaleY; + vertexBufferF32[vertexOffset++] = srcRotation; + + vertexBufferF32[vertexOffset++] = tx1; + vertexBufferF32[vertexOffset++] = ty1; + vertexBufferU32[vertexOffset++] = fillColor; + vertexBufferF32[vertexOffset++] = fillAlpha; + vertexBufferF32[vertexOffset++] = srcX; + vertexBufferF32[vertexOffset++] = srcY; + vertexBufferF32[vertexOffset++] = srcScaleX; + vertexBufferF32[vertexOffset++] = srcScaleY; + vertexBufferF32[vertexOffset++] = srcRotation; + + vertexBufferF32[vertexOffset++] = tx2; + vertexBufferF32[vertexOffset++] = ty2; + vertexBufferU32[vertexOffset++] = fillColor; + vertexBufferF32[vertexOffset++] = fillAlpha; + vertexBufferF32[vertexOffset++] = srcX; + vertexBufferF32[vertexOffset++] = srcY; + vertexBufferF32[vertexOffset++] = srcScaleX; + vertexBufferF32[vertexOffset++] = srcScaleY; + vertexBufferF32[vertexOffset++] = srcRotation; + + } + polygon.length = 0; + } + break; + case Commands.STROKE_PATH: + break; + case Commands.FILL_RECT: + vertexOffset = vertexDataBuffer.allocate(9 * 6); + vertexCount += 6; + + x = commandBuffer[cmdIndex + 1] - cameraScrollX; + y = commandBuffer[cmdIndex + 2] - cameraScrollY; + xw = x + commandBuffer[cmdIndex + 3]; + yh = y + commandBuffer[cmdIndex + 4]; + tx = x * a + y * c + e; + ty = x * b + y * d + f; + txw = xw * a + yh * c + e; + tyh = xw * b + yh * d + f; + + vertexBufferF32[vertexOffset++] = tx; + vertexBufferF32[vertexOffset++] = ty; + vertexBufferU32[vertexOffset++] = fillColor; + vertexBufferF32[vertexOffset++] = fillAlpha; + vertexBufferF32[vertexOffset++] = srcX; + vertexBufferF32[vertexOffset++] = srcY; + vertexBufferF32[vertexOffset++] = srcScaleX; + vertexBufferF32[vertexOffset++] = srcScaleY; + vertexBufferF32[vertexOffset++] = srcRotation; + vertexBufferF32[vertexOffset++] = tx; + vertexBufferF32[vertexOffset++] = tyh; + vertexBufferU32[vertexOffset++] = fillColor; + vertexBufferF32[vertexOffset++] = fillAlpha; + vertexBufferF32[vertexOffset++] = srcX; + vertexBufferF32[vertexOffset++] = srcY; + vertexBufferF32[vertexOffset++] = srcScaleX; + vertexBufferF32[vertexOffset++] = srcScaleY; + vertexBufferF32[vertexOffset++] = srcRotation; + vertexBufferF32[vertexOffset++] = txw; + vertexBufferF32[vertexOffset++] = tyh; + vertexBufferU32[vertexOffset++] = fillColor; + vertexBufferF32[vertexOffset++] = fillAlpha; + vertexBufferF32[vertexOffset++] = srcX; + vertexBufferF32[vertexOffset++] = srcY; + vertexBufferF32[vertexOffset++] = srcScaleX; + vertexBufferF32[vertexOffset++] = srcScaleY; + vertexBufferF32[vertexOffset++] = srcRotation; + vertexBufferF32[vertexOffset++] = tx; + vertexBufferF32[vertexOffset++] = ty; + vertexBufferU32[vertexOffset++] = fillColor; + vertexBufferF32[vertexOffset++] = fillAlpha; + vertexBufferF32[vertexOffset++] = srcX; + vertexBufferF32[vertexOffset++] = srcY; + vertexBufferF32[vertexOffset++] = srcScaleX; + vertexBufferF32[vertexOffset++] = srcScaleY; + vertexBufferF32[vertexOffset++] = srcRotation; + vertexBufferF32[vertexOffset++] = txw; + vertexBufferF32[vertexOffset++] = tyh; + vertexBufferU32[vertexOffset++] = fillColor; + vertexBufferF32[vertexOffset++] = fillAlpha; + vertexBufferF32[vertexOffset++] = srcX; + vertexBufferF32[vertexOffset++] = srcY; + vertexBufferF32[vertexOffset++] = srcScaleX; + vertexBufferF32[vertexOffset++] = srcScaleY; + vertexBufferF32[vertexOffset++] = srcRotation; + vertexBufferF32[vertexOffset++] = txw; + vertexBufferF32[vertexOffset++] = ty; + vertexBufferU32[vertexOffset++] = fillColor; + vertexBufferF32[vertexOffset++] = fillAlpha; + vertexBufferF32[vertexOffset++] = srcX; + vertexBufferF32[vertexOffset++] = srcY; + vertexBufferF32[vertexOffset++] = srcScaleX; + vertexBufferF32[vertexOffset++] = srcScaleY; + vertexBufferF32[vertexOffset++] = srcRotation; + + cmdIndex += 4; + break; + case Commands.STROKE_CIRCLE: + cmdIndex += 3; + break; + case Commands.STROKE_RECT: + cmdIndex += 4; + break; + case Commands.LINE_TO: + if (lastPath !== null) { + lastPath.points.push(new Point(commandBuffer[cmdIndex + 1], commandBuffer[cmdIndex + 2])); + } else { + lastPath = new Path(commandBuffer[cmdIndex + 1], commandBuffer[cmdIndex + 2]); + pathArray.push(lastPath); + } + cmdIndex += 2; + break; + case Commands.MOVE_TO: + lastPath = new Path(commandBuffer[cmdIndex + 1], commandBuffer[cmdIndex + 2]); + pathArray.push(lastPath); + cmdIndex += 2; + break; + default: + console.error('Phaser: Invalid Graphics Command ID ' + cmd); + break; + } + } + shapeBatch.vertexCount = vertexCount; + pathArray.length = 0; } module.exports = GraphicsWebGLRenderer; diff --git a/v3/src/gameobjects/graphics/earcut.js b/v3/src/gameobjects/graphics/earcut.js new file mode 100644 index 000000000..18146a82a --- /dev/null +++ b/v3/src/gameobjects/graphics/earcut.js @@ -0,0 +1 @@ +!function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{var n;n="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this,n.earcut=e()}}(function(){return function e(n,t,r){function x(u,f){if(!t[u]){if(!n[u]){var o="function"==typeof require&&require;if(!f&&o)return o(u,!0);if(i)return i(u,!0);var v=new Error("Cannot find module '"+u+"'");throw v.code="MODULE_NOT_FOUND",v}var l=t[u]={exports:{}};n[u][0].call(l.exports,function(e){var t=n[u][1][e];return x(t?t:e)},l,l.exports,e,n,t,r)}return t[u].exports}for(var i="function"==typeof require&&require,u=0;u80*t){v=p=e[0],l=a=e[1];for(var d=t;i>d;d+=t)h=e[d],s=e[d+1],v>h&&(v=h),l>s&&(l=s),h>p&&(p=h),s>a&&(a=s);c=Math.max(p-v,a-l)}return u(f,o,t,v,l,c),o}function x(e,n,t,r,x){var i,u;if(x===_(e,n,t,r)>0)for(i=n;t>i;i+=r)u=E(i,e[i],e[i+1],u);else for(i=t-r;i>=n;i-=r)u=E(i,e[i],e[i+1],u);return u&&z(u,u.next)&&(N(u),u=u.next),u}function i(e,n){if(!e)return e;n||(n=e);var t,r=e;do if(t=!1,r.steiner||!z(r,r.next)&&0!==b(r.prev,r,r.next))r=r.next;else{if(N(r),r=n=r.prev,r===r.next)return null;t=!0}while(t||r!==n);return n}function u(e,n,t,r,x,y,p){if(e){!p&&y&&s(e,r,x,y);for(var a,h,c=e;e.prev!==e.next;)if(a=e.prev,h=e.next,y?o(e,r,x,y):f(e))n.push(a.i/t),n.push(e.i/t),n.push(h.i/t),N(e),e=h.next,c=h.next;else if(e=h,e===c){p?1===p?(e=v(e,n,t),u(e,n,t,r,x,y,2)):2===p&&l(e,n,t,r,x,y):u(i(e),n,t,r,x,y,1);break}}}function f(e){var n=e.prev,t=e,r=e.next;if(b(n,t,r)>=0)return!1;for(var x=e.next.next;x!==e.prev;){if(g(n.x,n.y,t.x,t.y,r.x,r.y,x.x,x.y)&&b(x.prev,x,x.next)>=0)return!1;x=x.next}return!0}function o(e,n,t,r){var x=e.prev,i=e,u=e.next;if(b(x,i,u)>=0)return!1;for(var f=x.xi.x?x.x>u.x?x.x:u.x:i.x>u.x?i.x:u.x,l=x.y>i.y?x.y>u.y?x.y:u.y:i.y>u.y?i.y:u.y,y=d(f,o,n,t,r),p=d(v,l,n,t,r),a=e.nextZ;a&&a.z<=p;){if(a!==e.prev&&a!==e.next&&g(x.x,x.y,i.x,i.y,u.x,u.y,a.x,a.y)&&b(a.prev,a,a.next)>=0)return!1;a=a.nextZ}for(a=e.prevZ;a&&a.z>=y;){if(a!==e.prev&&a!==e.next&&g(x.x,x.y,i.x,i.y,u.x,u.y,a.x,a.y)&&b(a.prev,a,a.next)>=0)return!1;a=a.prevZ}return!0}function v(e,n,t){var r=e;do{var x=r.prev,i=r.next.next;!z(x,i)&&M(x,r,r.next,i)&&q(x,i)&&q(i,x)&&(n.push(x.i/t),n.push(r.i/t),n.push(i.i/t),N(r),N(r.next),r=e=i),r=r.next}while(r!==e);return r}function l(e,n,t,r,x,f){var o=e;do{for(var v=o.next.next;v!==o.prev;){if(o.i!==v.i&&w(o,v)){var l=D(o,v);return o=i(o,o.next),l=i(l,l.next),u(o,n,t,r,x,f),void u(l,n,t,r,x,f)}v=v.next}o=o.next}while(o!==e)}function y(e,n,t,r){var u,f,o,v,l,y=[];for(u=0,f=n.length;f>u;u++)o=n[u]*r,v=f-1>u?n[u+1]*r:e.length,l=x(e,o,v,r,!1),l===l.next&&(l.steiner=!0),y.push(Z(l));for(y.sort(p),u=0;u=r.next.y){var f=r.x+(i-r.y)*(r.next.x-r.x)/(r.next.y-r.y);if(x>=f&&f>u){if(u=f,f===x){if(i===r.y)return r;if(i===r.next.y)return r.next}t=r.x=r.x&&r.x>=l&&g(y>i?x:u,i,l,y,y>i?u:x,i,r.x,r.y)&&(o=Math.abs(i-r.y)/(x-r.x),(p>o||o===p&&r.x>t.x)&&q(r,e)&&(t=r,p=o)),r=r.next;return t}function s(e,n,t,r){var x=e;do null===x.z&&(x.z=d(x.x,x.y,n,t,r)),x.prevZ=x.prev,x.nextZ=x.next,x=x.next;while(x!==e);x.prevZ.nextZ=null,x.prevZ=null,c(x)}function c(e){var n,t,r,x,i,u,f,o,v=1;do{for(t=e,e=null,i=null,u=0;t;){for(u++,r=t,f=0,n=0;v>n&&(f++,r=r.nextZ,r);n++);for(o=v;f>0||o>0&&r;)0===f?(x=r,r=r.nextZ,o--):0!==o&&r?t.z<=r.z?(x=t,t=t.nextZ,f--):(x=r,r=r.nextZ,o--):(x=t,t=t.nextZ,f--),i?i.nextZ=x:e=x,x.prevZ=i,i=x;t=r}i.nextZ=null,v*=2}while(u>1);return e}function d(e,n,t,r,x){return e=32767*(e-t)/x,n=32767*(n-r)/x,e=16711935&(e|e<<8),e=252645135&(e|e<<4),e=858993459&(e|e<<2),e=1431655765&(e|e<<1),n=16711935&(n|n<<8),n=252645135&(n|n<<4),n=858993459&(n|n<<2),n=1431655765&(n|n<<1),e|n<<1}function Z(e){var n=e,t=e;do n.x=0&&(e-u)*(r-f)-(t-u)*(n-f)>=0&&(t-u)*(i-f)-(x-u)*(r-f)>=0}function w(e,n){return e.next.i!==n.i&&e.prev.i!==n.i&&!m(e,n)&&q(e,n)&&q(n,e)&&O(e,n)}function b(e,n,t){return(n.y-e.y)*(t.x-n.x)-(n.x-e.x)*(t.y-n.y)}function z(e,n){return e.x===n.x&&e.y===n.y}function M(e,n,t,r){return z(e,n)&&z(t,r)||z(e,r)&&z(t,n)?!0:b(e,n,t)>0!=b(e,n,r)>0&&b(t,r,e)>0!=b(t,r,n)>0}function m(e,n){var t=e;do{if(t.i!==e.i&&t.next.i!==e.i&&t.i!==n.i&&t.next.i!==n.i&&M(t,t.next,e,n))return!0;t=t.next}while(t!==e);return!1}function q(e,n){return b(e.prev,e,e.next)<0?b(e,n,e.next)>=0&&b(e,e.prev,n)>=0:b(e,n,e.prev)<0||b(e,e.next,n)<0}function O(e,n){var t=e,r=!1,x=(e.x+n.x)/2,i=(e.y+n.y)/2;do t.y>i!=t.next.y>i&&x<(t.next.x-t.x)*(i-t.y)/(t.next.y-t.y)+t.x&&(r=!r),t=t.next;while(t!==e);return r}function D(e,n){var t=new U(e.i,e.x,e.y),r=new U(n.i,n.x,n.y),x=e.next,i=n.prev;return e.next=n,n.prev=e,t.next=x,x.prev=t,r.next=t,t.prev=r,i.next=r,r.prev=i,r}function E(e,n,t,r){var x=new U(e,n,t);return r?(x.next=r.next,x.prev=r,r.next.prev=x,r.next=x):(x.prev=x,x.next=x),x}function N(e){e.next.prev=e.prev,e.prev.next=e.next,e.prevZ&&(e.prevZ.nextZ=e.nextZ),e.nextZ&&(e.nextZ.prevZ=e.prevZ)}function U(e,n,t){this.i=e,this.x=n,this.y=t,this.prev=null,this.next=null,this.z=null,this.prevZ=null,this.nextZ=null,this.steiner=!1}function _(e,n,t,r){for(var x=0,i=n,u=t-r;t>i;i+=r)x+=(e[u]-e[i])*(e[i+1]+e[u+1]),u=i;return x}n.exports=r,r.deviation=function(e,n,t,r){var x=n&&n.length,i=x?n[0]*t:e.length,u=Math.abs(_(e,0,i,t));if(x)for(var f=0,o=n.length;o>f;f++){var v=n[f]*t,l=o-1>f?n[f+1]*t:e.length;u-=Math.abs(_(e,v,l,t))}var y=0;for(f=0;fu;u++)t.vertices.push(e[x][i][u]);x>0&&(r+=e[x-1].length,t.holes.push(r))}return t}},{}]},{},[1])(1)}); \ No newline at end of file diff --git a/v3/src/renderer/webgl/batches/shape/FragmentShader.js b/v3/src/renderer/webgl/batches/shape/FragmentShader.js index 1be602a16..73d1fbd0a 100644 --- a/v3/src/renderer/webgl/batches/shape/FragmentShader.js +++ b/v3/src/renderer/webgl/batches/shape/FragmentShader.js @@ -1,7 +1,8 @@ module.exports = [ 'precision mediump float;', 'varying vec4 v_color;', + 'varying float v_alpha;', 'void main() {', - ' gl_FragColor = v_color;', + ' gl_FragColor = vec4(v_color.bgr, v_alpha);', '}' ].join('\n'); diff --git a/v3/src/renderer/webgl/batches/shape/ShapeBatch.js b/v3/src/renderer/webgl/batches/shape/ShapeBatch.js index c80d117d3..1122f8468 100644 --- a/v3/src/renderer/webgl/batches/shape/ShapeBatch.js +++ b/v3/src/renderer/webgl/batches/shape/ShapeBatch.js @@ -62,7 +62,11 @@ ShapeBatch.prototype = { var program = CreateProgram(gl, vertShader, fragShader); var attribArray = [ CreateAttribDesc(gl, program, 'a_position', 2, gl.FLOAT, false, CONST.VERTEX_SIZE, 0), - CreateAttribDesc(gl, program, 'a_color', 4, gl.FLOAT, true, CONST.VERTEX_SIZE, 8), + CreateAttribDesc(gl, program, 'a_color', 4, gl.UNSIGNED_BYTE, true, CONST.VERTEX_SIZE, 8), + CreateAttribDesc(gl, program, 'a_alpha', 1, gl.FLOAT, false, CONST.VERTEX_SIZE, 12), + CreateAttribDesc(gl, program, 'a_translate', 2, gl.FLOAT, false, CONST.VERTEX_SIZE, 16), + CreateAttribDesc(gl, program, 'a_scale', 2, gl.FLOAT, false, CONST.VERTEX_SIZE, 24), + CreateAttribDesc(gl, program, 'a_rotation', 1, gl.FLOAT, false, CONST.VERTEX_SIZE, 32), ]; var vertexArray = new VertexArray(CreateBuffer(gl, gl.ARRAY_BUFFER, gl.STREAM_DRAW, null, vertexDataBuffer.getByteCapacity()), attribArray); var viewMatrixLocation = gl.getUniformLocation(program, 'u_view_matrix'); @@ -108,11 +112,13 @@ ShapeBatch.prototype = { var gl = this.glContext; var vertexDataBuffer = this.vertexDataBuffer; - gl.bufferSubData(gl.ARRAY_BUFFER, 0, vertexDataBuffer.getUsedBufferAsFloat()); - gl.drawArrays(gl.TRIANGLES, 0, this.vertexCount); - vertexDataBuffer.clear(); - - this.vertexCount = 0; + if (this.vertexCount > 0) + { + gl.bufferSubData(gl.ARRAY_BUFFER, 0, vertexDataBuffer.getUsedBufferAsFloat()); + gl.drawArrays(gl.TRIANGLES, 0, this.vertexCount); + vertexDataBuffer.clear(); + this.vertexCount = 0; + } }, resize: function (width, height, resolution) diff --git a/v3/src/renderer/webgl/batches/shape/VertexShader.js b/v3/src/renderer/webgl/batches/shape/VertexShader.js index 315134c9a..ea25d26fa 100644 --- a/v3/src/renderer/webgl/batches/shape/VertexShader.js +++ b/v3/src/renderer/webgl/batches/shape/VertexShader.js @@ -2,9 +2,18 @@ module.exports = [ 'uniform mat4 u_view_matrix;', 'attribute vec2 a_position;', 'attribute vec4 a_color;', + 'attribute float a_alpha;', + 'attribute vec2 a_translate;', + 'attribute vec2 a_scale;', + 'attribute float a_rotation;', 'varying vec4 v_color;', + 'varying float v_alpha;', 'void main () {', - ' gl_Position = u_view_matrix * vec4(a_position, 1.0, 1.0);', + ' float c = cos(a_rotation);', + ' float s = sin(a_rotation);', + ' vec2 t_position = vec2(a_position.x * c - a_position.y * s, a_position.x * s + a_position.y * c);', + ' gl_Position = u_view_matrix * vec4(t_position * a_scale + a_translate, 1.0, 1.0);', ' v_color = a_color;', + ' v_alpha = a_alpha;', '}' ].join('\n'); diff --git a/v3/src/renderer/webgl/batches/shape/const.js b/v3/src/renderer/webgl/batches/shape/const.js index d1f363ea9..dd4cdb70e 100644 --- a/v3/src/renderer/webgl/batches/shape/const.js +++ b/v3/src/renderer/webgl/batches/shape/const.js @@ -3,14 +3,13 @@ var VertexShader = require('./VertexShader'); var CONST = { - // VERTEX_SIZE = sizeof(vec2) + sizeof(uint32) - VERTEX_SIZE: 12, + VERTEX_SIZE: 36, // How many 32-bit components does the vertex have. - SHAPE_VERTEX_COMPONENT_COUNT: 5, + SHAPE_VERTEX_COMPONENT_COUNT: 9, // Can't be bigger than 10,000 since index are 16-bit - MAX_VERTICES: 10000, + MAX_VERTICES: 1000000, VERTEX_SHADER_SOURCE: VertexShader, FRAGMENT_SHADER_SOURCE: FragmentShader