From 75b8afdfe7f03f7bec395904b137c7f1b8d940f3 Mon Sep 17 00:00:00 2001 From: Vamoss Date: Mon, 16 Nov 2020 16:43:05 -0300 Subject: [PATCH] Smooth Quad Distortion (relates to #4288) --- src/core/p5.Renderer2D.js | 50 ++++++++++++++++++++++++--- src/core/shape/2d_primitives.js | 9 +++-- src/webgl/3d_primitives.js | 60 ++++++++++++++++++++++++++------- 3 files changed, 100 insertions(+), 19 deletions(-) diff --git a/src/core/p5.Renderer2D.js b/src/core/p5.Renderer2D.js index 31f144a2fd..0bdaf5a0b1 100644 --- a/src/core/p5.Renderer2D.js +++ b/src/core/p5.Renderer2D.js @@ -582,7 +582,18 @@ p5.Renderer2D.prototype.point = function(x, y) { this._setFill(f); }; -p5.Renderer2D.prototype.quad = function(x1, y1, x2, y2, x3, y3, x4, y4) { +p5.Renderer2D.prototype.quad = function( + x1, + y1, + x2, + y2, + x3, + y3, + x4, + y4, + detailX, + detailY +) { const ctx = this.drawingContext; const doFill = this._doFill, doStroke = this._doStroke; @@ -595,12 +606,41 @@ p5.Renderer2D.prototype.quad = function(x1, y1, x2, y2, x3, y3, x4, y4) { return this; } } + + if (typeof detailX === 'undefined') { + detailX = 2; + } + if (typeof detailY === 'undefined') { + detailY = 2; + } + ctx.beginPath(); - ctx.moveTo(x1, y1); - ctx.lineTo(x2, y2); - ctx.lineTo(x3, y3); - ctx.lineTo(x4, y4); + + let xRes = 1.0 / (detailX - 1); + let yRes = 1.0 / (detailY - 1); + for (let y = 0; y < detailY; y++) { + for (let x = 0; x < detailX; x++) { + let pctx = x * xRes; + let pcty = y * yRes; + + let linePt0x = (1 - pcty) * x1 + pcty * x4; + let linePt0y = (1 - pcty) * y1 + pcty * y4; + let linePt1x = (1 - pcty) * x2 + pcty * x3; + let linePt1y = (1 - pcty) * y2 + pcty * y3; + + let ptx = (1 - pctx) * linePt0x + pctx * linePt1x; + let pty = (1 - pctx) * linePt0y + pctx * linePt1y; + + if (x === 0 && y === 0) { + ctx.moveTo(ptx, pty); + } else { + ctx.lineTo(ptx, pty); + } + } + } + ctx.closePath(); + if (doFill) { ctx.fill(); } diff --git a/src/core/shape/2d_primitives.js b/src/core/shape/2d_primitives.js index 081ac1ad01..9819ce252a 100644 --- a/src/core/shape/2d_primitives.js +++ b/src/core/shape/2d_primitives.js @@ -488,6 +488,8 @@ p5.prototype.point = function(...args) { * @param {Number} y3 the y-coordinate of the third point * @param {Number} x4 the x-coordinate of the fourth point * @param {Number} y4 the y-coordinate of the fourth point + * @param {Integer} [detailX] number of segments in the x-direction + * @param {Integer} [detailY] number of segments in the y-direction * @chainable * @example *
@@ -513,13 +515,15 @@ p5.prototype.point = function(...args) { * @param {Number} x4 * @param {Number} y4 * @param {Number} z4 the z-coordinate of the fourth point + * @param {Integer} [detailX] + * @param {Integer} [detailY] * @chainable */ p5.prototype.quad = function(...args) { p5._validateParameters('quad', args); if (this._renderer._doStroke || this._renderer._doFill) { - if (this._renderer.isP3D && args.length !== 12) { + if (this._renderer.isP3D && args.length <= 12) { // if 3D and we weren't passed 12 args, assume Z is 0 // prettier-ignore this._renderer.quad.call( @@ -527,7 +531,8 @@ p5.prototype.quad = function(...args) { args[0], args[1], 0, args[2], args[3], 0, args[4], args[5], 0, - args[6], args[7], 0); + args[6], args[7], 0, + args[8], args[9]); } else { this._renderer.quad(...args); //accessibile outputs diff --git a/src/webgl/3d_primitives.js b/src/webgl/3d_primitives.js index 3c17821f4c..5f91b564f0 100644 --- a/src/webgl/3d_primitives.js +++ b/src/webgl/3d_primitives.js @@ -1233,24 +1233,60 @@ p5.RendererGL.prototype.rect = function(args) { }; // prettier-ignore -p5.RendererGL.prototype.quad = function(x1, y1, z1, x2, y2, z2, x3, y3, z3, x4, y4, z4) { +p5.RendererGL.prototype.quad = function(x1, y1, z1, x2, y2, z2, x3, y3, z3, x4, y4, z4, detailX, detailY) { + if (typeof detailX === 'undefined') { + detailX = 2; + } + if (typeof detailY === 'undefined') { + detailY = 2; + } + const gId = - `quad|${x1}|${y1}|${z1}|${x2}|${y2}|${z2}|${x3}|${y3}|${z3}|${x4}|${y4}|${z4}`; + `quad|${x1}|${y1}|${z1}|${x2}|${y2}|${z2}|${x3}|${y3}|${z3}|${x4}|${y4}|${z4}|${detailX}|${detailY}`; + if (!this.geometryInHash(gId)) { - const _quad = function() { - this.vertices.push(new p5.Vector(x1, y1, z1)); - this.vertices.push(new p5.Vector(x2, y2, z2)); - this.vertices.push(new p5.Vector(x3, y3, z3)); - this.vertices.push(new p5.Vector(x4, y4, z4)); - this.uvs.push(0, 0, 1, 0, 1, 1, 0, 1); - this.strokeIndices = [[0, 1], [1, 2], [2, 3], [3, 0]]; - }; - const quadGeom = new p5.Geometry(2, 2, _quad); + const quadGeom = new p5.Geometry(detailX, detailY, function() { + //algorithm adapted from c++ to js + //https://stackoverflow.com/questions/16989181/whats-the-correct-way-to-draw-a-distorted-plane-in-opengl/16993202#16993202 + let xRes = 1.0 / (this.detailX - 1); + let yRes = 1.0 / (this.detailY - 1); + for (let y = 0; y < this.detailY; y++) { + for (let x = 0; x < this.detailX; x++) { + let pctx = x * xRes; + let pcty = y * yRes; + + let linePt0x = (1 - pcty) * x1 + pcty * x4; + let linePt0y = (1 - pcty) * y1 + pcty * y4; + let linePt0z = (1 - pcty) * z1 + pcty * z4; + let linePt1x = (1 - pcty) * x2 + pcty * x3; + let linePt1y = (1 - pcty) * y2 + pcty * y3; + let linePt1z = (1 - pcty) * z2 + pcty * z3; + + let ptx = (1 - pctx) * linePt0x + pctx * linePt1x; + let pty = (1 - pctx) * linePt0y + pctx * linePt1y; + let ptz = (1 - pctx) * linePt0z + pctx * linePt1z; + + this.vertices.push(new p5.Vector(ptx, pty, ptz)); + this.uvs.push([pctx, pcty]); + } + } + }); + + quadGeom.faces = []; + for(let y = 0; y < detailY-1; y++){ + for(let x = 0; x < detailX-1; x++){ + let pt0 = x + y * detailX; + let pt1 = (x + 1) + y * detailX; + let pt2 = (x + 1) + (y + 1) * detailX; + let pt3 = x + (y + 1) * detailX; + quadGeom.faces.push([pt0, pt1, pt2]); + quadGeom.faces.push([pt0, pt2, pt3]); + } + } quadGeom .computeNormals() ._makeTriangleEdges() ._edgesToVertices(); - quadGeom.faces = [[0, 1, 2], [2, 3, 0]]; this.createBuffers(gId, quadGeom); } this.drawBuffers(gId);