commit df591f57ff459fcfbe08ea4cbc7335fa448b7a73
parent 77b8f4b38b90b00ece693bb82dcbbfbfd07ef223
Author: Robert Russell <robertrussell.72001@gmail.com>
Date: Wed, 10 Jul 2024 15:09:11 -0700
Fix some bugs
- Blending was wrong
- Calculation of p and q used wrong x value
- I mixed up black and white in the test (this took embarrassingly
long to realize)
Diffstat:
| M | main.c | | | 84 | ++++++++++++++++++++++++++++++++++++++++++------------------------------------- |
1 file changed, 45 insertions(+), 39 deletions(-)
diff --git a/main.c b/main.c
@@ -58,7 +58,7 @@ void vec4_mul(Vec4 *r, f32 a, Vec4 v) { for (usize i = 0; i < 4; i++) (*r)[i] =
void
aff3_mul(Aff3 *r, Aff3 a, Aff3 b) {
- Aff3 rr = {
+ SET(*r, ((Aff3){
{
a[0][0] * b[0][0] + a[0][1] * b[1][0],
a[0][0] * b[0][1] + a[0][1] * b[1][1],
@@ -68,35 +68,31 @@ aff3_mul(Aff3 *r, Aff3 a, Aff3 b) {
a[1][0] * b[0][1] + a[1][1] * b[1][1],
a[1][0] * b[0][2] + a[1][1] * b[1][2] + a[1][2],
}
- };
- memcpy(r, rr, sizeof *r);
+ }));
}
void
aff3_app(Vec2 *r, Aff3 a, Vec2 b) {
- Vec2 rr = {
+ SET(*r, ((Vec2){
a[0][0] * b[0] + a[0][1] * b[1] + a[0][2],
a[1][0] * b[0] + a[1][1] * b[1] + a[1][2],
- };
- memcpy(r, rr, sizeof *r);
+ }));
}
void
aff3_scale(Aff3 *r, f32 x, f32 y) {
- Aff3 rr = {
+ SET(*r, ((Aff3){
{ x, 0.0f, 0.0f },
{ 0.0f, y, 0.0f },
- };
- memcpy(r, rr, sizeof *r);
+ }));
}
void
aff3_translate(Aff3 *r, f32 x, f32 y) {
- Aff3 rr = {
+ SET(*r, ((Aff3){
{ 1.0f, 0.0f, x },
{ 0.0f, 1.0f, y },
- };
- memcpy(r, rr, sizeof *r);
+ }));
}
// Find the affine transformation that maps src to dst.
@@ -125,20 +121,18 @@ quad2_transform(Quad2 *r, Aff3 t, Quad2 q) {
Vec2 v0, v1;
aff3_app(&v0, t, q[0]);
aff3_app(&v1, t, q[1]);
- Quad2 rr = {
+ SET(*r, ((Quad2){
{ MIN(v0[0], v1[0]), MIN(v0[1], v1[1]) },
{ MAX(v0[0], v1[0]), MAX(v0[1], v1[1]) },
- };
- memcpy(r, rr, sizeof *r);
+ }));
}
void
image2_bbox(Quad2 *r, Image2 image) {
- Quad2 rr = {
+ SET(*r, ((Quad2){
{ 0.0f, 0.0f },
{ (f32)image.w, (f32)image.h },
- };
- memcpy(r, rr, sizeof *r);
+ }));
}
int
@@ -165,7 +159,7 @@ fill(Image2 image, Quad2 src_view, Cycle2 cycle, Vec4 color) {
{ (f32)image.w, (f32)(image.h - i) },
};
- memset(values, 0, image.w * sizeof *deltas);
+ memset(values, 0, image.w * sizeof *values);
memset(deltas, 0, (image.w + 1) * sizeof *deltas);
for (usize k = 0; k < cycle.len; k++) {
@@ -225,7 +219,7 @@ fill(Image2 image, Quad2 src_view, Cycle2 cycle, Vec4 color) {
else
cl = c[1], cr = c[0];
- // ┌ ┐ ┘ └
+ // TODO: Diagrams for each case. ┌ ┐ ┘ └
// Case 1: The clipped edge is entirely to the right of the image.
if (row_bbox[1][0] <= cl[0]) {
@@ -278,7 +272,7 @@ fill(Image2 image, Quad2 src_view, Cycle2 cycle, Vec4 color) {
// Case 4:
{
Vec2 p;
- p[0] = MAX(cl[0], row_bbox[0][0]);
+ p[0] = MAX(coll + 1.0f, row_bbox[0][0]);
p[1] = dy_dx * (p[0] - cl[0]) + cl[1];
// Assume e goes from SW to NE. Then we can multiply areas
@@ -299,7 +293,7 @@ fill(Image2 image, Quad2 src_view, Cycle2 cycle, Vec4 color) {
values[j] += sign * area;
}
- f32 rect_area = p[0] - cl[0];
+ f32 rect_area = p[1] - cl[1];
// Account for the trapezoids in the middle pixels.
f32 trap_coll = MAX(coll + 1.0f, 0.0f);
@@ -316,7 +310,7 @@ fill(Image2 image, Quad2 src_view, Cycle2 cycle, Vec4 color) {
// Account for the pentagon in the right-most pixel.
if (cr[0] < row_bbox[1][0]) {
Vec2 q;
- q[0] = cr[0];
+ q[0] = colr;
q[1] = dy_dx * (q[0] - cr[0]) + cr[1];
// Compute area of trapezoid on top of the rectangle.
@@ -338,10 +332,13 @@ fill(Image2 image, Quad2 src_view, Cycle2 cycle, Vec4 color) {
for (usize j = 0; j < image.w; j++) {
s += deltas[j];
f32 a = clampf(values[j] + s, 0.0f, 1.0f);
- Vec4 *p = &image.pixels[i * image.h + j];
+
// TODO: More blending options.
- vec4_mul(p, 1.0f - a, *p);
- vec4_add(p, color, *p);
+ Vec4 c;
+ vec4_mul(&c, a, color);
+ Vec4 *p = &image.pixels[i * image.h + j];
+ vec4_mul(p, 1.0f - c[3], *p);
+ vec4_add(p, c, *p);
}
}
@@ -352,23 +349,23 @@ fill(Image2 image, Quad2 src_view, Cycle2 cycle, Vec4 color) {
void
image2_write_farbfeld(FILE *f, Image2 image) {
- usize w = image.w;
- usize h = image.h;
-
char header[16];
memcpy(header, "farbfeld", 8);
- r_writeb32(header + 8, w);
- r_writeb32(header + 12, h);
+ r_writeb32(header + 8, image.w);
+ r_writeb32(header + 12, image.h);
if (!fwrite(header, sizeof header, 1, f))
r_fatalf("image2_write_farbfeld: failed to write header");
- for (usize i = 0; i < h; i++) {
- for (usize j = 0; j < w; j++) {
- Vec4 *p = &image.pixels[i * w + j];
+ for (usize i = 0; i < image.h; i++) {
+ for (usize j = 0; j < image.w; j++) {
+ Vec4 *p = &image.pixels[i * image.w + j];
+ // TODO: Clamp pixel values?
u16 buf[4];
- for (usize k = 0; k < 3; k++)
- buf[k] = r_htob16(((*p)[k] / (*p)[3]) * (f32)U16_MAX);
+ for (usize k = 0; k < 3; k++) {
+ f32 a = (*p)[k] / (*p)[3]; // Un-premultiply alpha
+ buf[k] = r_htob16(a * (f32)U16_MAX);
+ }
buf[3] = r_htob16((*p)[3] * (f32)U16_MAX);
if (!fwrite(buf, sizeof buf, 1, f))
@@ -379,8 +376,8 @@ image2_write_farbfeld(FILE *f, Image2 image) {
int
main(void) {
- Vec4 white = { 0.0f, 0.0f, 0.0f, 1.0f };
- Vec4 black = { 1.0f, 1.0f, 1.0f, 1.0f };
+ Vec4 black = { 0.0f, 0.0f, 0.0f, 1.0f };
+ Vec4 white = { 1.0f, 1.0f, 1.0f, 1.0f };
Cycle2 cycle = {
.len = 3,
@@ -390,6 +387,15 @@ main(void) {
{ 0.5f, 1.0f },
},
};
+ //Cycle2 cycle = {
+ // .len = 4,
+ // .verts = (Vec2[]){
+ // { 0.2f, 0.2f },
+ // { 0.8f, 0.2f },
+ // { 0.8f, 0.8f },
+ // { 0.2f, 0.8f },
+ // },
+ //};
Quad2 cycle_view = {
{ 0.0f, 0.0f },
{ 1.0f, 1.0f },
@@ -402,7 +408,7 @@ main(void) {
};
for (usize i = 0; i < image.h; i++) {
for (usize j = 0; j < image.w; j++)
- memcpy(&image.pixels[i * image.h + j], white, sizeof white);
+ SET(image.pixels[i * image.h + j], white);
}
if (fill(image, cycle_view, cycle, black) < 0)