review sw_vertex_t

removes `float screen[2]`; each step stores the transformed coordinates in `float coord[4]`.
This also simplifies vertex interpolation during triangle rasterization.
This commit is contained in:
Bigfoot71 2026-03-18 13:38:27 +01:00
parent 1117b130c7
commit 4ae005857f

395
src/external/rlsw.h vendored
View File

@ -930,8 +930,7 @@ typedef struct {
float position[4]; // Position coordinates float position[4]; // Position coordinates
float color[4]; // Color value (RGBA) float color[4]; // Color value (RGBA)
float texcoord[2]; // Texture coordinates float texcoord[2]; // Texture coordinates
float homogeneous[4]; // Homogeneous coordinates float coord[4]; // Clip space (x,y,z,w) -> NDC (after /w) -> screen space (x,y,z,1/w)
float screen[2]; // Screen coordinates
} sw_vertex_t; } sw_vertex_t;
typedef struct { typedef struct {
@ -1216,11 +1215,11 @@ static inline void sw_lerp_vertex_PTCH(sw_vertex_t *SW_RESTRICT out, const sw_ve
out->texcoord[0] = a->texcoord[0]*tInv + b->texcoord[0]*t; out->texcoord[0] = a->texcoord[0]*tInv + b->texcoord[0]*t;
out->texcoord[1] = a->texcoord[1]*tInv + b->texcoord[1]*t; out->texcoord[1] = a->texcoord[1]*tInv + b->texcoord[1]*t;
// Homogeneous coordinate interpolation (4 components) // Pipeline coordinate interpolation (4 components)
out->homogeneous[0] = a->homogeneous[0]*tInv + b->homogeneous[0]*t; out->coord[0] = a->coord[0]*tInv + b->coord[0]*t;
out->homogeneous[1] = a->homogeneous[1]*tInv + b->homogeneous[1]*t; out->coord[1] = a->coord[1]*tInv + b->coord[1]*t;
out->homogeneous[2] = a->homogeneous[2]*tInv + b->homogeneous[2]*t; out->coord[2] = a->coord[2]*tInv + b->coord[2]*t;
out->homogeneous[3] = a->homogeneous[3]*tInv + b->homogeneous[3]*t; out->coord[3] = a->coord[3]*tInv + b->coord[3]*t;
} }
static inline void sw_get_vertex_grad_PTCH(sw_vertex_t *SW_RESTRICT out, const sw_vertex_t *SW_RESTRICT a, const sw_vertex_t *SW_RESTRICT b, float scale) static inline void sw_get_vertex_grad_PTCH(sw_vertex_t *SW_RESTRICT out, const sw_vertex_t *SW_RESTRICT a, const sw_vertex_t *SW_RESTRICT b, float scale)
@ -1241,11 +1240,11 @@ static inline void sw_get_vertex_grad_PTCH(sw_vertex_t *SW_RESTRICT out, const s
out->texcoord[0] = (b->texcoord[0] - a->texcoord[0])*scale; out->texcoord[0] = (b->texcoord[0] - a->texcoord[0])*scale;
out->texcoord[1] = (b->texcoord[1] - a->texcoord[1])*scale; out->texcoord[1] = (b->texcoord[1] - a->texcoord[1])*scale;
// Calculate gradients for Homogeneous coordinates // Calculate gradients for Pipeline coordinates
out->homogeneous[0] = (b->homogeneous[0] - a->homogeneous[0])*scale; out->coord[0] = (b->coord[0] - a->coord[0])*scale;
out->homogeneous[1] = (b->homogeneous[1] - a->homogeneous[1])*scale; out->coord[1] = (b->coord[1] - a->coord[1])*scale;
out->homogeneous[2] = (b->homogeneous[2] - a->homogeneous[2])*scale; out->coord[2] = (b->coord[2] - a->coord[2])*scale;
out->homogeneous[3] = (b->homogeneous[3] - a->homogeneous[3])*scale; out->coord[3] = (b->coord[3] - a->coord[3])*scale;
} }
static inline void sw_add_vertex_grad_PTCH(sw_vertex_t *SW_RESTRICT out, const sw_vertex_t *SW_RESTRICT gradients) static inline void sw_add_vertex_grad_PTCH(sw_vertex_t *SW_RESTRICT out, const sw_vertex_t *SW_RESTRICT gradients)
@ -1266,11 +1265,11 @@ static inline void sw_add_vertex_grad_PTCH(sw_vertex_t *SW_RESTRICT out, const s
out->texcoord[0] += gradients->texcoord[0]; out->texcoord[0] += gradients->texcoord[0];
out->texcoord[1] += gradients->texcoord[1]; out->texcoord[1] += gradients->texcoord[1];
// Add gradients to Homogeneous coordinates // Add gradients to Pipeline coordinates
out->homogeneous[0] += gradients->homogeneous[0]; out->coord[0] += gradients->coord[0];
out->homogeneous[1] += gradients->homogeneous[1]; out->coord[1] += gradients->coord[1];
out->homogeneous[2] += gradients->homogeneous[2]; out->coord[2] += gradients->coord[2];
out->homogeneous[3] += gradients->homogeneous[3]; out->coord[3] += gradients->coord[3];
} }
static inline void sw_add_vertex_grad_scaled_PTCH(sw_vertex_t *SW_RESTRICT out, const sw_vertex_t *SW_RESTRICT gradients, float scale) static inline void sw_add_vertex_grad_scaled_PTCH(sw_vertex_t *SW_RESTRICT out, const sw_vertex_t *SW_RESTRICT gradients, float scale)
@ -1291,11 +1290,11 @@ static inline void sw_add_vertex_grad_scaled_PTCH(sw_vertex_t *SW_RESTRICT out,
out->texcoord[0] += gradients->texcoord[0]*scale; out->texcoord[0] += gradients->texcoord[0]*scale;
out->texcoord[1] += gradients->texcoord[1]*scale; out->texcoord[1] += gradients->texcoord[1]*scale;
// Add gradients to Homogeneous coordinates // Add gradients to Pipeline coordinates
out->homogeneous[0] += gradients->homogeneous[0]*scale; out->coord[0] += gradients->coord[0]*scale;
out->homogeneous[1] += gradients->homogeneous[1]*scale; out->coord[1] += gradients->coord[1]*scale;
out->homogeneous[2] += gradients->homogeneous[2]*scale; out->coord[2] += gradients->coord[2]*scale;
out->homogeneous[3] += gradients->homogeneous[3]*scale; out->coord[3] += gradients->coord[3]*scale;
} }
// Half conversion functions // Half conversion functions
@ -2867,10 +2866,10 @@ static uint32_t sw_blend_compute_flags(SWfactor src, SWfactor dst)
// Projection helper functions // Projection helper functions
//------------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------------
static inline void sw_project_ndc_to_screen(float screen[2], const float ndc[4]) static inline void sw_project_ndc_to_screen(float ndc[4])
{ {
screen[0] = RLSW.vpCenter[0] + ndc[0]*RLSW.vpHalf[0] + 0.5f; ndc[0] = RLSW.vpCenter[0] + ndc[0]*RLSW.vpHalf[0] + 0.5f;
screen[1] = RLSW.vpCenter[1] + ndc[1]*RLSW.vpHalf[1] + 0.5f; ndc[1] = RLSW.vpCenter[1] + ndc[1]*RLSW.vpHalf[1] + 0.5f;
} }
//------------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------------
@ -2883,16 +2882,16 @@ static int sw_clip_##name(
int n) \ int n) \
{ \ { \
const sw_vertex_t *prev = &input[n - 1]; \ const sw_vertex_t *prev = &input[n - 1]; \
int prevInside = FUNC_IS_INSIDE(prev->homogeneous); \ int prevInside = FUNC_IS_INSIDE(prev->coord); \
int outputCount = 0; \ int outputCount = 0; \
\ \
for (int i = 0; i < n; i++) { \ for (int i = 0; i < n; i++) { \
const sw_vertex_t *curr = &input[i]; \ const sw_vertex_t *curr = &input[i]; \
int currInside = FUNC_IS_INSIDE(curr->homogeneous); \ int currInside = FUNC_IS_INSIDE(curr->coord); \
\ \
/* If transition between interior/exterior, calculate intersection point */ \ /* If transition between interior/exterior, calculate intersection point */ \
if (prevInside != currInside) { \ if (prevInside != currInside) { \
float t = FUNC_COMPUTE_T(prev->homogeneous, curr->homogeneous); \ float t = FUNC_COMPUTE_T(prev->coord, curr->coord); \
sw_lerp_vertex_PTCH(&output[outputCount++], prev, curr, t); \ sw_lerp_vertex_PTCH(&output[outputCount++], prev, curr, t); \
} \ } \
\ \
@ -3325,21 +3324,21 @@ static inline bool sw_triangle_face_culling(void)
{ {
// NOTE: Face culling is done before clipping to avoid unnecessary computations // NOTE: Face culling is done before clipping to avoid unnecessary computations
// To handle triangles crossing the w=0 plane correctly, // To handle triangles crossing the w=0 plane correctly,
// the winding order test is performeed in homogeneous coordinates directly, // the winding order test is performeed in clip space directly,
// before the perspective division (division by w) // before the perspective division (division by w)
// This test determines the orientation of the triangle in the (x,y,w) plane, // This test determines the orientation of the triangle in the (x,y,w) plane,
// which corresponds to the projected 2D winding order sign, // which corresponds to the projected 2D winding order sign,
// even with negative w values // even with negative w values
// Preload homogeneous coordinates into local variables // Preload clip coordinates into local variables
const float *h0 = RLSW.primitive.buffer[0].homogeneous; const float *h0 = RLSW.primitive.buffer[0].coord;
const float *h1 = RLSW.primitive.buffer[1].homogeneous; const float *h1 = RLSW.primitive.buffer[1].coord;
const float *h2 = RLSW.primitive.buffer[2].homogeneous; const float *h2 = RLSW.primitive.buffer[2].coord;
// Compute a value proportional to the signed area in the projected 2D plane, // Compute a value proportional to the signed area in the projected 2D plane,
// calculated directly using homogeneous coordinates BEFORE division by w // calculated directly using clip coordinates BEFORE division by w
// This is the determinant of the matrix formed by the (x, y, w) components // This is the determinant of the matrix formed by the (x, y, w) components
// of the vertices, which correctly captures the winding order in homogeneous // of the vertices, which correctly captures the winding order in clip
// space and its relationship to the projected 2D winding order, even with // space and its relationship to the projected 2D winding order, even with
// negative w values // negative w values
// The determinant formula used here is: // The determinant formula used here is:
@ -3381,13 +3380,13 @@ static void sw_triangle_clip_and_project(void)
// Calculation of the reciprocal of W for normalization // Calculation of the reciprocal of W for normalization
// as well as perspective-correct attributes // as well as perspective-correct attributes
const float wRcp = 1.0f/v->homogeneous[3]; const float wRcp = 1.0f/v->coord[3];
v->homogeneous[3] = wRcp; v->coord[3] = wRcp;
// Division of XYZ coordinates by weight // Division of XYZ coordinates by weight
v->homogeneous[0] *= wRcp; v->coord[0] *= wRcp;
v->homogeneous[1] *= wRcp; v->coord[1] *= wRcp;
v->homogeneous[2] *= wRcp; v->coord[2] *= wRcp;
// Division of texture coordinates (perspective-correct) // Division of texture coordinates (perspective-correct)
v->texcoord[0] *= wRcp; v->texcoord[0] *= wRcp;
@ -3400,7 +3399,7 @@ static void sw_triangle_clip_and_project(void)
v->color[3] *= wRcp; v->color[3] *= wRcp;
// Transformation to screen space // Transformation to screen space
sw_project_ndc_to_screen(v->screen, v->homogeneous); sw_project_ndc_to_screen(v->coord);
} }
} }
} }
@ -3434,27 +3433,27 @@ static inline bool sw_quad_face_culling(void)
{ {
// NOTE: Face culling is done before clipping to avoid unnecessary computations // NOTE: Face culling is done before clipping to avoid unnecessary computations
// To handle quads crossing the w=0 plane correctly, // To handle quads crossing the w=0 plane correctly,
// the winding order test is performed in homogeneous coordinates directly, // the winding order test is performed in clip space directly,
// before the perspective division (division by w) // before the perspective division (division by w)
// For a convex quad with vertices P0, P1, P2, P3 in sequential order, // For a convex quad with vertices P0, P1, P2, P3 in sequential order,
// the winding order of the quad is the same as the winding order // the winding order of the quad is the same as the winding order
// of the triangle P0 P1 P2. The homogeneous triangle is used on // of the triangle P0 P1 P2. The triangle in clip space is used on
// winding test on this first triangle // winding test on this first triangle
// Preload homogeneous coordinates into local variables // Preload clip coordinates into local variables
const float *h0 = RLSW.primitive.buffer[0].homogeneous; const float *h0 = RLSW.primitive.buffer[0].coord;
const float *h1 = RLSW.primitive.buffer[1].homogeneous; const float *h1 = RLSW.primitive.buffer[1].coord;
const float *h2 = RLSW.primitive.buffer[2].homogeneous; const float *h2 = RLSW.primitive.buffer[2].coord;
// NOTE: h3 is not needed for this test // NOTE: h3 is not needed for this test
// const float *h3 = RLSW.primitive.buffer[3].homogeneous; // const float *h3 = RLSW.primitive.buffer[3].coord;
// Compute a value proportional to the signed area of the triangle P0 P1 P2 // Compute a value proportional to the signed area of the triangle P0 P1 P2
// in the projected 2D plane, calculated directly using homogeneous coordinates // in the projected 2D plane, calculated directly using clip coordinates
// BEFORE division by w // BEFORE division by w
// This is the determinant of the matrix formed by the (x, y, w) components // This is the determinant of the matrix formed by the (x, y, w) components
// of the vertices P0, P1, and P2. Its sign correctly indicates the winding order // of the vertices P0, P1, and P2. Its sign correctly indicates the winding order
// in homogeneous space and its relationship to the projected 2D winding order, // in clip space and its relationship to the projected 2D winding order,
// even with negative w values // even with negative w values
// The determinant formula used here is: // The determinant formula used here is:
// h0.x*(h1.y*h2.w - h2.y*h1.w) + // h0.x*(h1.y*h2.w - h2.y*h1.w) +
@ -3496,13 +3495,13 @@ static void sw_quad_clip_and_project(void)
// Calculation of the reciprocal of W for normalization // Calculation of the reciprocal of W for normalization
// as well as perspective-correct attributes // as well as perspective-correct attributes
const float wRcp = 1.0f/v->homogeneous[3]; const float wRcp = 1.0f/v->coord[3];
v->homogeneous[3] = wRcp; v->coord[3] = wRcp;
// Division of XYZ coordinates by weight // Division of XYZ coordinates by weight
v->homogeneous[0] *= wRcp; v->coord[0] *= wRcp;
v->homogeneous[1] *= wRcp; v->coord[1] *= wRcp;
v->homogeneous[2] *= wRcp; v->coord[2] *= wRcp;
// Division of texture coordinates (perspective-correct) // Division of texture coordinates (perspective-correct)
v->texcoord[0] *= wRcp; v->texcoord[0] *= wRcp;
@ -3515,7 +3514,7 @@ static void sw_quad_clip_and_project(void)
v->color[3] *= wRcp; v->color[3] *= wRcp;
// Transformation to screen space // Transformation to screen space
sw_project_ndc_to_screen(v->screen, v->homogeneous); sw_project_ndc_to_screen(v->coord);
} }
} }
} }
@ -3527,17 +3526,17 @@ static bool sw_quad_is_axis_aligned(void)
// so it's required for all vertices to have homogeneous w = 1.0 // so it's required for all vertices to have homogeneous w = 1.0
for (int i = 0; i < 4; i++) for (int i = 0; i < 4; i++)
{ {
if (RLSW.primitive.buffer[i].homogeneous[3] != 1.0f) return false; if (RLSW.primitive.buffer[i].coord[3] != 1.0f) return false;
} }
// Epsilon tolerance in screen space (pixels) // Epsilon tolerance in screen space (pixels)
const float epsilon = 0.5f; const float epsilon = 0.5f;
// Fetch screen-space positions for the four quad vertices // Fetch screen-space positions for the four quad vertices
const float *p0 = RLSW.primitive.buffer[0].screen; const float *p0 = RLSW.primitive.buffer[0].coord;
const float *p1 = RLSW.primitive.buffer[1].screen; const float *p1 = RLSW.primitive.buffer[1].coord;
const float *p2 = RLSW.primitive.buffer[2].screen; const float *p2 = RLSW.primitive.buffer[2].coord;
const float *p3 = RLSW.primitive.buffer[3].screen; const float *p3 = RLSW.primitive.buffer[3].coord;
// Compute edge vectors between consecutive vertices // Compute edge vectors between consecutive vertices
// These define the four sides of the quad in screen space // These define the four sides of the quad in screen space
@ -3626,25 +3625,25 @@ static bool sw_line_clip(sw_vertex_t *v0, sw_vertex_t *v1)
for (int i = 0; i < 4; i++) for (int i = 0; i < 4; i++)
{ {
dH[i] = v1->homogeneous[i] - v0->homogeneous[i]; dH[i] = v1->coord[i] - v0->coord[i];
dC[i] = v1->color[i] - v0->color[i]; dC[i] = v1->color[i] - v0->color[i];
} }
// Clipping Liang-Barsky // Clipping Liang-Barsky
if (!sw_line_clip_coord(v0->homogeneous[3] - v0->homogeneous[0], -dH[3] + dH[0], &t0, &t1)) return false; if (!sw_line_clip_coord(v0->coord[3] - v0->coord[0], -dH[3] + dH[0], &t0, &t1)) return false;
if (!sw_line_clip_coord(v0->homogeneous[3] + v0->homogeneous[0], -dH[3] - dH[0], &t0, &t1)) return false; if (!sw_line_clip_coord(v0->coord[3] + v0->coord[0], -dH[3] - dH[0], &t0, &t1)) return false;
if (!sw_line_clip_coord(v0->homogeneous[3] - v0->homogeneous[1], -dH[3] + dH[1], &t0, &t1)) return false; if (!sw_line_clip_coord(v0->coord[3] - v0->coord[1], -dH[3] + dH[1], &t0, &t1)) return false;
if (!sw_line_clip_coord(v0->homogeneous[3] + v0->homogeneous[1], -dH[3] - dH[1], &t0, &t1)) return false; if (!sw_line_clip_coord(v0->coord[3] + v0->coord[1], -dH[3] - dH[1], &t0, &t1)) return false;
if (!sw_line_clip_coord(v0->homogeneous[3] - v0->homogeneous[2], -dH[3] + dH[2], &t0, &t1)) return false; if (!sw_line_clip_coord(v0->coord[3] - v0->coord[2], -dH[3] + dH[2], &t0, &t1)) return false;
if (!sw_line_clip_coord(v0->homogeneous[3] + v0->homogeneous[2], -dH[3] - dH[2], &t0, &t1)) return false; if (!sw_line_clip_coord(v0->coord[3] + v0->coord[2], -dH[3] - dH[2], &t0, &t1)) return false;
// Clipping Scissor // Clipping Scissor
if (RLSW.userState & SW_STATE_SCISSOR_TEST) if (RLSW.userState & SW_STATE_SCISSOR_TEST)
{ {
if (!sw_line_clip_coord(v0->homogeneous[0] - RLSW.scClipMin[0]*v0->homogeneous[3], RLSW.scClipMin[0]*dH[3] - dH[0], &t0, &t1)) return false; if (!sw_line_clip_coord(v0->coord[0] - RLSW.scClipMin[0]*v0->coord[3], RLSW.scClipMin[0]*dH[3] - dH[0], &t0, &t1)) return false;
if (!sw_line_clip_coord(RLSW.scClipMax[0]*v0->homogeneous[3] - v0->homogeneous[0], dH[0] - RLSW.scClipMax[0]*dH[3], &t0, &t1)) return false; if (!sw_line_clip_coord(RLSW.scClipMax[0]*v0->coord[3] - v0->coord[0], dH[0] - RLSW.scClipMax[0]*dH[3], &t0, &t1)) return false;
if (!sw_line_clip_coord(v0->homogeneous[1] - RLSW.scClipMin[1]*v0->homogeneous[3], RLSW.scClipMin[1]*dH[3] - dH[1], &t0, &t1)) return false; if (!sw_line_clip_coord(v0->coord[1] - RLSW.scClipMin[1]*v0->coord[3], RLSW.scClipMin[1]*dH[3] - dH[1], &t0, &t1)) return false;
if (!sw_line_clip_coord(RLSW.scClipMax[1]*v0->homogeneous[3] - v0->homogeneous[1], dH[1] - RLSW.scClipMax[1]*dH[3], &t0, &t1)) return false; if (!sw_line_clip_coord(RLSW.scClipMax[1]*v0->coord[3] - v0->coord[1], dH[1] - RLSW.scClipMax[1]*dH[3], &t0, &t1)) return false;
} }
// Interpolation of new coordinates // Interpolation of new coordinates
@ -3652,7 +3651,7 @@ static bool sw_line_clip(sw_vertex_t *v0, sw_vertex_t *v1)
{ {
for (int i = 0; i < 4; i++) for (int i = 0; i < 4; i++)
{ {
v1->homogeneous[i] = v0->homogeneous[i] + t1*dH[i]; v1->coord[i] = v0->coord[i] + t1*dH[i];
v1->color[i] = v0->color[i] + t1*dC[i]; v1->color[i] = v0->color[i] + t1*dC[i];
} }
} }
@ -3661,7 +3660,7 @@ static bool sw_line_clip(sw_vertex_t *v0, sw_vertex_t *v1)
{ {
for (int i = 0; i < 4; i++) for (int i = 0; i < 4; i++)
{ {
v0->homogeneous[i] += t0*dH[i]; v0->coord[i] += t0*dH[i];
v0->color[i] += t0*dC[i]; v0->color[i] += t0*dC[i];
} }
} }
@ -3673,25 +3672,25 @@ static bool sw_line_clip_and_project(sw_vertex_t *v0, sw_vertex_t *v1)
{ {
if (!sw_line_clip(v0, v1)) return false; if (!sw_line_clip(v0, v1)) return false;
// Convert homogeneous coordinates to NDC // Convert clip coordinates to NDC
v0->homogeneous[3] = 1.0f/v0->homogeneous[3]; v0->coord[3] = 1.0f/v0->coord[3];
v1->homogeneous[3] = 1.0f/v1->homogeneous[3]; v1->coord[3] = 1.0f/v1->coord[3];
for (int i = 0; i < 3; i++) for (int i = 0; i < 3; i++)
{ {
v0->homogeneous[i] *= v0->homogeneous[3]; v0->coord[i] *= v0->coord[3];
v1->homogeneous[i] *= v1->homogeneous[3]; v1->coord[i] *= v1->coord[3];
} }
// Convert NDC coordinates to screen space // Convert NDC coordinates to screen space
sw_project_ndc_to_screen(v0->screen, v0->homogeneous); sw_project_ndc_to_screen(v0->coord);
sw_project_ndc_to_screen(v1->screen, v1->homogeneous); sw_project_ndc_to_screen(v1->coord);
// NDC +1.0 projects to exactly (width + 0.5f), which truncates out of bounds // NDC +1.0 projects to exactly (width + 0.5f), which truncates out of bounds
// The clamp is at most 0.5px on a boundary endpoint, it's visually imperceptible // The clamp is at most 0.5px on a boundary endpoint, it's visually imperceptible
v0->screen[0] = sw_clamp(v0->screen[0], 0.0f, (float)(RLSW.colorBuffer->width - 1) + 0.5f); v0->coord[0] = sw_clamp(v0->coord[0], 0.0f, (float)(RLSW.colorBuffer->width - 1) + 0.5f);
v0->screen[1] = sw_clamp(v0->screen[1], 0.0f, (float)(RLSW.colorBuffer->height - 1) + 0.5f); v0->coord[1] = sw_clamp(v0->coord[1], 0.0f, (float)(RLSW.colorBuffer->height - 1) + 0.5f);
v1->screen[0] = sw_clamp(v1->screen[0], 0.0f, (float)(RLSW.colorBuffer->width - 1) + 0.5f); v1->coord[0] = sw_clamp(v1->coord[0], 0.0f, (float)(RLSW.colorBuffer->width - 1) + 0.5f);
v1->screen[1] = sw_clamp(v1->screen[1], 0.0f, (float)(RLSW.colorBuffer->height - 1) + 0.5f); v1->coord[1] = sw_clamp(v1->coord[1], 0.0f, (float)(RLSW.colorBuffer->height - 1) + 0.5f);
return true; return true;
} }
@ -3717,20 +3716,20 @@ static void sw_line_render(uint32_t state, sw_vertex_t *vertices)
//------------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------------
static bool sw_point_clip_and_project(sw_vertex_t *v) static bool sw_point_clip_and_project(sw_vertex_t *v)
{ {
if (v->homogeneous[3] != 1.0f) if (v->coord[3] != 1.0f)
{ {
for (int_fast8_t i = 0; i < 3; i++) for (int_fast8_t i = 0; i < 3; i++)
{ {
if ((v->homogeneous[i] < -v->homogeneous[3]) || (v->homogeneous[i] > v->homogeneous[3])) return false; if ((v->coord[i] < -v->coord[3]) || (v->coord[i] > v->coord[3])) return false;
} }
v->homogeneous[3] = 1.0f/v->homogeneous[3]; v->coord[3] = 1.0f/v->coord[3];
v->homogeneous[0] *= v->homogeneous[3]; v->coord[0] *= v->coord[3];
v->homogeneous[1] *= v->homogeneous[3]; v->coord[1] *= v->coord[3];
v->homogeneous[2] *= v->homogeneous[3]; v->coord[2] *= v->coord[3];
} }
sw_project_ndc_to_screen(v->screen, v->homogeneous); sw_project_ndc_to_screen(v->coord);
int min[2] = { 0, 0 }; int min[2] = { 0, 0 };
int max[2] = { RLSW.colorBuffer->width, RLSW.colorBuffer->height }; int max[2] = { RLSW.colorBuffer->width, RLSW.colorBuffer->height };
@ -3743,8 +3742,8 @@ static bool sw_point_clip_and_project(sw_vertex_t *v)
max[1] = sw_clamp_int(RLSW.scMax[1], 0, RLSW.colorBuffer->height); max[1] = sw_clamp_int(RLSW.scMax[1], 0, RLSW.colorBuffer->height);
} }
bool insideX = (v->screen[0] - RLSW.pointRadius < max[0]) && (v->screen[0] + RLSW.pointRadius > min[0]); bool insideX = (v->coord[0] - RLSW.pointRadius < max[0]) && (v->coord[0] + RLSW.pointRadius > min[0]);
bool insideY = (v->screen[1] - RLSW.pointRadius < max[1]) && (v->screen[1] + RLSW.pointRadius > min[1]); bool insideY = (v->coord[1] - RLSW.pointRadius < max[1]) && (v->coord[1] + RLSW.pointRadius > min[1]);
return (insideX && insideY); return (insideX && insideY);
} }
@ -3858,12 +3857,12 @@ static void sw_immediate_push_vertex(const float position[4])
for (int i = 0; i < 4; i++) vertex->color[i] = RLSW.primitive.color[i]; for (int i = 0; i < 4; i++) vertex->color[i] = RLSW.primitive.color[i];
for (int i = 0; i < 2; i++) vertex->texcoord[i] = RLSW.primitive.texcoord[i]; for (int i = 0; i < 2; i++) vertex->texcoord[i] = RLSW.primitive.texcoord[i];
// Calculate homogeneous coordinates // Calculate clip coordinates
const float *m = RLSW.matMVP, *v = vertex->position; const float *m = RLSW.matMVP, *v = vertex->position;
vertex->homogeneous[0] = m[0]*v[0] + m[4]*v[1] + m[8]*v[2] + m[12]*v[3]; vertex->coord[0] = m[0]*v[0] + m[4]*v[1] + m[8]*v[2] + m[12]*v[3];
vertex->homogeneous[1] = m[1]*v[0] + m[5]*v[1] + m[9]*v[2] + m[13]*v[3]; vertex->coord[1] = m[1]*v[0] + m[5]*v[1] + m[9]*v[2] + m[13]*v[3];
vertex->homogeneous[2] = m[2]*v[0] + m[6]*v[1] + m[10]*v[2] + m[14]*v[3]; vertex->coord[2] = m[2]*v[0] + m[6]*v[1] + m[10]*v[2] + m[14]*v[3];
vertex->homogeneous[3] = m[3]*v[0] + m[7]*v[1] + m[11]*v[2] + m[15]*v[3]; vertex->coord[3] = m[3]*v[0] + m[7]*v[1] + m[11]*v[2] + m[15]*v[3];
// Immediate rendering of the primitive if the required number is reached // Immediate rendering of the primitive if the required number is reached
if (RLSW.primitive.vertexCount == SW_PRIMITIVE_VERTEX_COUNT[RLSW.drawMode]) if (RLSW.primitive.vertexCount == SW_PRIMITIVE_VERTEX_COUNT[RLSW.drawMode])
@ -5252,23 +5251,23 @@ void swGetFramebufferAttachmentParameteriv(SWattachment attachment, SWattachget
static void SW_RASTER_TRIANGLE_SPAN(const sw_vertex_t *start, const sw_vertex_t *end, float dUdy, float dVdy) static void SW_RASTER_TRIANGLE_SPAN(const sw_vertex_t *start, const sw_vertex_t *end, float dUdy, float dVdy)
{ {
// Gets the start and end coordinates // Gets the start and end coordinates
int xStart = (int)start->screen[0]; int xStart = (int)start->coord[0];
int xEnd = (int)end->screen[0]; int xEnd = (int)end->coord[0];
// Avoid empty lines // Avoid empty lines
if (xStart == xEnd) return; if (xStart == xEnd) return;
// Compute the subpixel distance to traverse before the first pixel // Compute the subpixel distance to traverse before the first pixel
float xSubstep = 1.0f - sw_fract(start->screen[0]); float xSubstep = 1.0f - sw_fract(start->coord[0]);
// Compute the inverse horizontal distance along the X axis // Compute the inverse horizontal distance along the X axis
float dxRcp = 1.0f/(end->screen[0] - start->screen[0]); float dxRcp = 1.0f/(end->coord[0] - start->coord[0]);
// Compute the interpolation steps along the X axis // Compute the interpolation steps along the X axis
#ifdef SW_ENABLE_DEPTH_TEST #ifdef SW_ENABLE_DEPTH_TEST
float dZdx = (end->homogeneous[2] - start->homogeneous[2])*dxRcp; float dZdx = (end->coord[2] - start->coord[2])*dxRcp;
#endif #endif
float dWdx = (end->homogeneous[3] - start->homogeneous[3])*dxRcp; float dWdx = (end->coord[3] - start->coord[3])*dxRcp;
float dCdx[4] = { float dCdx[4] = {
(end->color[0] - start->color[0])*dxRcp, (end->color[0] - start->color[0])*dxRcp,
(end->color[1] - start->color[1])*dxRcp, (end->color[1] - start->color[1])*dxRcp,
@ -5282,9 +5281,9 @@ static void SW_RASTER_TRIANGLE_SPAN(const sw_vertex_t *start, const sw_vertex_t
// Initializing the interpolation starting values // Initializing the interpolation starting values
#ifdef SW_ENABLE_DEPTH_TEST #ifdef SW_ENABLE_DEPTH_TEST
float z = start->homogeneous[2] + dZdx*xSubstep; float z = start->coord[2] + dZdx*xSubstep;
#endif #endif
float w = start->homogeneous[3] + dWdx*xSubstep; float w = start->coord[3] + dWdx*xSubstep;
float color[4] = { float color[4] = {
start->color[0] + dCdx[0]*xSubstep, start->color[0] + dCdx[0]*xSubstep,
start->color[1] + dCdx[1]*xSubstep, start->color[1] + dCdx[1]*xSubstep,
@ -5297,7 +5296,7 @@ static void SW_RASTER_TRIANGLE_SPAN(const sw_vertex_t *start, const sw_vertex_t
#endif #endif
// Pre-calculate the starting pointers for the framebuffer row // Pre-calculate the starting pointers for the framebuffer row
int y = (int)start->screen[1]; int y = (int)start->coord[1];
int baseOffset = y*RLSW.colorBuffer->width + xStart; int baseOffset = y*RLSW.colorBuffer->width + xStart;
uint8_t *cPtr = (uint8_t *)(RLSW.colorBuffer->pixels) + baseOffset*SW_FRAMEBUFFER_COLOR_SIZE; uint8_t *cPtr = (uint8_t *)(RLSW.colorBuffer->pixels) + baseOffset*SW_FRAMEBUFFER_COLOR_SIZE;
#ifdef SW_ENABLE_DEPTH_TEST #ifdef SW_ENABLE_DEPTH_TEST
@ -5387,14 +5386,14 @@ static void SW_RASTER_TRIANGLE_SPAN(const sw_vertex_t *start, const sw_vertex_t
static void SW_RASTER_TRIANGLE(const sw_vertex_t *v0, const sw_vertex_t *v1, const sw_vertex_t *v2) static void SW_RASTER_TRIANGLE(const sw_vertex_t *v0, const sw_vertex_t *v1, const sw_vertex_t *v2)
{ {
// Swap vertices by increasing Y // Swap vertices by increasing Y
if (v0->screen[1] > v1->screen[1]) { const sw_vertex_t *tmp = v0; v0 = v1; v1 = tmp; } if (v0->coord[1] > v1->coord[1]) { const sw_vertex_t *tmp = v0; v0 = v1; v1 = tmp; }
if (v1->screen[1] > v2->screen[1]) { const sw_vertex_t *tmp = v1; v1 = v2; v2 = tmp; } if (v1->coord[1] > v2->coord[1]) { const sw_vertex_t *tmp = v1; v1 = v2; v2 = tmp; }
if (v0->screen[1] > v1->screen[1]) { const sw_vertex_t *tmp = v0; v0 = v1; v1 = tmp; } if (v0->coord[1] > v1->coord[1]) { const sw_vertex_t *tmp = v0; v0 = v1; v1 = tmp; }
// Extracting coordinates from the sorted vertices // Extracting coordinates from the sorted vertices
float x0 = v0->screen[0], y0 = v0->screen[1]; float x0 = v0->coord[0], y0 = v0->coord[1];
float x1 = v1->screen[0], y1 = v1->screen[1]; float x1 = v1->coord[0], y1 = v1->coord[1];
float x2 = v2->screen[0], y2 = v2->screen[1]; float x2 = v2->coord[0], y2 = v2->coord[1];
// Compute height differences // Compute height differences
float h02 = y2 - y0; float h02 = y2 - y0;
@ -5403,72 +5402,57 @@ static void SW_RASTER_TRIANGLE(const sw_vertex_t *v0, const sw_vertex_t *v1, con
if (h02 < 1e-6f) return; if (h02 < 1e-6f) return;
// Precompute the inverse values without additional checks // Inverse edge dy for per-edge dV/dy (scanline interpolation)
float h02Rcp = 1.0f/h02; float h02Rcp = 1.0f/h02;
float h01Rcp = (h01 > 1e-6f)? 1.0f/h01 : 0.0f; float h01Rcp = (h01 > 1e-6f)? 1.0f/h01 : 0.0f;
float h12Rcp = (h12 > 1e-6f)? 1.0f/h12 : 0.0f; float h12Rcp = (h12 > 1e-6f)? 1.0f/h12 : 0.0f;
// Pre-calculation of slopes
float dXdy02 = (x2 - x0)*h02Rcp;
float dXdy01 = (x1 - x0)*h01Rcp;
float dXdy12 = (x2 - x1)*h12Rcp;
// Y subpixel correction
float y0Substep = 1.0f - sw_fract(y0);
float y1Substep = 1.0f - sw_fract(y1);
// Y bounds (vertical clipping)
int yTop = (int)y0;
int yMid = (int)y1;
int yBot = (int)y2;
// Compute gradients for each side of the triangle // Compute gradients for each side of the triangle
sw_vertex_t dVXdy02, dVXdy01, dVXdy12; sw_vertex_t dVXdy02, dVXdy01, dVXdy12;
sw_get_vertex_grad_PTCH(&dVXdy02, v0, v2, h02Rcp); sw_get_vertex_grad_PTCH(&dVXdy02, v0, v2, h02Rcp);
sw_get_vertex_grad_PTCH(&dVXdy01, v0, v1, h01Rcp); sw_get_vertex_grad_PTCH(&dVXdy01, v0, v1, h01Rcp);
sw_get_vertex_grad_PTCH(&dVXdy12, v1, v2, h12Rcp); sw_get_vertex_grad_PTCH(&dVXdy12, v1, v2, h12Rcp);
// Get a copy of vertices for interpolation and apply substep correction // Y subpixel correction
sw_vertex_t vLeft = *v0, vRight = *v0; float y0Substep = 1.0f - sw_fract(y0);
sw_add_vertex_grad_scaled_PTCH(&vLeft, &dVXdy02, y0Substep); float y1Substep = 1.0f - sw_fract(y1);
sw_add_vertex_grad_scaled_PTCH(&vRight, &dVXdy01, y0Substep);
vLeft.screen[0] += dXdy02*y0Substep; // Get a copy of vertices for interpolation and apply substep correction
vRight.screen[0] += dXdy01*y0Substep; sw_vertex_t lVert = *v0, rVert = *v0;
sw_add_vertex_grad_scaled_PTCH(&lVert, &dVXdy02, y0Substep);
sw_add_vertex_grad_scaled_PTCH(&rVert, &dVXdy01, y0Substep);
// Y bounds (vertical clipping)
int yTop = (int)y0;
int yMid = (int)y1;
int yBot = (int)y2;
// Scanline for the upper part of the triangle // Scanline for the upper part of the triangle
for (int y = yTop; y < yMid; y++) for (int y = yTop; y < yMid; y++)
{ {
vLeft.screen[1] = vRight.screen[1] = y; lVert.coord[1] = rVert.coord[1] = y;
if (vLeft.screen[0] < vRight.screen[0]) SW_RASTER_TRIANGLE_SPAN(&vLeft, &vRight, dVXdy02.texcoord[0], dVXdy02.texcoord[1]); if (lVert.coord[0] < rVert.coord[0]) SW_RASTER_TRIANGLE_SPAN(&lVert, &rVert, dVXdy02.texcoord[0], dVXdy02.texcoord[1]);
else SW_RASTER_TRIANGLE_SPAN(&vRight, &vLeft, dVXdy02.texcoord[0], dVXdy02.texcoord[1]); else SW_RASTER_TRIANGLE_SPAN(&rVert, &lVert, dVXdy02.texcoord[0], dVXdy02.texcoord[1]);
sw_add_vertex_grad_PTCH(&vLeft, &dVXdy02); sw_add_vertex_grad_PTCH(&lVert, &dVXdy02);
vLeft.screen[0] += dXdy02; sw_add_vertex_grad_PTCH(&rVert, &dVXdy01);
sw_add_vertex_grad_PTCH(&vRight, &dVXdy01);
vRight.screen[0] += dXdy01;
} }
// Get a copy of next right for interpolation and apply substep correction // Get a copy of next right for interpolation and apply substep correction
vRight = *v1; rVert = *v1;
sw_add_vertex_grad_scaled_PTCH(&vRight, &dVXdy12, y1Substep); sw_add_vertex_grad_scaled_PTCH(&rVert, &dVXdy12, y1Substep);
vRight.screen[0] += dXdy12*y1Substep;
// Scanline for the lower part of the triangle // Scanline for the lower part of the triangle
for (int y = yMid; y < yBot; y++) for (int y = yMid; y < yBot; y++)
{ {
vLeft.screen[1] = vRight.screen[1] = y; lVert.coord[1] = rVert.coord[1] = y;
if (vLeft.screen[0] < vRight.screen[0]) SW_RASTER_TRIANGLE_SPAN(&vLeft, &vRight, dVXdy02.texcoord[0], dVXdy02.texcoord[1]); if (lVert.coord[0] < rVert.coord[0]) SW_RASTER_TRIANGLE_SPAN(&lVert, &rVert, dVXdy02.texcoord[0], dVXdy02.texcoord[1]);
else SW_RASTER_TRIANGLE_SPAN(&vRight, &vLeft, dVXdy02.texcoord[0], dVXdy02.texcoord[1]); else SW_RASTER_TRIANGLE_SPAN(&rVert, &lVert, dVXdy02.texcoord[0], dVXdy02.texcoord[1]);
sw_add_vertex_grad_PTCH(&vLeft, &dVXdy02); sw_add_vertex_grad_PTCH(&lVert, &dVXdy02);
vLeft.screen[0] += dXdy02; sw_add_vertex_grad_PTCH(&rVert, &dVXdy12);
sw_add_vertex_grad_PTCH(&vRight, &dVXdy12);
vRight.screen[0] += dXdy12;
} }
} }
@ -5487,9 +5471,8 @@ static void SW_RASTER_TRIANGLE(const sw_vertex_t *v0, const sw_vertex_t *v1, con
#define SW_RASTER_QUAD SW_CONCATX(sw_raster_quad_, RLSW_TEMPLATE_RASTER_QUAD) #define SW_RASTER_QUAD SW_CONCATX(sw_raster_quad_, RLSW_TEMPLATE_RASTER_QUAD)
// REVIEW: Could a perfectly aligned quad, where one of the four points has a different depth, // NOTE: This function should only render affine axis-aligned quads
// still appear perfectly aligned from a certain point of view? // No perspective divide is applied after interpolation
// Because in that case, it's still needed to perform perspective division for textures and colors...
static void SW_RASTER_QUAD(const sw_vertex_t *a, const sw_vertex_t *b, static void SW_RASTER_QUAD(const sw_vertex_t *a, const sw_vertex_t *b,
const sw_vertex_t *c, const sw_vertex_t *d) const sw_vertex_t *c, const sw_vertex_t *d)
@ -5500,18 +5483,18 @@ static void SW_RASTER_QUAD(const sw_vertex_t *a, const sw_vertex_t *b,
const sw_vertex_t *tl = verts[0], *tr = verts[0], *br = verts[0], *bl = verts[0]; const sw_vertex_t *tl = verts[0], *tr = verts[0], *br = verts[0], *bl = verts[0];
for (int i = 1; i < 4; i++) for (int i = 1; i < 4; i++)
{ {
float sum = verts[i]->screen[0] + verts[i]->screen[1]; float sum = verts[i]->coord[0] + verts[i]->coord[1];
float diff = verts[i]->screen[0] - verts[i]->screen[1]; float diff = verts[i]->coord[0] - verts[i]->coord[1];
if (sum < tl->screen[0] + tl->screen[1]) tl = verts[i]; if (sum < tl->coord[0] + tl->coord[1]) tl = verts[i];
if (diff > tr->screen[0] - tr->screen[1]) tr = verts[i]; if (diff > tr->coord[0] - tr->coord[1]) tr = verts[i];
if (sum > br->screen[0] + br->screen[1]) br = verts[i]; if (sum > br->coord[0] + br->coord[1]) br = verts[i];
if (diff < bl->screen[0] - bl->screen[1]) bl = verts[i]; if (diff < bl->coord[0] - bl->coord[1]) bl = verts[i];
} }
int xMin = (int)tl->screen[0]; int xMin = (int)tl->coord[0];
int yMin = (int)tl->screen[1]; int yMin = (int)tl->coord[1];
int xMax = (int)br->screen[0]; int xMax = (int)br->coord[0];
int yMax = (int)br->screen[1]; int yMax = (int)br->coord[1];
float w = (float)(xMax - xMin); float w = (float)(xMax - xMin);
float h = (float)(yMax - yMin); float h = (float)(yMax - yMin);
@ -5521,8 +5504,8 @@ static void SW_RASTER_QUAD(const sw_vertex_t *a, const sw_vertex_t *b,
float hRcp = 1.0f/h; float hRcp = 1.0f/h;
// Subpixel corrections // Subpixel corrections
float xSubstep = 1.0f - sw_fract(tl->screen[0]); float xSubstep = 1.0f - sw_fract(tl->coord[0]);
float ySubstep = 1.0f - sw_fract(tl->screen[1]); float ySubstep = 1.0f - sw_fract(tl->coord[1]);
// Gradients along X (tl->tr) and Y (tl->bl) // Gradients along X (tl->tr) and Y (tl->bl)
float dCdx[4] = { float dCdx[4] = {
@ -5539,9 +5522,9 @@ static void SW_RASTER_QUAD(const sw_vertex_t *a, const sw_vertex_t *b,
}; };
#ifdef SW_ENABLE_DEPTH_TEST #ifdef SW_ENABLE_DEPTH_TEST
float dZdx = (tr->homogeneous[2] - tl->homogeneous[2])*wRcp; float dZdx = (tr->coord[2] - tl->coord[2])*wRcp;
float dZdy = (bl->homogeneous[2] - tl->homogeneous[2])*hRcp; float dZdy = (bl->coord[2] - tl->coord[2])*hRcp;
float zRow = tl->homogeneous[2] + dZdx*xSubstep + dZdy*ySubstep; float zRow = tl->coord[2] + dZdx*xSubstep + dZdy*ySubstep;
#endif #endif
#ifdef SW_ENABLE_TEXTURE #ifdef SW_ENABLE_TEXTURE
@ -5677,10 +5660,10 @@ static void SW_RASTER_QUAD(const sw_vertex_t *a, const sw_vertex_t *b,
static void SW_RASTER_LINE(const sw_vertex_t *v0, const sw_vertex_t *v1) static void SW_RASTER_LINE(const sw_vertex_t *v0, const sw_vertex_t *v1)
{ {
// Convert from pixel-center convention (n+0.5) to pixel-origin convention (n) // Convert from pixel-center convention (n+0.5) to pixel-origin convention (n)
float x0 = v0->screen[0] - 0.5f; float x0 = v0->coord[0] - 0.5f;
float y0 = v0->screen[1] - 0.5f; float y0 = v0->coord[1] - 0.5f;
float x1 = v1->screen[0] - 0.5f; float x1 = v1->coord[0] - 0.5f;
float y1 = v1->screen[1] - 0.5f; float y1 = v1->coord[1] - 0.5f;
float dx = x1 - x0; float dx = x1 - x0;
float dy = y1 - y0; float dy = y1 - y0;
@ -5705,7 +5688,7 @@ static void SW_RASTER_LINE(const sw_vertex_t *v0, const sw_vertex_t *v1)
float yInc = dy/steps; float yInc = dy/steps;
float stepRcp = 1.0f/steps; float stepRcp = 1.0f/steps;
#ifdef SW_ENABLE_DEPTH_TEST #ifdef SW_ENABLE_DEPTH_TEST
float zInc = (v1->homogeneous[2] - v0->homogeneous[2])*stepRcp; float zInc = (v1->coord[2] - v0->coord[2])*stepRcp;
#endif #endif
float rInc = (v1->color[0] - v0->color[0])*stepRcp; float rInc = (v1->color[0] - v0->color[0])*stepRcp;
float gInc = (v1->color[1] - v0->color[1])*stepRcp; float gInc = (v1->color[1] - v0->color[1])*stepRcp;
@ -5716,7 +5699,7 @@ static void SW_RASTER_LINE(const sw_vertex_t *v0, const sw_vertex_t *v1)
float x = x0 + xInc*substep; float x = x0 + xInc*substep;
float y = y0 + yInc*substep; float y = y0 + yInc*substep;
#ifdef SW_ENABLE_DEPTH_TEST #ifdef SW_ENABLE_DEPTH_TEST
float z = v0->homogeneous[2] + zInc*substep; float z = v0->coord[2] + zInc*substep;
#endif #endif
float r = v0->color[0] + rInc*substep; float r = v0->color[0] + rInc*substep;
float g = v0->color[1] + gInc*substep; float g = v0->color[1] + gInc*substep;
@ -5784,19 +5767,19 @@ static void SW_RASTER_LINE(const sw_vertex_t *v0, const sw_vertex_t *v1)
} }
} }
static void SW_RASTER_LINE_THICK(const sw_vertex_t *v1, const sw_vertex_t *v2) static void SW_RASTER_LINE_THICK(const sw_vertex_t *v0, const sw_vertex_t *v1)
{ {
sw_vertex_t tv1, tv2; sw_vertex_t tv0, tv1;
int x1 = (int)v1->screen[0]; int x0 = (int)v0->coord[0];
int y1 = (int)v1->screen[1]; int y0 = (int)v0->coord[1];
int x2 = (int)v2->screen[0]; int x1 = (int)v1->coord[0];
int y2 = (int)v2->screen[1]; int y1 = (int)v1->coord[1];
int dx = x2 - x1; int dx = x1 - x0;
int dy = y2 - y1; int dy = y1 - y0;
SW_RASTER_LINE(v1, v2); SW_RASTER_LINE(v0, v1);
if ((dx != 0) && (abs(dy/dx) < 1)) if ((dx != 0) && (abs(dy/dx) < 1))
{ {
@ -5804,14 +5787,14 @@ static void SW_RASTER_LINE_THICK(const sw_vertex_t *v1, const sw_vertex_t *v2)
wy >>= 1; wy >>= 1;
for (int i = 1; i <= wy; i++) for (int i = 1; i <= wy; i++)
{ {
tv1 = *v1, tv2 = *v2; tv0 = *v0, tv1 = *v1;
tv1.screen[1] -= i; tv0.coord[1] -= i;
tv2.screen[1] -= i; tv1.coord[1] -= i;
SW_RASTER_LINE(&tv1, &tv2); SW_RASTER_LINE(&tv0, &tv1);
tv1 = *v1, tv2 = *v2; tv0 = *v0, tv1 = *v1;
tv1.screen[1] += i; tv0.coord[1] += i;
tv2.screen[1] += i; tv1.coord[1] += i;
SW_RASTER_LINE(&tv1, &tv2); SW_RASTER_LINE(&tv0, &tv1);
} }
} }
else if (dy != 0) else if (dy != 0)
@ -5820,14 +5803,14 @@ static void SW_RASTER_LINE_THICK(const sw_vertex_t *v1, const sw_vertex_t *v2)
wx >>= 1; wx >>= 1;
for (int i = 1; i <= wx; i++) for (int i = 1; i <= wx; i++)
{ {
tv1 = *v1, tv2 = *v2; tv0 = *v0, tv1 = *v1;
tv1.screen[0] -= i; tv0.coord[0] -= i;
tv2.screen[0] -= i; tv1.coord[0] -= i;
SW_RASTER_LINE(&tv1, &tv2); SW_RASTER_LINE(&tv0, &tv1);
tv1 = *v1, tv2 = *v2; tv0 = *v0, tv1 = *v1;
tv1.screen[0] += i; tv0.coord[0] += i;
tv2.screen[0] += i; tv1.coord[0] += i;
SW_RASTER_LINE(&tv1, &tv2); SW_RASTER_LINE(&tv0, &tv1);
} }
} }
} }
@ -5882,9 +5865,9 @@ static void SW_RASTER_POINT_PIXEL(int x, int y, float z, const float color[4])
static void SW_RASTER_POINT(const sw_vertex_t *v) static void SW_RASTER_POINT(const sw_vertex_t *v)
{ {
int cx = v->screen[0]; int cx = v->coord[0];
int cy = v->screen[1]; int cy = v->coord[1];
float cz = v->homogeneous[2]; float cz = v->coord[2];
int radius = RLSW.pointRadius; int radius = RLSW.pointRadius;
const float *color = v->color; const float *color = v->color;