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

Rework triangle drawing interface

This commit is contained in:
Miloslav Číž 2019-05-09 19:06:21 +02:00
parent fcd7956158
commit 48c44943e9
2 changed files with 78 additions and 39 deletions

113
s3l.h
View file

@ -290,7 +290,7 @@ typedef struct
} S3L_Vec4;
#define S3L_writeVec4(v)\
printf("Vec4: %d %d %d %d\n",(v.x),(v.y),(v.z),(v.w))
printf("Vec4: %d %d %d %d\n",((v).x),((v).y),((v).z),((v).w))
static inline void S3L_initVec4(S3L_Vec4 *v)
{
@ -800,12 +800,31 @@ int S3L_bresenhamStep(S3L_BresenhamState *state)
return state->steps >= 0;
}
static inline void S3L_mapProjectionPlaneToScreen(S3L_Vec4 point,
S3L_ScreenCoord *screenX, S3L_ScreenCoord *screenY)
{
*screenX =
S3L_HALF_RESOLUTION_X +
(point.x * S3L_HALF_RESOLUTION_X) / S3L_FRACTIONS_PER_UNIT;
*screenY =
S3L_HALF_RESOLUTION_Y -
(point.y * S3L_HALF_RESOLUTION_X) / S3L_FRACTIONS_PER_UNIT;
}
void _S3L_drawFilledTriangle(
S3L_ScreenCoord x0, S3L_ScreenCoord y0, S3L_Unit depth0,
S3L_ScreenCoord x1, S3L_ScreenCoord y1, S3L_Unit depth1,
S3L_ScreenCoord x2, S3L_ScreenCoord y2, S3L_Unit depth2,
S3L_Vec4 point0,
S3L_Vec4 point1,
S3L_Vec4 point2,
const S3L_Camera *camera,
S3L_PixelInfo *p)
{
S3L_ScreenCoord x0, y0, x1, y1, x2, y2;
S3L_mapProjectionPlaneToScreen(point0,&x0,&y0);
S3L_mapProjectionPlaneToScreen(point1,&x1,&y1);
S3L_mapProjectionPlaneToScreen(point2,&x2,&y2);
S3L_ScreenCoord
tPointX, tPointY, // top triangle point coords
lPointX, lPointY, // left triangle point coords
@ -1042,20 +1061,29 @@ void _S3L_drawFilledTriangle(
#undef stepSide
}
void S3L_drawTriangle(
S3L_ScreenCoord x0, S3L_ScreenCoord y0, S3L_Unit depth0,
S3L_ScreenCoord x1, S3L_ScreenCoord y1, S3L_Unit depth1,
S3L_ScreenCoord x2, S3L_ScreenCoord y2, S3L_Unit depth2,
S3L_DrawConfig config,
/**
Draws a triangle according to given config. The vertices are specified in
projection-plane space (NOT screen space!) -- they wll be mapped to screen
space by thies function. If perspective correction is enabled, each vertex
has to have a depth (Z position in camera space) specified in the Z
component.
*/
void S3L_drawTriangle(S3L_Vec4 point0, S3L_Vec4 point1, S3L_Vec4 point2,
const S3L_DrawConfig *config, const S3L_Camera *camera,
S3L_Index triangleID)
{
if (config.backfaceCulling != S3L_BACKFACE_CULLING_NONE)
{
int cw = // matrix determinant
x0 * y1 + y0 * x2 + x1 * y2 - y1 * x2 - y0 * x1 - x0 * y2 > 0;
if ((config.backfaceCulling == S3L_BACKFACE_CULLING_CW && !cw) ||
(config.backfaceCulling == S3L_BACKFACE_CULLING_CCW && cw))
if (config->backfaceCulling != S3L_BACKFACE_CULLING_NONE)
{
int32_t winding = // determines CW or CCW
(
(point1.y - point0.y) * (point2.x - point1.x) -
(point1.x - point0.x) * (point2.y - point1.y)
);
if ((config->backfaceCulling == S3L_BACKFACE_CULLING_CW && winding < 0) ||
(config->backfaceCulling == S3L_BACKFACE_CULLING_CCW && winding >= 0))
return;
}
@ -1063,11 +1091,23 @@ void S3L_drawTriangle(
S3L_initPixelInfo(&p);
p.triangleID = triangleID;
if (config.mode == S3L_MODE_TRIANGLES) // triangle mode
if (config->mode == S3L_MODE_TRIANGLES) // triangle mode
{
_S3L_drawFilledTriangle(x0,y0,depth0,x1,y1,depth1,x2,y2,depth2,&p);
/* This function will perform the mapping to screen space itself, it needs
the original values, hence no conversion here. */
_S3L_drawFilledTriangle(point0,point1,point2,camera,&p);
return;
}
else if (config.mode == S3L_MODE_LINES) // line mode
// map to screen space
S3L_ScreenCoord x0, y0, x1, y1, x2, y2;
S3L_mapProjectionPlaneToScreen(point0,&x0,&y0);
S3L_mapProjectionPlaneToScreen(point1,&x1,&y1);
S3L_mapProjectionPlaneToScreen(point2,&x2,&y2);
if (config->mode == S3L_MODE_LINES) // line mode
{
S3L_BresenhamState line;
S3L_Unit lineLen;
@ -1165,15 +1205,10 @@ void S3L_makeCameraMatrix(S3L_Transform3D cameraTransform, S3L_Mat4 *m)
m);
}
static inline void S3L_mapCameraToScreen(S3L_Vec4 point, S3L_Camera *camera,
S3L_ScreenCoord *screenX, S3L_ScreenCoord *screenY)
static inline void S3L_zDivide(S3L_Vec4 *vector)
{
*screenX =
S3L_HALF_RESOLUTION_X + (point.x * S3L_HALF_RESOLUTION_X) / point.z;
*screenY =
S3L_HALF_RESOLUTION_Y - (point.y * S3L_HALF_RESOLUTION_X) / point.z;
// ^ S3L_FRACTIONS_PER_UNIT cancel out
vector->x = (vector->x * S3L_FRACTIONS_PER_UNIT) / S3L_nonZero(vector->z);
vector->y = (vector->y * S3L_FRACTIONS_PER_UNIT) / S3L_nonZero(vector->z);
}
void S3L_drawModelIndexed(
@ -1181,14 +1216,13 @@ void S3L_drawModelIndexed(
const S3L_Index triangleVertexIndices[],
uint16_t triangleCount,
S3L_Transform3D modelTransform,
S3L_Camera camera,
S3L_DrawConfig config)
const S3L_Camera *camera,
const S3L_DrawConfig *config)
{
S3L_Index triangleIndex = 0;
S3L_Index coordIndex = 0;
S3L_ScreenCoord sX0, sY0, sX1, sY1, sX2, sY2, d0, d1, d2;
S3L_Vec4 pointModel;
S3L_Vec4 pointModel, transformed0, transformed1, transformed2;
S3L_Unit indexIndex;
pointModel.w = S3L_FRACTIONS_PER_UNIT; // has to be "1.0" for translation
@ -1196,12 +1230,12 @@ void S3L_drawModelIndexed(
S3L_Mat4 mat1, mat2;
S3L_makeWorldMatrix(modelTransform,&mat1);
S3L_makeCameraMatrix(camera.transform,&mat2);
S3L_makeCameraMatrix(camera->transform,&mat2);
S3L_mat4Xmat4(&mat1,&mat2);
while (triangleIndex < triangleCount)
{
#define mapCoords(n)\
#define project(n)\
indexIndex = triangleVertexIndices[coordIndex] * 3;\
pointModel.x = coords[indexIndex];\
++indexIndex; /* TODO: put into square brackets? */\
@ -1210,14 +1244,17 @@ void S3L_drawModelIndexed(
pointModel.z = coords[indexIndex];\
++coordIndex;\
S3L_vec4Xmat4(&pointModel,&mat1);\
d##n = pointModel.z;\
S3L_mapCameraToScreen(pointModel,&camera,&sX##n,&sY##n);
transformed##n.x = pointModel.x;\
transformed##n.y = pointModel.y;\
transformed##n.z = pointModel.z;\
S3L_zDivide(&transformed##n);
mapCoords(0)
mapCoords(1)
mapCoords(2)
project(0)
project(1)
project(2)
S3L_drawTriangle(sX0,sY0,d0,sX1,sY1,d1,sX2,sY2,d2,config,triangleIndex);
S3L_drawTriangle(transformed0,transformed1,transformed2,config,camera,
triangleIndex);
++triangleIndex;
}

View file

@ -117,10 +117,12 @@ void draw()
{
clearScreen();
//frame = 853;
modelTransform.rotation.z = frame * 0.1;
modelTransform.rotation.x = frame * 0.3;
S3L_drawModelIndexed(ver,tri,12,modelTransform,camera,conf);
S3L_drawModelIndexed(ver,tri,12,modelTransform,&camera,&conf);
/*
conf.backfaceCulling = S3L_BACKFACE_CULLING_NONE;