diff --git a/docs/parameterData.json b/docs/parameterData.json index 6cf76f3c4a..41da80e4ab 100644 --- a/docs/parameterData.json +++ b/docs/parameterData.json @@ -305,6 +305,7 @@ }, "ellipseMode": { "overloads": [ + [], [ "CENTER|RADIUS|CORNER|CORNERS" ] @@ -808,6 +809,7 @@ }, "rectMode": { "overloads": [ + [], [ "CENTER|RADIUS|CORNER|CORNERS" ] @@ -878,7 +880,8 @@ "ARROW|CROSS|HAND|MOVE|TEXT|WAIT|String", "Number?", "Number?" - ] + ], + [] ] }, "createElement": { @@ -1086,7 +1089,8 @@ "overloads": [ [ "ROUND|SQUARE|PROJECT" - ] + ], + [] ] }, "lerp": { @@ -1292,7 +1296,8 @@ "overloads": [ [ "MITER|BEVEL|ROUND" - ] + ], + [] ] }, "noCursor": { @@ -1391,7 +1396,8 @@ "overloads": [ [ "Number" - ] + ], + [] ] }, "degrees": { @@ -2268,6 +2274,7 @@ }, "colorMode": { "overloads": [ + [], [ "RGB|HSB|HSL|RGBHDR|HWB|LAB|LCH|OKLAB|OKLCH", "Number?" @@ -2492,6 +2499,7 @@ }, "tint": { "overloads": [ + [], [ "Number", "Number", @@ -2631,6 +2639,7 @@ }, "fill": { "overloads": [ + [], [ "Number", "Number", @@ -2680,7 +2689,8 @@ [ "LEFT|CENTER|RIGHT?", "TOP|BOTTOM|CENTER|BASELINE?" - ] + ], + [] ] }, "textAscent": { @@ -2701,7 +2711,8 @@ "overloads": [ [ "Number?" - ] + ], + [] ] }, "textFont": { @@ -2709,7 +2720,8 @@ [ "p5.Font|String|Object?", "Number?" - ] + ], + [] ] }, "textSize": { @@ -2854,6 +2866,7 @@ }, "imageMode": { "overloads": [ + [], [ "CORNER|CORNERS|CENTER" ] @@ -2983,6 +2996,7 @@ }, "stroke": { "overloads": [ + [], [ "Number", "Number", @@ -3227,6 +3241,7 @@ }, "blendMode": { "overloads": [ + [], [ "BLEND|DARKEST|LIGHTEST|DIFFERENCE|MULTIPLY|EXCLUSION|SCREEN|REPLACE|OVERLAY|HARD_LIGHT|SOFT_LIGHT|DODGE|BURN|ADD|REMOVE|SUBTRACT" ] @@ -3298,7 +3313,8 @@ "overloads": [ [ "Object" - ] + ], + [] ] }, "linePerspective": { @@ -3387,7 +3403,8 @@ "overloads": [ [ "IMAGE|NORMAL" - ] + ], + [] ] }, "setCamera": { @@ -3409,7 +3426,8 @@ [ "CLAMP|REPEAT|MIRROR", "CLAMP|REPEAT|MIRROR?" - ] + ], + [] ] }, "normalMaterial": { diff --git a/src/color/p5.Color.js b/src/color/p5.Color.js index cd7561b939..1c89b21f9a 100644 --- a/src/color/p5.Color.js +++ b/src/color/p5.Color.js @@ -724,7 +724,7 @@ class Color { if(!Array.isArray(v)){ return [0, v]; }else{ - return v + return v; } }); diff --git a/src/color/setting.js b/src/color/setting.js index 6a066b986e..cae961600b 100644 --- a/src/color/setting.js +++ b/src/color/setting.js @@ -580,8 +580,7 @@ function setting(p5, fn){ * @chainable */ fn.background = function(...args) { - this._renderer.background(...args); - return this; + return this._renderer.background(...args); }; /** @@ -1096,6 +1095,8 @@ function setting(p5, fn){ * or `HSLA` colors, depending on the current colorMode(). The last parameter * sets the alpha (transparency) value. * + * Calling `fill()` without an argument returns the current fill as a p5.Color object. + * * @method fill * @param {Number} v1 red value if color mode is RGB or hue value if color mode is HSB. * @param {Number} v2 green value if color mode is RGB or saturation value if color mode is HSB. @@ -1284,9 +1285,12 @@ function setting(p5, fn){ * @param {p5.Color} color the fill color. * @chainable */ + /** + * @method fill + * @return {p5.Color} the current fill color. + */ fn.fill = function(...args) { - this._renderer.fill(...args); - return this; + return this._renderer.fill(...args); }; /** @@ -1415,6 +1419,8 @@ function setting(p5, fn){ * or HSLA colors, depending on the current `colorMode()`. The last parameter * sets the alpha (transparency) value. * + * Calling `stroke()` without an argument returns the current stroke as a p5.Color object. + * * @method stroke * @param {Number} v1 red value if color mode is RGB or hue value if color mode is HSB. * @param {Number} v2 green value if color mode is RGB or saturation value if color mode is HSB. @@ -1601,9 +1607,12 @@ function setting(p5, fn){ * @param {p5.Color} color the stroke color. * @chainable */ + /** + * @method stroke + * @return {p5.Color} the current stroke color. + */ fn.stroke = function(...args) { - this._renderer.stroke(...args); - return this; + return this._renderer.stroke(...args); }; /** @@ -1768,6 +1777,8 @@ function setting(p5, fn){ * EXCLUSION, SCREEN, REPLACE, OVERLAY, HARD_LIGHT, * SOFT_LIGHT, DODGE, BURN, ADD, REMOVE or SUBTRACT * + * Calling `blendMode()` without an argument returns the current blendMode. + * * @example * function setup() { * createCanvas(100, 100); @@ -2136,6 +2147,10 @@ function setting(p5, fn){ * describe('A yellow line and a turquoise line form an X on a gray background. The area where they overlap is green.'); * } */ + /** + * @method blendMode + * @return {(BLEND|DARKEST|LIGHTEST|DIFFERENCE|MULTIPLY|EXCLUSION|SCREEN|REPLACE|OVERLAY|HARD_LIGHT|SOFT_LIGHT|DODGE|BURN|ADD|REMOVE|SUBTRACT)} the current blend mode. + */ fn.blendMode = function (mode) { // p5._validateParameters('blendMode', arguments); if (mode === constants.NORMAL) { @@ -2145,7 +2160,7 @@ function setting(p5, fn){ ); mode = constants.BLEND; } - this._renderer.blendMode(mode); + return this._renderer.blendMode(mode); }; } diff --git a/src/core/environment.js b/src/core/environment.js index 350d1d1e54..6fffe81973 100644 --- a/src/core/environment.js +++ b/src/core/environment.js @@ -215,6 +215,8 @@ function environment(p5, fn, lifecycles){ * cursor, `x` and `y` set the location pointed to within the image. They are * both 0 by default, so the cursor points to the image's top-left corner. `x` * and `y` must be less than the image's width and height, respectively. + * + * Calling `cursor()` without an argument returns the current cursor type as a string. * * @method cursor * @param {(ARROW|CROSS|HAND|MOVE|TEXT|WAIT|String)} type Built-in: either ARROW, CROSS, HAND, MOVE, TEXT, or WAIT. @@ -281,9 +283,17 @@ function environment(p5, fn, lifecycles){ * } * } */ + /** + * @method cursor + * @return {(ARROW|CROSS|HAND|MOVE|TEXT|WAIT|String)} the current cursor type + */ fn.cursor = function(type, x, y) { let cursor = 'auto'; const canvas = this._curElement.elt; + if (typeof type === 'undefined') { + let curstr = canvas.style.cursor; + return curstr.length ? curstr : 'default'; + } if (standardCursors.includes(type)) { // Standard css cursor cursor = type; diff --git a/src/core/p5.Renderer.js b/src/core/p5.Renderer.js index c0fe4a6c02..f9caac7793 100644 --- a/src/core/p5.Renderer.js +++ b/src/core/p5.Renderer.js @@ -45,6 +45,11 @@ class Renderer { rectMode: constants.CORNER, ellipseMode: constants.CENTER, strokeWeight: 1, + bezierOrder: 3, + splineProperties: new ClonableObject({ + ends: constants.INCLUDE, + tightness: 0 + }), textFont: { family: 'sans-serif' }, textLeading: 15, @@ -52,15 +57,8 @@ class Renderer { textSize: 12, textAlign: constants.LEFT, textBaseline: constants.BASELINE, - bezierOrder: 3, - splineProperties: new ClonableObject({ - ends: constants.INCLUDE, - tightness: 0 - }), textWrap: constants.WORD, - - // added v2.0 - fontStyle: constants.NORMAL, // v1: textStyle + fontStyle: constants.NORMAL, // v1: was textStyle fontStretch: constants.NORMAL, fontWeight: constants.NORMAL, lineHeight: constants.NORMAL, @@ -330,9 +328,12 @@ class Renderer { } fill(...args) { - this.states.setValue('fillSet', true); - this.states.setValue('fillColor', this._pInst.color(...args)); - this.updateShapeVertexProperties(); + if (args.length > 0) { + this.states.setValue('fillSet', true); + this.states.setValue('fillColor', this._pInst.color(...args)); + this.updateShapeVertexProperties(); + } + return this.states.fillColor; } noFill() { @@ -340,14 +341,16 @@ class Renderer { } strokeWeight(w) { - if (w === undefined) { + if (typeof w === 'undefined') { return this.states.strokeWeight; - } else { - this.states.setValue('strokeWeight', w); } + this.states.setValue('strokeWeight', w); } stroke(...args) { + if (args.length === 0) { + return this.states.strokeColor; + } this.states.setValue('strokeSet', true); this.states.setValue('strokeColor', this._pInst.color(...args)); this.updateShapeVertexProperties(); diff --git a/src/core/p5.Renderer2D.js b/src/core/p5.Renderer2D.js index fbe5747449..a98f60f339 100644 --- a/src/core/p5.Renderer2D.js +++ b/src/core/p5.Renderer2D.js @@ -166,18 +166,18 @@ class Renderer2D extends Renderer { ////////////////////////////////////////////// background(...args) { + if (args.length === 0) { + return this;// setter with no args does nothing + } this.push(); this.resetMatrix(); - if (args[0] instanceof Image) { + const img = args[0]; if (args[1] >= 0) { // set transparency of background - const img = args[0]; this.drawingContext.globalAlpha = args[1] / 255; - this._pInst.image(img, 0, 0, this.width, this.height); - } else { - this._pInst.image(args[0], 0, 0, this.width, this.height); } + this._pInst.image(img, 0, 0, this.width, this.height); } else { // create background rect const color = this._pInst.color(...args); @@ -202,6 +202,8 @@ class Renderer2D extends Renderer { } } this.pop(); + + return this; } clear() { @@ -214,6 +216,9 @@ class Renderer2D extends Renderer { fill(...args) { super.fill(...args); const color = this.states.fillColor; + if (args.length === 0) { + return color; // getter + } this._setFill(color.toString()); // Add accessible outputs if the method exists; on success, @@ -226,6 +231,9 @@ class Renderer2D extends Renderer { stroke(...args) { super.stroke(...args); const color = this.states.strokeColor; + if (args.length === 0) { + return color; // getter + } this._setStroke(color.toString()); // Add accessible outputs if the method exists; on success, @@ -484,6 +492,9 @@ class Renderer2D extends Renderer { ////////////////////////////////////////////// blendMode(mode) { + if (typeof mode === 'undefined') { // getter + return this._cachedBlendMode; + } if (mode === constants.SUBTRACT) { console.warn('blendMode(SUBTRACT) only works in WEBGL mode.'); } else if ( @@ -1004,6 +1015,9 @@ class Renderer2D extends Renderer { ////////////////////////////////////////////// strokeCap(cap) { + if (typeof cap === 'undefined') { // getter + return this.drawingContext.lineCap; + } if ( cap === constants.ROUND || cap === constants.SQUARE || @@ -1015,6 +1029,9 @@ class Renderer2D extends Renderer { } strokeJoin(join) { + if (typeof join === 'undefined') { // getter + return this.drawingContext.lineJoin; + } if ( join === constants.ROUND || join === constants.BEVEL || @@ -1027,7 +1044,10 @@ class Renderer2D extends Renderer { strokeWeight(w) { super.strokeWeight(w); - if (typeof w === 'undefined' || w === 0) { + if (typeof w === 'undefined') { + return this.states.strokeWeight; + } + if (w === 0) { // hack because lineWidth 0 doesn't work this.drawingContext.lineWidth = 0.0001; } else { @@ -1090,16 +1110,22 @@ class Renderer2D extends Renderer { rotate(rad) { this.drawingContext.rotate(rad); + return this; } scale(x, y) { + // support passing objects with x,y properties (including p5.Vector) + if (typeof x === 'object' && 'x' in x && 'y' in x) { + y = x.y; + x = x.x; + } this.drawingContext.scale(x, y); return this; } translate(x, y) { - // support passing a vector as the 1st parameter - if (x instanceof p5.Vector) { + // support passing objects with x,y properties (including p5.Vector) + if (typeof x === 'object' && 'x' in x && 'y' in x) { y = x.y; x = x.x; } diff --git a/src/core/p5.Renderer3D.js b/src/core/p5.Renderer3D.js index 4241a56157..b98cb19178 100644 --- a/src/core/p5.Renderer3D.js +++ b/src/core/p5.Renderer3D.js @@ -132,7 +132,7 @@ export class Renderer3D extends Renderer { this.states._useShininess = 1; this.states._useMetalness = 0; - this.states.tint = [255, 255, 255, 255]; + this.states.tint = new Color([1, 1, 1, 1]); this.states.constantAttenuation = 1; this.states.linearAttenuation = 0; @@ -721,10 +721,10 @@ export class Renderer3D extends Renderer { this.states.setValue("enableLighting", false); //reset tint value for new frame - this.states.setValue("tint", [255, 255, 255, 255]); + this.states.setValue("tint", new Color([1,1,1,1])); //Clear depth every frame - this._resetBuffersBeforeDraw() + this._resetBuffersBeforeDraw(); } background(...args) { @@ -1486,7 +1486,7 @@ export class Renderer3D extends Renderer { // works differently and is global p5 state. If the p5 state has // been cleared, we also need to clear the value in uSampler to match. fillShader.setUniform("uSampler", this.states._tex || empty); - fillShader.setUniform("uTint", this.states.tint); + fillShader.setUniform("uTint", this.states.tint._getRGBA([255, 255, 255, 255])); fillShader.setUniform("uHasSetAmbient", this.states._hasSetAmbient); fillShader.setUniform("uAmbientMatColor", this.states.curAmbientColor); diff --git a/src/core/transform.js b/src/core/transform.js index e8a6a32da3..0b8eb95a5b 100644 --- a/src/core/transform.js +++ b/src/core/transform.js @@ -420,8 +420,7 @@ function transform(p5, fn){ */ fn.rotate = function(angle, axis) { // p5._validateParameters('rotate', arguments); - this._renderer.rotate(this._toRadians(angle), axis); - return this; + return this._renderer.rotate(this._toRadians(angle), axis); }; /** @@ -543,8 +542,7 @@ function transform(p5, fn){ fn.rotateX = function(angle) { this._assert3d('rotateX'); // p5._validateParameters('rotateX', arguments); - this._renderer.rotateX(this._toRadians(angle)); - return this; + return this._renderer.rotateX(this._toRadians(angle)); }; /** @@ -666,8 +664,7 @@ function transform(p5, fn){ fn.rotateY = function(angle) { this._assert3d('rotateY'); // p5._validateParameters('rotateY', arguments); - this._renderer.rotateY(this._toRadians(angle)); - return this; + return this._renderer.rotateY(this._toRadians(angle)); }; /** @@ -789,8 +786,7 @@ function transform(p5, fn){ fn.rotateZ = function(angle) { this._assert3d('rotateZ'); // p5._validateParameters('rotateZ', arguments); - this._renderer.rotateZ(this._toRadians(angle)); - return this; + return this._renderer.rotateZ(this._toRadians(angle)); }; /** @@ -966,9 +962,7 @@ function transform(p5, fn){ z = 1; } - this._renderer.scale(x, y, z); - - return this; + return this._renderer.scale(x, y, z); }; /** @@ -1274,11 +1268,10 @@ function transform(p5, fn){ fn.translate = function(x, y, z) { // p5._validateParameters('translate', arguments); if (this._renderer.isP3D) { - this._renderer.translate(x, y, z); + return this._renderer.translate(x, y, z); } else { - this._renderer.translate(x, y); + return this._renderer.translate(x, y); } - return this; }; /** diff --git a/src/image/loading_displaying.js b/src/image/loading_displaying.js index 3b9ed18fd6..28149c4412 100644 --- a/src/image/loading_displaying.js +++ b/src/image/loading_displaying.js @@ -1138,6 +1138,9 @@ function loadingDisplaying(p5, fn){ * sets the alpha value. For example, `tint(255, 0, 0, 100)` will give images * a red tint and make them transparent. * + * Calling `tint()` without an argument returns the current tint as a + * p5.Color object. + * * @method tint * @param {Number} v1 red or hue value. * @param {Number} v2 green or saturation value. @@ -1242,10 +1245,18 @@ function loadingDisplaying(p5, fn){ * @method tint * @param {p5.Color} color the tint color */ + /** + * @method tint + * @return {p5.Color} the current tint color + */ fn.tint = function(...args) { - // p5._validateParameters('tint', args); - const c = this.color(...args); - this._renderer.states.setValue('tint', c._getRGBA([255, 255, 255, 255])); + if (args.length === 0) { + return this._renderer.states.tint; // getter + } + else { + this._renderer.states.setValue('tint', this.color(...args)); + return this; + } }; /** @@ -1279,6 +1290,7 @@ function loadingDisplaying(p5, fn){ */ fn.noTint = function() { this._renderer.states.setValue('tint', null); + return this; }; /** @@ -1310,6 +1322,8 @@ function loadingDisplaying(p5, fn){ * image() as the x- and y-coordinates of the image's * center. The next parameters are its width and height. * + * Calling `imageMode()` without an argument returns the current image mode, either `CORNER`, `CORNERS`, or `CENTER`. + * * @method imageMode * @param {(CORNER|CORNERS|CENTER)} mode either CORNER, CORNERS, or CENTER. * @@ -1373,8 +1387,15 @@ function loadingDisplaying(p5, fn){ * describe('A square image of a brick wall is drawn on a gray square.'); * } */ + /** + * @method imageMode + * @return {(CORNER|CORNERS|CENTER)} the current image mode + */ fn.imageMode = function(m) { // p5._validateParameters('imageMode', arguments); + if (typeof m === 'undefined') { // getter + return this._renderer.states.imageMode; + } if ( m === constants.CORNER || m === constants.CORNERS || diff --git a/src/math/trigonometry.js b/src/math/trigonometry.js index 979adb1c16..d2c5491b7d 100644 --- a/src/math/trigonometry.js +++ b/src/math/trigonometry.js @@ -774,7 +774,8 @@ function trigonometry(p5, fn){ * @returns {Number} */ fn._toRadians = function(angle) { - if (this._angleMode === DEGREES) { + // returns undefined if no argument + if (typeof angle !== 'undefined' && this._angleMode === DEGREES) { return angle * constants.DEG_TO_RAD; } return angle; diff --git a/src/shape/attributes.js b/src/shape/attributes.js index f6bcf02576..812159267f 100644 --- a/src/shape/attributes.js +++ b/src/shape/attributes.js @@ -35,6 +35,8 @@ function attributes(p5, fn){ * the constants `CENTER`, `RADIUS`, `CORNER`, and `CORNERS` are defined this * way. JavaScript is a case-sensitive language. * + * Calling `ellipseMode()` without an argument returns the current ellipseMode, either `CENTER`, `RADIUS`, `CORNER`, or `CORNERS`. + * * @method ellipseMode * @param {(CENTER|RADIUS|CORNER|CORNERS)} mode either CENTER, RADIUS, CORNER, or CORNERS * @chainable @@ -77,8 +79,15 @@ function attributes(p5, fn){ * describe('A white circle with a gray circle at its top-left corner. Both circles have black outlines.'); * } */ + /** + * @method ellipseMode + * @return {(CENTER|RADIUS|CORNER|CORNERS)} the current ellipseMode. + */ fn.ellipseMode = function(m) { // p5._validateParameters('ellipseMode', arguments); + if (typeof m === 'undefined') { // getter + return this._renderer?.states.ellipseMode; + } if ( m === constants.CORNER || m === constants.CORNERS || @@ -186,6 +195,8 @@ function attributes(p5, fn){ * constants `CENTER`, `RADIUS`, `CORNER`, and `CORNERS` are defined this way. * JavaScript is a case-sensitive language. * + * Calling `rectMode()` without an argument returns the current rectMode, either `CORNER`, `CORNERS`, `CENTER`, or `RADIUS`. + * * @method rectMode * @param {(CENTER|RADIUS|CORNER|CORNERS)} mode either CORNER, CORNERS, CENTER, or RADIUS * @chainable @@ -254,8 +265,15 @@ function attributes(p5, fn){ * describe('A small gray square drawn at the center of a white square.'); * } */ + /** + * @method rectMode + * @return {(CENTER|RADIUS|CORNER|CORNERS)} the current rectMode. + */ fn.rectMode = function(m) { // p5._validateParameters('rectMode', arguments); + if (typeof m === 'undefined') { // getter + return this._renderer?.states.rectMode; + } if ( m === constants.CORNER || m === constants.CORNERS || @@ -380,6 +398,9 @@ function attributes(p5, fn){ */ fn.strokeCap = function(cap) { // p5._validateParameters('strokeCap', arguments); + if (typeof cap === 'undefined') { // getter + return this._renderer.strokeCap(); + } if ( cap === constants.ROUND || cap === constants.SQUARE || @@ -401,6 +422,8 @@ function attributes(p5, fn){ * the constants `MITER`, `BEVEL`, and `ROUND` are defined this way. * JavaScript is a case-sensitive language. * + * Calling `strokeJoin()` without an argument returns the current stroke join style, either `MITER`, `BEVEL`, or `ROUND`. + * * @method strokeJoin * @param {(MITER|BEVEL|ROUND)} join either MITER, BEVEL, or ROUND * @chainable @@ -467,8 +490,15 @@ function attributes(p5, fn){ * describe('A right-facing arrowhead shape with a rounded tip in center of canvas.'); * } */ + /** + * @method strokeJoin + * @return {(MITER|BEVEL|ROUND)} the current stroke join style. + */ fn.strokeJoin = function(join) { // p5._validateParameters('strokeJoin', arguments); + if (typeof join === 'undefined') { // getter + return this._renderer.strokeJoin(); + } if ( join === constants.ROUND || join === constants.BEVEL || @@ -485,6 +515,8 @@ function attributes(p5, fn){ * * Note: `strokeWeight()` is affected by transformations, especially calls to * scale(). + * + * Calling `strokeWeight()` without an argument returns the current stroke weight as a number. * * @method strokeWeight * @param {Number} weight the weight of the stroke (in pixels). @@ -527,10 +559,13 @@ function attributes(p5, fn){ * describe('Two horizontal black lines. The top line is thin and the bottom is five times thicker than the top.'); * } */ + /** + * @method strokeWeight + * @return {Number} the current stroke weight. + */ fn.strokeWeight = function(w) { // p5._validateParameters('strokeWeight', arguments); - this._renderer.strokeWeight(w); - return this; + return this._renderer.strokeWeight(w); }; } diff --git a/src/shape/custom_shapes.js b/src/shape/custom_shapes.js index 3a09200f75..f287a4823e 100644 --- a/src/shape/custom_shapes.js +++ b/src/shape/custom_shapes.js @@ -1611,6 +1611,8 @@ function customShapes(p5, fn) { * Note: `bezierVertex()` won’t work when an argument is passed to * beginShape(). * + * Calling `bezierOrder()` without an argument returns the current Bézier order. + * * @method bezierOrder * @param {Number} order The new order to set. Can be either 2 or 3, by default 3 * diff --git a/src/type/textCore.js b/src/type/textCore.js index 345267fa4c..909609ef0c 100644 --- a/src/type/textCore.js +++ b/src/type/textCore.js @@ -1459,22 +1459,37 @@ function textCore(p5, fn) { Renderer.prototype.textAlign = function (h, v) { - // the setter - if (typeof h !== 'undefined') { + if (arguments.length === 0) { // the getter + return { + horizontal: this.states.textAlign, + vertical: this.states.textBaseline + }; + } + + // allow an object with horizontal and vertical properties + if (typeof h === 'object' && h !== null) { + if (h.hasOwnProperty('vertical')) { + v = h.vertical; + } + if (h.hasOwnProperty('horizontal')) { + h = h.horizontal; + } + } + + // horizontal value as separate argument + if (typeof h === 'string' || h instanceof String) { this.states.setValue('textAlign', h); - if (typeof v !== 'undefined') { - if (v === fn.CENTER) { - v = textCoreConstants._CTX_MIDDLE; - } - this.states.setValue('textBaseline', v); + } + + // vertical value as separate argument + if (typeof v === 'string' || v instanceof String) { + if (v === fn.CENTER) { + v = textCoreConstants._CTX_MIDDLE; } - return this._applyTextProperties(); + this.states.setValue('textBaseline', v); } - // the getter - return { - horizontal: this.states.textAlign, - vertical: this.states.textBaseline - }; + + return this._applyTextProperties(); }; Renderer.prototype._currentTextFont = function () { diff --git a/src/webgl/material.js b/src/webgl/material.js index 2e1bc0c7e1..3d0378e26e 100644 --- a/src/webgl/material.js +++ b/src/webgl/material.js @@ -2652,6 +2652,8 @@ function material(p5, fn) { * * Note: `textureMode()` can only be used in WebGL mode. * + * Calling `textureMode()` with no arguments returns the current texture mode. + * * @method textureMode * @param {(IMAGE|NORMAL)} mode either IMAGE or NORMAL. * @@ -2714,7 +2716,14 @@ function material(p5, fn) { * endShape(); * } */ + /** + * @method textureMode + * @return {(IMAGE|NORMAL)} The current texture mode, either IMAGE or NORMAL. + */ fn.textureMode = function (mode) { + if (typeof mode === 'undefined') { // getter + return this._renderer.states.textureMode; + } if (mode !== constants.IMAGE && mode !== constants.NORMAL) { console.warn( `You tried to set ${mode} textureMode only supports IMAGE & NORMAL `, @@ -2822,6 +2831,9 @@ function material(p5, fn) { * * Note: `textureWrap()` can only be used in WebGL mode. * + * Calling `textureWrap()` with no arguments returns an object with the current + * mode for x and y directions, as in `{ wrapX: CLAMP, wrapY: REPEAT }`. + * * @method textureWrap * @param {(CLAMP|REPEAT|MIRROR)} wrapX either CLAMP, REPEAT, or MIRROR * @param {(CLAMP|REPEAT|MIRROR)} [wrapY=wrapX] either CLAMP, REPEAT, or MIRROR @@ -2977,13 +2989,31 @@ function material(p5, fn) { * endShape(); * } */ + /** + * @method textureWrap + * @return {{x: (CLAMP|REPEAT|MIRROR), y: (CLAMP|REPEAT|MIRROR)}} The current texture wrapping for x and y. + */ fn.textureWrap = function (wrapX, wrapY = wrapX) { - this._renderer.states.setValue("textureWrapX", wrapX); - this._renderer.states.setValue("textureWrapY", wrapY); + if (typeof wrapX === 'undefined') { // getter + return { + x: this._renderer.states.textureWrapX, + y: this._renderer.states.textureWrapY + }; + } + // accept what is returned from the getter + if (wrapX.hasOwnProperty('x') && wrapX.hasOwnProperty('y')) { + wrapX = wrapX.x; + wrapY = wrapX.y; + } + this._renderer.states.setValue('textureWrapX', wrapX); + this._renderer.states.setValue('textureWrapY', wrapY); - for (const texture of this._renderer.textures.values()) { - texture.setWrapMode(wrapX, wrapY); + if (this._renderer.textures) { + for (const texture of this._renderer.textures.values()) { + texture.setWrapMode(wrapX, wrapY); + } } + return this; }; /** diff --git a/test/unit/core/properties.js b/test/unit/core/properties.js new file mode 100644 index 0000000000..e7def6900e --- /dev/null +++ b/test/unit/core/properties.js @@ -0,0 +1,68 @@ +import p5 from '../../../src/app.js'; + +suite('Set/get properties', function() { + + let p = new p5(function (sketch) { + sketch.setup = function () { }; + sketch.draw = function () { }; + }); + + let getters = { + fill: new p5.Color([100, 200, 50]), + stroke: new p5.Color([200, 100, 50, 100]), + tint: new p5.Color([100, 140, 50]), + + rectMode: p.CENTER, + colorMode: p.HSB, + blendMode: p.BLEND, + imageMode: p.CORNER, + ellipseMode: p.CORNER, + angleMode: p.DEGREES, + + strokeWeight: 6, + strokeCap: p.ROUND, + strokeJoin: p.MITER, + cursor: p.HAND, + pixelDensity: 1, + + bezierOrder: 2, + splineProperties: { ends: p.EXCLUDE, tightness: -5 }, + + textureMode: p.IMAGE, // 3D only + textureWrap: { x: p.REPEAT, y: p.MIRROR }, // 3D only + + textAlign: { horizontal: p.CENTER, vertical: p.CENTER }, + textLeading: 18, + textFont: 'arial', + textSize: 1, + textStyle: 1, + textWrap: p.WORD, + textDirection: 1, + textWeight: 1 + + // see #8278 + // rotate: p.PI, + // translate: { x: 1, y: 2 }, + // scale: { x: 1, y: 2 }, + // background: new p5.Color([100, 100, 50]) + }; + + Object.keys(getters).forEach(prop => { + let arg = getters[prop]; + test(`${prop}()`, function() { + + // setter + if (typeof arg === 'object' && !(arg instanceof p5.Color)) { + p[prop](...Object.values(arg)); // set with object + } + else if (Array.isArray(arg)) { + p[prop](...arg); // set with array + } + else { + p[prop](arg); // set with primitive or p5.Color + } + // getter + assert.strictEqual(p[prop]().toString(), arg.toString(), `${arg.toString()}`); + }); + }); +}); diff --git a/test/unit/webgl/p5.RendererGL.js b/test/unit/webgl/p5.RendererGL.js index b42562051f..4d3eaaf7aa 100644 --- a/test/unit/webgl/p5.RendererGL.js +++ b/test/unit/webgl/p5.RendererGL.js @@ -1492,31 +1492,52 @@ suite('p5.RendererGL', function() { suite('tint() in WEBGL mode', function() { test('default tint value is set and not null', function() { myp5.createCanvas(100, 100, myp5.WEBGL); - assert.deepEqual(myp5._renderer.states.tint, [255, 255, 255, 255]); + assert.deepEqual(myp5._renderer.states.tint + ._getRGBA([255, 255, 255, 255]), [255, 255, 255, 255]); }); + + test('tint value is modified correctly when tint() is called', function() { + + function assertColorEq(tint, colArray) { + assert.deepEqual(tint._getRGBA([255, 255, 255, 255]), colArray); + } + myp5.createCanvas(100, 100, myp5.WEBGL); + myp5.tint(0, 153, 204, 126); - assert.deepEqual(myp5._renderer.states.tint, [0, 153, 204, 126]); + assertColorEq(myp5._renderer.states.tint, [0, 153, 204, 126]); + myp5.tint(100, 120, 140); - assert.deepEqual(myp5._renderer.states.tint, [100, 120, 140, 255]); + assertColorEq(myp5._renderer.states.tint, [100, 120, 140, 255]); + myp5.tint('violet'); - assert.deepEqual(myp5._renderer.states.tint, [238, 130, 238, 255]); + // Note that in WEBGL mode, we don't convert color strings to arrays until the shader, + // so the tint state is still the string 'violet' at this point, not the array [238, 130, 238, 255]. + //assertDeepEqualColor(myp5._renderer.states.tint, [238, 130, 238, 255]); + assert.equal(myp5._renderer.states.tint, 'violet'); + myp5.tint(100); - assert.deepEqual(myp5._renderer.states.tint, [100, 100, 100, 255]); + assertColorEq(myp5._renderer.states.tint, [100, 100, 100, 255]); + myp5.tint(100, 126); - assert.deepEqual(myp5._renderer.states.tint, [100, 100, 100, 126]); + assertColorEq(myp5._renderer.states.tint, [100, 100, 100, 126]); + myp5.tint([100, 126, 0, 200]); - assert.deepEqual(myp5._renderer.states.tint, [100, 126, 0, 200]); + assertColorEq(myp5._renderer.states.tint, [100, 126, 0, 200]); + myp5.tint([100, 126, 0]); - assert.deepEqual(myp5._renderer.states.tint, [100, 126, 0, 255]); + assertColorEq(myp5._renderer.states.tint, [100, 126, 0, 255]); + myp5.tint([100]); - assert.deepEqual(myp5._renderer.states.tint, [100, 100, 100, 255]); + assertColorEq(myp5._renderer.states.tint, [100, 100, 100, 255]); + myp5.tint([100, 126]); - assert.deepEqual(myp5._renderer.states.tint, [100, 100, 100, 126]); + assertColorEq(myp5._renderer.states.tint, [100, 100, 100, 126]); + myp5.tint(myp5.color(255, 204, 0)); - assert.deepEqual(myp5._renderer.states.tint, [255, 204, 0, 255]); + assertColorEq(myp5._renderer.states.tint, [255, 204, 0, 255]); }); test('tint should be reset after draw loop', function() { @@ -1533,7 +1554,8 @@ suite('p5.RendererGL', function() { }; }); }).then(function(_tint) { - assert.deepEqual(_tint, [255, 255, 255, 255]); + assert.deepEqual(_tint._getRGBA([255, 255, 255, 255]), + [255, 255, 255, 255]); }); }); });