Skip to content

Commit

Permalink
Add vgerRadialGradient
Browse files Browse the repository at this point in the history
  • Loading branch information
wtholliday committed May 29, 2024
1 parent b1c53a9 commit f07edd8
Show file tree
Hide file tree
Showing 6 changed files with 96 additions and 8 deletions.
9 changes: 9 additions & 0 deletions Sources/vger/include/vger.h
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,15 @@ vgerPaintIndex vgerLinearGradient(vgerContext vg,
vector_float4 outerColor,
float glow);

/// Create a paint for a linear gradient. Returns paint index. Paints are cleared each frame.
vgerPaintIndex vgerRadialGradient(vgerContext vg,
vector_float2 center,
float innerRadius,
float outerRadius,
vector_float4 innerColor,
vector_float4 outerColor,
float glow);

/// Create a paint using a texture image. Returns paint index. Paints are cleared each frame.
vgerPaintIndex vgerImagePattern(vgerContext vg,
vector_float2 origin,
Expand Down
35 changes: 28 additions & 7 deletions Sources/vger/paint.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,16 @@

#include "metal_compat.h"

enum vgerPaintType {
vgerPaintTypeLinearGradient,
vgerPaintTypeRadialGradient,
vgerPaintTypeImagePattern,
};

struct vgerPaint {

vgerPaintType type;

#ifdef __METAL_VERSION__
float3x3 xform;
#else
Expand All @@ -16,6 +24,12 @@ struct vgerPaint {

float4 outerColor;

/// Inner radius for radial gradients.
float innerRadius;

/// Inner radius for radial gradients.
float outerRadius;

/// Render into the glow layer?
float glow;

Expand All @@ -29,12 +43,19 @@ struct vgerPaint {

inline float4 applyPaint(const DEVICE vgerPaint& paint, float2 p) {

float d = clamp((paint.xform * float3{p.x, p.y, 1.0}).x, 0.0, 1.0);

#ifdef __METAL_VERSION__
return mix(paint.innerColor, paint.outerColor, d);
#else
return simd_mix(paint.innerColor, paint.outerColor, d);
#endif
switch (paint.type) {
case vgerPaintTypeLinearGradient:
{
float d = clamp((paint.xform * float3{p.x, p.y, 1.0}).x, 0.0, 1.0);
return mix(paint.innerColor, paint.outerColor, d);
}
case vgerPaintTypeRadialGradient:
{
float d = clamp(length( (paint.xform * float3{p.x, p.y, 1.0}).xy), paint.innerRadius, paint.outerRadius);
return mix(paint.innerColor, paint.outerColor, (d-paint.innerRadius) / (paint.outerRadius - paint.innerRadius));
}
default:
return 0;
}

}
11 changes: 11 additions & 0 deletions Sources/vger/vger.mm
Original file line number Diff line number Diff line change
Expand Up @@ -939,6 +939,7 @@ void vgerSetLayer(vgerContext vg, int layer) {
vgerPaintIndex vgerColorPaint(vgerContext vg, float4 color) {

vgerPaint p;
p.type = vgerPaintTypeLinearGradient;
p.xform = matrix_identity_float3x3;
p.innerColor = color;
p.outerColor = color;
Expand All @@ -959,6 +960,16 @@ vgerPaintIndex vgerLinearGradient(vgerContext vg,

}

vgerPaintIndex vgerRadialGradient(vgerContext vg,
vector_float2 center,
float innerRadius,
float outerRadius,
vector_float4 innerColor,
vector_float4 outerColor,
float glow) {
return vg->addPaint(makeRadialGradient(center, innerRadius, outerRadius, innerColor, outerColor, glow));
}

vgerPaintIndex vgerImagePattern(vgerContext vg,
float2 origin,
float2 size,
Expand Down
28 changes: 28 additions & 0 deletions Sources/vger/vger_private.h
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,7 @@ inline vgerPaint makeLinearGradient(float2 start,
float glow) {

vgerPaint p;
p.type = vgerPaintTypeLinearGradient;

// Calculate transform aligned to the line
float2 d = end - start;
Expand All @@ -206,6 +207,32 @@ inline vgerPaint makeLinearGradient(float2 start,
return p;
}

inline vgerPaint makeRadialGradient(float2 center,
float innerRadius,
float outerRadius,
float4 innerColor,
float4 outerColor,
float glow) {

vgerPaint p;
p.type = vgerPaintTypeRadialGradient;

p.xform = inverse(float3x3{
float3{1, 0, 0},
float3{0, 1, 0},
float3{center.x, center.y, 1}
});

p.innerRadius = innerRadius;
p.outerRadius = outerRadius;
p.innerColor = innerColor;
p.outerColor = outerColor;
p.image = -1;
p.glow = glow;

return p;
}

inline vgerPaint makeImagePattern(float2 origin,
float2 size,
float angle,
Expand All @@ -214,6 +241,7 @@ inline vgerPaint makeImagePattern(float2 origin,
float alpha) {

vgerPaint p;
p.type = vgerPaintTypeImagePattern;
p.image = image.index;
p.flipY = flipY;

Expand Down
Binary file modified Tests/vgerTests/images/vger_basics.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
21 changes: 20 additions & 1 deletion Tests/vgerTests/vgerTests.mm
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ static void SplitBezier(float t,
}

- (void) testSizes {
XCTAssertEqual(sizeof(vgerPaint), 96);
XCTAssertEqual(sizeof(vgerPaint), 128);
XCTAssertEqual(sizeof(vgerPrim), 96);
}

Expand All @@ -137,6 +137,7 @@ - (void) testBasic {
vgerFillCircle(vg, float2{256, 256}, 40, cyan);
vgerStrokeBezier(vg, {{256,256}, {256,384}, {384,384}}, 1, white);
vgerFillRect(vg, float2{400,100}, float2{450,150}, 10, vgerLinearGradient(vg, float2{400,100}, float2{450, 150}, float4{0,1,1,1}, float4{1,0,1,1}, 0));
vgerFillRect(vg, float2{400,200}, float2{450,250}, 10, vgerRadialGradient(vg, float2{425,225}, 10, 40, float4{0,1,1,1}, float4{1,0,1,1}, 0));
vgerStrokeArc(vg, float2{100,400}, 30, 3, theta, ap, white);
vgerStrokeSegment(vg, float2{100,100}, float2{200,200}, 10, magenta);
vgerStrokeRect(vg, float2{400,100}, float2{450,150}, 10, 2.0, magenta);
Expand Down Expand Up @@ -553,6 +554,24 @@ - (void) testPaint {
v = p.xform * float3{20,20,1};
XCTAssertTrue(equal(v, float3{1,1,1}));

p = makeRadialGradient(float2(0), 0, 1, float4(0), float4(1), 0);

XCTAssertTrue(equal(applyPaint(p, float2{0,0}), float4(0)));
XCTAssertTrue(equal(applyPaint(p, float2{1,0}), float4(1)));
XCTAssertTrue(equal(applyPaint(p, float2{0,1}), float4(1)));
XCTAssertTrue(equal(applyPaint(p, float2{-1,0}), float4(1)));
XCTAssertTrue(equal(applyPaint(p, float2{0,-1}), float4(1)));
XCTAssertTrue(equal(applyPaint(p, float2{1,1}), float4(1)));

p = makeRadialGradient(float2{1,0}, 0, 1, float4(0), float4(1), 0);
XCTAssertTrue(equal(applyPaint(p, float2{1,0}), float4(0)));
XCTAssertTrue(equal(applyPaint(p, float2{1,1}), float4(1)));

p = makeRadialGradient(float2{425,225}, 10, 40, float4{0,1,1,1}, float4{1,0,1,1}, 0);

c = applyPaint(p, float2{425,225});
XCTAssertTrue(equal(c, float4{0,1,1,1}));

}

- (void) testTextAlgin {
Expand Down

0 comments on commit f07edd8

Please sign in to comment.