Skip to content

Commit

Permalink
Mirrored rendering for negative dimensions with rect().
Browse files Browse the repository at this point in the history
ellipse() and arc() use absolute values
  • Loading branch information
martinleopold committed Nov 15, 2024
1 parent 0923553 commit ebd00c2
Show file tree
Hide file tree
Showing 7 changed files with 25 additions and 11 deletions.
8 changes: 3 additions & 5 deletions src/core/helpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,12 @@ function modeAdjust(a, b, c, d, mode) {
if (mode === constants.CORNER) {

// CORNER mode already corresponds to a bounding box (top-left corner, width, height).
// Negative dimensions (width and/or height) result in 'flipping' the shape.
if (c < 0) { c = -c; a -= c; } // Negative width: Move shape to the left (flip left)
if (d < 0) { d = -d; b -= d; } // Negative height: Move shape up (flip up)
// For negative widhts or heights, the absolute value is used.
bbox = {
x: a,
y: b,
w: c,
h: d
w: Math.abs(c),
h: Math.abs(d)
};

} else if (mode === constants.CORNERS) {
Expand Down
9 changes: 9 additions & 0 deletions src/core/shape/2d_primitives.js
Original file line number Diff line number Diff line change
Expand Up @@ -1339,6 +1339,15 @@ p5.prototype._renderRect = function() {
this._renderer._rectMode
);

// For the default rectMode (CORNER), restore a possible negative width/height
// removed by modeAdjust(). This results in flipped/mirrored rendering,
// which is especially noticable when using WEGBL rendering and texture().
// Note that this behavior only applies to rect(), NOT to ellipse() and arc().
if (this._renderer._rectMode === constants.CORNER) {
vals.w = arguments[2];
vals.h = arguments[3];
}

const args = [vals.x, vals.y, vals.w, vals.h];
// append the additional arguments (either cornder radii, or
// segment details) to the argument list
Expand Down
19 changes: 13 additions & 6 deletions test/unit/visual/cases/shape_modes.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,12 @@ function shapeCorners(p5, shape, mode, x1, y1, x2, y2) {
// Don't use abs(), so we get negative values as well
let w = x2 - x1; // w
let h = y2 - y1; // h
// With mode CORNER, negative widths/heights result in mirrored/flipped shapes
// In this case, adjust position so the shape is in line with the other cases
if (w < 0) { x += (-w); } // Move right
if (h < 0) { y += (-h); } // Move down
// With mode CORNER, rects with negative widths/heights result in mirrored/flipped rendering
// In this case, adjust position so the rect is in line with the other cases
if (shape === 'rect') {
if (w < 0) { x += (-w); } // Move right
if (h < 0) { y += (-h); } // Move down
}
x1 = x; y1 = y; x2 = w; y2 = h;
} else if (mode === p5.CENTER) {
// Find center
Expand Down Expand Up @@ -124,10 +126,11 @@ visualSuite('Shape Modes', function(...args) {

/*
An extra test suite specific to shape mode CORNER and negative dimensions.
Negative width should result in the shape flipped horizontally (to the left).
Negative height should result in the shape flipped vertically (up).
For rect, negative widths/heights result in flipped rendering (horizontally/vertically)
For ellipse and arc, using negative widths/heights has no effect (the absolute value is used)
*/
visualSuite('Negative dimensions', function() {
// Negative widths/height result in flipped rects.
visualTest('rect', function(p5, screenshot) {
p5.createCanvas(50, 50);
p5.translate(p5.width/2, p5.height/2);
Expand All @@ -141,6 +144,8 @@ visualSuite('Shape Modes', function(...args) {
p5.rect(0, 0, -20, -10);
screenshot();
});
// Since negative widths/heights are used with their absolute value,
// ellipses are drawn on top of each other, blue one last
visualTest('ellipse', function(p5, screenshot) {
p5.createCanvas(50, 50);
p5.translate(p5.width/2, p5.height/2);
Expand All @@ -154,6 +159,8 @@ visualSuite('Shape Modes', function(...args) {
p5.ellipse(0, 0, -20, -10);
screenshot();
});
// Since negative widths/heights are used with their absolute value,
// arcs are drawn on top of each other, blue one last.
visualTest('arc', function(p5, screenshot) {
p5.createCanvas(50, 50);
p5.translate(p5.width/2, p5.height/2);
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit ebd00c2

Please sign in to comment.