|
|
|
@ -531,7 +531,6 @@ SWAPI void swClose(void); |
|
|
|
SWAPI bool swResizeFramebuffer(int w, int h); |
|
|
|
SWAPI void swCopyFramebuffer(int x, int y, int w, int h, SWformat format, SWtype type, void *pixels); |
|
|
|
SWAPI void swBlitFramebuffer(int xDst, int yDst, int wDst, int hDst, int xSrc, int ySrc, int wSrc, int hSrc, SWformat format, SWtype type, void *pixels); |
|
|
|
SWAPI void *swGetColorBuffer(int *w, int *h); |
|
|
|
|
|
|
|
SWAPI void swEnable(SWstate state); |
|
|
|
SWAPI void swDisable(SWstate state); |
|
|
|
@ -616,12 +615,23 @@ SWAPI void swBindTexture(uint32_t id); |
|
|
|
#include <math.h> // Required for: floorf(), fabsf() |
|
|
|
|
|
|
|
#if defined(_MSC_VER) |
|
|
|
#define ALIGNAS(x) __declspec(align(x)) |
|
|
|
#define SW_ALIGN(x) __declspec(align(x)) |
|
|
|
#elif defined(__GNUC__) || defined(__clang__) |
|
|
|
#define ALIGNAS(x) __attribute__((aligned(x))) |
|
|
|
#define SW_ALIGN(x) __attribute__((aligned(x))) |
|
|
|
#else |
|
|
|
#include <stdalign.h> |
|
|
|
#define ALIGNAS(x) alignas(x) |
|
|
|
#define SW_ALIGN(x) // Do nothing if not available |
|
|
|
#endif |
|
|
|
|
|
|
|
#if defined(_M_X64) || defined(__x86_64__) |
|
|
|
#define SW_ARCH_X86_64 |
|
|
|
#elif defined(_M_IX86) || defined(__i386__) |
|
|
|
#define SW_ARCH_X86 |
|
|
|
#elif defined(_M_ARM) || defined(__arm__) |
|
|
|
#define SW_ARCH_ARM32 |
|
|
|
#elif defined(_M_ARM64) || defined(__aarch64__) |
|
|
|
#define SW_ARCH_ARM64 |
|
|
|
#elif defined(__riscv) |
|
|
|
#define SW_ARCH_RISCV |
|
|
|
#endif |
|
|
|
|
|
|
|
#if defined(__FMA__) && defined(__AVX2__) |
|
|
|
@ -696,8 +706,15 @@ SWAPI void swBindTexture(uint32_t id); |
|
|
|
#define SW_DEG2RAD (SW_PI/180.0f) |
|
|
|
#define SW_RAD2DEG (180.0f/SW_PI) |
|
|
|
|
|
|
|
#define SW_COLOR_PIXEL_SIZE 4 //(SW_COLOR_BUFFER_BITS >> 3) |
|
|
|
#define SW_COLOR_PIXEL_SIZE (SW_COLOR_BUFFER_BITS >> 3) |
|
|
|
#define SW_DEPTH_PIXEL_SIZE (SW_DEPTH_BUFFER_BITS >> 3) |
|
|
|
#define SW_PIXEL_SIZE (SW_COLOR_PIXEL_SIZE + SW_DEPTH_PIXEL_SIZE) |
|
|
|
|
|
|
|
#if (SW_PIXEL_SIZE <= 4) |
|
|
|
#define SW_PIXEL_ALIGNMENT 4 |
|
|
|
#else // if (SW_PIXEL_SIZE <= 8) |
|
|
|
#define SW_PIXEL_ALIGNMENT 8 |
|
|
|
#endif |
|
|
|
|
|
|
|
#if (SW_COLOR_BUFFER_BITS == 8) |
|
|
|
#define SW_COLOR_TYPE uint8_t |
|
|
|
@ -827,10 +844,12 @@ typedef struct { |
|
|
|
} sw_texture_t; |
|
|
|
|
|
|
|
// Pixel data type |
|
|
|
// WARNING: ALIGNAS() macro requires a constant value (not operand) |
|
|
|
typedef ALIGNAS(SW_COLOR_PIXEL_SIZE) struct { |
|
|
|
typedef SW_ALIGN(SW_PIXEL_ALIGNMENT) struct { |
|
|
|
SW_COLOR_TYPE color[SW_COLOR_PACK_COMP]; |
|
|
|
SW_DEPTH_TYPE depth[SW_DEPTH_PACK_COMP]; |
|
|
|
#if (SW_PIXEL_SIZE % SW_PIXEL_ALIGNMENT != 0) |
|
|
|
uint8_t padding[SW_PIXEL_ALIGNMENT - SW_PIXEL_SIZE % SW_PIXEL_ALIGNMENT]; |
|
|
|
#endif |
|
|
|
} sw_pixel_t; |
|
|
|
|
|
|
|
typedef struct { |
|
|
|
@ -2624,25 +2643,38 @@ static inline void sw_quad_clip_and_project(void) |
|
|
|
|
|
|
|
static inline bool sw_quad_is_axis_aligned(void) |
|
|
|
{ |
|
|
|
kt">int horizontal = 0; |
|
|
|
kt">int vertical = 0; |
|
|
|
|
|
|
|
o">// Reject quads with perspective projection |
|
|
|
o">// The fast path assumes affine (non-perspective) quads, |
|
|
|
// so we require all vertices to have homogeneous w = 1.0 |
|
|
|
for (int i = 0; i < 4; i++) |
|
|
|
{ |
|
|
|
if (RLSW.vertexBuffer[i].homogeneous[3] != 1.0f) return false; |
|
|
|
|
|
|
|
const float *v0 = RLSW.vertexBuffer[i].position; |
|
|
|
const float *v1 = RLSW.vertexBuffer[(i + 1)%4].position; |
|
|
|
|
|
|
|
float dx = v1[0] - v0[0]; |
|
|
|
float dy = v1[1] - v0[1]; |
|
|
|
|
|
|
|
if ((fabsf(dx) > 1e-6f) && (fabsf(dy) < 1e-6f)) horizontal++; |
|
|
|
else if ((fabsf(dy) > 1e-6f) && (fabsf(dx) < 1e-6f)) vertical++; |
|
|
|
else return false; // Diagonal edge -> not axis-aligned |
|
|
|
} |
|
|
|
|
|
|
|
return ((horizontal == 2) && (vertical == 2)); |
|
|
|
// Epsilon tolerance in screen space (pixels) |
|
|
|
const float epsilon = 0.5f; |
|
|
|
|
|
|
|
// Fetch screen-space positions for the four quad vertices |
|
|
|
const float *p0 = RLSW.vertexBuffer[0].screen; |
|
|
|
const float *p1 = RLSW.vertexBuffer[1].screen; |
|
|
|
const float *p2 = RLSW.vertexBuffer[2].screen; |
|
|
|
const float *p3 = RLSW.vertexBuffer[3].screen; |
|
|
|
|
|
|
|
// Compute edge vectors between consecutive vertices |
|
|
|
// These define the four sides of the quad in screen space |
|
|
|
float dx01 = p1[0] - p0[0], dy01 = p1[1] - p0[1]; |
|
|
|
float dx12 = p2[0] - p1[0], dy12 = p2[1] - p1[1]; |
|
|
|
float dx23 = p3[0] - p2[0], dy23 = p3[1] - p2[1]; |
|
|
|
float dx30 = p0[0] - p3[0], dy30 = p0[1] - p3[1]; |
|
|
|
|
|
|
|
// Each edge must be either horizontal or vertical within epsilon tolerance |
|
|
|
// If any edge deviates significantly from either axis, the quad is not axis-aligned |
|
|
|
if (!((fabsf(dy01) < epsilon) || (fabsf(dx01) < epsilon))) return false; |
|
|
|
if (!((fabsf(dy12) < epsilon) || (fabsf(dx12) < epsilon))) return false; |
|
|
|
if (!((fabsf(dy23) < epsilon) || (fabsf(dx23) < epsilon))) return false; |
|
|
|
if (!((fabsf(dy30) < epsilon) || (fabsf(dx30) < epsilon))) return false; |
|
|
|
|
|
|
|
return true; |
|
|
|
} |
|
|
|
|
|
|
|
static inline void sw_quad_sort_cw(const sw_vertex_t* *output) |
|
|
|
@ -3660,11 +3692,6 @@ void swBlitFramebuffer(int xDst, int yDst, int wDst, int hDst, int xSrc, int ySr |
|
|
|
{ |
|
|
|
sw_pixelformat_t pFormat = (sw_pixelformat_t)sw_get_pixel_format(format, type); |
|
|
|
|
|
|
|
if (xDst == xSrc && yDst == ySrc && wDst == wSrc && hDst == hSrc) |
|
|
|
{ |
|
|
|
swCopyFramebuffer(xSrc, ySrc, wSrc, hSrc, format, type, pixels); |
|
|
|
} |
|
|
|
|
|
|
|
if (wSrc <= 0) { RLSW.errCode = SW_INVALID_VALUE; return; } |
|
|
|
if (hSrc <= 0) { RLSW.errCode = SW_INVALID_VALUE; return; } |
|
|
|
|
|
|
|
@ -3674,6 +3701,13 @@ void swBlitFramebuffer(int xDst, int yDst, int wDst, int hDst, int xSrc, int ySr |
|
|
|
xSrc = sw_clampi(xSrc, 0, wSrc); |
|
|
|
ySrc = sw_clampi(ySrc, 0, hSrc); |
|
|
|
|
|
|
|
// Check if the sizes are identical after clamping the source to avoid unexpected issues |
|
|
|
// REVIEW: This repeats the operations if true, so we could make a copy function without these checks |
|
|
|
if (xDst == xSrc && yDst == ySrc && wDst == wSrc && hDst == hSrc) |
|
|
|
{ |
|
|
|
swCopyFramebuffer(xSrc, ySrc, wSrc, hSrc, format, type, pixels); |
|
|
|
} |
|
|
|
|
|
|
|
switch (pFormat) |
|
|
|
{ |
|
|
|
case SW_PIXELFORMAT_UNCOMPRESSED_GRAYSCALE: sw_framebuffer_blit_to_GRAYALPHA(xDst, yDst, wDst, hDst, xSrc, ySrc, wSrc, hSrc, (uint8_t *)pixels); break; |
|
|
|
@ -3696,14 +3730,6 @@ void swBlitFramebuffer(int xDst, int yDst, int wDst, int hDst, int xSrc, int ySr |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
void *swGetColorBuffer(int *w, int *h) |
|
|
|
{ |
|
|
|
if (w) *w = RLSW.framebuffer.width; |
|
|
|
if (h) *h = RLSW.framebuffer.height; |
|
|
|
|
|
|
|
return (void *)RLSW.framebuffer.pixels->color; |
|
|
|
} |
|
|
|
|
|
|
|
void swEnable(SWstate state) |
|
|
|
{ |
|
|
|
switch (state) |
|
|
|
|