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:
parent
fcd7956158
commit
48c44943e9
2 changed files with 78 additions and 39 deletions
113
s3l.h
113
s3l.h
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
Loading…
Reference in a new issue