Skip to content

Commit

Permalink
[#648][#809] add stroke and fill operation for ellipse shape object
Browse files Browse the repository at this point in the history
- ellipse drawing is approximative and aliased, proper way to get a clean circle is probably through a shader
- also optimized/prevented buffer allocation when drawing shapes in WebGL (by passing the _glPoints (former _linePoints) array  and the actual "used" len to the drawLine method)
  • Loading branch information
obiot committed Dec 13, 2018
1 parent 90d8510 commit c56355a
Show file tree
Hide file tree
Showing 7 changed files with 89 additions and 57 deletions.
3 changes: 2 additions & 1 deletion CHANGELOG
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
6 changes: 4 additions & 2 deletions examples/alphablending/index.html
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<!DOCTYPE html>
<html>
<head>
<title>melonJS - alpha blending</title>
<title>melonJS - Graphics drawing</title>
<link rel="stylesheet" type="text/css" media="screen" href="index.css">
</head>
<body bgcolor="white">
Expand Down Expand Up @@ -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);

Expand All @@ -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);
});
</script>
Expand Down
2 changes: 1 addition & 1 deletion src/shapes/poly.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
12 changes: 6 additions & 6 deletions src/video/canvas/canvas_renderer.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
*/
Expand Down Expand Up @@ -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
*/
Expand Down
30 changes: 8 additions & 22 deletions src/video/renderer.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
);
}
},

Expand Down
9 changes: 6 additions & 3 deletions src/video/webgl/compositor.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
);

Expand All @@ -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(
Expand Down
84 changes: 62 additions & 22 deletions src/video/webgl/webgl_renderer.js
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@
/**
* @ignore
*/
this._linePoints = [
this._glPoints = [
new me.Vector2d(),
new me.Vector2d(),
new me.Vector2d(),
Expand Down Expand Up @@ -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");
}
},

/**
Expand All @@ -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)
);
}
},

/**
Expand All @@ -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);
},


Expand Down Expand Up @@ -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);
}
},

Expand Down Expand Up @@ -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;
Expand All @@ -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);
},

/**
Expand Down

0 comments on commit c56355a

Please sign in to comment.