implement state support
Also replace the triangle rasterization functions with macros that generate specific functions for each state of the rendering system. Also, add the OpenGL definitions in order to add a binding for rlgl.
This commit is contained in:
parent
7d36568eeb
commit
8aed39ff49
567
src/external/rlsw.h
vendored
567
src/external/rlsw.h
vendored
|
|
@ -28,6 +28,9 @@
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
|
|
||||||
|
/* === RLSW Definition And Macros === */
|
||||||
|
|
||||||
#ifndef SW_MALLOC
|
#ifndef SW_MALLOC
|
||||||
# define SW_MALLOC(sz) malloc(sz)
|
# define SW_MALLOC(sz) malloc(sz)
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -60,30 +63,94 @@
|
||||||
# define SW_CLIP_EPSILON 1e-4f
|
# define SW_CLIP_EPSILON 1e-4f
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/* === OpenGL Definitions === */
|
||||||
|
|
||||||
|
#define GL_TEXTURE_2D 0x0DE1
|
||||||
|
#define GL_DEPTH_TEST 0x0B71
|
||||||
|
#define GL_CULL_FACE 0x0B44
|
||||||
|
|
||||||
|
#define GL_MODELVIEW 0x1700
|
||||||
|
#define GL_PROJECTION 0x1701
|
||||||
|
#define GL_TEXTURE 0x1702
|
||||||
|
|
||||||
|
#define GL_VERTEX_ARRAY 0x8074
|
||||||
|
#define GL_NORMAL_ARRAY 0x8075
|
||||||
|
#define GL_COLOR_ARRAY 0x8076
|
||||||
|
//#define GL_INDEX_ARRAY 0x8077
|
||||||
|
#define GL_TEXTURE_COORD_ARRAY 0x8078
|
||||||
|
|
||||||
|
#define GL_POINTS 0x0000
|
||||||
|
#define GL_LINES 0x0001
|
||||||
|
//#define GL_LINE_LOOP 0x0002
|
||||||
|
//#define GL_LINE_STRIP 0x0003
|
||||||
|
#define GL_TRIANGLES 0x0004
|
||||||
|
//#define GL_TRIANGLE_STRIP 0x0005
|
||||||
|
//#define GL_TRIANGLE_FAN 0x0006
|
||||||
|
#define GL_QUADS 0x0007
|
||||||
|
//#define GL_QUAD_STRIP 0x0008
|
||||||
|
//#define GL_POLYGON 0x0009
|
||||||
|
|
||||||
|
//#define GL_CW 0x0900
|
||||||
|
//#define GL_CCW 0x0901
|
||||||
|
|
||||||
|
#define GL_FRONT 0x0404
|
||||||
|
#define GL_BACK 0x0405
|
||||||
|
|
||||||
|
#define GL_NEAREST 0x2600
|
||||||
|
#define GL_LINEAR 0x2601
|
||||||
|
|
||||||
|
#define GL_REPEAT 0x2901
|
||||||
|
#define GL_CLAMP_TO_EDGE 0x812F //< (OpenGL 1.2)
|
||||||
|
#define GL_MIRRORED_REPEAT 0x8370 //< (OpenGL 2.0)
|
||||||
|
|
||||||
|
#define GL_TEXTURE_MAG_FILTER 0x2800
|
||||||
|
#define GL_TEXTURE_MIN_FILTER 0x2801
|
||||||
|
|
||||||
|
#define GL_TEXTURE_WRAP_S 0x2802
|
||||||
|
#define GL_TEXTURE_WRAP_T 0x2803
|
||||||
|
|
||||||
|
#define GL_NO_ERROR 0
|
||||||
|
#define GL_INVALID_ENUM 0x0500
|
||||||
|
#define GL_INVALID_VALUE 0x0501
|
||||||
|
#define GL_INVALID_OPERATION 0x0502
|
||||||
|
#define GL_STACK_OVERFLOW 0x0503
|
||||||
|
#define GL_STACK_UNDERFLOW 0x0504
|
||||||
|
#define GL_OUT_OF_MEMORY 0x0505
|
||||||
|
|
||||||
|
|
||||||
|
/* === RLSW Enums === */
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
SW_PROJECTION,
|
SW_TEXTURE_2D = GL_TEXTURE_2D,
|
||||||
SW_MODELVIEW,
|
SW_DEPTH_TEST = GL_DEPTH_TEST,
|
||||||
SW_TEXTURE
|
SW_CULL_FACE = GL_CULL_FACE
|
||||||
|
} SWstate;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
SW_PROJECTION = GL_PROJECTION,
|
||||||
|
SW_MODELVIEW = GL_MODELVIEW,
|
||||||
|
SW_TEXTURE = GL_TEXTURE
|
||||||
} SWmatrix;
|
} SWmatrix;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
SW_VERTEX_ARRAY,
|
SW_VERTEX_ARRAY = GL_VERTEX_ARRAY,
|
||||||
SW_TEXTURE_COORD_ARRAY,
|
SW_TEXTURE_COORD_ARRAY = GL_TEXTURE_COORD_ARRAY,
|
||||||
SW_NORMAL_ARRAY,
|
SW_NORMAL_ARRAY = GL_NORMAL_ARRAY,
|
||||||
SW_COLOR_ARRAY
|
SW_COLOR_ARRAY = GL_COLOR_ARRAY
|
||||||
} SWarray;
|
} SWarray;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
SW_POINTS,
|
SW_POINTS = GL_POINTS,
|
||||||
SW_LINES,
|
SW_LINES = GL_LINES,
|
||||||
SW_TRIANGLES,
|
SW_TRIANGLES = GL_TRIANGLES,
|
||||||
SW_QUADS,
|
SW_QUADS = GL_QUADS,
|
||||||
} SWfill;
|
} SWfill;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
SW_CULL_FRONT,
|
SW_FRONT = GL_FRONT,
|
||||||
SW_CULL_BACK,
|
SW_BACK = GL_BACK,
|
||||||
} SWcull;
|
} SWface;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
SW_PIXELFORMAT_UNCOMPRESSED_GRAYSCALE = 1, // 8 bit per pixel (no alpha)
|
SW_PIXELFORMAT_UNCOMPRESSED_GRAYSCALE = 1, // 8 bit per pixel (no alpha)
|
||||||
|
|
@ -113,35 +180,30 @@
|
||||||
} SWpixelformat;
|
} SWpixelformat;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
SW_NEAREST,
|
SW_NEAREST = GL_NEAREST,
|
||||||
SW_LINEAR,
|
SW_LINEAR = GL_LINEAR
|
||||||
SW_NEAREST_MIPMAP_NEAREST,
|
|
||||||
SW_NEAREST_MIPMAP_LINEAR,
|
|
||||||
SW_LINEAR_MIPMAP_NEAREST,
|
|
||||||
SW_LINEAR_MIPMAP_LINEAR
|
|
||||||
} SWfilter;
|
} SWfilter;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
SW_REPEAT,
|
SW_REPEAT = GL_REPEAT,
|
||||||
SW_CLAMP_TO_EDGE,
|
SW_CLAMP_TO_EDGE = GL_CLAMP_TO_EDGE,
|
||||||
SW_MIRRORED_REPEAT
|
SW_MIRRORED_REPEAT = GL_MIRRORED_REPEAT
|
||||||
} SWwrap;
|
} SWwrap;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
SW_TEXTURE_MIN_FILTER,
|
SW_TEXTURE_MIN_FILTER = GL_TEXTURE_MIN_FILTER,
|
||||||
SW_TEXTURE_MAG_FILTER,
|
SW_TEXTURE_MAG_FILTER = GL_TEXTURE_MAG_FILTER,
|
||||||
SW_TEXTURE_WRAP_S,
|
SW_TEXTURE_WRAP_S = GL_TEXTURE_WRAP_S,
|
||||||
SW_TEXTURE_WRAP_T
|
SW_TEXTURE_WRAP_T = GL_TEXTURE_WRAP_T
|
||||||
} SWtexparam;
|
} SWtexparam;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
SW_NO_ERROR,
|
SW_NO_ERROR = GL_NO_ERROR,
|
||||||
SW_INVALID_ENUM,
|
SW_INVALID_ENUM = GL_INVALID_ENUM,
|
||||||
SW_INVALID_VALUE,
|
SW_INVALID_VALUE = GL_INVALID_VALUE,
|
||||||
SW_STACK_OVERFLOW,
|
SW_STACK_OVERFLOW = GL_STACK_OVERFLOW,
|
||||||
SW_STACK_UNDERFLOW,
|
SW_STACK_UNDERFLOW = GL_STACK_UNDERFLOW,
|
||||||
SW_INVALID_OPERATION,
|
SW_INVALID_OPERATION = GL_INVALID_OPERATION,
|
||||||
SW_ERROR_OUT_OF_MEMORY
|
|
||||||
} SWerrcode;
|
} SWerrcode;
|
||||||
|
|
||||||
/* === Public API === */
|
/* === Public API === */
|
||||||
|
|
@ -149,6 +211,9 @@
|
||||||
void swInit(int w, int h);
|
void swInit(int w, int h);
|
||||||
void swClose(void);
|
void swClose(void);
|
||||||
|
|
||||||
|
void swEnable(SWstate state);
|
||||||
|
void swDisable(SWstate state);
|
||||||
|
|
||||||
void* swGetColorBuffer(int* w, int* h);
|
void* swGetColorBuffer(int* w, int* h);
|
||||||
|
|
||||||
void swMatrixMode(SWmatrix mode);
|
void swMatrixMode(SWmatrix mode);
|
||||||
|
|
@ -216,7 +281,6 @@
|
||||||
#endif // RLSW_H
|
#endif // RLSW_H
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef RLSW_IMPL
|
#ifdef RLSW_IMPL
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
@ -228,6 +292,10 @@
|
||||||
#define SW_DEG2RAD (SW_PI/180.0f)
|
#define SW_DEG2RAD (SW_PI/180.0f)
|
||||||
#define SW_RAD2DEG (180.0f/SW_PI)
|
#define SW_RAD2DEG (180.0f/SW_PI)
|
||||||
|
|
||||||
|
#define SW_STATE_TEXTURE_2D (1 << 0)
|
||||||
|
#define SW_STATE_DEPTH_TEST (1 << 1)
|
||||||
|
#define SW_STATE_CULL_FACE (1 << 2)
|
||||||
|
|
||||||
/* === Internal Structs === */
|
/* === Internal Structs === */
|
||||||
|
|
||||||
typedef float sw_matrix_t[4*4];
|
typedef float sw_matrix_t[4*4];
|
||||||
|
|
@ -316,7 +384,7 @@
|
||||||
SWmatrix currentMatrixMode; // Current matrix mode (e.g., sw_MODELVIEW, sw_PROJECTION)
|
SWmatrix currentMatrixMode; // Current matrix mode (e.g., sw_MODELVIEW, sw_PROJECTION)
|
||||||
bool modelMatrixUsed; // Flag indicating if the model matrix is used
|
bool modelMatrixUsed; // Flag indicating if the model matrix is used
|
||||||
|
|
||||||
SWcull cullFace; // Faces to cull
|
SWface cullFace; // Faces to cull
|
||||||
SWerrcode errCode; // Last error code
|
SWerrcode errCode; // Last error code
|
||||||
|
|
||||||
sw_texture_t* loadedTextures;
|
sw_texture_t* loadedTextures;
|
||||||
|
|
@ -325,6 +393,8 @@
|
||||||
uint32_t* freeTextureIds;
|
uint32_t* freeTextureIds;
|
||||||
int freeTextureIdCount;
|
int freeTextureIdCount;
|
||||||
|
|
||||||
|
uint32_t stateFlags;
|
||||||
|
|
||||||
} sw_data_t;
|
} sw_data_t;
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -847,170 +917,212 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void sw_raster_scanline(const sw_texture_t* tex, const sw_vertex_t* start, const sw_vertex_t* end, float yDu, float yDv)
|
#define DEFINE_RASTER_SCANLINE(FUNC_NAME, ENABLE_TEXTURE, ENABLE_DEPTH_TEST) \
|
||||||
{
|
void FUNC_NAME(const sw_texture_t* tex, const sw_vertex_t* start, \
|
||||||
// Calculate the horizontal width and avoid division by zero
|
const sw_vertex_t* end, float yDu, float yDv) \
|
||||||
float dx = end->screen[0] - start->screen[0];
|
{ \
|
||||||
if (fabsf(dx) < 1e-4f) return;
|
/* Calculate the horizontal width and avoid division by zero */ \
|
||||||
|
float dx = end->screen[0] - start->screen[0]; \
|
||||||
// Convert and center the screen coordinates
|
if (fabsf(dx) < 1e-4f) return; \
|
||||||
int xStart = (int)(start->screen[0] + 0.5f);
|
\
|
||||||
int xEnd = (int)(end->screen[0] + 0.5f);
|
/* Convert and center the screen coordinates */ \
|
||||||
int y = (int)(start->screen[1] + 0.5f);
|
int xStart = (int)(start->screen[0] + 0.5f); \
|
||||||
|
int xEnd = (int)(end->screen[0] + 0.5f); \
|
||||||
// Calculate the initial interpolation parameter and its increment
|
int y = (int)(start->screen[1] + 0.5f); \
|
||||||
float dt = 1.0f / dx;
|
\
|
||||||
float t = (xStart - start->screen[0]) * dt;
|
/* Calculate the initial interpolation parameter and its increment */ \
|
||||||
|
float dt = 1.0f / dx; \
|
||||||
// Calculate the horizontal gradients for UV coordinates
|
float t = (xStart - start->screen[0]) * dt; \
|
||||||
float xDu = (end->texcoord[0] - start->texcoord[0]) * dt;
|
\
|
||||||
float xDv = (end->texcoord[1] - start->texcoord[1]) * dt;
|
float xDu, xDv; \
|
||||||
|
if (ENABLE_TEXTURE) { \
|
||||||
// Pre-calculate the color differences for interpolation
|
/* Calculate the horizontal gradients for UV coordinates */ \
|
||||||
float dcol[4];
|
xDu = (end->texcoord[0] - start->texcoord[0]) * dt; \
|
||||||
for (int i = 0; i < 4; i++) {
|
xDv = (end->texcoord[1] - start->texcoord[1]) * dt; \
|
||||||
dcol[i] = end->color[i] - start->color[i];
|
} \
|
||||||
|
\
|
||||||
|
/* Pre-calculate the color differences for interpolation */ \
|
||||||
|
float dcol[4]; \
|
||||||
|
for (int i = 0; i < 4; i++) { \
|
||||||
|
dcol[i] = end->color[i] - start->color[i]; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
/* Pre-calculate the differences in Z and W \
|
||||||
|
(for depth testing and perspective correction) */ \
|
||||||
|
float dz = end->homogeneous[2] - start->homogeneous[2]; \
|
||||||
|
float dw = end->homogeneous[3] - start->homogeneous[3]; \
|
||||||
|
\
|
||||||
|
float u, v; \
|
||||||
|
if (ENABLE_TEXTURE) { \
|
||||||
|
/* Initialize the interpolated texture coordinates */ \
|
||||||
|
u = start->texcoord[0] + t * xDu; \
|
||||||
|
v = start->texcoord[1] + t * xDv; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
/* Pre-calculate the starting pointer for the color framebuffer row */ \
|
||||||
|
uint8_t* row_ptr = (uint8_t*)((uint32_t*)RLSW.framebuffer.color + y * RLSW.framebuffer.width); \
|
||||||
|
uint8_t* dst = row_ptr + xStart * 4; \
|
||||||
|
\
|
||||||
|
/* Pre-calculate the pointer for the depth buffer row */ \
|
||||||
|
uint16_t* depth_row = RLSW.framebuffer.depth + y * RLSW.framebuffer.width + xStart; \
|
||||||
|
uint16_t* dptr = depth_row; \
|
||||||
|
\
|
||||||
|
/* Scanline rasterization loop */ \
|
||||||
|
for (int x = xStart; x < xEnd; x++) { \
|
||||||
|
/* Interpolate Z and W for depth testing and perspective correction */ \
|
||||||
|
float w = 1.0f / (start->homogeneous[3] + t * dw); \
|
||||||
|
float z = start->homogeneous[2] + t * dz; \
|
||||||
|
\
|
||||||
|
if (ENABLE_DEPTH_TEST) { \
|
||||||
|
/* Depth testing with direct access to the depth buffer */ \
|
||||||
|
/* TODO: Implement different depth funcs? */ \
|
||||||
|
float depth = (float)(*dptr) / UINT16_MAX; \
|
||||||
|
if (z > depth) goto discard; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
/* Update the depth buffer */ \
|
||||||
|
*dptr = (uint16_t)(z * UINT16_MAX); \
|
||||||
|
\
|
||||||
|
if (ENABLE_TEXTURE) \
|
||||||
|
{ \
|
||||||
|
/* Sample the texture */ \
|
||||||
|
float texColor[4]; \
|
||||||
|
sw_sample_texture(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++) { \
|
||||||
|
float lerp = start->color[i] + t * dcol[i]; \
|
||||||
|
float finalColor = texColor[i] * lerp; \
|
||||||
|
/* Inline clamp to keep the value between 0 and 1 */ \
|
||||||
|
/* NOTE: The need for clamp the colors could be a sign of problem during interpolation (?) */ \
|
||||||
|
finalColor = (finalColor < 0.0f) ? 0.0f : (finalColor > 1.0f ? 1.0f : finalColor); \
|
||||||
|
dst[i] = (uint8_t)(finalColor * 255.0f); \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
else \
|
||||||
|
{ \
|
||||||
|
/* Interpolate the color */ \
|
||||||
|
for (int i = 0; i < 4; i++) { \
|
||||||
|
float finalColor = start->color[i] + t * dcol[i]; \
|
||||||
|
/* Inline clamp to keep the value between 0 and 1 */ \
|
||||||
|
/* NOTE: The need for clamp the colors could be a sign of problem during interpolation (?) */ \
|
||||||
|
finalColor = (finalColor < 0.0f) ? 0.0f : (finalColor > 1.0f ? 1.0f : finalColor); \
|
||||||
|
dst[i] = (uint8_t)(finalColor * 255.0f); \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
/* Increment the interpolation parameter, UVs, and pointers */ \
|
||||||
|
discard: \
|
||||||
|
t += dt; \
|
||||||
|
dst += 4; \
|
||||||
|
dptr++; \
|
||||||
|
if (ENABLE_TEXTURE) { \
|
||||||
|
u += xDu; \
|
||||||
|
v += xDv; \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pre-calculate the differences in Z and W (for depth testing and perspective correction)
|
#define DEFINE_RASTER_TRIANGLE(FUNC_NAME, FUNC_SCANLINE, ENABLE_TEXTURE) \
|
||||||
float dz = end->homogeneous[2] - start->homogeneous[2];
|
void FUNC_NAME(const sw_vertex_t* v0, const sw_vertex_t* v1, const sw_vertex_t* v2, \
|
||||||
float dw = end->homogeneous[3] - start->homogeneous[3];
|
const sw_texture_t* tex) \
|
||||||
|
{ \
|
||||||
// Initialize the interpolated texture coordinates
|
/* Swap vertices by increasing y */ \
|
||||||
float u = start->texcoord[0] + t * xDu;
|
if (v0->screen[1] > v1->screen[1]) { const sw_vertex_t* tmp = v0; v0 = v1; v1 = tmp; } \
|
||||||
float v = start->texcoord[1] + t * xDv;
|
if (v1->screen[1] > v2->screen[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; } \
|
||||||
// Pre-calculate the starting pointer for the color framebuffer row
|
\
|
||||||
uint8_t* row_ptr = (uint8_t*)((uint32_t*)RLSW.framebuffer.color + y * RLSW.framebuffer.width);
|
/* Extracting coordinates from the sorted vertices */ \
|
||||||
uint8_t* dst = row_ptr + xStart * 4;
|
float x0 = v0->screen[0], y0 = v0->screen[1]; \
|
||||||
|
float x1 = v1->screen[0], y1 = v1->screen[1]; \
|
||||||
// Pre-calculate the pointer for the depth buffer row
|
float x2 = v2->screen[0], y2 = v2->screen[1]; \
|
||||||
uint16_t* depth_row = RLSW.framebuffer.depth + y * RLSW.framebuffer.width + xStart;
|
\
|
||||||
uint16_t* dptr = depth_row;
|
/* Reject degenerate triangles */ \
|
||||||
|
float height = y2 - y0; \
|
||||||
// Scanline rasterization loop
|
if (height < 1e-4f) return; \
|
||||||
for (int x = xStart; x < xEnd; x++) {
|
\
|
||||||
// Interpolate Z and W for depth testing and perspective correction
|
/* Precompute the inverse of the triangle height and */ \
|
||||||
float w = 1.0f / (start->homogeneous[3] + t * dw);
|
/* edge lengths with checks to avoid division by zero. */ \
|
||||||
float z = start->homogeneous[2] + t * dz;
|
float inv_height = 1.0f / height; \
|
||||||
|
float inv_y1y0 = (y1 - y0 > 1e-4f) ? 1.0f / (y1 - y0) : 0.0f; \
|
||||||
// Depth testing with direct access to the depth buffer
|
float inv_y2y1 = (y2 - y1 > 1e-4f) ? 1.0f / (y2 - y1) : 0.0f; \
|
||||||
// TODO: Implement different depth funcs?
|
\
|
||||||
float depth = (float)(*dptr) / UINT16_MAX;
|
/* Pre-calculation of slopes (dx/dy) */ \
|
||||||
if (z > depth) goto discard;
|
float dx02 = (x2 - x0) * inv_height; \
|
||||||
|
float dx01 = (x1 - x0) * inv_y1y0; \
|
||||||
// Update the depth buffer
|
float dx12 = (x2 - x1) * inv_y2y1; \
|
||||||
*dptr = (uint16_t)(z * UINT16_MAX);
|
\
|
||||||
|
/* Y bounds (vertical clipping) */ \
|
||||||
// Sample the texture
|
int yTop = (int)(y0 + 0.5f); \
|
||||||
float texColor[4];
|
int yMiddle = (int)(y1 + 0.5f); \
|
||||||
sw_sample_texture(texColor, tex, u * w, v * w, xDu, yDu, xDv, yDv);
|
int yBottom = (int)(y2 + 0.5f); \
|
||||||
|
\
|
||||||
// Interpolate the color and modulate by the texture color
|
/* Global calculation of vertical texture gradients for the triangle */ \
|
||||||
for (int i = 0; i < 4; i++) {
|
float yDu, yDv; \
|
||||||
float lerp = start->color[i] + t * dcol[i];
|
if (ENABLE_TEXTURE) { \
|
||||||
float finalColor = texColor[i] * lerp;
|
yDu = (v2->texcoord[0] - v0->texcoord[0]) * inv_height; \
|
||||||
// Inline clamp to keep the value between 0 and 1
|
yDv = (v2->texcoord[1] - v0->texcoord[1]) * inv_height; \
|
||||||
// NOTE: The need for clamp, the colors could be a sign of problem during interpolation (?)
|
} \
|
||||||
finalColor = (finalColor < 0.0f) ? 0.0f : (finalColor > 1.0f ? 1.0f : finalColor);
|
\
|
||||||
dst[i] = (uint8_t)(finalColor * 255.0f);
|
/* Initializing scanline variables */ \
|
||||||
|
float xLeft = x0, xRight = x0; \
|
||||||
|
sw_vertex_t start, end; \
|
||||||
|
\
|
||||||
|
/* Scanline for the upper part of the triangle */ \
|
||||||
|
for (int y = yTop; y < yMiddle; y++) { \
|
||||||
|
float dy = (float)y - y0; \
|
||||||
|
float t1 = dy * inv_height; \
|
||||||
|
float t2 = dy * inv_y1y0; \
|
||||||
|
\
|
||||||
|
/* Vertex interpolation */ \
|
||||||
|
start = sw_lerp_vertex(v0, v2, t1); \
|
||||||
|
end = sw_lerp_vertex(v0, v1, t2); \
|
||||||
|
start.screen[0] = xLeft; \
|
||||||
|
start.screen[1] = (float)y; \
|
||||||
|
end.screen[0] = xRight; \
|
||||||
|
end.screen[1] = (float)y; \
|
||||||
|
\
|
||||||
|
if (xLeft > xRight) { sw_vertex_t tmp = start; start = end; end = tmp; } \
|
||||||
|
FUNC_SCANLINE(tex, &start, &end, yDu, yDv); \
|
||||||
|
\
|
||||||
|
/* Incremental update */ \
|
||||||
|
xLeft += dx02; \
|
||||||
|
xRight += dx01; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
/* Scanline for the lower part of the triangle */ \
|
||||||
|
xRight = x1; /* Restart the right side from the second vertex */ \
|
||||||
|
for (int y = yMiddle; y < yBottom; y++) { \
|
||||||
|
float dy = (float)y - y0; \
|
||||||
|
float t1 = dy * inv_height; \
|
||||||
|
float t2 = (float)(y - y1) * inv_y2y1; \
|
||||||
|
\
|
||||||
|
/* Vertex interpolation */ \
|
||||||
|
start = sw_lerp_vertex(v0, v2, t1); \
|
||||||
|
end = sw_lerp_vertex(v1, v2, t2); \
|
||||||
|
start.screen[0] = xLeft; \
|
||||||
|
start.screen[1] = (float)y; \
|
||||||
|
end.screen[0] = xRight; \
|
||||||
|
end.screen[1] = (float)y; \
|
||||||
|
\
|
||||||
|
if (xLeft > xRight) { sw_vertex_t tmp = start; start = end; end = tmp; } \
|
||||||
|
FUNC_SCANLINE(tex, &start, &end, yDu, yDv); \
|
||||||
|
\
|
||||||
|
/* Incremental update */ \
|
||||||
|
xLeft += dx02; \
|
||||||
|
xRight += dx12; \
|
||||||
|
} \
|
||||||
}
|
}
|
||||||
|
|
||||||
// Increment the interpolation parameter, UVs, and pointers
|
DEFINE_RASTER_SCANLINE(sw_raster_scanline, false, false)
|
||||||
discard:
|
DEFINE_RASTER_SCANLINE(sw_raster_scanline_tex, true, false)
|
||||||
t += dt;
|
DEFINE_RASTER_SCANLINE(sw_raster_scanline_depth, false, true)
|
||||||
u += xDu;
|
DEFINE_RASTER_SCANLINE(sw_raster_scanline_tex_depth, true, true)
|
||||||
v += xDv;
|
|
||||||
dst += 4;
|
|
||||||
dptr++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void sw_raster_triangle(const sw_vertex_t* v0, const sw_vertex_t* v1, const sw_vertex_t* v2, const sw_texture_t* tex)
|
DEFINE_RASTER_TRIANGLE(sw_raster_triangle, sw_raster_scanline, false)
|
||||||
{
|
DEFINE_RASTER_TRIANGLE(sw_raster_triangle_tex, sw_raster_scanline_tex, true)
|
||||||
// Swap vertices by increasing y
|
DEFINE_RASTER_TRIANGLE(sw_raster_triangle_depth, sw_raster_scanline_depth, false)
|
||||||
if (v0->screen[1] > v1->screen[1]) { const sw_vertex_t* tmp = v0; v0 = v1; v1 = tmp; }
|
DEFINE_RASTER_TRIANGLE(sw_raster_triangle_tex_depth, sw_raster_scanline_tex_depth, true)
|
||||||
if (v1->screen[1] > v2->screen[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; }
|
|
||||||
|
|
||||||
// Extracting coordinates from the sorted vertices
|
|
||||||
float x0 = v0->screen[0], y0 = v0->screen[1];
|
|
||||||
float x1 = v1->screen[0], y1 = v1->screen[1];
|
|
||||||
float x2 = v2->screen[0], y2 = v2->screen[1];
|
|
||||||
|
|
||||||
// Reject degenerate triangles
|
|
||||||
float height = y2 - y0;
|
|
||||||
if (height < 1e-4f) return;
|
|
||||||
|
|
||||||
// Global calculation of vertical texture gradients for the triangle
|
|
||||||
float yDu = (v2->texcoord[0] - v0->texcoord[0]) / height;
|
|
||||||
float yDv = (v2->texcoord[1] - v0->texcoord[1]) / height;
|
|
||||||
|
|
||||||
// Precompute the inverse of the triangle height and
|
|
||||||
// edge lengths with checks to avoid division by zero.
|
|
||||||
float inv_height = 1.0f / height;
|
|
||||||
float inv_y1y0 = (y1 - y0 > 1e-4f) ? 1.0f / (y1 - y0) : 0.0f;
|
|
||||||
float inv_y2y1 = (y2 - y1 > 1e-4f) ? 1.0f / (y2 - y1) : 0.0f;
|
|
||||||
|
|
||||||
// Pre-calculation of slopes (dx/dy)
|
|
||||||
float dx02 = (x2 - x0) * inv_height;
|
|
||||||
float dx01 = (x1 - x0) * inv_y1y0;
|
|
||||||
float dx12 = (x2 - x1) * inv_y2y1;
|
|
||||||
|
|
||||||
// Y bounds (vertical clipping)
|
|
||||||
int yTop = (int)(y0 + 0.5f);
|
|
||||||
int yMiddle = (int)(y1 + 0.5f);
|
|
||||||
int yBottom = (int)(y2 + 0.5f);
|
|
||||||
|
|
||||||
// Initializing scanline variables
|
|
||||||
float xLeft = x0, xRight = x0;
|
|
||||||
sw_vertex_t start, end;
|
|
||||||
|
|
||||||
// Scanline for the upper part of the triangle
|
|
||||||
for (int y = yTop; y < yMiddle; y++) {
|
|
||||||
float dy = (float)y - y0;
|
|
||||||
float t1 = dy * inv_height;
|
|
||||||
float t2 = dy * inv_y1y0;
|
|
||||||
|
|
||||||
// Optimized interpolation
|
|
||||||
start = sw_lerp_vertex(v0, v2, t1);
|
|
||||||
end = sw_lerp_vertex(v0, v1, t2);
|
|
||||||
start.screen[0] = xLeft;
|
|
||||||
start.screen[1] = (float)y;
|
|
||||||
end.screen[0] = xRight;
|
|
||||||
end.screen[1] = (float)y;
|
|
||||||
|
|
||||||
if (xLeft > xRight) { sw_vertex_t tmp = start; start = end; end = tmp; }
|
|
||||||
sw_raster_scanline(tex, &start, &end, yDu, yDv);
|
|
||||||
|
|
||||||
// Incremental update
|
|
||||||
xLeft += dx02;
|
|
||||||
xRight += dx01;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Scanline for the lower part of the triangle
|
|
||||||
xRight = x1; // Restart the right side from the second vertex
|
|
||||||
for (int y = yMiddle; y < yBottom; y++) {
|
|
||||||
float dy = (float)y - y0;
|
|
||||||
float t1 = dy * inv_height;
|
|
||||||
float t2 = (float)(y - y1) * inv_y2y1;
|
|
||||||
|
|
||||||
// Optimized interpolation
|
|
||||||
start = sw_lerp_vertex(v0, v2, t1);
|
|
||||||
end = sw_lerp_vertex(v1, v2, t2);
|
|
||||||
start.screen[0] = xLeft;
|
|
||||||
start.screen[1] = (float)y;
|
|
||||||
end.screen[0] = xRight;
|
|
||||||
end.screen[1] = (float)y;
|
|
||||||
|
|
||||||
if (xLeft > xRight) { sw_vertex_t tmp = start; start = end; end = tmp; }
|
|
||||||
sw_raster_scanline(tex, &start, &end, yDu, yDv);
|
|
||||||
|
|
||||||
// Incremental update
|
|
||||||
xLeft += dx02;
|
|
||||||
xRight += dx12;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void sw_render_triangle(const sw_vertex_t* v0, const sw_vertex_t* v1, const sw_vertex_t* v2)
|
void sw_render_triangle(const sw_vertex_t* v0, const sw_vertex_t* v1, const sw_vertex_t* v2)
|
||||||
{
|
{
|
||||||
|
|
@ -1027,6 +1139,31 @@
|
||||||
return;
|
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(
|
||||||
|
&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(
|
||||||
|
&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(
|
||||||
|
&polygon[0], &polygon[i + 1], &polygon[i + 2],
|
||||||
|
&RLSW.loadedTextures[RLSW.currentTexture]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
for (int_fast8_t i = 0; i < vertexCounter - 2; i++) {
|
for (int_fast8_t i = 0; i < vertexCounter - 2; i++) {
|
||||||
sw_raster_triangle(
|
sw_raster_triangle(
|
||||||
&polygon[0], &polygon[i + 1], &polygon[i + 2],
|
&polygon[0], &polygon[i + 1], &polygon[i + 2],
|
||||||
|
|
@ -1034,6 +1171,7 @@
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static inline bool sw_is_texture_id_valid(uint32_t id)
|
static inline bool sw_is_texture_id_valid(uint32_t id)
|
||||||
{
|
{
|
||||||
|
|
@ -1128,6 +1266,42 @@
|
||||||
SW_FREE(RLSW.freeTextureIds);
|
SW_FREE(RLSW.freeTextureIds);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void swEnable(SWstate state)
|
||||||
|
{
|
||||||
|
switch (state) {
|
||||||
|
case SW_TEXTURE_2D:
|
||||||
|
RLSW.stateFlags |= SW_STATE_TEXTURE_2D;
|
||||||
|
break;
|
||||||
|
case SW_DEPTH_TEST:
|
||||||
|
RLSW.stateFlags |= SW_STATE_DEPTH_TEST;
|
||||||
|
break;
|
||||||
|
case SW_CULL_FACE:
|
||||||
|
RLSW.stateFlags |= SW_STATE_CULL_FACE;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
RLSW.errCode = SW_INVALID_ENUM;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void swDisable(SWstate state)
|
||||||
|
{
|
||||||
|
switch (state) {
|
||||||
|
case SW_TEXTURE_2D:
|
||||||
|
RLSW.stateFlags &= ~SW_STATE_TEXTURE_2D;
|
||||||
|
break;
|
||||||
|
case SW_DEPTH_TEST:
|
||||||
|
RLSW.stateFlags &= ~SW_STATE_DEPTH_TEST;
|
||||||
|
break;
|
||||||
|
case SW_CULL_FACE:
|
||||||
|
RLSW.stateFlags &= ~SW_STATE_CULL_FACE;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
RLSW.errCode = SW_INVALID_ENUM;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void* swGetColorBuffer(int* w, int* h)
|
void* swGetColorBuffer(int* w, int* h)
|
||||||
{
|
{
|
||||||
if (w) *w = RLSW.framebuffer.width;
|
if (w) *w = RLSW.framebuffer.width;
|
||||||
|
|
@ -1799,7 +1973,7 @@
|
||||||
uint32_t swLoadTexture(const void *data, int width, int height, int format, int mipmapCount)
|
uint32_t swLoadTexture(const void *data, int width, int height, int format, int mipmapCount)
|
||||||
{
|
{
|
||||||
if (RLSW.loadedTextureCount >= SW_MAX_TEXTURES) {
|
if (RLSW.loadedTextureCount >= SW_MAX_TEXTURES) {
|
||||||
RLSW.errCode = SW_ERROR_OUT_OF_MEMORY;
|
RLSW.errCode = SW_STACK_OVERFLOW; //< Out of memory, not really stack overflow
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1906,4 +2080,3 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // RLSW_IMPL
|
#endif // RLSW_IMPL
|
||||||
|
|
||||||
Loading…
Reference in New Issue
Block a user