1
0
Fork 0
mirror of https://git.coom.tech/drummyfish/small3dlib.git synced 2024-11-21 20:39:57 +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; } S3L_Vec4;
#define S3L_writeVec4(v)\ #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) static inline void S3L_initVec4(S3L_Vec4 *v)
{ {
@ -800,12 +800,31 @@ int S3L_bresenhamStep(S3L_BresenhamState *state)
return state->steps >= 0; 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( void _S3L_drawFilledTriangle(
S3L_ScreenCoord x0, S3L_ScreenCoord y0, S3L_Unit depth0, S3L_Vec4 point0,
S3L_ScreenCoord x1, S3L_ScreenCoord y1, S3L_Unit depth1, S3L_Vec4 point1,
S3L_ScreenCoord x2, S3L_ScreenCoord y2, S3L_Unit depth2, S3L_Vec4 point2,
const S3L_Camera *camera,
S3L_PixelInfo *p) 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 S3L_ScreenCoord
tPointX, tPointY, // top triangle point coords tPointX, tPointY, // top triangle point coords
lPointX, lPointY, // left triangle point coords lPointX, lPointY, // left triangle point coords
@ -1042,20 +1061,29 @@ void _S3L_drawFilledTriangle(
#undef stepSide #undef stepSide
} }
void S3L_drawTriangle( /**
S3L_ScreenCoord x0, S3L_ScreenCoord y0, S3L_Unit depth0, Draws a triangle according to given config. The vertices are specified in
S3L_ScreenCoord x1, S3L_ScreenCoord y1, S3L_Unit depth1, projection-plane space (NOT screen space!) -- they wll be mapped to screen
S3L_ScreenCoord x2, S3L_ScreenCoord y2, S3L_Unit depth2, space by thies function. If perspective correction is enabled, each vertex
S3L_DrawConfig config, 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) 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) || if (config->backfaceCulling != S3L_BACKFACE_CULLING_NONE)
(config.backfaceCulling == S3L_BACKFACE_CULLING_CCW && cw)) {
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; return;
} }
@ -1063,11 +1091,23 @@ void S3L_drawTriangle(
S3L_initPixelInfo(&p); S3L_initPixelInfo(&p);
p.triangleID = triangleID; 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_BresenhamState line;
S3L_Unit lineLen; S3L_Unit lineLen;
@ -1165,15 +1205,10 @@ void S3L_makeCameraMatrix(S3L_Transform3D cameraTransform, S3L_Mat4 *m)
m); m);
} }
static inline void S3L_mapCameraToScreen(S3L_Vec4 point, S3L_Camera *camera, static inline void S3L_zDivide(S3L_Vec4 *vector)
S3L_ScreenCoord *screenX, S3L_ScreenCoord *screenY)
{ {
*screenX = vector->x = (vector->x * S3L_FRACTIONS_PER_UNIT) / S3L_nonZero(vector->z);
S3L_HALF_RESOLUTION_X + (point.x * S3L_HALF_RESOLUTION_X) / point.z; vector->y = (vector->y * S3L_FRACTIONS_PER_UNIT) / S3L_nonZero(vector->z);
*screenY =
S3L_HALF_RESOLUTION_Y - (point.y * S3L_HALF_RESOLUTION_X) / point.z;
// ^ S3L_FRACTIONS_PER_UNIT cancel out
} }
void S3L_drawModelIndexed( void S3L_drawModelIndexed(
@ -1181,14 +1216,13 @@ void S3L_drawModelIndexed(
const S3L_Index triangleVertexIndices[], const S3L_Index triangleVertexIndices[],
uint16_t triangleCount, uint16_t triangleCount,
S3L_Transform3D modelTransform, S3L_Transform3D modelTransform,
S3L_Camera camera, const S3L_Camera *camera,
S3L_DrawConfig config) const S3L_DrawConfig *config)
{ {
S3L_Index triangleIndex = 0; S3L_Index triangleIndex = 0;
S3L_Index coordIndex = 0; S3L_Index coordIndex = 0;
S3L_ScreenCoord sX0, sY0, sX1, sY1, sX2, sY2, d0, d1, d2; S3L_Vec4 pointModel, transformed0, transformed1, transformed2;
S3L_Vec4 pointModel;
S3L_Unit indexIndex; S3L_Unit indexIndex;
pointModel.w = S3L_FRACTIONS_PER_UNIT; // has to be "1.0" for translation 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_Mat4 mat1, mat2;
S3L_makeWorldMatrix(modelTransform,&mat1); S3L_makeWorldMatrix(modelTransform,&mat1);
S3L_makeCameraMatrix(camera.transform,&mat2); S3L_makeCameraMatrix(camera->transform,&mat2);
S3L_mat4Xmat4(&mat1,&mat2); S3L_mat4Xmat4(&mat1,&mat2);
while (triangleIndex < triangleCount) while (triangleIndex < triangleCount)
{ {
#define mapCoords(n)\ #define project(n)\
indexIndex = triangleVertexIndices[coordIndex] * 3;\ indexIndex = triangleVertexIndices[coordIndex] * 3;\
pointModel.x = coords[indexIndex];\ pointModel.x = coords[indexIndex];\
++indexIndex; /* TODO: put into square brackets? */\ ++indexIndex; /* TODO: put into square brackets? */\
@ -1210,14 +1244,17 @@ void S3L_drawModelIndexed(
pointModel.z = coords[indexIndex];\ pointModel.z = coords[indexIndex];\
++coordIndex;\ ++coordIndex;\
S3L_vec4Xmat4(&pointModel,&mat1);\ S3L_vec4Xmat4(&pointModel,&mat1);\
d##n = pointModel.z;\ transformed##n.x = pointModel.x;\
S3L_mapCameraToScreen(pointModel,&camera,&sX##n,&sY##n); transformed##n.y = pointModel.y;\
transformed##n.z = pointModel.z;\
S3L_zDivide(&transformed##n);
mapCoords(0) project(0)
mapCoords(1) project(1)
mapCoords(2) project(2)
S3L_drawTriangle(sX0,sY0,d0,sX1,sY1,d1,sX2,sY2,d2,config,triangleIndex); S3L_drawTriangle(transformed0,transformed1,transformed2,config,camera,
triangleIndex);
++triangleIndex; ++triangleIndex;
} }

View file

@ -117,10 +117,12 @@ void draw()
{ {
clearScreen(); clearScreen();
//frame = 853;
modelTransform.rotation.z = frame * 0.1; modelTransform.rotation.z = frame * 0.1;
modelTransform.rotation.x = frame * 0.3; 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; conf.backfaceCulling = S3L_BACKFACE_CULLING_NONE;