diff --git a/CHANGELOG b/CHANGELOG index 19a39127ee..2973b6abdb 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -4,7 +4,8 @@ Version History * Renderable : added support for rendering mask (in both Canvas and WebGL mode), allowing to use any polygon based Shape as a mask * Renderer : `drawShape()` is deprecated and has been replaced by a `fill()` and `stroke() methods * Renderer : cleaned and aligned drawing APIs between the Canvas and WebGL Renderer -* WebGLRenderer : added fill operations for polygon based shapes +* WebGLRenderer : added stroke and fill operations for all me.Shape objects +* WebGLRenderer : optimized shape drawing operations by preventing temporary array allocation 6.2.0 * Audio : fixed a regression when passing an initial volume value to the play function (thanks @PLAYERKILLERS) diff --git a/examples/alphablending/index.html b/examples/alphablending/index.html index dc7df9a320..5918f9536c 100644 --- a/examples/alphablending/index.html +++ b/examples/alphablending/index.html @@ -1,7 +1,7 @@ - melonJS - alpha blending + melonJS - Graphics drawing @@ -43,6 +43,7 @@ me.video.renderer.setColor(r); mask.pos.set(60 + 50, 25); me.video.renderer.fill(mask); + me.video.renderer.stroke(mask); me.video.renderer.fillRect(60, 20, 100 ,100); me.video.renderer.strokeRect(65, 25, 90 , 90); @@ -56,8 +57,9 @@ me.video.renderer.setColor(b); mask.pos.set(160 + 50, 125); - me.video.renderer.fill(mask); me.video.renderer.fillRect(160, 120, 100 ,100); + me.video.renderer.fillEllipse(160 + 50, 120 + 50, 35, 35); + me.video.renderer.strokeEllipse(160 + 50, 120 + 50, 30, 30); me.video.renderer.strokeRect(165, 125, 90 , 90); }); diff --git a/src/shapes/poly.js b/src/shapes/poly.js index 0ed1577f1a..e315b66d84 100644 --- a/src/shapes/poly.js +++ b/src/shapes/poly.js @@ -260,7 +260,7 @@ /** * returns a list of indices for all triangles defined in this polygon - * @name toIndices + * @name getIndices * @memberOf me.Polygon * @function * @param {Vector2d[]} a list of vector diff --git a/src/video/canvas/canvas_renderer.js b/src/video/canvas/canvas_renderer.js index 77b8603453..e42e2ef6cc 100644 --- a/src/video/canvas/canvas_renderer.js +++ b/src/video/canvas/canvas_renderer.js @@ -315,12 +315,12 @@ }, /** - * Stroke an ellipse at the specified coordinates with given radius, start and end points + * Stroke an ellipse at the specified coordinates with given radius * @name strokeEllipse * @memberOf me.CanvasRenderer * @function - * @param {Number} x arc center point x-axis - * @param {Number} y arc center point y-axis + * @param {Number} x ellipse center point x-axis + * @param {Number} y ellipse center point y-axis * @param {Number} w horizontal radius of the ellipse * @param {Number} h vertical radius of the ellipse */ @@ -356,12 +356,12 @@ }, /** - * Fill an ellipse at the specified coordinates with given radius, start and end points + * Fill an ellipse at the specified coordinates with given radius * @name fillEllipse * @memberOf me.CanvasRenderer * @function - * @param {Number} x arc center point x-axis - * @param {Number} y arc center point y-axis + * @param {Number} x ellipse center point x-axis + * @param {Number} y ellipse center point y-axis * @param {Number} w horizontal radius of the ellipse * @param {Number} h vertical radius of the ellipse */ diff --git a/src/video/renderer.js b/src/video/renderer.js index 51d825ac72..79bc1d950f 100644 --- a/src/video/renderer.js +++ b/src/video/renderer.js @@ -309,28 +309,14 @@ } else if (shape instanceof me.Line || shape instanceof me.Polygon) { this.strokePolygon(shape, fill); } else if (shape instanceof me.Ellipse) { - if (shape.radiusV.x === shape.radiusV.y) { - // it's a circle - this.strokeArc( - shape.pos.x - shape.radius, - shape.pos.y - shape.radius, - shape.radius, - 0, - 2 * Math.PI, - false, - fill - ); - } else { - // it's an ellipse - this.strokeEllipse( - shape.pos.x, - shape.pos.y, - shape.radiusV.x, - shape.radiusV.y, - false, - fill - ); - } + this.strokeEllipse( + shape.pos.x, + shape.pos.y, + shape.radiusV.x, + shape.radiusV.y, + false, + fill + ); } }, diff --git a/src/video/webgl/compositor.js b/src/video/webgl/compositor.js index 225e78a1c1..d8fae0d49a 100644 --- a/src/video/webgl/compositor.js +++ b/src/video/webgl/compositor.js @@ -547,11 +547,14 @@ * @memberOf me.WebGLRenderer.Compositor * @function * @param {me.Vector2d[]} points Line vertices + * @param {Number} [len=points.length] amount of points defined in the points array * @param {Boolean} [open=false] Whether the line is open (true) or closed (false) */ - drawLine : function (points, open) { + drawLine : function (points, len, open) { var gl = this.gl; + len = len || points.length; + this.useShader(this.primitiveShader.handle); // Put vertex data into the stream buffer @@ -573,7 +576,7 @@ // Copy data into the stream buffer gl.bufferData( gl.ARRAY_BUFFER, - this.stream.subarray(0, points.length * 2), + this.stream.subarray(0, len * 2), gl.STREAM_DRAW ); @@ -588,7 +591,7 @@ ); // Draw the stream buffer - gl.drawArrays(open ? gl.LINE_STRIP : gl.LINE_LOOP, 0, points.length); + gl.drawArrays(open ? gl.LINE_STRIP : gl.LINE_LOOP, 0, len); // FIXME: Configure vertex attrib pointers in `useShader` gl.vertexAttribPointer( diff --git a/src/video/webgl/webgl_renderer.js b/src/video/webgl/webgl_renderer.js index 7dafc0a1e7..17a7859901 100644 --- a/src/video/webgl/webgl_renderer.js +++ b/src/video/webgl/webgl_renderer.js @@ -59,7 +59,7 @@ /** * @ignore */ - this._linePoints = [ + this._glPoints = [ new me.Vector2d(), new me.Vector2d(), new me.Vector2d(), @@ -643,8 +643,12 @@ * @param {Number} end end angle in radians * @param {Boolean} [antiClockwise=false] draw arc anti-clockwise */ - strokeArc : function (/*x, y, radius, start, end, antiClockwise*/) { - console.warn("strokeArc() is not implemented"); + strokeArc : function (x, y, radius, start, end, antiClockwise, fill) { + if (fill === true ) { + this.fillArc(x, y, radius, start, end, antiClockwise); + } else { + console.warn("strokeArc() is not implemented"); + } }, /** @@ -660,35 +664,71 @@ * @param {Boolean} [antiClockwise=false] draw arc anti-clockwise */ fillArc : function (x, y, radius, start, end, antiClockwise) { - this.strokeArc(x, y, radius, start, end, antiClockwise || false, true); + console.warn("fillArc() is not implemented"); }, /** - * Stroke an ellipse at the specified coordinates with given radius, start and end points + * Stroke an ellipse at the specified coordinates with given radius * @name strokeEllipse * @memberOf me.WebGLRenderer * @function - * @param {Number} x arc center point x-axis - * @param {Number} y arc center point y-axis + * @param {Number} x ellipse center point x-axis + * @param {Number} y ellipse center point y-axis * @param {Number} w horizontal radius of the ellipse * @param {Number} h vertical radius of the ellipse */ - strokeEllipse : function (/*x, y, w, h*/) { - console.warn("strokeEllipse() is not implemented"); + strokeEllipse : function (x, y, w, h, fill) { + if (fill === true ) { + this.fillEllipse(x, y, w, h); + } else { + // XXX to be optimzed using a specific shader + var len = Math.floor(24 * Math.sqrt(w)) || + Math.floor(12 * Math.sqrt(w + h)); + var segment = (Math.PI * 2) / len; + var points = this._glPoints, + i; + + // Grow internal points buffer if necessary + for (i = points.length; i < len; i++) { + points.push(new me.Vector2d()); + } + + // calculate and draw all segments + for (i = 0; i < len; i++) { + points[i].x = x + (Math.sin(segment * -i) * w); + points[i].y = y + (Math.cos(segment * -i) * h); + } + this.compositor.drawLine(points, len); + } + }, /** - * Fill an ellipse at the specified coordinates with given radius, start and end points + * Fill an ellipse at the specified coordinates with given radius * @name fillEllipse * @memberOf me.WebGLRenderer * @function - * @param {Number} x arc center point x-axis - * @param {Number} y arc center point y-axis + * @param {Number} x ellipse center point x-axis + * @param {Number} y ellipse center point y-axis * @param {Number} w horizontal radius of the ellipse * @param {Number} h vertical radius of the ellipse */ fillEllipse : function (x, y, w, h) { - this.strokeEllipse(x, y, w, h, true); + // XXX to be optimzed using a specific shader + var len = Math.floor(24 * Math.sqrt(w)) || + Math.floor(12 * Math.sqrt(w + h)); + var segment = (Math.PI * 2) / len; + + // draw all vertices vertex coordinates + for (var i = 0; i < len; i++) { + this.compositor.drawTriangle( + x, y, + x + (Math.sin(segment * i) * w), + y + (Math.cos(segment * i) * h), + x + (Math.sin(segment * (i + 1)) * w), + y + (Math.cos(segment * (i + 1)) * h) + ); + } }, /** @@ -702,12 +742,12 @@ * @param {Number} endY the end y coordinate */ strokeLine : function (startX, startY, endX, endY) { - var points = this._linePoints.slice(0, 2); + var points = this._glPoints; points[0].x = startX; points[0].y = startY; points[1].x = endX; points[1].y = endY; - this.compositor.drawLine(points, true); + this.compositor.drawLine(points, 2, true); }, @@ -737,20 +777,20 @@ this.fillPolygon(poly); } else { var len = poly.points.length, - points, + points = this._glPoints, i; // Grow internal points buffer if necessary - for (i = this._linePoints.length; i < len; i++) { - this._linePoints.push(new me.Vector2d()); + for (i = points.length; i < len; i++) { + points.push(new me.Vector2d()); } - points = this._linePoints.slice(0, len); + // calculate and draw all segments for (i = 0; i < len; i++) { points[i].x = poly.pos.x + poly.points[i].x; points[i].y = poly.pos.y + poly.points[i].y; } - this.compositor.drawLine(points); + this.compositor.drawLine(points, len); } }, @@ -786,7 +826,7 @@ * @param {Number} height */ strokeRect : function (x, y, width, height) { - var points = this._linePoints.slice(0, 4); + var points = this._glPoints; points[0].x = x; points[0].y = y; points[1].x = x + width; @@ -795,7 +835,7 @@ points[2].y = y + height; points[3].x = x; points[3].y = y + height; - this.compositor.drawLine(points); + this.compositor.drawLine(points, 4); }, /**