impl line clipping and rasterization
+ tweak function names
This commit is contained in:
parent
b70f02fdf2
commit
dcd60be477
404
src/external/rlsw.h
vendored
404
src/external/rlsw.h
vendored
|
|
@ -296,6 +296,12 @@ void swBindTexture(uint32_t id);
|
|||
#define SW_STATE_DEPTH_TEST (1 << 1)
|
||||
#define SW_STATE_CULL_FACE (1 << 2)
|
||||
|
||||
#define SW_CLIP_INSIDE (0x00) // 0000
|
||||
#define SW_CLIP_LEFT (0x01) // 0001
|
||||
#define SW_CLIP_RIGHT (0x02) // 0010
|
||||
#define SW_CLIP_BOTTOM (0x04) // 0100
|
||||
#define SW_CLIP_TOP (0x08) // 1000
|
||||
|
||||
/* === Internal Structs === */
|
||||
|
||||
typedef float sw_matrix_t[4*4];
|
||||
|
|
@ -479,6 +485,9 @@ static inline sw_vertex_t sw_lerp_vertex(const sw_vertex_t* a, const sw_vertex_t
|
|||
return result;
|
||||
}
|
||||
|
||||
|
||||
/* === Pixel Format Conversion Part === */
|
||||
|
||||
static inline uint32_t sw_cvt_hf_ui(uint16_t h)
|
||||
{
|
||||
uint32_t s = (uint32_t)(h & 0x8000) << 16;
|
||||
|
|
@ -708,7 +717,10 @@ static inline void sw_get_pixel(float* color, const void* pixels, uint32_t offse
|
|||
}
|
||||
}
|
||||
|
||||
static inline void sw_map_repeat(int* out, float in, int max)
|
||||
|
||||
/* === Texture Sampling Part === */
|
||||
|
||||
static inline void sw_texture_map_repeat(int* out, float in, int max)
|
||||
{
|
||||
// Upscale to nearest texture coordinates
|
||||
// NOTE: We use '(int)(x+0.5)' although this is incorrect
|
||||
|
|
@ -719,48 +731,48 @@ static inline void sw_map_repeat(int* out, float in, int max)
|
|||
*out = abs((int)((in - (int)in) * (max - 1) + 0.5f));
|
||||
}
|
||||
|
||||
static inline void sw_map_clamp_to_edge(int* out, float in, int max)
|
||||
static inline void sw_texture_map_clamp_to_edge(int* out, float in, int max)
|
||||
{
|
||||
*out = (int)(sw_saturate(in) * (max - 1) + 0.5f);
|
||||
}
|
||||
|
||||
static inline void sw_map_mirrored_repeat(int* out, float in, int max)
|
||||
static inline void sw_texture_map_mirrored_repeat(int* out, float in, int max)
|
||||
{
|
||||
in = fmodf(fabsf(in), 2);
|
||||
if (in > 1.0f) in = 1.0f - (in - 1.0f);
|
||||
*out = (int)(in * (max - 1) + 0.5f);
|
||||
}
|
||||
|
||||
static inline void sw_map(int* out, float in, int max, SWwrap mode)
|
||||
static inline void sw_texture_map(int* out, float in, int max, SWwrap mode)
|
||||
{
|
||||
switch (mode) {
|
||||
case SW_REPEAT:
|
||||
sw_map_repeat(out, in, max);
|
||||
sw_texture_map_repeat(out, in, max);
|
||||
break;
|
||||
case SW_CLAMP_TO_EDGE:
|
||||
sw_map_clamp_to_edge(out, in, max);
|
||||
sw_texture_map_clamp_to_edge(out, in, max);
|
||||
break;
|
||||
case SW_MIRRORED_REPEAT:
|
||||
sw_map_mirrored_repeat(out, in, max);
|
||||
sw_texture_map_mirrored_repeat(out, in, max);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void sw_sample_texture_nearest(float* color, const sw_texture_t* tex, float u, float v)
|
||||
static inline void sw_texture_sample_nearest(float* color, const sw_texture_t* tex, float u, float v)
|
||||
{
|
||||
int x, y;
|
||||
sw_map(&x, u, tex->width, tex->sWrap);
|
||||
sw_map(&y, v, tex->height, tex->tWrap);
|
||||
sw_texture_map(&x, u, tex->width, tex->sWrap);
|
||||
sw_texture_map(&y, v, tex->height, tex->tWrap);
|
||||
sw_get_pixel(color, tex->pixels, y * tex->width + x, tex->format);
|
||||
}
|
||||
|
||||
static inline void sw_sample_texture_bilinear(float* color, const sw_texture_t* tex, float u, float v)
|
||||
static inline void sw_texture_sample_linear(float* color, const sw_texture_t* tex, float u, float v)
|
||||
{
|
||||
int x0, y0, x1, y1;
|
||||
sw_map(&x0, u, tex->width, tex->sWrap);
|
||||
sw_map(&y0, v, tex->height, tex->tWrap);
|
||||
sw_map(&x1, u + tex->tx, tex->width, tex->sWrap);
|
||||
sw_map(&y1, v + tex->ty, tex->height, tex->tWrap);
|
||||
sw_texture_map(&x0, u, tex->width, tex->sWrap);
|
||||
sw_texture_map(&y0, v, tex->height, tex->tWrap);
|
||||
sw_texture_map(&x1, u + tex->tx, tex->width, tex->sWrap);
|
||||
sw_texture_map(&y1, v + tex->ty, tex->height, tex->tWrap);
|
||||
|
||||
float fx = u * (tex->width - 1) - x0;
|
||||
float fy = v * (tex->height - 1) - y0;
|
||||
|
|
@ -779,7 +791,7 @@ static inline void sw_sample_texture_bilinear(float* color, const sw_texture_t*
|
|||
}
|
||||
}
|
||||
|
||||
static inline void sw_sample_texture(float* color, const sw_texture_t* tex, float u, float v,
|
||||
static inline void sw_texture_sample(float* color, const sw_texture_t* tex, float u, float v,
|
||||
float xDu, float yDu, float xDv, float yDv)
|
||||
{
|
||||
// TODO: It seems there are some incorrect detections depending on the context
|
||||
|
|
@ -796,21 +808,33 @@ static inline void sw_sample_texture(float* color, const sw_texture_t* tex, floa
|
|||
if (L > 1.0f) {
|
||||
// Minification
|
||||
if (tex->minFilter == SW_NEAREST) {
|
||||
sw_sample_texture_nearest(color, tex, u, v);
|
||||
sw_texture_sample_nearest(color, tex, u, v);
|
||||
} else if (tex->minFilter == SW_LINEAR) {
|
||||
sw_sample_texture_bilinear(color, tex, u, v);
|
||||
sw_texture_sample_linear(color, tex, u, v);
|
||||
}
|
||||
} else {
|
||||
// Magnification
|
||||
if (tex->magFilter == SW_NEAREST) {
|
||||
sw_sample_texture_nearest(color, tex, u, v);
|
||||
sw_texture_sample_nearest(color, tex, u, v);
|
||||
} else if (tex->magFilter == SW_LINEAR) {
|
||||
sw_sample_texture_bilinear(color, tex, u, v);
|
||||
sw_texture_sample_linear(color, tex, u, v);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline bool sw_clip_polygon_w(sw_vertex_t polygon[SW_MAX_CLIPPED_POLYGON_VERTICES], int* vertexCounter)
|
||||
|
||||
/* === Projection Helper Functions === */
|
||||
|
||||
static inline void sw_project_ndc_to_screen(float screen[2], const float ndc[4])
|
||||
{
|
||||
screen[0] = RLSW.vpPos[0] + (ndc[0] + 1.0f) * 0.5f * RLSW.vpDim[0];
|
||||
screen[1] = RLSW.vpPos[1] + (ndc[1] + 1.0f) * 0.5f * RLSW.vpDim[1];
|
||||
}
|
||||
|
||||
|
||||
/* === Triangle Rendering Part === */
|
||||
|
||||
static inline bool sw_triangle_clip_w(sw_vertex_t polygon[SW_MAX_CLIPPED_POLYGON_VERTICES], int* vertexCounter)
|
||||
{
|
||||
sw_vertex_t input[SW_MAX_CLIPPED_POLYGON_VERTICES];
|
||||
for (int i = 0; i < SW_MAX_CLIPPED_POLYGON_VERTICES; i++) {
|
||||
|
|
@ -839,7 +863,7 @@ static inline bool sw_clip_polygon_w(sw_vertex_t polygon[SW_MAX_CLIPPED_POLYGON_
|
|||
return *vertexCounter > 0;
|
||||
}
|
||||
|
||||
static inline bool sw_clip_polygon_xyz(sw_vertex_t polygon[SW_MAX_CLIPPED_POLYGON_VERTICES], int* vertexCounter)
|
||||
static inline bool sw_triangle_clip_xyz(sw_vertex_t polygon[SW_MAX_CLIPPED_POLYGON_VERTICES], int* vertexCounter)
|
||||
{
|
||||
for (int iAxis = 0; iAxis < 3; iAxis++)
|
||||
{
|
||||
|
|
@ -905,15 +929,14 @@ static inline bool sw_clip_polygon_xyz(sw_vertex_t polygon[SW_MAX_CLIPPED_POLYGO
|
|||
return *vertexCounter > 0;
|
||||
}
|
||||
|
||||
void sw_project_and_clip_triangle(sw_vertex_t polygon[SW_MAX_CLIPPED_POLYGON_VERTICES], int* vertexCounter)
|
||||
static inline void sw_triangle_project_and_clip(sw_vertex_t polygon[SW_MAX_CLIPPED_POLYGON_VERTICES], int* vertexCounter)
|
||||
{
|
||||
for (int i = 0; i < *vertexCounter; i++) {
|
||||
sw_vertex_t *v = polygon + i;
|
||||
for (int j = 0; j < 4; j++) v->homogeneous[j] = v->position[j];
|
||||
sw_vec4_transform(v->homogeneous, v->homogeneous, RLSW.matMVP);
|
||||
sw_vec4_transform(v->homogeneous, v->position, RLSW.matMVP);
|
||||
}
|
||||
|
||||
if (sw_clip_polygon_w(polygon, vertexCounter) && sw_clip_polygon_xyz(polygon, vertexCounter)) {
|
||||
if (sw_triangle_clip_w(polygon, vertexCounter) && sw_triangle_clip_xyz(polygon, vertexCounter)) {
|
||||
for (int i = 0; i < *vertexCounter; i++) {
|
||||
sw_vertex_t *v = polygon + i;
|
||||
|
||||
|
|
@ -937,14 +960,13 @@ void sw_project_and_clip_triangle(sw_vertex_t polygon[SW_MAX_CLIPPED_POLYGON_VER
|
|||
v->color[3] *= v->homogeneous[3];
|
||||
|
||||
// Transform to screen space
|
||||
v->screen[0] = RLSW.vpPos[0] + (v->homogeneous[0] + 1.0f) * 0.5f * RLSW.vpDim[0];
|
||||
v->screen[1] = RLSW.vpPos[1] + (v->homogeneous[1] + 1.0f) * 0.5f * RLSW.vpDim[1];
|
||||
sw_project_ndc_to_screen(v->screen, v->homogeneous);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#define DEFINE_RASTER_SCANLINE(FUNC_NAME, ENABLE_TEXTURE, ENABLE_DEPTH_TEST) \
|
||||
void FUNC_NAME(const sw_texture_t* tex, const sw_vertex_t* start, \
|
||||
#define DEFINE_TRIANGLE_RASTER_SCANLINE(FUNC_NAME, ENABLE_TEXTURE, ENABLE_DEPTH_TEST) \
|
||||
static inline void FUNC_NAME(const sw_texture_t* tex, const sw_vertex_t* start, \
|
||||
const sw_vertex_t* end, float yDu, float yDv) \
|
||||
{ \
|
||||
/* Calculate the horizontal width and avoid division by zero */ \
|
||||
|
|
@ -1013,7 +1035,7 @@ void FUNC_NAME(const sw_texture_t* tex, const sw_vertex_t* start,
|
|||
{ \
|
||||
/* Sample the texture */ \
|
||||
float texColor[4]; \
|
||||
sw_sample_texture(texColor, tex, u * w, v * w, xDu, yDu, xDv, yDv); \
|
||||
sw_texture_sample(texColor, tex, u * w, v * w, xDu, yDu, xDv, yDv); \
|
||||
\
|
||||
/* Interpolate the color and modulate by the texture color */ \
|
||||
for (int i = 0; i < 4; i++) { \
|
||||
|
|
@ -1043,8 +1065,8 @@ void FUNC_NAME(const sw_texture_t* tex, const sw_vertex_t* start,
|
|||
} \
|
||||
}
|
||||
|
||||
#define DEFINE_RASTER_TRIANGLE(FUNC_NAME, FUNC_SCANLINE, ENABLE_TEXTURE) \
|
||||
void FUNC_NAME(const sw_vertex_t* v0, const sw_vertex_t* v1, const sw_vertex_t* v2, \
|
||||
#define DEFINE_TRIANGLE_RASTER(FUNC_NAME, FUNC_SCANLINE, ENABLE_TEXTURE) \
|
||||
static inline void FUNC_NAME(const sw_vertex_t* v0, const sw_vertex_t* v1, const sw_vertex_t* v2, \
|
||||
const sw_texture_t* tex) \
|
||||
{ \
|
||||
/* Swap vertices by increasing y */ \
|
||||
|
|
@ -1134,17 +1156,17 @@ void FUNC_NAME(const sw_vertex_t* v0, const sw_vertex_t* v1, const sw_vertex_t*
|
|||
} \
|
||||
}
|
||||
|
||||
DEFINE_RASTER_SCANLINE(sw_raster_scanline, false, false)
|
||||
DEFINE_RASTER_SCANLINE(sw_raster_scanline_tex, true, false)
|
||||
DEFINE_RASTER_SCANLINE(sw_raster_scanline_depth, false, true)
|
||||
DEFINE_RASTER_SCANLINE(sw_raster_scanline_tex_depth, true, true)
|
||||
DEFINE_TRIANGLE_RASTER_SCANLINE(sw_triangle_raster_scanline, false, false)
|
||||
DEFINE_TRIANGLE_RASTER_SCANLINE(sw_triangle_raster_scanline_tex, true, false)
|
||||
DEFINE_TRIANGLE_RASTER_SCANLINE(sw_triangle_raster_scanline_depth, false, true)
|
||||
DEFINE_TRIANGLE_RASTER_SCANLINE(sw_triangle_raster_scanline_tex_depth, true, true)
|
||||
|
||||
DEFINE_RASTER_TRIANGLE(sw_raster_triangle, sw_raster_scanline, false)
|
||||
DEFINE_RASTER_TRIANGLE(sw_raster_triangle_tex, sw_raster_scanline_tex, true)
|
||||
DEFINE_RASTER_TRIANGLE(sw_raster_triangle_depth, sw_raster_scanline_depth, false)
|
||||
DEFINE_RASTER_TRIANGLE(sw_raster_triangle_tex_depth, sw_raster_scanline_tex_depth, true)
|
||||
DEFINE_TRIANGLE_RASTER(sw_triangle_raster, sw_triangle_raster_scanline, false)
|
||||
DEFINE_TRIANGLE_RASTER(sw_triangle_raster_tex, sw_triangle_raster_scanline_tex, true)
|
||||
DEFINE_TRIANGLE_RASTER(sw_triangle_raster_depth, sw_triangle_raster_scanline_depth, false)
|
||||
DEFINE_TRIANGLE_RASTER(sw_triangle_raster_tex_depth, sw_triangle_raster_scanline_tex_depth, true)
|
||||
|
||||
void sw_render_triangle(const sw_vertex_t* v0, const sw_vertex_t* v1, const sw_vertex_t* v2)
|
||||
static inline void sw_triangle_render(const sw_vertex_t* v0, const sw_vertex_t* v1, const sw_vertex_t* v2)
|
||||
{
|
||||
int vertexCounter = 3;
|
||||
|
||||
|
|
@ -1153,39 +1175,39 @@ void sw_render_triangle(const sw_vertex_t* v0, const sw_vertex_t* v1, const sw_v
|
|||
polygon[1] = *v1;
|
||||
polygon[2] = *v2;
|
||||
|
||||
sw_project_and_clip_triangle(polygon, &vertexCounter);
|
||||
sw_triangle_project_and_clip(polygon, &vertexCounter);
|
||||
|
||||
if (vertexCounter < 3) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ((RLSW.stateFlags & SW_STATE_TEXTURE_2D) && (RLSW.stateFlags & SW_STATE_DEPTH_TEST)) {
|
||||
for (int_fast8_t i = 0; i < vertexCounter - 2; i++) {
|
||||
sw_raster_triangle_tex_depth(
|
||||
for (int i = 0; i < vertexCounter - 2; i++) {
|
||||
sw_triangle_raster_tex_depth(
|
||||
&polygon[0], &polygon[i + 1], &polygon[i + 2],
|
||||
&RLSW.loadedTextures[RLSW.currentTexture]
|
||||
);
|
||||
}
|
||||
}
|
||||
else if (RLSW.stateFlags & SW_STATE_TEXTURE_2D) {
|
||||
for (int_fast8_t i = 0; i < vertexCounter - 2; i++) {
|
||||
sw_raster_triangle_tex(
|
||||
for (int i = 0; i < vertexCounter - 2; i++) {
|
||||
sw_triangle_raster_tex(
|
||||
&polygon[0], &polygon[i + 1], &polygon[i + 2],
|
||||
&RLSW.loadedTextures[RLSW.currentTexture]
|
||||
);
|
||||
}
|
||||
}
|
||||
else if (RLSW.stateFlags & SW_STATE_DEPTH_TEST) {
|
||||
for (int_fast8_t i = 0; i < vertexCounter - 2; i++) {
|
||||
sw_raster_triangle_depth(
|
||||
for (int i = 0; i < vertexCounter - 2; i++) {
|
||||
sw_triangle_raster_depth(
|
||||
&polygon[0], &polygon[i + 1], &polygon[i + 2],
|
||||
&RLSW.loadedTextures[RLSW.currentTexture]
|
||||
);
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (int_fast8_t i = 0; i < vertexCounter - 2; i++) {
|
||||
sw_raster_triangle(
|
||||
for (int i = 0; i < vertexCounter - 2; i++) {
|
||||
sw_triangle_raster(
|
||||
&polygon[0], &polygon[i + 1], &polygon[i + 2],
|
||||
&RLSW.loadedTextures[RLSW.currentTexture]
|
||||
);
|
||||
|
|
@ -1193,6 +1215,274 @@ void sw_render_triangle(const sw_vertex_t* v0, const sw_vertex_t* v1, const sw_v
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
/* === Line Rendering Part === */
|
||||
|
||||
uint8_t sw_line_clip_encode_2d(const float screen[2], int xMin, int yMin, int xMax, int yMax)
|
||||
{
|
||||
uint8_t code = SW_CLIP_INSIDE;
|
||||
if (screen[0] < xMin) code |= SW_CLIP_LEFT;
|
||||
if (screen[0] > xMax) code |= SW_CLIP_RIGHT;
|
||||
if (screen[1] < yMin) code |= SW_CLIP_TOP;
|
||||
if (screen[1] > yMax) code |= SW_CLIP_BOTTOM;
|
||||
return code;
|
||||
}
|
||||
|
||||
bool sw_line_clip_2d(sw_vertex_t* v1, sw_vertex_t* v2)
|
||||
{
|
||||
int xMin = RLSW.vpMin[0];
|
||||
int yMin = RLSW.vpMin[1];
|
||||
int xMax = RLSW.vpMax[0];
|
||||
int yMax = RLSW.vpMax[1];
|
||||
|
||||
bool accept = false;
|
||||
uint8_t code0, code1;
|
||||
float m = 0;
|
||||
|
||||
if (v1->screen[0] != v2->screen[0]) {
|
||||
m = (v2->screen[1] - v1->screen[1]) / (v2->screen[0] - v1->screen[0]);
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
code0 = sw_line_clip_encode_2d(v1->screen, xMin, yMin, xMax, yMax);
|
||||
code1 = sw_line_clip_encode_2d(v2->screen, xMin, yMin, xMax, yMax);
|
||||
|
||||
// Accepted if both endpoints lie within rectangle
|
||||
if ((code0 | code1) == 0) {
|
||||
accept = true;
|
||||
break;
|
||||
}
|
||||
|
||||
// Rejected if both endpoints are outside rectangle, in same region
|
||||
if (code0 & code1) break;
|
||||
|
||||
if (code0 == SW_CLIP_INSIDE) {
|
||||
uint8_t ctmp = code0; code0 = code1; code1 = ctmp;
|
||||
sw_vertex_t vtmp = *v1; *v1 = *v2; *v2 = vtmp;
|
||||
}
|
||||
|
||||
if (code0 & SW_CLIP_LEFT) {
|
||||
v1->screen[1] += (RLSW.vpMin[0] - v1->screen[0])*m;
|
||||
v1->screen[0] = (float)RLSW.vpMin[0];
|
||||
}
|
||||
else if (code0 & SW_CLIP_RIGHT) {
|
||||
v1->screen[1] += (RLSW.vpMax[0] - v1->screen[0])*m;
|
||||
v1->screen[0] = (float)RLSW.vpMax[0];
|
||||
}
|
||||
else if (code0 & SW_CLIP_BOTTOM) {
|
||||
if (m) v1->screen[0] += (RLSW.vpMin[1] - v1->screen[1]) / m;
|
||||
v1->screen[1] = (float)RLSW.vpMin[1];
|
||||
}
|
||||
else if (code0 & SW_CLIP_TOP) {
|
||||
if (m) v1->screen[0] += (RLSW.vpMax[1] - v1->screen[1]) / m;
|
||||
v1->screen[1] = (float)RLSW.vpMax[1];
|
||||
}
|
||||
}
|
||||
|
||||
return accept;
|
||||
}
|
||||
|
||||
bool sw_line_clip_coord_3d(float q, float p, float* t1, float* t2)
|
||||
{
|
||||
if (fabsf(p) < SW_CLIP_EPSILON) {
|
||||
// Check if the line is entirely outside the window
|
||||
if (q < -SW_CLIP_EPSILON) return 0; // Completely outside
|
||||
return 1; // Completely inside or on the edges
|
||||
}
|
||||
|
||||
const float r = q / p;
|
||||
|
||||
if (p < 0) {
|
||||
if (r > *t2) return 0;
|
||||
if (r > *t1) *t1 = r;
|
||||
} else {
|
||||
if (r < *t1) return 0;
|
||||
if (r < *t2) *t2 = r;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
bool sw_line_clip_3d(sw_vertex_t* v1, sw_vertex_t* v2)
|
||||
{
|
||||
// TODO: Lerp all vertices here, not just homogeneous coordinates
|
||||
|
||||
float t1 = 0, t2 = 1;
|
||||
|
||||
float delta[4];
|
||||
for (int i = 0; i < 4; i++) {
|
||||
delta[i] = v2->homogeneous[i] - v1->homogeneous[i];
|
||||
}
|
||||
|
||||
if (!sw_line_clip_coord_3d(v1->homogeneous[3] - v1->homogeneous[0], -delta[3] + delta[0], &t1, &t2)) return false;
|
||||
if (!sw_line_clip_coord_3d(v1->homogeneous[3] + v1->homogeneous[0], -delta[3] - delta[0], &t1, &t2)) return false;
|
||||
|
||||
if (!sw_line_clip_coord_3d(v1->homogeneous[3] - v1->homogeneous[1], -delta[3] + delta[1], &t1, &t2)) return false;
|
||||
if (!sw_line_clip_coord_3d(v1->homogeneous[3] + v1->homogeneous[1], -delta[3] - delta[1], &t1, &t2)) return false;
|
||||
|
||||
if (!sw_line_clip_coord_3d(v1->homogeneous[3] - v1->homogeneous[2], -delta[3] + delta[2], &t1, &t2)) return false;
|
||||
if (!sw_line_clip_coord_3d(v1->homogeneous[3] + v1->homogeneous[2], -delta[3] - delta[2], &t1, &t2)) return false;
|
||||
|
||||
if (t2 < 1) {
|
||||
for (int i = 0; i < 4; i++) {
|
||||
v2->homogeneous[i] = v1->homogeneous[i] + t2 * delta[i];
|
||||
}
|
||||
}
|
||||
|
||||
if (t1 > 0) {
|
||||
for (int i = 0; i < 4; i++) {
|
||||
v1->homogeneous[i] = v1->homogeneous[i] + t1 * delta[i];
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool sw_line_project_and_clip(sw_vertex_t* v0, sw_vertex_t* v1)
|
||||
{
|
||||
sw_vec4_transform(v0->homogeneous, v0->position, RLSW.matMVP);
|
||||
sw_vec4_transform(v1->homogeneous, v1->position, RLSW.matMVP);
|
||||
|
||||
if (v0->homogeneous[3] == 1.0f && v1->homogeneous[3] == 1.0f) {
|
||||
sw_project_ndc_to_screen(v0->screen, v0->homogeneous);
|
||||
sw_project_ndc_to_screen(v1->screen, v1->homogeneous);
|
||||
if (!sw_line_clip_2d(v0, v1)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (!sw_line_clip_3d(v0, v1)) {
|
||||
return false;
|
||||
}
|
||||
// Convert XYZ coordinates to NDC
|
||||
v0->homogeneous[3] = 1.0f / v0->homogeneous[3];
|
||||
v1->homogeneous[3] = 1.0f / v1->homogeneous[3];
|
||||
for (int i = 0; i < 3; i++) {
|
||||
v0->homogeneous[i] *= v0->homogeneous[3];
|
||||
v1->homogeneous[i] *= v1->homogeneous[3];
|
||||
}
|
||||
// Convert NDC coordinates to screen space
|
||||
sw_project_ndc_to_screen(v0->screen, v0->homogeneous);
|
||||
sw_project_ndc_to_screen(v1->screen, v1->homogeneous);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#define DEFINE_LINE_RASTER(FUNC_NAME, ENABLE_DEPTH_TEST) \
|
||||
void FUNC_NAME(const sw_vertex_t* v0, const sw_vertex_t* v1) \
|
||||
{ \
|
||||
int x1 = (int)v0->screen[0]; \
|
||||
int y1 = (int)v0->screen[1]; \
|
||||
int x2 = (int)v1->screen[0]; \
|
||||
int y2 = (int)v1->screen[1]; \
|
||||
\
|
||||
float z1 = v0->homogeneous[2]; \
|
||||
float z2 = v1->homogeneous[2]; \
|
||||
\
|
||||
int shortLen = y2 - y1; \
|
||||
int longLen = x2 - x1; \
|
||||
bool yLonger = 0; \
|
||||
\
|
||||
if (abs(shortLen) > abs(longLen)) { \
|
||||
int tmp = shortLen; \
|
||||
shortLen = longLen; \
|
||||
longLen = tmp; \
|
||||
yLonger = 1; \
|
||||
} \
|
||||
\
|
||||
float invEndVal = 1.0f / longLen; \
|
||||
int endVal = longLen; \
|
||||
int sgnInc = 1; \
|
||||
\
|
||||
if (longLen < 0) { \
|
||||
longLen = -longLen; \
|
||||
sgnInc = -1; \
|
||||
} \
|
||||
\
|
||||
int decInc = (longLen == 0) ? 0 \
|
||||
: (shortLen << 16) / longLen; \
|
||||
\
|
||||
const int fb_width = RLSW.framebuffer.width; \
|
||||
const float z_diff = z2 - z1; \
|
||||
\
|
||||
uint8_t* color_buffer = RLSW.framebuffer.color; \
|
||||
uint16_t* depth_buffer = RLSW.framebuffer.depth; \
|
||||
\
|
||||
int j = 0; \
|
||||
if (yLonger) { \
|
||||
for (int i = 0; i != endVal; i += sgnInc, j += decInc) { \
|
||||
float t = (float)i * invEndVal; \
|
||||
\
|
||||
int x = x1 + (j >> 16); \
|
||||
int y = y1 + i; \
|
||||
float z = z1 + t * z_diff; \
|
||||
int pixel_index = y * fb_width + x; \
|
||||
\
|
||||
uint16_t* dptr = &depth_buffer[pixel_index]; \
|
||||
if (ENABLE_DEPTH_TEST) { \
|
||||
float depth = (float)(*dptr) / UINT16_MAX; \
|
||||
if (z > depth) continue; \
|
||||
} \
|
||||
\
|
||||
*dptr = (uint16_t)(z * UINT16_MAX); \
|
||||
\
|
||||
int color_index = 4 * pixel_index; \
|
||||
uint8_t* cptr = &color_buffer[color_index]; \
|
||||
\
|
||||
for (int j = 0; j < 4; j++) { \
|
||||
float finalColor = sw_lerp(v0->color[j], v1->color[j], t); \
|
||||
cptr[j] = (uint8_t)(finalColor * 255); \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
else { \
|
||||
for (int i = 0; i != endVal; i += sgnInc, j += decInc) { \
|
||||
float t = (float)i * invEndVal; \
|
||||
\
|
||||
int x = x1 + i; \
|
||||
int y = y1 + (j >> 16); \
|
||||
float z = z1 + t * z_diff; \
|
||||
int pixel_index = y * fb_width + x; \
|
||||
\
|
||||
uint16_t* dptr = &depth_buffer[pixel_index]; \
|
||||
if (ENABLE_DEPTH_TEST) { \
|
||||
float depth = (float)(*dptr) / UINT16_MAX; \
|
||||
if (z > depth) continue; \
|
||||
} \
|
||||
\
|
||||
*dptr = (uint16_t)(z * UINT16_MAX); \
|
||||
\
|
||||
int color_index = 4 * pixel_index; \
|
||||
uint8_t* cptr = &color_buffer[color_index]; \
|
||||
\
|
||||
for (int j = 0; j < 4; j++) { \
|
||||
float finalColor = sw_lerp(v0->color[j], v1->color[j], t); \
|
||||
cptr[j] = (uint8_t)(finalColor * 255); \
|
||||
} \
|
||||
} \
|
||||
} \
|
||||
}
|
||||
|
||||
DEFINE_LINE_RASTER(sw_line_raster, false)
|
||||
DEFINE_LINE_RASTER(sw_line_raster_depth, true)
|
||||
|
||||
static inline void sw_line_render(sw_vertex_t* v0, sw_vertex_t* v1)
|
||||
{
|
||||
if (!sw_line_project_and_clip(v0, v1)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (RLSW.stateFlags & SW_STATE_DEPTH_TEST) {
|
||||
sw_line_raster_depth(v0, v1);
|
||||
}
|
||||
else {
|
||||
sw_line_raster(v0, v1);
|
||||
}
|
||||
}
|
||||
|
||||
/* === Some Validity Check Helper === */
|
||||
|
||||
static inline bool sw_is_texture_id_valid(uint32_t id)
|
||||
{
|
||||
bool valid = true;
|
||||
|
|
@ -1214,6 +1504,7 @@ static inline bool sw_is_texture_wrap_valid(int wrap)
|
|||
return (wrap == SW_REPEAT || wrap == SW_CLAMP_TO_EDGE || SW_MIRRORED_REPEAT);
|
||||
}
|
||||
|
||||
|
||||
/* === Public Implementation === */
|
||||
|
||||
void swInit(int w, int h)
|
||||
|
|
@ -1694,22 +1985,25 @@ void swVertex4fv(const float* v)
|
|||
case SW_POINTS:
|
||||
break;
|
||||
case SW_LINES:
|
||||
neededVertices = 2;
|
||||
sw_line_render(
|
||||
&RLSW.vertexBuffer[0],
|
||||
&RLSW.vertexBuffer[1]
|
||||
);
|
||||
break;
|
||||
case SW_TRIANGLES:
|
||||
sw_render_triangle(
|
||||
sw_triangle_render(
|
||||
&RLSW.vertexBuffer[0],
|
||||
&RLSW.vertexBuffer[1],
|
||||
&RLSW.vertexBuffer[2]
|
||||
);
|
||||
break;
|
||||
case SW_QUADS:
|
||||
sw_render_triangle(
|
||||
sw_triangle_render(
|
||||
&RLSW.vertexBuffer[0],
|
||||
&RLSW.vertexBuffer[1],
|
||||
&RLSW.vertexBuffer[2]
|
||||
);
|
||||
sw_render_triangle(
|
||||
sw_triangle_render(
|
||||
&RLSW.vertexBuffer[2],
|
||||
&RLSW.vertexBuffer[3],
|
||||
&RLSW.vertexBuffer[0]
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user