1
0
Fork 0
mirror of https://git.coom.tech/drummyfish/small3dlib.git synced 2024-11-23 20:59:58 +01:00

Fix discontinities in long triangles

This commit is contained in:
Miloslav Číž 2019-04-28 20:53:02 +02:00
parent e0467330e9
commit c0a0270c96
2 changed files with 32 additions and 11 deletions

38
s3l.h
View file

@ -85,6 +85,9 @@ typedef int32_t S3L_Unit; /**< Units of measurement in 3D space. There is
it will overflow. Also other things it will overflow. Also other things
may overflow, so rather don't do it. */ may overflow, so rather don't do it. */
#define S3L_NONZERO(value) ((value) != 0 ? (value) : 1) /**< prevents division
by zero */
#define S3L_SIN_TABLE_LENGTH 128 #define S3L_SIN_TABLE_LENGTH 128
static const S3L_Unit S3L_sinTable[S3L_SIN_TABLE_LENGTH] = static const S3L_Unit S3L_sinTable[S3L_SIN_TABLE_LENGTH] =
{ {
@ -722,9 +725,9 @@ void S3L_drawTriangle(
#undef handleLR #undef handleLR
S3L_ScreenCoord splitY; // Y at which one side (L or R) changes S3L_ScreenCoord splitY; // Y of the vertically middle point of the triangle
S3L_ScreenCoord endY; // bottom Y of the whole triangle S3L_ScreenCoord endY; // bottom Y of the whole triangle
int splitOnLeft; // whether split happens on L or R int splitOnLeft; // whether splitY happens on L or R side
if (rPointY <= lPointY) if (rPointY <= lPointY)
{ {
@ -761,6 +764,11 @@ void S3L_drawTriangle(
int16_t helperDxAbs; int16_t helperDxAbs;
/* init side for the algorithm, params:
v - which side (l or r)
p1 - point from (t, l or r)
p2 - point to (t, l or r)
down - whether going top-down or bottom-up */
#define initSide(v,p1,p2,down)\ #define initSide(v,p1,p2,down)\
v##X = p1##PointX;\ v##X = p1##PointX;\
v##Dx = p2##PointX - p1##PointX;\ v##Dx = p2##PointX - p1##PointX;\
@ -791,10 +799,14 @@ void S3L_drawTriangle(
initSide(r,t,r,1) initSide(r,t,r,1)
initSide(l,t,l,1) initSide(l,t,l,1)
while (currentY <= endY) S3L_Unit xFrom_prev = tPointX; // helper vars, hold previous values of xFrom
{ S3L_Unit xTo_prev = tPointX; // and xTo (declared later) to prevent
if (currentY == splitY) // discontinuities
while (currentY <= endY) // draw the triangle from top to bottom
{ {
if (currentY == splitY) // reached a vertical split of the triangle?
{ // then reinit one side
if (splitOnLeft) if (splitOnLeft)
{ {
initSide(l,l,r,0); initSide(l,l,r,0);
@ -821,15 +833,20 @@ void S3L_drawTriangle(
p.y = currentY; p.y = currentY;
// draw the line // draw the horizontal line
S3L_Unit tMax = rX - lX; S3L_Unit xFrom = lX < (xTo_prev + 1) ? lX : (xTo_prev + 1);
tMax = tMax != 0 ? tMax : 1; // prevent division by zero S3L_Unit xTo = rX > (xFrom_prev - 1) ? rX : (xFrom_prev - 1);
/* ^ these conditions prevent discontinuities when drawing
"long" triangles (thinner than 1 px) */
S3L_Unit tMax = xTo - xFrom;
tMax = S3L_NONZERO(tMax); // prevent division by zero
S3L_Unit t1 = 0; S3L_Unit t1 = 0;
S3L_Unit t2 = tMax; S3L_Unit t2 = tMax;
for (S3L_ScreenCoord x = lX; x <= rX; ++x) for (S3L_ScreenCoord x = xFrom; x <= xTo; ++x)
{ {
*barycentric0 = S3L_interpolateFrom0(rSideUnitPos,t1,tMax); *barycentric0 = S3L_interpolateFrom0(rSideUnitPos,t1,tMax);
*barycentric1 = S3L_interpolateFrom0(lSideUnitPos,t2,tMax); *barycentric1 = S3L_interpolateFrom0(lSideUnitPos,t2,tMax);
@ -848,6 +865,9 @@ void S3L_drawTriangle(
lSideUnitPos += lSideUnitStep; lSideUnitPos += lSideUnitStep;
rSideUnitPos += rSideUnitStep; rSideUnitPos += rSideUnitStep;
xFrom_prev = xFrom;
xTo_prev = xTo;
++currentY; ++currentY;
} }

View file

@ -76,7 +76,8 @@ conf.mode = S3L_MODE_TRIANGLES;
y2 = test_coords[6 * c + 5]; y2 = test_coords[6 * c + 5];
int cent = (x0 + x1 + x2) / 3.0; int cent = (x0 + x1 + x2) / 3.0;
x2 = cent + (x2 - cent) * sin(frame * 0.01) * 2; x2 = cent + (x2 - cent) * sin(frame * 0.001) * 2;
//x2 = cent + (x2 - cent) * sin(600 * 0.001) * 2;
S3L_drawTriangle(x0,y0,x1,y1,x2,y2,conf,0); S3L_drawTriangle(x0,y0,x1,y1,x2,y2,conf,0);