|
@@ -574,7 +574,7 @@ OLIVECDEF void olivec_line(Olivec_Canvas oc, int x1, int y1, int x2, int y2, uin
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-OLIVECDEF uint32_t mix_colors3(uint32_t c1, uint32_t c2, uint32_t c3, int t1, int t2, int t3, int den)
|
|
|
+OLIVECDEF uint32_t mix_colors3(uint32_t c1, uint32_t c2, uint32_t c3, int u1, int u2, int det)
|
|
|
{
|
|
|
// TODO: estimate how much overflows are an issue in integer only environment
|
|
|
int64_t r1 = OLIVEC_RED(c1);
|
|
@@ -592,11 +592,12 @@ OLIVECDEF uint32_t mix_colors3(uint32_t c1, uint32_t c2, uint32_t c3, int t1, in
|
|
|
int64_t b3 = OLIVEC_BLUE(c3);
|
|
|
int64_t a3 = OLIVEC_ALPHA(c3);
|
|
|
|
|
|
- if (den != 0) {
|
|
|
- int64_t r4 = (r1*t1 + r2*t2 + r3*t3)/den;
|
|
|
- int64_t g4 = (g1*t1 + g2*t2 + g3*t3)/den;
|
|
|
- int64_t b4 = (b1*t1 + b2*t2 + b3*t3)/den;
|
|
|
- int64_t a4 = (a1*t1 + a2*t2 + a3*t3)/den;
|
|
|
+ if (det != 0) {
|
|
|
+ int u3 = det - u1 - u2;
|
|
|
+ int64_t r4 = (r1*u1 + r2*u2 + r3*u3)/det;
|
|
|
+ int64_t g4 = (g1*u1 + g2*u2 + g3*u3)/det;
|
|
|
+ int64_t b4 = (b1*u1 + b2*u2 + b3*u3)/det;
|
|
|
+ int64_t a4 = (a1*u1 + a2*u2 + a3*u3)/det;
|
|
|
|
|
|
return OLIVEC_RGBA(r4, g4, b4, a4);
|
|
|
}
|
|
@@ -617,62 +618,14 @@ OLIVECDEF void barycentric(int x1, int y1, int x2, int y2, int x3, int y3,
|
|
|
OLIVECDEF void olivec_triangle3c(Olivec_Canvas oc, int x1, int y1, int x2, int y2, int x3, int y3,
|
|
|
uint32_t c1, uint32_t c2, uint32_t c3)
|
|
|
{
|
|
|
- if (y1 > y2) {
|
|
|
- OLIVEC_SWAP(int, x1, x2);
|
|
|
- OLIVEC_SWAP(int, y1, y2);
|
|
|
- OLIVEC_SWAP(int, c1, c2);
|
|
|
- }
|
|
|
-
|
|
|
- if (y2 > y3) {
|
|
|
- OLIVEC_SWAP(int, x2, x3);
|
|
|
- OLIVEC_SWAP(int, y2, y3);
|
|
|
- OLIVEC_SWAP(int, c2, c3);
|
|
|
- }
|
|
|
-
|
|
|
- if (y1 > y2) {
|
|
|
- OLIVEC_SWAP(int, x1, x2);
|
|
|
- OLIVEC_SWAP(int, y1, y2);
|
|
|
- OLIVEC_SWAP(int, c1, c2);
|
|
|
- }
|
|
|
-
|
|
|
- int dx12 = x2 - x1;
|
|
|
- int dy12 = y2 - y1;
|
|
|
- int dx13 = x3 - x1;
|
|
|
- int dy13 = y3 - y1;
|
|
|
-
|
|
|
- for (int y = y1; y <= y2; ++y) {
|
|
|
- // TODO: move boundary checks outside of loops in olivec_fill_triangle
|
|
|
- if (0 <= y && (size_t) y < oc.height) {
|
|
|
- int s1 = dy12 != 0 ? (y - y1)*dx12/dy12 + x1 : x1;
|
|
|
- int s2 = dy13 != 0 ? (y - y1)*dx13/dy13 + x1 : x1;
|
|
|
- if (s1 > s2) OLIVEC_SWAP(int, s1, s2);
|
|
|
- for (int x = s1; x <= s2; ++x) {
|
|
|
- if (0 <= x && (size_t) x < oc.width) {
|
|
|
- int u1, u2, det;
|
|
|
- barycentric(x1, y1, x2, y2, x3, y3, x, y, &u1, &u2, &det);
|
|
|
- uint32_t color = mix_colors3(c1, c2, c3, u1, u2, det - u1 - u2, det);
|
|
|
- olivec_blend_color(&OLIVEC_PIXEL(oc, x, y), color);
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- int dx32 = x2 - x3;
|
|
|
- int dy32 = y2 - y3;
|
|
|
- int dx31 = x1 - x3;
|
|
|
- int dy31 = y1 - y3;
|
|
|
-
|
|
|
- for (int y = y2; y <= y3; ++y) {
|
|
|
- if (0 <= y && (size_t) y < oc.height) {
|
|
|
- int s1 = dy32 != 0 ? (y - y3)*dx32/dy32 + x3 : x3;
|
|
|
- int s2 = dy31 != 0 ? (y - y3)*dx31/dy31 + x3 : x3;
|
|
|
- if (s1 > s2) OLIVEC_SWAP(int, s1, s2);
|
|
|
- for (int x = s1; x <= s2; ++x) {
|
|
|
- if (0 <= x && (size_t) x < oc.width) {
|
|
|
+ Olivec_Tri tri = olivec_tri_new(x1, y1, x2, y2, x3, y3);
|
|
|
+ if (olivec_tri_vert(&tri, oc.height, &y1, &y2)) {
|
|
|
+ for (int y = y1; y <= y2; ++y) {
|
|
|
+ if (olivec_tri_horz(&tri, oc.width, y, &x1, &x2)) {
|
|
|
+ for (int x = x1; x <= x2; ++x) {
|
|
|
int u1, u2, det;
|
|
|
- barycentric(x1, y1, x2, y2, x3, y3, x, y, &u1, &u2, &det);
|
|
|
- uint32_t color = mix_colors3(c1, c2, c3, u1, u2, det - u1 - u2, det);
|
|
|
- olivec_blend_color(&OLIVEC_PIXEL(oc, x, y), color);
|
|
|
+ olivec_tri_bary(&tri, x, y, &u1, &u2, &det);
|
|
|
+ olivec_blend_color(&OLIVEC_PIXEL(oc, x, y), mix_colors3(c1, c2, c3, u1, u2, det));
|
|
|
}
|
|
|
}
|
|
|
}
|
|
@@ -784,9 +737,9 @@ OLIVECDEF void olivec_triangle3uv(Olivec_Canvas oc, int x1, int y1, int x2, int
|
|
|
int u3 = det - u1 - u2;
|
|
|
float z = z1*u1/det + z2*u2/det + z3*(det - u1 - u2)/det;
|
|
|
Uv uv = olivec_uv(
|
|
|
- uv1.u*u1/det + uv2.u*u2/det + uv3.u*u3/det,
|
|
|
- uv1.v*u1/det + uv2.v*u2/det + uv3.v*u3/det
|
|
|
- );
|
|
|
+ uv1.u*u1/det + uv2.u*u2/det + uv3.u*u3/det,
|
|
|
+ uv1.v*u1/det + uv2.v*u2/det + uv3.v*u3/det
|
|
|
+ );
|
|
|
int texture_x = uv.u/z*texture.width;
|
|
|
if (texture_x < 0) texture_x = 0;
|
|
|
if ((size_t) texture_x >= texture.width) texture_x = texture.width - 1;
|
|
@@ -816,9 +769,9 @@ OLIVECDEF void olivec_triangle3uv(Olivec_Canvas oc, int x1, int y1, int x2, int
|
|
|
int u3 = det - u1 - u2;
|
|
|
float z = z1*u1/det + z2*u2/det + z3*(det - u1 - u2)/det;
|
|
|
Uv uv = olivec_uv(
|
|
|
- uv1.u*u1/det + uv2.u*u2/det + uv3.u*u3/det,
|
|
|
- uv1.v*u1/det + uv2.v*u2/det + uv3.v*u3/det
|
|
|
- );
|
|
|
+ uv1.u*u1/det + uv2.u*u2/det + uv3.u*u3/det,
|
|
|
+ uv1.v*u1/det + uv2.v*u2/det + uv3.v*u3/det
|
|
|
+ );
|
|
|
int texture_x = uv.u/z*texture.width;
|
|
|
if (texture_x < 0) texture_x = 0;
|
|
|
if ((size_t) texture_x >= texture.width) texture_x = texture.width - 1;
|
|
@@ -835,52 +788,11 @@ OLIVECDEF void olivec_triangle3uv(Olivec_Canvas oc, int x1, int y1, int x2, int
|
|
|
// TODO: AA for triangle
|
|
|
OLIVECDEF void olivec_triangle(Olivec_Canvas oc, int x1, int y1, int x2, int y2, int x3, int y3, uint32_t color)
|
|
|
{
|
|
|
- if (y1 > y2) {
|
|
|
- OLIVEC_SWAP(int, x1, x2);
|
|
|
- OLIVEC_SWAP(int, y1, y2);
|
|
|
- }
|
|
|
-
|
|
|
- if (y2 > y3) {
|
|
|
- OLIVEC_SWAP(int, x2, x3);
|
|
|
- OLIVEC_SWAP(int, y2, y3);
|
|
|
- }
|
|
|
-
|
|
|
- if (y1 > y2) {
|
|
|
- OLIVEC_SWAP(int, x1, x2);
|
|
|
- OLIVEC_SWAP(int, y1, y2);
|
|
|
- }
|
|
|
-
|
|
|
- int dx12 = x2 - x1;
|
|
|
- int dy12 = y2 - y1;
|
|
|
- int dx13 = x3 - x1;
|
|
|
- int dy13 = y3 - y1;
|
|
|
-
|
|
|
- for (int y = y1; y <= y2; ++y) {
|
|
|
- // TODO: move boundary checks outside of loops in olivec_fill_triangle
|
|
|
- if (0 <= y && (size_t) y < oc.height) {
|
|
|
- int s1 = dy12 != 0 ? (y - y1)*dx12/dy12 + x1 : x1;
|
|
|
- int s2 = dy13 != 0 ? (y - y1)*dx13/dy13 + x1 : x1;
|
|
|
- if (s1 > s2) OLIVEC_SWAP(int, s1, s2);
|
|
|
- for (int x = s1; x <= s2; ++x) {
|
|
|
- if (0 <= x && (size_t) x < oc.width) {
|
|
|
- olivec_blend_color(&OLIVEC_PIXEL(oc, x, y), color);
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- int dx32 = x2 - x3;
|
|
|
- int dy32 = y2 - y3;
|
|
|
- int dx31 = x1 - x3;
|
|
|
- int dy31 = y1 - y3;
|
|
|
-
|
|
|
- for (int y = y2; y <= y3; ++y) {
|
|
|
- if (0 <= y && (size_t) y < oc.height) {
|
|
|
- int s1 = dy32 != 0 ? (y - y3)*dx32/dy32 + x3 : x3;
|
|
|
- int s2 = dy31 != 0 ? (y - y3)*dx31/dy31 + x3 : x3;
|
|
|
- if (s1 > s2) OLIVEC_SWAP(int, s1, s2);
|
|
|
- for (int x = s1; x <= s2; ++x) {
|
|
|
- if (0 <= x && (size_t) x < oc.width) {
|
|
|
+ Olivec_Tri tri = olivec_tri_new(x1, y1, x2, y2, x3, y3);
|
|
|
+ if (olivec_tri_vert(&tri, oc.height, &y1, &y2)) {
|
|
|
+ for (int y = y1; y <= y2; ++y) {
|
|
|
+ if (olivec_tri_horz(&tri, oc.width, y, &x1, &x2)) {
|
|
|
+ for (int x = x1; x <= x2; ++x) {
|
|
|
olivec_blend_color(&OLIVEC_PIXEL(oc, x, y), color);
|
|
|
}
|
|
|
}
|
|
@@ -917,8 +829,10 @@ OLIVECDEF void olivec_sprite_blend(Olivec_Canvas oc, int x, int y, int w, int h,
|
|
|
Olivec_Normalized_Rect nr = {0};
|
|
|
if (!olivec_normalize_rect(x, y, w, h, oc.width, oc.height, &nr)) return;
|
|
|
|
|
|
- int xa = nr.ox1; if (w < 0) xa = nr.ox2;
|
|
|
- int ya = nr.oy1; if (h < 0) ya = nr.oy2;
|
|
|
+ int xa = nr.ox1;
|
|
|
+ if (w < 0) xa = nr.ox2;
|
|
|
+ int ya = nr.oy1;
|
|
|
+ if (h < 0) ya = nr.oy2;
|
|
|
for (int y = nr.y1; y <= nr.y2; ++y) {
|
|
|
for (int x = nr.x1; x <= nr.x2; ++x) {
|
|
|
size_t nx = (x - xa)*((int) sprite.width)/w;
|
|
@@ -936,8 +850,10 @@ OLIVECDEF void olivec_sprite_copy(Olivec_Canvas oc, int x, int y, int w, int h,
|
|
|
Olivec_Normalized_Rect nr = {0};
|
|
|
if (!olivec_normalize_rect(x, y, w, h, oc.width, oc.height, &nr)) return;
|
|
|
|
|
|
- int xa = nr.ox1; if (w < 0) xa = nr.ox2;
|
|
|
- int ya = nr.oy1; if (h < 0) ya = nr.oy2;
|
|
|
+ int xa = nr.ox1;
|
|
|
+ if (w < 0) xa = nr.ox2;
|
|
|
+ int ya = nr.oy1;
|
|
|
+ if (h < 0) ya = nr.oy2;
|
|
|
for (int y = nr.y1; y <= nr.y2; ++y) {
|
|
|
for (int x = nr.x1; x <= nr.x2; ++x) {
|
|
|
size_t nx = (x - xa)*((int) sprite.width)/w;
|
|
@@ -958,27 +874,32 @@ OLIVECDEF Uv olivec_uv(float u, float v)
|
|
|
Olivec_Tri olivec_tri_new(int x1, int y1, int x2, int y2, int x3, int y3)
|
|
|
{
|
|
|
Olivec_Tri tri = {
|
|
|
- .order = {0, 1, 2},
|
|
|
.xs = {x1, x2, x3},
|
|
|
.ys = {y1, y2, y3},
|
|
|
};
|
|
|
|
|
|
+ int order[3] = {0, 1, 2};
|
|
|
+
|
|
|
if (tri.ys[0] > tri.ys[1]) {
|
|
|
OLIVEC_SWAP(int, tri.xs[0], tri.xs[1]);
|
|
|
OLIVEC_SWAP(int, tri.ys[0], tri.ys[1]);
|
|
|
- OLIVEC_SWAP(int, tri.order[0], tri.order[1]);
|
|
|
+ OLIVEC_SWAP(int, order[0], order[1]);
|
|
|
}
|
|
|
|
|
|
if (tri.ys[1] > tri.ys[2]) {
|
|
|
OLIVEC_SWAP(int, tri.xs[1], tri.xs[2]);
|
|
|
OLIVEC_SWAP(int, tri.ys[1], tri.ys[2]);
|
|
|
- OLIVEC_SWAP(int, tri.order[1], tri.order[2]);
|
|
|
+ OLIVEC_SWAP(int, order[1], order[2]);
|
|
|
}
|
|
|
|
|
|
if (tri.ys[0] > tri.ys[1]) {
|
|
|
OLIVEC_SWAP(int, tri.xs[0], tri.xs[1]);
|
|
|
OLIVEC_SWAP(int, tri.ys[0], tri.ys[1]);
|
|
|
- OLIVEC_SWAP(int, tri.order[0], tri.order[1]);
|
|
|
+ OLIVEC_SWAP(int, order[0], order[1]);
|
|
|
+ }
|
|
|
+
|
|
|
+ for (int i = 0; i < 3; ++i) {
|
|
|
+ tri.order[order[i]] = i;
|
|
|
}
|
|
|
|
|
|
return tri;
|
|
@@ -1006,7 +927,7 @@ bool olivec_tri_horz(Olivec_Tri *tri, size_t width, int y, int *s1, int *s2)
|
|
|
int y2 = tri->ys[1];
|
|
|
int y3 = tri->ys[2];
|
|
|
|
|
|
- if (y1 <= y && y < y2) {
|
|
|
+ if (y1 <= y && y <= y2) {
|
|
|
// upper triangle
|
|
|
int dx12 = x2 - x1;
|
|
|
int dy12 = y2 - y1;
|
|
@@ -1014,7 +935,7 @@ bool olivec_tri_horz(Olivec_Tri *tri, size_t width, int y, int *s1, int *s2)
|
|
|
int dy13 = y3 - y1;
|
|
|
*s1 = dy12 != 0 ? (y - y1)*dx12/dy12 + x1 : x1;
|
|
|
*s2 = dy13 != 0 ? (y - y1)*dx13/dy13 + x1 : x1;
|
|
|
- } else if (y2 <= y && y <= y3) {
|
|
|
+ } else if (y2 < y && y <= y3) {
|
|
|
// bottom triangle
|
|
|
int dx32 = x2 - x3;
|
|
|
int dy32 = y2 - y3;
|