aboutsummaryrefslogtreecommitdiffstats
path: root/src/small3dlib.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/small3dlib.h')
-rw-r--r--src/small3dlib.h4000
1 files changed, 1899 insertions, 2101 deletions
diff --git a/src/small3dlib.h b/src/small3dlib.h
index b620295..3ba5589 100644
--- a/src/small3dlib.h
+++ b/src/small3dlib.h
@@ -71,7 +71,7 @@
into S3L_FRACTIONS_PER_UNIT fractions (fixed point arithmetic).
y ^
- | _
+ | _
| /| z
| /
| /
@@ -90,7 +90,7 @@
| |/ |
-----[0,0,0]-|-----> x
|____|____|
- |
+ |
|
Rotations use Euler angles and are generally in the extrinsic Euler angles in
@@ -141,43 +141,43 @@
#include <stdint.h>
#ifdef S3L_RESOLUTION_X
- #ifdef S3L_RESOLUTION_Y
- #define S3L_MAX_PIXELS (S3L_RESOLUTION_X * S3L_RESOLUTION_Y)
- #endif
+#ifdef S3L_RESOLUTION_Y
+#define S3L_MAX_PIXELS (S3L_RESOLUTION_X * S3L_RESOLUTION_Y)
+#endif
#endif
#ifndef S3L_RESOLUTION_X
- #ifndef S3L_MAX_PIXELS
- #error Dynamic resolution set (S3L_RESOLUTION_X not defined), but\
+#ifndef S3L_MAX_PIXELS
+#error Dynamic resolution set (S3L_RESOLUTION_X not defined), but\
S3L_MAX_PIXELS not defined!
- #endif
+#endif
- uint16_t S3L_resolutionX = 512; /**< If a static resolution is not set with
- S3L_RESOLUTION_X, this variable can be
- used to change X resolution at runtime,
- in which case S3L_MAX_PIXELS has to be
- defined (to allocate zBuffer etc.)! */
- #define S3L_RESOLUTION_X S3L_resolutionX
+uint16_t S3L_resolutionX = 512; /**< If a static resolution is not set with
+ S3L_RESOLUTION_X, this variable can be
+ used to change X resolution at runtime,
+ in which case S3L_MAX_PIXELS has to be
+ defined (to allocate zBuffer etc.)! */
+#define S3L_RESOLUTION_X S3L_resolutionX
#endif
#ifndef S3L_RESOLUTION_Y
- #ifndef S3L_MAX_PIXELS
- #error Dynamic resolution set (S3L_RESOLUTION_Y not defined), but\
+#ifndef S3L_MAX_PIXELS
+#error Dynamic resolution set (S3L_RESOLUTION_Y not defined), but\
S3L_MAX_PIXELS not defined!
- #endif
+#endif
- uint16_t S3L_resolutionY = 512; /**< Same as S3L_resolutionX, but for Y
- resolution. */
- #define S3L_RESOLUTION_Y S3L_resolutionY
+uint16_t S3L_resolutionY = 512; /**< Same as S3L_resolutionX, but for Y
+ resolution. */
+#define S3L_RESOLUTION_Y S3L_resolutionY
#endif
#ifndef S3L_USE_WIDER_TYPES
- /** If true, the library will use wider data types which will largely supress
- many rendering bugs and imprecisions happening due to overflows, but this will
- also consumer more RAM and may potentially be slower on computers with smaller
- native integer. */
+/** If true, the library will use wider data types which will largely supress
+many rendering bugs and imprecisions happening due to overflows, but this will
+also consumer more RAM and may potentially be slower on computers with smaller
+native integer. */
- #define S3L_USE_WIDER_TYPES 0
+#define S3L_USE_WIDER_TYPES 0
#endif
/** Units of measurement in 3D space. There is S3L_FRACTIONS_PER_UNIT in one
@@ -187,296 +187,294 @@ fixed point arithmetic. The number of fractions is a constant that serves as
typedef
#if S3L_USE_WIDER_TYPES
- int64_t
+ int64_t
#else
- int32_t
+ int32_t
#endif
- S3L_Unit;
-
+ S3L_Unit;
+
/** How many fractions a spatial unit is split into. This is NOT SUPPOSED TO
BE REDEFINED, so rather don't do it (otherwise things may overflow etc.). */
#define S3L_FRACTIONS_PER_UNIT 512
-typedef
+typedef
#if S3L_USE_WIDER_TYPES
- int32_t
+ int32_t
#else
- int16_t
+ int16_t
#endif
- S3L_ScreenCoord;
+ S3L_ScreenCoord;
-typedef
+typedef
#if S3L_USE_WIDER_TYPES
- uint32_t
+ uint32_t
#else
- uint16_t
+ uint16_t
#endif
- S3L_Index;
+ S3L_Index;
#ifndef S3L_NEAR_CROSS_STRATEGY
- /** Specifies how the library will handle triangles that partially cross the
- near plane. These are problematic and require special handling. Possible
- values:
-
- 0: Strictly cull any triangle crossing the near plane. This will make such
- triangles disappear. This is good for performance or models viewed only
- from at least small distance.
- 1: Forcefully push the vertices crossing near plane in front of it. This is
- a cheap technique that can be good enough for displaying simple
- environments on slow devices, but texturing and geometric artifacts/warps
- will appear.
- 2: Geometrically correct the triangles crossing the near plane. This may
- result in some triangles being subdivided into two and is a little more
- expensive, but the results will be geometrically correct, even though
- barycentric correction is not performed so texturing artifacts will
- appear. Can be ideal with S3L_FLAT.
- 3: Perform both geometrical and barycentric correction of triangle crossing
- the near plane. This is significantly more expensive but results in
- correct rendering. */
-
- #define S3L_NEAR_CROSS_STRATEGY 0
+/** Specifies how the library will handle triangles that partially cross the
+near plane. These are problematic and require special handling. Possible
+values:
+
+ 0: Strictly cull any triangle crossing the near plane. This will make such
+ triangles disappear. This is good for performance or models viewed only
+ from at least small distance.
+ 1: Forcefully push the vertices crossing near plane in front of it. This is
+ a cheap technique that can be good enough for displaying simple
+ environments on slow devices, but texturing and geometric artifacts/warps
+ will appear.
+ 2: Geometrically correct the triangles crossing the near plane. This may
+ result in some triangles being subdivided into two and is a little more
+ expensive, but the results will be geometrically correct, even though
+ barycentric correction is not performed so texturing artifacts will
+ appear. Can be ideal with S3L_FLAT.
+ 3: Perform both geometrical and barycentric correction of triangle crossing
+ the near plane. This is significantly more expensive but results in
+ correct rendering. */
+
+#define S3L_NEAR_CROSS_STRATEGY 0
#endif
#ifndef S3L_FLAT
- /** If on, disables computation of per-pixel values such as barycentric
- coordinates and depth -- these will still be available but will be the same
- for the whole triangle. This can be used to create flat-shaded renders and
- will be a lot faster. With this option on you will probably want to use
- sorting instead of z-buffer. */
+/** If on, disables computation of per-pixel values such as barycentric
+coordinates and depth -- these will still be available but will be the same
+for the whole triangle. This can be used to create flat-shaded renders and
+will be a lot faster. With this option on you will probably want to use
+sorting instead of z-buffer. */
- #define S3L_FLAT 0
+#define S3L_FLAT 0
#endif
#if S3L_FLAT
- #define S3L_COMPUTE_DEPTH 0
- #define S3L_PERSPECTIVE_CORRECTION 0
- // don't disable z-buffer, it makes sense to use it with no sorting
+#define S3L_COMPUTE_DEPTH 0
+#define S3L_PERSPECTIVE_CORRECTION 0
+// don't disable z-buffer, it makes sense to use it with no sorting
#endif
#ifndef S3L_PERSPECTIVE_CORRECTION
- /** Specifies what type of perspective correction (PC) to use. Remember this
- is an expensive operation! Possible values:
-
- 0: No perspective correction. Fastest, inaccurate from most angles.
- 1: Per-pixel perspective correction, accurate but very expensive.
- 2: Approximation (computing only at every S3L_PC_APPROX_LENGTHth pixel).
- Quake-style approximation is used, which only computes the PC after
- S3L_PC_APPROX_LENGTH pixels. This is reasonably accurate and fast. */
+/** Specifies what type of perspective correction (PC) to use. Remember this
+is an expensive operation! Possible values:
- #define S3L_PERSPECTIVE_CORRECTION 0
+0: No perspective correction. Fastest, inaccurate from most angles.
+1: Per-pixel perspective correction, accurate but very expensive.
+2: Approximation (computing only at every S3L_PC_APPROX_LENGTHth pixel).
+ Quake-style approximation is used, which only computes the PC after
+ S3L_PC_APPROX_LENGTH pixels. This is reasonably accurate and fast. */
+
+#define S3L_PERSPECTIVE_CORRECTION 0
#endif
#ifndef S3L_PC_APPROX_LENGTH
- /** For S3L_PERSPECTIVE_CORRECTION == 2, this specifies after how many pixels
- PC is recomputed. Should be a power of two to keep up the performance.
- Smaller is nicer but slower. */
+/** For S3L_PERSPECTIVE_CORRECTION == 2, this specifies after how many pixels
+PC is recomputed. Should be a power of two to keep up the performance.
+Smaller is nicer but slower. */
- #define S3L_PC_APPROX_LENGTH 32
+#define S3L_PC_APPROX_LENGTH 32
#endif
#if S3L_PERSPECTIVE_CORRECTION
- #define S3L_COMPUTE_DEPTH 1 // PC inevitably computes depth, so enable it
+#define S3L_COMPUTE_DEPTH 1 // PC inevitably computes depth, so enable it
#endif
#ifndef S3L_COMPUTE_DEPTH
- /** Whether to compute depth for each pixel (fragment). Some other options
- may turn this on automatically. If you don't need depth information, turning
- this off can save performance. Depth will still be accessible in
- S3L_PixelInfo, but will be constant -- equal to center point depth -- over
- the whole triangle. */
- #define S3L_COMPUTE_DEPTH 1
+/** Whether to compute depth for each pixel (fragment). Some other options
+may turn this on automatically. If you don't need depth information, turning
+this off can save performance. Depth will still be accessible in
+S3L_PixelInfo, but will be constant -- equal to center point depth -- over
+the whole triangle. */
+#define S3L_COMPUTE_DEPTH 1
#endif
#ifndef S3L_Z_BUFFER
- /** What type of z-buffer (depth buffer) to use for visibility determination.
- Possible values:
-
- 0: Don't use z-buffer. This saves a lot of memory, but visibility checking
- won't be pixel-accurate and has to mostly be done by other means (typically
- sorting).
- 1: Use full z-buffer (of S3L_Units) for visibiltiy determination. This is the
- most accurate option (and also a fast one), but requires a big amount of
- memory.
- 2: Use reduced-size z-buffer (of bytes). This is fast and somewhat accurate,
- but inaccuracies can occur and a considerable amount of memory is
- needed. */
-
- #define S3L_Z_BUFFER 0
+/** What type of z-buffer (depth buffer) to use for visibility determination.
+Possible values:
+
+0: Don't use z-buffer. This saves a lot of memory, but visibility checking
+ won't be pixel-accurate and has to mostly be done by other means (typically
+ sorting).
+1: Use full z-buffer (of S3L_Units) for visibiltiy determination. This is the
+ most accurate option (and also a fast one), but requires a big amount of
+ memory.
+2: Use reduced-size z-buffer (of bytes). This is fast and somewhat accurate,
+ but inaccuracies can occur and a considerable amount of memory is
+ needed. */
+
+#define S3L_Z_BUFFER 0
#endif
#ifndef S3L_REDUCED_Z_BUFFER_GRANULARITY
- /** For S3L_Z_BUFFER == 2 this sets the reduced z-buffer granularity. */
+/** For S3L_Z_BUFFER == 2 this sets the reduced z-buffer granularity. */
- #define S3L_REDUCED_Z_BUFFER_GRANULARITY 5
+#define S3L_REDUCED_Z_BUFFER_GRANULARITY 5
#endif
#ifndef S3L_STENCIL_BUFFER
- /** Whether to use stencil buffer for drawing -- with this a pixel that would
- be resterized over an already rasterized pixel (within a frame) will be
- discarded. This is mostly for front-to-back sorted drawing. */
+/** Whether to use stencil buffer for drawing -- with this a pixel that would
+be resterized over an already rasterized pixel (within a frame) will be
+discarded. This is mostly for front-to-back sorted drawing. */
- #define S3L_STENCIL_BUFFER 0
+#define S3L_STENCIL_BUFFER 0
#endif
#ifndef S3L_SORT
- /** Defines how to sort triangles before drawing a frame. This can be used to
- solve visibility in case z-buffer is not used, to prevent overwriting already
- rasterized pixels, implement transparency etc. Note that for simplicity and
- performance a relatively simple sorting is used which doesn't work completely
- correctly, so mistakes can occur (even the best sorting wouldn't be able to
- solve e.g. intersecting triangles). Note that sorting requires a bit of extra
- memory -- an array of the triangles to sort -- the size of this array limits
- the maximum number of triangles that can be drawn in a single frame
- (S3L_MAX_TRIANGES_DRAWN). Possible values:
-
- 0: Don't sort triangles. This is fastest and doesn't use extra memory.
- 1: Sort triangles from back to front. This can in most cases solve visibility
- without requiring almost any extra memory compared to z-buffer.
- 2: Sort triangles from front to back. This can be faster than back to front
- because we prevent computing pixels that will be overwritten by nearer
- ones, but we need a 1b stencil buffer for this (enable S3L_STENCIL_BUFFER),
- so a bit more memory is needed. */
-
- #define S3L_SORT 0
+/** Defines how to sort triangles before drawing a frame. This can be used to
+solve visibility in case z-buffer is not used, to prevent overwriting already
+rasterized pixels, implement transparency etc. Note that for simplicity and
+performance a relatively simple sorting is used which doesn't work completely
+correctly, so mistakes can occur (even the best sorting wouldn't be able to
+solve e.g. intersecting triangles). Note that sorting requires a bit of extra
+memory -- an array of the triangles to sort -- the size of this array limits
+the maximum number of triangles that can be drawn in a single frame
+(S3L_MAX_TRIANGES_DRAWN). Possible values:
+
+0: Don't sort triangles. This is fastest and doesn't use extra memory.
+1: Sort triangles from back to front. This can in most cases solve visibility
+ without requiring almost any extra memory compared to z-buffer.
+2: Sort triangles from front to back. This can be faster than back to front
+ because we prevent computing pixels that will be overwritten by nearer
+ ones, but we need a 1b stencil buffer for this (enable S3L_STENCIL_BUFFER),
+ so a bit more memory is needed. */
+
+#define S3L_SORT 0
#endif
#ifndef S3L_MAX_TRIANGES_DRAWN
- /** Maximum number of triangles that can be drawn in sorted modes. This
- affects the size of the cache used for triangle sorting. */
+/** Maximum number of triangles that can be drawn in sorted modes. This
+affects the size of the cache used for triangle sorting. */
- #define S3L_MAX_TRIANGES_DRAWN 128
+#define S3L_MAX_TRIANGES_DRAWN 128
#endif
#ifndef S3L_NEAR
- /** Distance of the near clipping plane. Points in front or EXATLY ON this
- plane are considered outside the frustum. This must be >= 0. */
+/** Distance of the near clipping plane. Points in front or EXATLY ON this
+plane are considered outside the frustum. This must be >= 0. */
- #define S3L_NEAR (S3L_FRACTIONS_PER_UNIT / 4)
+#define S3L_NEAR (S3L_FRACTIONS_PER_UNIT / 4)
#endif
#if S3L_NEAR <= 0
-#define S3L_NEAR 1 // Can't be <= 0.
+#define S3L_NEAR 1 // Can't be <= 0.
#endif
#ifndef S3L_NORMAL_COMPUTE_MAXIMUM_AVERAGE
- /** Affects the S3L_computeModelNormals function. See its description for
- details. */
+/** Affects the S3L_computeModelNormals function. See its description for
+details. */
- #define S3L_NORMAL_COMPUTE_MAXIMUM_AVERAGE 6
+#define S3L_NORMAL_COMPUTE_MAXIMUM_AVERAGE 6
#endif
#ifndef S3L_FAST_LERP_QUALITY
- /** Quality (scaling) of SOME (stepped) linear interpolations. 0 will most
- likely be a tiny bit faster, but artifacts can occur for bigger tris, while
- higher values can fix this -- in theory all higher values will have the same
- speed (it is a shift value), but it mustn't be too high to prevent
- overflow. */
+/** Quality (scaling) of SOME (stepped) linear interpolations. 0 will most
+likely be a tiny bit faster, but artifacts can occur for bigger tris, while
+higher values can fix this -- in theory all higher values will have the same
+speed (it is a shift value), but it mustn't be too high to prevent
+overflow. */
- #define S3L_FAST_LERP_QUALITY 11
+#define S3L_FAST_LERP_QUALITY 11
#endif
/** Vector that consists of four scalars and can represent homogenous
coordinates, but is generally also used as Vec3 and Vec2 for various
purposes. */
-typedef struct
-{
- S3L_Unit x;
- S3L_Unit y;
- S3L_Unit z;
- S3L_Unit w;
+typedef struct {
+ S3L_Unit x;
+ S3L_Unit y;
+ S3L_Unit z;
+ S3L_Unit w;
} S3L_Vec4;
-#define S3L_logVec4(v)\
- printf("Vec4: %d %d %d %d\n",((v).x),((v).y),((v).z),((v).w))
-
-static inline void S3L_vec4Init(S3L_Vec4 *v);
-static inline void S3L_vec4Set(S3L_Vec4 *v, S3L_Unit x, S3L_Unit y,
- S3L_Unit z, S3L_Unit w);
-static inline void S3L_vec3Add(S3L_Vec4 *result, S3L_Vec4 added);
-static inline void S3L_vec3Sub(S3L_Vec4 *result, S3L_Vec4 substracted);
+#define S3L_logVec4(v) \
+ printf("Vec4: %d %d %d %d\n", ((v).x), ((v).y), ((v).z), ((v).w))
+
+static inline void S3L_vec4Init(S3L_Vec4* v);
+static inline void S3L_vec4Set(S3L_Vec4* v,
+ S3L_Unit x,
+ S3L_Unit y,
+ S3L_Unit z,
+ S3L_Unit w);
+static inline void S3L_vec3Add(S3L_Vec4* result, S3L_Vec4 added);
+static inline void S3L_vec3Sub(S3L_Vec4* result, S3L_Vec4 substracted);
S3L_Unit S3L_vec3Length(S3L_Vec4 v);
/** Normalizes Vec3. Note that this function tries to normalize correctly
rather than quickly! If you need to normalize quickly, do it yourself in a
way that best fits your case. */
-void S3L_vec3Normalize(S3L_Vec4 *v);
+void S3L_vec3Normalize(S3L_Vec4* v);
/** Like S3L_vec3Normalize, but doesn't perform any checks on the input vector,
which is faster, but can be very innacurate or overflowing. You are supposed
to provide a "nice" vector (not too big or small). */
-static inline void S3L_vec3NormalizeFast(S3L_Vec4 *v);
+static inline void S3L_vec3NormalizeFast(S3L_Vec4* v);
S3L_Unit S3L_vec2Length(S3L_Vec4 v);
-void S3L_vec3Cross(S3L_Vec4 a, S3L_Vec4 b, S3L_Vec4 *result);
+void S3L_vec3Cross(S3L_Vec4 a, S3L_Vec4 b, S3L_Vec4* result);
static inline S3L_Unit S3L_vec3Dot(S3L_Vec4 a, S3L_Vec4 b);
/** Computes a reflection direction (typically used e.g. for specular component
in Phong illumination). The input vectors must be normalized. The result will
be normalized as well. */
-void S3L_reflect(S3L_Vec4 toLight, S3L_Vec4 normal, S3L_Vec4 *result);
+void S3L_reflect(S3L_Vec4 toLight, S3L_Vec4 normal, S3L_Vec4* result);
/** Determines the winding of a triangle, returns 1 (CW, clockwise), -1 (CCW,
counterclockwise) or 0 (points lie on a single line). */
-static inline int8_t S3L_triangleWinding(
- S3L_ScreenCoord x0,
- S3L_ScreenCoord y0,
- S3L_ScreenCoord x1,
- S3L_ScreenCoord y1,
- S3L_ScreenCoord x2,
- S3L_ScreenCoord y2);
-
-typedef struct
-{
- S3L_Vec4 translation;
- S3L_Vec4 rotation; /**< Euler angles. Rortation is applied in this order:
- 1. z = by z (roll) CW looking along z+
- 2. x = by x (pitch) CW looking along x+
- 3. y = by y (yaw) CW looking along y+ */
- S3L_Vec4 scale;
+static inline int8_t S3L_triangleWinding(S3L_ScreenCoord x0,
+ S3L_ScreenCoord y0,
+ S3L_ScreenCoord x1,
+ S3L_ScreenCoord y1,
+ S3L_ScreenCoord x2,
+ S3L_ScreenCoord y2);
+
+typedef struct {
+ S3L_Vec4 translation;
+ S3L_Vec4 rotation; /**< Euler angles. Rortation is applied in this order:
+ 1. z = by z (roll) CW looking along z+
+ 2. x = by x (pitch) CW looking along x+
+ 3. y = by y (yaw) CW looking along y+ */
+ S3L_Vec4 scale;
} S3L_Transform3D;
-#define S3L_logTransform3D(t)\
- printf("Transform3D: T = [%d %d %d], R = [%d %d %d], S = [%d %d %d]\n",\
- (t).translation.x,(t).translation.y,(t).translation.z,\
- (t).rotation.x,(t).rotation.y,(t).rotation.z,\
- (t).scale.x,(t).scale.y,(t).scale.z)
+#define S3L_logTransform3D(t) \
+ printf("Transform3D: T = [%d %d %d], R = [%d %d %d], S = [%d %d %d]\n", \
+ (t).translation.x, (t).translation.y, (t).translation.z, \
+ (t).rotation.x, (t).rotation.y, (t).rotation.z, (t).scale.x, \
+ (t).scale.y, (t).scale.z)
-static inline void S3L_transform3DInit(S3L_Transform3D *t);
+static inline void S3L_transform3DInit(S3L_Transform3D* t);
-void S3L_lookAt(S3L_Vec4 pointTo, S3L_Transform3D *t);
+void S3L_lookAt(S3L_Vec4 pointTo, S3L_Transform3D* t);
-void S3L_transform3DSet(
- S3L_Unit tx,
- S3L_Unit ty,
- S3L_Unit tz,
- S3L_Unit rx,
- S3L_Unit ry,
- S3L_Unit rz,
- S3L_Unit sx,
- S3L_Unit sy,
- S3L_Unit sz,
- S3L_Transform3D *t);
+void S3L_transform3DSet(S3L_Unit tx,
+ S3L_Unit ty,
+ S3L_Unit tz,
+ S3L_Unit rx,
+ S3L_Unit ry,
+ S3L_Unit rz,
+ S3L_Unit sx,
+ S3L_Unit sy,
+ S3L_Unit sz,
+ S3L_Transform3D* t);
/** Converts rotation transformation to three direction vectors of given length
(any one can be NULL, in which case it won't be computed). */
-void S3L_rotationToDirections(
- S3L_Vec4 rotation,
- S3L_Unit length,
- S3L_Vec4 *forw,
- S3L_Vec4 *right,
- S3L_Vec4 *up);
+void S3L_rotationToDirections(S3L_Vec4 rotation,
+ S3L_Unit length,
+ S3L_Vec4* forw,
+ S3L_Vec4* right,
+ S3L_Vec4* up);
/** 4x4 matrix, used mostly for 3D transforms. The indexing is this:
matrix[column][row]. */
-typedef S3L_Unit S3L_Mat4[4][4];
+typedef S3L_Unit S3L_Mat4[4][4];
-#define S3L_logMat4(m)\
- printf("Mat4:\n %d %d %d %d\n %d %d %d %d\n %d %d %d %d\n %d %d %d %d\n"\
- ,(m)[0][0],(m)[1][0],(m)[2][0],(m)[3][0],\
- (m)[0][1],(m)[1][1],(m)[2][1],(m)[3][1],\
- (m)[0][2],(m)[1][2],(m)[2][2],(m)[3][2],\
- (m)[0][3],(m)[1][3],(m)[2][3],(m)[3][3])
+#define S3L_logMat4(m) \
+ printf( \
+ "Mat4:\n %d %d %d %d\n %d %d %d %d\n %d %d %d %d\n %d %d %d %d\n", \
+ (m)[0][0], (m)[1][0], (m)[2][0], (m)[3][0], (m)[0][1], (m)[1][1], \
+ (m)[2][1], (m)[3][1], (m)[0][2], (m)[1][2], (m)[2][2], (m)[3][2], \
+ (m)[0][3], (m)[1][3], (m)[2][3], (m)[3][3])
/** Initializes a 4x4 matrix to identity. */
static inline void S3L_mat4Init(S3L_Mat4 m);
@@ -485,37 +483,34 @@ void S3L_mat4Copy(S3L_Mat4 src, S3L_Mat4 dst);
void S3L_mat4Transpose(S3L_Mat4 m);
-void S3L_makeTranslationMat(
- S3L_Unit offsetX,
- S3L_Unit offsetY,
- S3L_Unit offsetZ,
- S3L_Mat4 m);
+void S3L_makeTranslationMat(S3L_Unit offsetX,
+ S3L_Unit offsetY,
+ S3L_Unit offsetZ,
+ S3L_Mat4 m);
/** Makes a scaling matrix. DON'T FORGET: scale of 1.0 is set with
S3L_FRACTIONS_PER_UNIT! */
-void S3L_makeScaleMatrix(
- S3L_Unit scaleX,
- S3L_Unit scaleY,
- S3L_Unit scaleZ,
- S3L_Mat4 m);
+void S3L_makeScaleMatrix(S3L_Unit scaleX,
+ S3L_Unit scaleY,
+ S3L_Unit scaleZ,
+ S3L_Mat4 m);
/** Makes a matrix for rotation in the ZXY order. */
-void S3L_makeRotationMatrixZXY(
- S3L_Unit byX,
- S3L_Unit byY,
- S3L_Unit byZ,
- S3L_Mat4 m);
+void S3L_makeRotationMatrixZXY(S3L_Unit byX,
+ S3L_Unit byY,
+ S3L_Unit byZ,
+ S3L_Mat4 m);
void S3L_makeWorldMatrix(S3L_Transform3D worldTransform, S3L_Mat4 m);
void S3L_makeCameraMatrix(S3L_Transform3D cameraTransform, S3L_Mat4 m);
/** Multiplies a vector by a matrix with normalization by
S3L_FRACTIONS_PER_UNIT. Result is stored in the input vector. */
-void S3L_vec4Xmat4(S3L_Vec4 *v, S3L_Mat4 m);
+void S3L_vec4Xmat4(S3L_Vec4* v, S3L_Mat4 m);
/** Same as S3L_vec4Xmat4 but faster, because this version doesn't compute the
W component of the result, which is usually not needed. */
-void S3L_vec3Xmat4(S3L_Vec4 *v, S3L_Mat4 m);
+void S3L_vec3Xmat4(S3L_Vec4* v, S3L_Mat4 m);
/** Multiplies two matrices with normalization by S3L_FRACTIONS_PER_UNIT.
Result is stored in the first matrix. The result represents a transformation
@@ -523,91 +518,82 @@ void S3L_vec3Xmat4(S3L_Vec4 *v, S3L_Mat4 m);
then m2 (in that order). */
void S3L_mat4Xmat4(S3L_Mat4 m1, S3L_Mat4 m2);
-typedef struct
-{
- S3L_Unit focalLength; ///< Defines the field of view (FOV).
- S3L_Transform3D transform;
+typedef struct {
+ S3L_Unit focalLength; ///< Defines the field of view (FOV).
+ S3L_Transform3D transform;
} S3L_Camera;
-void S3L_cameraInit(S3L_Camera *camera);
+void S3L_cameraInit(S3L_Camera* camera);
-typedef struct
-{
- uint8_t backfaceCulling; /**< What backface culling to use. Possible
- values:
- - 0 none
- - 1 clock-wise
- - 2 counter clock-wise */
- int8_t visible; /**< Can be used to easily hide the model. */
+typedef struct {
+ uint8_t backfaceCulling; /**< What backface culling to use. Possible
+ values:
+ - 0 none
+ - 1 clock-wise
+ - 2 counter clock-wise */
+ int8_t visible; /**< Can be used to easily hide the model. */
} S3L_DrawConfig;
-void S3L_drawConfigInit(S3L_DrawConfig *config);
-
-typedef struct
-{
- const S3L_Unit *vertices;
- S3L_Index vertexCount;
- const S3L_Index *triangles;
- S3L_Index triangleCount;
- S3L_Transform3D transform;
- S3L_Mat4 *customTransformMatrix; /**< This can be used to override the
- transform (if != 0) with a custom
- transform matrix, which is more
- general. */
- S3L_DrawConfig config;
-} S3L_Model3D; ///< Represents a 3D model.
-
-void S3L_model3DInit(
- const S3L_Unit *vertices,
- S3L_Index vertexCount,
- const S3L_Index *triangles,
- S3L_Index triangleCount,
- S3L_Model3D *model);
-
-typedef struct
-{
- S3L_Model3D *models;
- S3L_Index modelCount;
- S3L_Camera camera;
-} S3L_Scene; ///< Represent the 3D scene to be rendered.
-
-void S3L_sceneInit(
- S3L_Model3D *models,
- S3L_Index modelCount,
- S3L_Scene *scene);
-
-typedef struct
-{
- S3L_ScreenCoord x; ///< Screen X coordinate.
- S3L_ScreenCoord y; ///< Screen Y coordinate.
-
- S3L_Unit barycentric[3]; /**< Barycentric coords correspond to the three
- vertices. These serve to locate the pixel on a
- triangle and interpolate values between its
- three points. Each one goes from 0 to
- S3L_FRACTIONS_PER_UNIT (including), but due to
- rounding error may fall outside this range (you
- can use S3L_correctBarycentricCoords to fix this
- for the price of some performance). The sum of
- the three coordinates will always be exactly
- S3L_FRACTIONS_PER_UNIT. */
- S3L_Index modelIndex; ///< Model index within the scene.
- S3L_Index triangleIndex; ///< Triangle index within the model.
- uint32_t triangleID; /**< Unique ID of the triangle withing the whole
- scene. This can be used e.g. by a cache to
- quickly find out if a triangle has changed. */
- S3L_Unit depth; ///< Depth (only if depth is turned on).
- S3L_Unit previousZ; /**< Z-buffer value (not necessarily world depth in
- S3L_Units!) that was in the z-buffer on the
- pixels position before this pixel was
- rasterized. This can be used to set the value
- back, e.g. for transparency. */
- S3L_ScreenCoord triangleSize[2]; /**< Rasterized triangle width and height,
- can be used e.g. for MIP mapping. */
-} S3L_PixelInfo; /**< Used to pass the info about a rasterized pixel
- (fragment) to the user-defined drawing func. */
-
-static inline void S3L_pixelInfoInit(S3L_PixelInfo *p);
+void S3L_drawConfigInit(S3L_DrawConfig* config);
+
+typedef struct {
+ const S3L_Unit* vertices;
+ S3L_Index vertexCount;
+ const S3L_Index* triangles;
+ S3L_Index triangleCount;
+ S3L_Transform3D transform;
+ S3L_Mat4* customTransformMatrix; /**< This can be used to override the
+ transform (if != 0) with a custom
+ transform matrix, which is more
+ general. */
+ S3L_DrawConfig config;
+} S3L_Model3D; ///< Represents a 3D model.
+
+void S3L_model3DInit(const S3L_Unit* vertices,
+ S3L_Index vertexCount,
+ const S3L_Index* triangles,
+ S3L_Index triangleCount,
+ S3L_Model3D* model);
+
+typedef struct {
+ S3L_Model3D* models;
+ S3L_Index modelCount;
+ S3L_Camera camera;
+} S3L_Scene; ///< Represent the 3D scene to be rendered.
+
+void S3L_sceneInit(S3L_Model3D* models, S3L_Index modelCount, S3L_Scene* scene);
+
+typedef struct {
+ S3L_ScreenCoord x; ///< Screen X coordinate.
+ S3L_ScreenCoord y; ///< Screen Y coordinate.
+
+ S3L_Unit barycentric[3]; /**< Barycentric coords correspond to the three
+ vertices. These serve to locate the pixel on a
+ triangle and interpolate values between its
+ three points. Each one goes from 0 to
+ S3L_FRACTIONS_PER_UNIT (including), but due to
+ rounding error may fall outside this range (you
+ can use S3L_correctBarycentricCoords to fix this
+ for the price of some performance). The sum of
+ the three coordinates will always be exactly
+ S3L_FRACTIONS_PER_UNIT. */
+ S3L_Index modelIndex; ///< Model index within the scene.
+ S3L_Index triangleIndex; ///< Triangle index within the model.
+ uint32_t triangleID; /**< Unique ID of the triangle withing the whole
+ scene. This can be used e.g. by a cache to
+ quickly find out if a triangle has changed. */
+ S3L_Unit depth; ///< Depth (only if depth is turned on).
+ S3L_Unit previousZ; /**< Z-buffer value (not necessarily world depth in
+ S3L_Units!) that was in the z-buffer on the
+ pixels position before this pixel was
+ rasterized. This can be used to set the value
+ back, e.g. for transparency. */
+ S3L_ScreenCoord triangleSize[2]; /**< Rasterized triangle width and height,
+ can be used e.g. for MIP mapping. */
+} S3L_PixelInfo; /**< Used to pass the info about a rasterized pixel
+ (fragment) to the user-defined drawing func. */
+
+static inline void S3L_pixelInfoInit(S3L_PixelInfo* p);
/** Corrects barycentric coordinates so that they exactly meet the defined
conditions (each fall into <0,S3L_FRACTIONS_PER_UNIT>, sum =
@@ -635,14 +621,12 @@ S3L_Unit S3L_sqrt(S3L_Unit value);
can be useful e.g. for drawing sprites. The w component of input and result
holds the point size. If this size is 0 in the result, the sprite is outside
the view. */
-void project3DPointToScreen(
- S3L_Vec4 point,
- S3L_Camera camera,
- S3L_Vec4 *result);
+void project3DPointToScreen(S3L_Vec4 point,
+ S3L_Camera camera,
+ S3L_Vec4* result);
/** Computes a normalized normal of given triangle. */
-void S3L_triangleNormal(S3L_Vec4 t0, S3L_Vec4 t1, S3L_Vec4 t2,
- S3L_Vec4 *n);
+void S3L_triangleNormal(S3L_Vec4 t0, S3L_Vec4 t1, S3L_Vec4 t2, S3L_Vec4* n);
/** Helper function for retrieving per-vertex indexed values from an array,
e.g. texturing (UV) coordinates. The 'indices' array contains three indices
@@ -652,80 +636,72 @@ void S3L_triangleNormal(S3L_Vec4 t0, S3L_Vec4 t1, S3L_Vec4 t2,
vectors (into x, y, z and w, depending on 'numComponents'). This function is
meant to be used per-triangle (typically from a cache), NOT per-pixel, as it
is not as fast as possible! */
-void S3L_getIndexedTriangleValues(
- S3L_Index triangleIndex,
- const S3L_Index *indices,
- const S3L_Unit *values,
- uint8_t numComponents,
- S3L_Vec4 *v0,
- S3L_Vec4 *v1,
- S3L_Vec4 *v2);
+void S3L_getIndexedTriangleValues(S3L_Index triangleIndex,
+ const S3L_Index* indices,
+ const S3L_Unit* values,
+ uint8_t numComponents,
+ S3L_Vec4* v0,
+ S3L_Vec4* v1,
+ S3L_Vec4* v2);
/** Computes a normalized normal for every vertex of given model (this is
relatively slow and SHOUDN'T be done each frame). The dst array must have a
sufficient size preallocated! The size is: number of model vertices * 3 *
sizeof(S3L_Unit). Note that for advanced allowing sharp edges it is not
sufficient to have per-vertex normals, but must be per-triangle. This
- function doesn't support this.
+ function doesn't support this.
The function computes a normal for each vertex by averaging normals of
the triangles containing the vertex. The maximum number of these triangle
normals that will be averaged is set with
S3L_NORMAL_COMPUTE_MAXIMUM_AVERAGE. */
-void S3L_computeModelNormals(S3L_Model3D model, S3L_Unit *dst,
- int8_t transformNormals);
+void S3L_computeModelNormals(S3L_Model3D model,
+ S3L_Unit* dst,
+ int8_t transformNormals);
/** Interpolated between two values, v1 and v2, in the same ratio as t is to
tMax. Does NOT prevent zero division. */
-static inline S3L_Unit S3L_interpolate(
- S3L_Unit v1,
- S3L_Unit v2,
- S3L_Unit t,
- S3L_Unit tMax);
+static inline S3L_Unit S3L_interpolate(S3L_Unit v1,
+ S3L_Unit v2,
+ S3L_Unit t,
+ S3L_Unit tMax);
/** Same as S3L_interpolate but with v1 == 0. Should be faster. */
-static inline S3L_Unit S3L_interpolateFrom0(
- S3L_Unit v2,
- S3L_Unit t,
- S3L_Unit tMax);
+static inline S3L_Unit S3L_interpolateFrom0(S3L_Unit v2,
+ S3L_Unit t,
+ S3L_Unit tMax);
/** Like S3L_interpolate, but uses a parameter that goes from 0 to
S3L_FRACTIONS_PER_UNIT - 1, which can be faster. */
-static inline S3L_Unit S3L_interpolateByUnit(
- S3L_Unit v1,
- S3L_Unit v2,
- S3L_Unit t);
+static inline S3L_Unit S3L_interpolateByUnit(S3L_Unit v1,
+ S3L_Unit v2,
+ S3L_Unit t);
/** Same as S3L_interpolateByUnit but with v1 == 0. Should be faster. */
-static inline S3L_Unit S3L_interpolateByUnitFrom0(
- S3L_Unit v2,
- S3L_Unit t);
+static inline S3L_Unit S3L_interpolateByUnitFrom0(S3L_Unit v2, S3L_Unit t);
static inline S3L_Unit S3L_distanceManhattan(S3L_Vec4 a, S3L_Vec4 b);
/** Returns a value interpolated between the three triangle vertices based on
barycentric coordinates. */
-static inline S3L_Unit S3L_interpolateBarycentric(
- S3L_Unit value0,
- S3L_Unit value1,
- S3L_Unit value2,
- S3L_Unit barycentric[3]);
+static inline S3L_Unit S3L_interpolateBarycentric(S3L_Unit value0,
+ S3L_Unit value1,
+ S3L_Unit value2,
+ S3L_Unit barycentric[3]);
-static inline void S3L_mapProjectionPlaneToScreen(
- S3L_Vec4 point,
- S3L_ScreenCoord *screenX,
- S3L_ScreenCoord *screenY);
+static inline void S3L_mapProjectionPlaneToScreen(S3L_Vec4 point,
+ S3L_ScreenCoord* screenX,
+ S3L_ScreenCoord* screenY);
/** Draws a triangle according to given config. The vertices are specified in
Screen Space space (pixels). If perspective correction is enabled, each
vertex has to have a depth (Z position in camera space) specified in the Z
component. */
-void S3L_drawTriangle(
- S3L_Vec4 point0,
- S3L_Vec4 point1,
- S3L_Vec4 point2,
- S3L_Index modelIndex,
- S3L_Index triangleIndex);
+void S3L_drawTriangle(S3L_Vec4 point0,
+ S3L_Vec4 point1,
+ S3L_Vec4 point2,
+ S3L_Index modelIndex,
+ S3L_Index triangleIndex);
/** This should be called before rendering each frame. The function clears
buffers and does potentially other things needed for the frame. */
@@ -742,1069 +718,976 @@ void S3L_zBufferWrite(S3L_ScreenCoord x, S3L_ScreenCoord y, S3L_Unit value);
from z-buffer (if enabled). Does NOT check boundaries! */
S3L_Unit S3L_zBufferRead(S3L_ScreenCoord x, S3L_ScreenCoord y);
-static inline void S3L_rotate2DPoint(S3L_Unit *x, S3L_Unit *y, S3L_Unit angle);
+static inline void S3L_rotate2DPoint(S3L_Unit* x, S3L_Unit* y, S3L_Unit angle);
/** Predefined vertices of a cube to simply insert in an array. These come with
S3L_CUBE_TRIANGLES and S3L_CUBE_TEXCOORDS. */
-#define S3L_CUBE_VERTICES(m)\
- /* 0 front, bottom, right */\
- m/2, -m/2, -m/2,\
- /* 1 front, bottom, left */\
--m/2, -m/2, -m/2,\
- /* 2 front, top, right */\
- m/2, m/2, -m/2,\
- /* 3 front, top, left */\
--m/2, m/2, -m/2,\
- /* 4 back, bottom, right */\
- m/2, -m/2, m/2,\
- /* 5 back, bottom, left */\
--m/2, -m/2, m/2,\
- /* 6 back, top, right */\
- m/2, m/2, m/2,\
- /* 7 back, top, left */\
--m/2, m/2, m/2
+#define S3L_CUBE_VERTICES(m) \
+ /* 0 front, bottom, right */ \
+ m / 2, -m / 2, -m / 2, /* 1 front, bottom, left */ \
+ -m / 2, -m / 2, -m / 2, /* 2 front, top, right */ \
+ m / 2, m / 2, -m / 2, /* 3 front, top, left */ \
+ -m / 2, m / 2, -m / 2, /* 4 back, bottom, right */ \
+ m / 2, -m / 2, m / 2, /* 5 back, bottom, left */ \
+ -m / 2, -m / 2, m / 2, /* 6 back, top, right */ \
+ m / 2, m / 2, m / 2, /* 7 back, top, left */ \
+ -m / 2, m / 2, m / 2
#define S3L_CUBE_VERTEX_COUNT 8
/** Predefined triangle indices of a cube, to be used with S3L_CUBE_VERTICES
and S3L_CUBE_TEXCOORDS. */
-#define S3L_CUBE_TRIANGLES\
- 3, 0, 2, /* front */\
- 1, 0, 3,\
- 0, 4, 2, /* right */\
- 2, 4, 6,\
- 4, 5, 6, /* back */\
- 7, 6, 5,\
- 3, 7, 1, /* left */\
- 1, 7, 5,\
- 6, 3, 2, /* top */\
- 7, 3, 6,\
- 1, 4, 0, /* bottom */\
- 5, 4, 1
+#define S3L_CUBE_TRIANGLES \
+ 3, 0, 2, /* front */ \
+ 1, 0, 3, 0, 4, 2, /* right */ \
+ 2, 4, 6, 4, 5, 6, /* back */ \
+ 7, 6, 5, 3, 7, 1, /* left */ \
+ 1, 7, 5, 6, 3, 2, /* top */ \
+ 7, 3, 6, 1, 4, 0, /* bottom */ \
+ 5, 4, 1
#define S3L_CUBE_TRIANGLE_COUNT 12
/** Predefined texture coordinates of a cube, corresponding to triangles (NOT
vertices), to be used with S3L_CUBE_VERTICES and S3L_CUBE_TRIANGLES. */
-#define S3L_CUBE_TEXCOORDS(m)\
- 0,0, m,m, m,0,\
- 0,m, m,m, 0,0,\
- m,m, m,0, 0,m,\
- 0,m, m,0, 0,0,\
- m,0, 0,0, m,m,\
- 0,m, m,m, 0,0,\
- 0,0, 0,m, m,0,\
- m,0, 0,m, m,m,\
- 0,0, m,m, m,0,\
- 0,m, m,m, 0,0,\
- m,0, 0,m, m,m,\
- 0,0, 0,m, m,0
+#define S3L_CUBE_TEXCOORDS(m) \
+ 0, 0, m, m, m, 0, 0, m, m, m, 0, 0, m, m, m, 0, 0, m, 0, m, m, 0, 0, 0, m, \
+ 0, 0, 0, m, m, 0, m, m, m, 0, 0, 0, 0, 0, m, m, 0, m, 0, 0, m, m, m, \
+ 0, 0, m, m, m, 0, 0, m, m, m, 0, 0, m, 0, 0, m, m, m, 0, 0, 0, m, m, 0
//=============================================================================
// privates
-#define S3L_UNUSED(what) (void)(what) ///< helper macro for unused vars
+#define S3L_UNUSED(what) (void)(what) ///< helper macro for unused vars
#define S3L_HALF_RESOLUTION_X (S3L_RESOLUTION_X >> 1)
#define S3L_HALF_RESOLUTION_Y (S3L_RESOLUTION_Y >> 1)
-#define S3L_PROJECTION_PLANE_HEIGHT\
- ((S3L_RESOLUTION_Y * S3L_FRACTIONS_PER_UNIT * 2) / S3L_RESOLUTION_X)
+#define S3L_PROJECTION_PLANE_HEIGHT \
+ ((S3L_RESOLUTION_Y * S3L_FRACTIONS_PER_UNIT * 2) / S3L_RESOLUTION_X)
#if S3L_Z_BUFFER == 1
- #define S3L_MAX_DEPTH 2147483647
- S3L_Unit S3L_zBuffer[S3L_MAX_PIXELS];
- #define S3L_zBufferFormat(depth) (depth)
+#define S3L_MAX_DEPTH 2147483647
+S3L_Unit S3L_zBuffer[S3L_MAX_PIXELS];
+#define S3L_zBufferFormat(depth) (depth)
#elif S3L_Z_BUFFER == 2
- #define S3L_MAX_DEPTH 255
- uint8_t S3L_zBuffer[S3L_MAX_PIXELS];
- #define S3L_zBufferFormat(depth)\
- S3L_min(255,(depth) >> S3L_REDUCED_Z_BUFFER_GRANULARITY)
+#define S3L_MAX_DEPTH 255
+uint8_t S3L_zBuffer[S3L_MAX_PIXELS];
+#define S3L_zBufferFormat(depth) \
+ S3L_min(255, (depth) >> S3L_REDUCED_Z_BUFFER_GRANULARITY)
#endif
#if S3L_Z_BUFFER
-static inline int8_t S3L_zTest(
- S3L_ScreenCoord x,
- S3L_ScreenCoord y,
- S3L_Unit depth)
-{
- uint32_t index = y * S3L_RESOLUTION_X + x;
+static inline int8_t S3L_zTest(S3L_ScreenCoord x,
+ S3L_ScreenCoord y,
+ S3L_Unit depth) {
+ uint32_t index = y * S3L_RESOLUTION_X + x;
- depth = S3L_zBufferFormat(depth);
+ depth = S3L_zBufferFormat(depth);
#if S3L_Z_BUFFER == 2
- #define cmp <= /* For reduced z-buffer we need equality test, because
- otherwise pixels at the maximum depth (255) would never be
- drawn over the background (which also has the depth of
- 255). */
+#define cmp \
+ <= /* For reduced z-buffer we need equality test, because \
+ otherwise pixels at the maximum depth (255) would never be \
+ drawn over the background (which also has the depth of \
+ 255). */
#else
- #define cmp < /* For normal z-buffer we leave out equality test to not waste
- time by drawing over already drawn pixls. */
+#define cmp \
+ < /* For normal z-buffer we leave out equality test to not waste \
+ time by drawing over already drawn pixls. */
#endif
- if (depth cmp S3L_zBuffer[index])
- {
- S3L_zBuffer[index] = depth;
- return 1;
- }
+ if (depth cmp S3L_zBuffer[index]) {
+ S3L_zBuffer[index] = depth;
+ return 1;
+ }
#undef cmp
- return 0;
+ return 0;
}
#endif
-S3L_Unit S3L_zBufferRead(S3L_ScreenCoord x, S3L_ScreenCoord y)
-{
+S3L_Unit S3L_zBufferRead(S3L_ScreenCoord x, S3L_ScreenCoord y) {
#if S3L_Z_BUFFER
- return S3L_zBuffer[y * S3L_RESOLUTION_X + x];
+ return S3L_zBuffer[y * S3L_RESOLUTION_X + x];
#else
- S3L_UNUSED(x);
- S3L_UNUSED(y);
+ S3L_UNUSED(x);
+ S3L_UNUSED(y);
- return 0;
+ return 0;
#endif
}
-void S3L_zBufferWrite(S3L_ScreenCoord x, S3L_ScreenCoord y, S3L_Unit value)
-{
+void S3L_zBufferWrite(S3L_ScreenCoord x, S3L_ScreenCoord y, S3L_Unit value) {
#if S3L_Z_BUFFER
- S3L_zBuffer[y * S3L_RESOLUTION_X + x] = value;
+ S3L_zBuffer[y * S3L_RESOLUTION_X + x] = value;
#else
- S3L_UNUSED(x);
- S3L_UNUSED(y);
- S3L_UNUSED(value);
+ S3L_UNUSED(x);
+ S3L_UNUSED(y);
+ S3L_UNUSED(value);
#endif
}
#if S3L_STENCIL_BUFFER
- #define S3L_STENCIL_BUFFER_SIZE\
+#define S3L_STENCIL_BUFFER_SIZE \
((S3L_RESOLUTION_X * S3L_RESOLUTION_Y - 1) / 8 + 1)
uint8_t S3L_stencilBuffer[S3L_STENCIL_BUFFER_SIZE];
-static inline int8_t S3L_stencilTest(
- S3L_ScreenCoord x,
- S3L_ScreenCoord y)
-{
- uint32_t index = y * S3L_RESOLUTION_X + x;
- uint32_t bit = (index & 0x00000007);
- index = index >> 3;
+static inline int8_t S3L_stencilTest(S3L_ScreenCoord x, S3L_ScreenCoord y) {
+ uint32_t index = y * S3L_RESOLUTION_X + x;
+ uint32_t bit = (index & 0x00000007);
+ index = index >> 3;
- uint8_t val = S3L_stencilBuffer[index];
+ uint8_t val = S3L_stencilBuffer[index];
- if ((val >> bit) & 0x1)
- return 0;
-
- S3L_stencilBuffer[index] = val | (0x1 << bit);
+ if ((val >> bit) & 0x1)
+ return 0;
+
+ S3L_stencilBuffer[index] = val | (0x1 << bit);
- return 1;
+ return 1;
}
#endif
-#define S3L_COMPUTE_LERP_DEPTH\
- (S3L_COMPUTE_DEPTH && (S3L_PERSPECTIVE_CORRECTION == 0))
+#define S3L_COMPUTE_LERP_DEPTH \
+ (S3L_COMPUTE_DEPTH && (S3L_PERSPECTIVE_CORRECTION == 0))
#define S3L_SIN_TABLE_LENGTH 128
-static const S3L_Unit S3L_sinTable[S3L_SIN_TABLE_LENGTH] =
-{
- /* 511 was chosen here as a highest number that doesn't overflow during
- compilation for S3L_FRACTIONS_PER_UNIT == 1024 */
-
- (0*S3L_FRACTIONS_PER_UNIT)/511, (6*S3L_FRACTIONS_PER_UNIT)/511,
- (12*S3L_FRACTIONS_PER_UNIT)/511, (18*S3L_FRACTIONS_PER_UNIT)/511,
- (25*S3L_FRACTIONS_PER_UNIT)/511, (31*S3L_FRACTIONS_PER_UNIT)/511,
- (37*S3L_FRACTIONS_PER_UNIT)/511, (43*S3L_FRACTIONS_PER_UNIT)/511,
- (50*S3L_FRACTIONS_PER_UNIT)/511, (56*S3L_FRACTIONS_PER_UNIT)/511,
- (62*S3L_FRACTIONS_PER_UNIT)/511, (68*S3L_FRACTIONS_PER_UNIT)/511,
- (74*S3L_FRACTIONS_PER_UNIT)/511, (81*S3L_FRACTIONS_PER_UNIT)/511,
- (87*S3L_FRACTIONS_PER_UNIT)/511, (93*S3L_FRACTIONS_PER_UNIT)/511,
- (99*S3L_FRACTIONS_PER_UNIT)/511, (105*S3L_FRACTIONS_PER_UNIT)/511,
- (111*S3L_FRACTIONS_PER_UNIT)/511, (118*S3L_FRACTIONS_PER_UNIT)/511,
- (124*S3L_FRACTIONS_PER_UNIT)/511, (130*S3L_FRACTIONS_PER_UNIT)/511,
- (136*S3L_FRACTIONS_PER_UNIT)/511, (142*S3L_FRACTIONS_PER_UNIT)/511,
- (148*S3L_FRACTIONS_PER_UNIT)/511, (154*S3L_FRACTIONS_PER_UNIT)/511,
- (160*S3L_FRACTIONS_PER_UNIT)/511, (166*S3L_FRACTIONS_PER_UNIT)/511,
- (172*S3L_FRACTIONS_PER_UNIT)/511, (178*S3L_FRACTIONS_PER_UNIT)/511,
- (183*S3L_FRACTIONS_PER_UNIT)/511, (189*S3L_FRACTIONS_PER_UNIT)/511,
- (195*S3L_FRACTIONS_PER_UNIT)/511, (201*S3L_FRACTIONS_PER_UNIT)/511,
- (207*S3L_FRACTIONS_PER_UNIT)/511, (212*S3L_FRACTIONS_PER_UNIT)/511,
- (218*S3L_FRACTIONS_PER_UNIT)/511, (224*S3L_FRACTIONS_PER_UNIT)/511,
- (229*S3L_FRACTIONS_PER_UNIT)/511, (235*S3L_FRACTIONS_PER_UNIT)/511,
- (240*S3L_FRACTIONS_PER_UNIT)/511, (246*S3L_FRACTIONS_PER_UNIT)/511,
- (251*S3L_FRACTIONS_PER_UNIT)/511, (257*S3L_FRACTIONS_PER_UNIT)/511,
- (262*S3L_FRACTIONS_PER_UNIT)/511, (268*S3L_FRACTIONS_PER_UNIT)/511,
- (273*S3L_FRACTIONS_PER_UNIT)/511, (278*S3L_FRACTIONS_PER_UNIT)/511,
- (283*S3L_FRACTIONS_PER_UNIT)/511, (289*S3L_FRACTIONS_PER_UNIT)/511,
- (294*S3L_FRACTIONS_PER_UNIT)/511, (299*S3L_FRACTIONS_PER_UNIT)/511,
- (304*S3L_FRACTIONS_PER_UNIT)/511, (309*S3L_FRACTIONS_PER_UNIT)/511,
- (314*S3L_FRACTIONS_PER_UNIT)/511, (319*S3L_FRACTIONS_PER_UNIT)/511,
- (324*S3L_FRACTIONS_PER_UNIT)/511, (328*S3L_FRACTIONS_PER_UNIT)/511,
- (333*S3L_FRACTIONS_PER_UNIT)/511, (338*S3L_FRACTIONS_PER_UNIT)/511,
- (343*S3L_FRACTIONS_PER_UNIT)/511, (347*S3L_FRACTIONS_PER_UNIT)/511,
- (352*S3L_FRACTIONS_PER_UNIT)/511, (356*S3L_FRACTIONS_PER_UNIT)/511,
- (361*S3L_FRACTIONS_PER_UNIT)/511, (365*S3L_FRACTIONS_PER_UNIT)/511,
- (370*S3L_FRACTIONS_PER_UNIT)/511, (374*S3L_FRACTIONS_PER_UNIT)/511,
- (378*S3L_FRACTIONS_PER_UNIT)/511, (382*S3L_FRACTIONS_PER_UNIT)/511,
- (386*S3L_FRACTIONS_PER_UNIT)/511, (391*S3L_FRACTIONS_PER_UNIT)/511,
- (395*S3L_FRACTIONS_PER_UNIT)/511, (398*S3L_FRACTIONS_PER_UNIT)/511,
- (402*S3L_FRACTIONS_PER_UNIT)/511, (406*S3L_FRACTIONS_PER_UNIT)/511,
- (410*S3L_FRACTIONS_PER_UNIT)/511, (414*S3L_FRACTIONS_PER_UNIT)/511,
- (417*S3L_FRACTIONS_PER_UNIT)/511, (421*S3L_FRACTIONS_PER_UNIT)/511,
- (424*S3L_FRACTIONS_PER_UNIT)/511, (428*S3L_FRACTIONS_PER_UNIT)/511,
- (431*S3L_FRACTIONS_PER_UNIT)/511, (435*S3L_FRACTIONS_PER_UNIT)/511,
- (438*S3L_FRACTIONS_PER_UNIT)/511, (441*S3L_FRACTIONS_PER_UNIT)/511,
- (444*S3L_FRACTIONS_PER_UNIT)/511, (447*S3L_FRACTIONS_PER_UNIT)/511,
- (450*S3L_FRACTIONS_PER_UNIT)/511, (453*S3L_FRACTIONS_PER_UNIT)/511,
- (456*S3L_FRACTIONS_PER_UNIT)/511, (459*S3L_FRACTIONS_PER_UNIT)/511,
- (461*S3L_FRACTIONS_PER_UNIT)/511, (464*S3L_FRACTIONS_PER_UNIT)/511,
- (467*S3L_FRACTIONS_PER_UNIT)/511, (469*S3L_FRACTIONS_PER_UNIT)/511,
- (472*S3L_FRACTIONS_PER_UNIT)/511, (474*S3L_FRACTIONS_PER_UNIT)/511,
- (476*S3L_FRACTIONS_PER_UNIT)/511, (478*S3L_FRACTIONS_PER_UNIT)/511,
- (481*S3L_FRACTIONS_PER_UNIT)/511, (483*S3L_FRACTIONS_PER_UNIT)/511,
- (485*S3L_FRACTIONS_PER_UNIT)/511, (487*S3L_FRACTIONS_PER_UNIT)/511,
- (488*S3L_FRACTIONS_PER_UNIT)/511, (490*S3L_FRACTIONS_PER_UNIT)/511,
- (492*S3L_FRACTIONS_PER_UNIT)/511, (494*S3L_FRACTIONS_PER_UNIT)/511,
- (495*S3L_FRACTIONS_PER_UNIT)/511, (497*S3L_FRACTIONS_PER_UNIT)/511,
- (498*S3L_FRACTIONS_PER_UNIT)/511, (499*S3L_FRACTIONS_PER_UNIT)/511,
- (501*S3L_FRACTIONS_PER_UNIT)/511, (502*S3L_FRACTIONS_PER_UNIT)/511,
- (503*S3L_FRACTIONS_PER_UNIT)/511, (504*S3L_FRACTIONS_PER_UNIT)/511,
- (505*S3L_FRACTIONS_PER_UNIT)/511, (506*S3L_FRACTIONS_PER_UNIT)/511,
- (507*S3L_FRACTIONS_PER_UNIT)/511, (507*S3L_FRACTIONS_PER_UNIT)/511,
- (508*S3L_FRACTIONS_PER_UNIT)/511, (509*S3L_FRACTIONS_PER_UNIT)/511,
- (509*S3L_FRACTIONS_PER_UNIT)/511, (510*S3L_FRACTIONS_PER_UNIT)/511,
- (510*S3L_FRACTIONS_PER_UNIT)/511, (510*S3L_FRACTIONS_PER_UNIT)/511,
- (510*S3L_FRACTIONS_PER_UNIT)/511, (510*S3L_FRACTIONS_PER_UNIT)/511
-};
-
-#define S3L_SIN_TABLE_UNIT_STEP\
- (S3L_FRACTIONS_PER_UNIT / (S3L_SIN_TABLE_LENGTH * 4))
-
-void S3L_vec4Init(S3L_Vec4 *v)
-{
- v->x = 0; v->y = 0; v->z = 0; v->w = S3L_FRACTIONS_PER_UNIT;
-}
-
-void S3L_vec4Set(S3L_Vec4 *v, S3L_Unit x, S3L_Unit y, S3L_Unit z, S3L_Unit w)
-{
- v->x = x;
- v->y = y;
- v->z = z;
- v->w = w;
-}
-
-void S3L_vec3Add(S3L_Vec4 *result, S3L_Vec4 added)
-{
- result->x += added.x;
- result->y += added.y;
- result->z += added.z;
-}
-
-void S3L_vec3Sub(S3L_Vec4 *result, S3L_Vec4 substracted)
-{
- result->x -= substracted.x;
- result->y -= substracted.y;
- result->z -= substracted.z;
-}
-
-void S3L_mat4Init(S3L_Mat4 m)
-{
- #define M(x,y) m[x][y]
- #define S S3L_FRACTIONS_PER_UNIT
-
- M(0,0) = S; M(1,0) = 0; M(2,0) = 0; M(3,0) = 0;
- M(0,1) = 0; M(1,1) = S; M(2,1) = 0; M(3,1) = 0;
- M(0,2) = 0; M(1,2) = 0; M(2,2) = S; M(3,2) = 0;
- M(0,3) = 0; M(1,3) = 0; M(2,3) = 0; M(3,3) = S;
-
- #undef M
- #undef S
-}
-
-void S3L_mat4Copy(S3L_Mat4 src, S3L_Mat4 dst)
-{
- for (uint8_t j = 0; j < 4; ++j)
- for (uint8_t i = 0; i < 4; ++i)
- dst[i][j] = src[i][j];
-}
-
-S3L_Unit S3L_vec3Dot(S3L_Vec4 a, S3L_Vec4 b)
-{
- return (a.x * b.x + a.y * b.y + a.z * b.z) / S3L_FRACTIONS_PER_UNIT;
-}
-
-void S3L_reflect(S3L_Vec4 toLight, S3L_Vec4 normal, S3L_Vec4 *result)
-{
- S3L_Unit d = 2 * S3L_vec3Dot(toLight,normal);
-
- result->x = (normal.x * d) / S3L_FRACTIONS_PER_UNIT - toLight.x;
- result->y = (normal.y * d) / S3L_FRACTIONS_PER_UNIT - toLight.y;
- result->z = (normal.z * d) / S3L_FRACTIONS_PER_UNIT - toLight.z;
-}
-
-void S3L_vec3Cross(S3L_Vec4 a, S3L_Vec4 b, S3L_Vec4 *result)
-{
- result->x = a.y * b.z - a.z * b.y;
- result->y = a.z * b.x - a.x * b.z;
- result->z = a.x * b.y - a.y * b.x;
-}
-
-void S3L_triangleNormal(S3L_Vec4 t0, S3L_Vec4 t1, S3L_Vec4 t2, S3L_Vec4 *n)
-{
- #define ANTI_OVERFLOW 32
-
- t1.x = (t1.x - t0.x) / ANTI_OVERFLOW;
- t1.y = (t1.y - t0.y) / ANTI_OVERFLOW;
- t1.z = (t1.z - t0.z) / ANTI_OVERFLOW;
+static const S3L_Unit S3L_sinTable[S3L_SIN_TABLE_LENGTH] = {
+ /* 511 was chosen here as a highest number that doesn't overflow during
+ compilation for S3L_FRACTIONS_PER_UNIT == 1024 */
+
+ (0 * S3L_FRACTIONS_PER_UNIT) / 511, (6 * S3L_FRACTIONS_PER_UNIT) / 511,
+ (12 * S3L_FRACTIONS_PER_UNIT) / 511, (18 * S3L_FRACTIONS_PER_UNIT) / 511,
+ (25 * S3L_FRACTIONS_PER_UNIT) / 511, (31 * S3L_FRACTIONS_PER_UNIT) / 511,
+ (37 * S3L_FRACTIONS_PER_UNIT) / 511, (43 * S3L_FRACTIONS_PER_UNIT) / 511,
+ (50 * S3L_FRACTIONS_PER_UNIT) / 511, (56 * S3L_FRACTIONS_PER_UNIT) / 511,
+ (62 * S3L_FRACTIONS_PER_UNIT) / 511, (68 * S3L_FRACTIONS_PER_UNIT) / 511,
+ (74 * S3L_FRACTIONS_PER_UNIT) / 511, (81 * S3L_FRACTIONS_PER_UNIT) / 511,
+ (87 * S3L_FRACTIONS_PER_UNIT) / 511, (93 * S3L_FRACTIONS_PER_UNIT) / 511,
+ (99 * S3L_FRACTIONS_PER_UNIT) / 511, (105 * S3L_FRACTIONS_PER_UNIT) / 511,
+ (111 * S3L_FRACTIONS_PER_UNIT) / 511, (118 * S3L_FRACTIONS_PER_UNIT) / 511,
+ (124 * S3L_FRACTIONS_PER_UNIT) / 511, (130 * S3L_FRACTIONS_PER_UNIT) / 511,
+ (136 * S3L_FRACTIONS_PER_UNIT) / 511, (142 * S3L_FRACTIONS_PER_UNIT) / 511,
+ (148 * S3L_FRACTIONS_PER_UNIT) / 511, (154 * S3L_FRACTIONS_PER_UNIT) / 511,
+ (160 * S3L_FRACTIONS_PER_UNIT) / 511, (166 * S3L_FRACTIONS_PER_UNIT) / 511,
+ (172 * S3L_FRACTIONS_PER_UNIT) / 511, (178 * S3L_FRACTIONS_PER_UNIT) / 511,
+ (183 * S3L_FRACTIONS_PER_UNIT) / 511, (189 * S3L_FRACTIONS_PER_UNIT) / 511,
+ (195 * S3L_FRACTIONS_PER_UNIT) / 511, (201 * S3L_FRACTIONS_PER_UNIT) / 511,
+ (207 * S3L_FRACTIONS_PER_UNIT) / 511, (212 * S3L_FRACTIONS_PER_UNIT) / 511,
+ (218 * S3L_FRACTIONS_PER_UNIT) / 511, (224 * S3L_FRACTIONS_PER_UNIT) / 511,
+ (229 * S3L_FRACTIONS_PER_UNIT) / 511, (235 * S3L_FRACTIONS_PER_UNIT) / 511,
+ (240 * S3L_FRACTIONS_PER_UNIT) / 511, (246 * S3L_FRACTIONS_PER_UNIT) / 511,
+ (251 * S3L_FRACTIONS_PER_UNIT) / 511, (257 * S3L_FRACTIONS_PER_UNIT) / 511,
+ (262 * S3L_FRACTIONS_PER_UNIT) / 511, (268 * S3L_FRACTIONS_PER_UNIT) / 511,
+ (273 * S3L_FRACTIONS_PER_UNIT) / 511, (278 * S3L_FRACTIONS_PER_UNIT) / 511,
+ (283 * S3L_FRACTIONS_PER_UNIT) / 511, (289 * S3L_FRACTIONS_PER_UNIT) / 511,
+ (294 * S3L_FRACTIONS_PER_UNIT) / 511, (299 * S3L_FRACTIONS_PER_UNIT) / 511,
+ (304 * S3L_FRACTIONS_PER_UNIT) / 511, (309 * S3L_FRACTIONS_PER_UNIT) / 511,
+ (314 * S3L_FRACTIONS_PER_UNIT) / 511, (319 * S3L_FRACTIONS_PER_UNIT) / 511,
+ (324 * S3L_FRACTIONS_PER_UNIT) / 511, (328 * S3L_FRACTIONS_PER_UNIT) / 511,
+ (333 * S3L_FRACTIONS_PER_UNIT) / 511, (338 * S3L_FRACTIONS_PER_UNIT) / 511,
+ (343 * S3L_FRACTIONS_PER_UNIT) / 511, (347 * S3L_FRACTIONS_PER_UNIT) / 511,
+ (352 * S3L_FRACTIONS_PER_UNIT) / 511, (356 * S3L_FRACTIONS_PER_UNIT) / 511,
+ (361 * S3L_FRACTIONS_PER_UNIT) / 511, (365 * S3L_FRACTIONS_PER_UNIT) / 511,
+ (370 * S3L_FRACTIONS_PER_UNIT) / 511, (374 * S3L_FRACTIONS_PER_UNIT) / 511,
+ (378 * S3L_FRACTIONS_PER_UNIT) / 511, (382 * S3L_FRACTIONS_PER_UNIT) / 511,
+ (386 * S3L_FRACTIONS_PER_UNIT) / 511, (391 * S3L_FRACTIONS_PER_UNIT) / 511,
+ (395 * S3L_FRACTIONS_PER_UNIT) / 511, (398 * S3L_FRACTIONS_PER_UNIT) / 511,
+ (402 * S3L_FRACTIONS_PER_UNIT) / 511, (406 * S3L_FRACTIONS_PER_UNIT) / 511,
+ (410 * S3L_FRACTIONS_PER_UNIT) / 511, (414 * S3L_FRACTIONS_PER_UNIT) / 511,
+ (417 * S3L_FRACTIONS_PER_UNIT) / 511, (421 * S3L_FRACTIONS_PER_UNIT) / 511,
+ (424 * S3L_FRACTIONS_PER_UNIT) / 511, (428 * S3L_FRACTIONS_PER_UNIT) / 511,
+ (431 * S3L_FRACTIONS_PER_UNIT) / 511, (435 * S3L_FRACTIONS_PER_UNIT) / 511,
+ (438 * S3L_FRACTIONS_PER_UNIT) / 511, (441 * S3L_FRACTIONS_PER_UNIT) / 511,
+ (444 * S3L_FRACTIONS_PER_UNIT) / 511, (447 * S3L_FRACTIONS_PER_UNIT) / 511,
+ (450 * S3L_FRACTIONS_PER_UNIT) / 511, (453 * S3L_FRACTIONS_PER_UNIT) / 511,
+ (456 * S3L_FRACTIONS_PER_UNIT) / 511, (459 * S3L_FRACTIONS_PER_UNIT) / 511,
+ (461 * S3L_FRACTIONS_PER_UNIT) / 511, (464 * S3L_FRACTIONS_PER_UNIT) / 511,
+ (467 * S3L_FRACTIONS_PER_UNIT) / 511, (469 * S3L_FRACTIONS_PER_UNIT) / 511,
+ (472 * S3L_FRACTIONS_PER_UNIT) / 511, (474 * S3L_FRACTIONS_PER_UNIT) / 511,
+ (476 * S3L_FRACTIONS_PER_UNIT) / 511, (478 * S3L_FRACTIONS_PER_UNIT) / 511,
+ (481 * S3L_FRACTIONS_PER_UNIT) / 511, (483 * S3L_FRACTIONS_PER_UNIT) / 511,
+ (485 * S3L_FRACTIONS_PER_UNIT) / 511, (487 * S3L_FRACTIONS_PER_UNIT) / 511,
+ (488 * S3L_FRACTIONS_PER_UNIT) / 511, (490 * S3L_FRACTIONS_PER_UNIT) / 511,
+ (492 * S3L_FRACTIONS_PER_UNIT) / 511, (494 * S3L_FRACTIONS_PER_UNIT) / 511,
+ (495 * S3L_FRACTIONS_PER_UNIT) / 511, (497 * S3L_FRACTIONS_PER_UNIT) / 511,
+ (498 * S3L_FRACTIONS_PER_UNIT) / 511, (499 * S3L_FRACTIONS_PER_UNIT) / 511,
+ (501 * S3L_FRACTIONS_PER_UNIT) / 511, (502 * S3L_FRACTIONS_PER_UNIT) / 511,
+ (503 * S3L_FRACTIONS_PER_UNIT) / 511, (504 * S3L_FRACTIONS_PER_UNIT) / 511,
+ (505 * S3L_FRACTIONS_PER_UNIT) / 511, (506 * S3L_FRACTIONS_PER_UNIT) / 511,
+ (507 * S3L_FRACTIONS_PER_UNIT) / 511, (507 * S3L_FRACTIONS_PER_UNIT) / 511,
+ (508 * S3L_FRACTIONS_PER_UNIT) / 511, (509 * S3L_FRACTIONS_PER_UNIT) / 511,
+ (509 * S3L_FRACTIONS_PER_UNIT) / 511, (510 * S3L_FRACTIONS_PER_UNIT) / 511,
+ (510 * S3L_FRACTIONS_PER_UNIT) / 511, (510 * S3L_FRACTIONS_PER_UNIT) / 511,
+ (510 * S3L_FRACTIONS_PER_UNIT) / 511, (510 * S3L_FRACTIONS_PER_UNIT) / 511};
+
+#define S3L_SIN_TABLE_UNIT_STEP \
+ (S3L_FRACTIONS_PER_UNIT / (S3L_SIN_TABLE_LENGTH * 4))
+
+void S3L_vec4Init(S3L_Vec4* v) {
+ v->x = 0;
+ v->y = 0;
+ v->z = 0;
+ v->w = S3L_FRACTIONS_PER_UNIT;
+}
+
+void S3L_vec4Set(S3L_Vec4* v, S3L_Unit x, S3L_Unit y, S3L_Unit z, S3L_Unit w) {
+ v->x = x;
+ v->y = y;
+ v->z = z;
+ v->w = w;
+}
+
+void S3L_vec3Add(S3L_Vec4* result, S3L_Vec4 added) {
+ result->x += added.x;
+ result->y += added.y;
+ result->z += added.z;
+}
+
+void S3L_vec3Sub(S3L_Vec4* result, S3L_Vec4 substracted) {
+ result->x -= substracted.x;
+ result->y -= substracted.y;
+ result->z -= substracted.z;
+}
+
+void S3L_mat4Init(S3L_Mat4 m) {
+#define M(x, y) m[x][y]
+#define S S3L_FRACTIONS_PER_UNIT
+
+ M(0, 0) = S;
+ M(1, 0) = 0;
+ M(2, 0) = 0;
+ M(3, 0) = 0;
+ M(0, 1) = 0;
+ M(1, 1) = S;
+ M(2, 1) = 0;
+ M(3, 1) = 0;
+ M(0, 2) = 0;
+ M(1, 2) = 0;
+ M(2, 2) = S;
+ M(3, 2) = 0;
+ M(0, 3) = 0;
+ M(1, 3) = 0;
+ M(2, 3) = 0;
+ M(3, 3) = S;
+
+#undef M
+#undef S
+}
+
+void S3L_mat4Copy(S3L_Mat4 src, S3L_Mat4 dst) {
+ for (uint8_t j = 0; j < 4; ++j)
+ for (uint8_t i = 0; i < 4; ++i)
+ dst[i][j] = src[i][j];
+}
+
+S3L_Unit S3L_vec3Dot(S3L_Vec4 a, S3L_Vec4 b) {
+ return (a.x * b.x + a.y * b.y + a.z * b.z) / S3L_FRACTIONS_PER_UNIT;
+}
+
+void S3L_reflect(S3L_Vec4 toLight, S3L_Vec4 normal, S3L_Vec4* result) {
+ S3L_Unit d = 2 * S3L_vec3Dot(toLight, normal);
+
+ result->x = (normal.x * d) / S3L_FRACTIONS_PER_UNIT - toLight.x;
+ result->y = (normal.y * d) / S3L_FRACTIONS_PER_UNIT - toLight.y;
+ result->z = (normal.z * d) / S3L_FRACTIONS_PER_UNIT - toLight.z;
+}
+
+void S3L_vec3Cross(S3L_Vec4 a, S3L_Vec4 b, S3L_Vec4* result) {
+ result->x = a.y * b.z - a.z * b.y;
+ result->y = a.z * b.x - a.x * b.z;
+ result->z = a.x * b.y - a.y * b.x;
+}
+
+void S3L_triangleNormal(S3L_Vec4 t0, S3L_Vec4 t1, S3L_Vec4 t2, S3L_Vec4* n) {
+#define ANTI_OVERFLOW 32
+
+ t1.x = (t1.x - t0.x) / ANTI_OVERFLOW;
+ t1.y = (t1.y - t0.y) / ANTI_OVERFLOW;
+ t1.z = (t1.z - t0.z) / ANTI_OVERFLOW;
- t2.x = (t2.x - t0.x) / ANTI_OVERFLOW;
- t2.y = (t2.y - t0.y) / ANTI_OVERFLOW;
- t2.z = (t2.z - t0.z) / ANTI_OVERFLOW;
+ t2.x = (t2.x - t0.x) / ANTI_OVERFLOW;
+ t2.y = (t2.y - t0.y) / ANTI_OVERFLOW;
+ t2.z = (t2.z - t0.z) / ANTI_OVERFLOW;
- #undef ANTI_OVERFLOW
+#undef ANTI_OVERFLOW
- S3L_vec3Cross(t1,t2,n);
+ S3L_vec3Cross(t1, t2, n);
- S3L_vec3Normalize(n);
+ S3L_vec3Normalize(n);
}
-void S3L_getIndexedTriangleValues(
- S3L_Index triangleIndex,
- const S3L_Index *indices,
- const S3L_Unit *values,
- uint8_t numComponents,
- S3L_Vec4 *v0,
- S3L_Vec4 *v1,
- S3L_Vec4 *v2)
-{
- uint32_t i0, i1;
- S3L_Unit *value;
+void S3L_getIndexedTriangleValues(S3L_Index triangleIndex,
+ const S3L_Index* indices,
+ const S3L_Unit* values,
+ uint8_t numComponents,
+ S3L_Vec4* v0,
+ S3L_Vec4* v1,
+ S3L_Vec4* v2) {
+ uint32_t i0, i1;
+ S3L_Unit* value;
- i0 = triangleIndex * 3;
- i1 = indices[i0] * numComponents;
- value = (S3L_Unit *) v0;
+ i0 = triangleIndex * 3;
+ i1 = indices[i0] * numComponents;
+ value = (S3L_Unit*)v0;
- if (numComponents > 4)
- numComponents = 4;
+ if (numComponents > 4)
+ numComponents = 4;
- for (uint8_t j = 0; j < numComponents; ++j)
- {
- *value = values[i1];
- i1++;
- value++;
- }
+ for (uint8_t j = 0; j < numComponents; ++j) {
+ *value = values[i1];
+ i1++;
+ value++;
+ }
- i0++;
- i1 = indices[i0] * numComponents;
- value = (S3L_Unit *) v1;
+ i0++;
+ i1 = indices[i0] * numComponents;
+ value = (S3L_Unit*)v1;
- for (uint8_t j = 0; j < numComponents; ++j)
- {
- *value = values[i1];
- i1++;
- value++;
- }
+ for (uint8_t j = 0; j < numComponents; ++j) {
+ *value = values[i1];
+ i1++;
+ value++;
+ }
- i0++;
- i1 = indices[i0] * numComponents;
- value = (S3L_Unit *) v2;
+ i0++;
+ i1 = indices[i0] * numComponents;
+ value = (S3L_Unit*)v2;
- for (uint8_t j = 0; j < numComponents; ++j)
- {
- *value = values[i1];
- i1++;
- value++;
- }
+ for (uint8_t j = 0; j < numComponents; ++j) {
+ *value = values[i1];
+ i1++;
+ value++;
+ }
}
-void S3L_computeModelNormals(S3L_Model3D model, S3L_Unit *dst,
- int8_t transformNormals)
-{
- S3L_Index vPos = 0;
+void S3L_computeModelNormals(S3L_Model3D model,
+ S3L_Unit* dst,
+ int8_t transformNormals) {
+ S3L_Index vPos = 0;
- S3L_Vec4 n;
+ S3L_Vec4 n;
- n.w = 0;
+ n.w = 0;
- S3L_Vec4 ns[S3L_NORMAL_COMPUTE_MAXIMUM_AVERAGE];
- S3L_Index normalCount;
+ S3L_Vec4 ns[S3L_NORMAL_COMPUTE_MAXIMUM_AVERAGE];
+ S3L_Index normalCount;
- for (uint32_t i = 0; i < model.vertexCount; ++i)
- {
- normalCount = 0;
+ for (uint32_t i = 0; i < model.vertexCount; ++i) {
+ normalCount = 0;
- for (uint32_t j = 0; j < model.triangleCount * 3; j += 3)
- {
- if (
- (model.triangles[j] == i) ||
- (model.triangles[j + 1] == i) ||
- (model.triangles[j + 2] == i))
- {
- S3L_Vec4 t0, t1, t2;
- uint32_t vIndex;
-
- #define getVertex(n)\
- vIndex = model.triangles[j + n] * 3;\
- t##n.x = model.vertices[vIndex];\
- vIndex++;\
- t##n.y = model.vertices[vIndex];\
- vIndex++;\
- t##n.z = model.vertices[vIndex];
-
- getVertex(0)
- getVertex(1)
- getVertex(2)
-
- #undef getVertex
-
- S3L_triangleNormal(t0,t1,t2,&(ns[normalCount]));
-
- normalCount++;
-
- if (normalCount >= S3L_NORMAL_COMPUTE_MAXIMUM_AVERAGE)
- break;
- }
- }
-
- n.x = S3L_FRACTIONS_PER_UNIT;
- n.y = 0;
- n.z = 0;
+ for (uint32_t j = 0; j < model.triangleCount * 3; j += 3) {
+ if ((model.triangles[j] == i) || (model.triangles[j + 1] == i) ||
+ (model.triangles[j + 2] == i)) {
+ S3L_Vec4 t0, t1, t2;
+ uint32_t vIndex;
- if (normalCount != 0)
- {
- // compute average
+#define getVertex(n) \
+ vIndex = model.triangles[j + n] * 3; \
+ t##n.x = model.vertices[vIndex]; \
+ vIndex++; \
+ t##n.y = model.vertices[vIndex]; \
+ vIndex++; \
+ t##n.z = model.vertices[vIndex];
- n.x = 0;
+ getVertex(0) getVertex(1) getVertex(2)
- for (uint8_t i = 0; i < normalCount; ++i)
- {
- n.x += ns[i].x;
- n.y += ns[i].y;
- n.z += ns[i].z;
- }
+#undef getVertex
- n.x /= normalCount;
- n.y /= normalCount;
- n.z /= normalCount;
+ S3L_triangleNormal(t0, t1, t2, &(ns[normalCount]));
- S3L_vec3Normalize(&n);
- }
+ normalCount++;
- dst[vPos] = n.x;
- vPos++;
+ if (normalCount >= S3L_NORMAL_COMPUTE_MAXIMUM_AVERAGE)
+ break;
+ }
+ }
- dst[vPos] = n.y;
- vPos++;
+ n.x = S3L_FRACTIONS_PER_UNIT;
+ n.y = 0;
+ n.z = 0;
- dst[vPos] = n.z;
- vPos++;
- }
-
- S3L_Mat4 m;
+ if (normalCount != 0) {
+ // compute average
- S3L_makeWorldMatrix(model.transform,m);
+ n.x = 0;
- if (transformNormals)
- for (S3L_Index i = 0; i < model.vertexCount * 3; i += 3)
- {
- n.x = dst[i];
- n.y = dst[i + 1];
- n.z = dst[i + 2];
+ for (uint8_t i = 0; i < normalCount; ++i) {
+ n.x += ns[i].x;
+ n.y += ns[i].y;
+ n.z += ns[i].z;
+ }
+
+ n.x /= normalCount;
+ n.y /= normalCount;
+ n.z /= normalCount;
+
+ S3L_vec3Normalize(&n);
+ }
- S3L_vec4Xmat4(&n,m);
+ dst[vPos] = n.x;
+ vPos++;
- dst[i] = n.x;
- dst[i + 1] = n.y;
- dst[i + 2] = n.z;
+ dst[vPos] = n.y;
+ vPos++;
+
+ dst[vPos] = n.z;
+ vPos++;
}
+
+ S3L_Mat4 m;
+
+ S3L_makeWorldMatrix(model.transform, m);
+
+ if (transformNormals)
+ for (S3L_Index i = 0; i < model.vertexCount * 3; i += 3) {
+ n.x = dst[i];
+ n.y = dst[i + 1];
+ n.z = dst[i + 2];
+
+ S3L_vec4Xmat4(&n, m);
+
+ dst[i] = n.x;
+ dst[i + 1] = n.y;
+ dst[i + 2] = n.z;
+ }
}
-void S3L_vec4Xmat4(S3L_Vec4 *v, S3L_Mat4 m)
-{
- S3L_Vec4 vBackup;
+void S3L_vec4Xmat4(S3L_Vec4* v, S3L_Mat4 m) {
+ S3L_Vec4 vBackup;
- vBackup.x = v->x;
- vBackup.y = v->y;
- vBackup.z = v->z;
- vBackup.w = v->w;
+ vBackup.x = v->x;
+ vBackup.y = v->y;
+ vBackup.z = v->z;
+ vBackup.w = v->w;
- #define dotCol(col)\
- ((vBackup.x * m[col][0]) +\
- (vBackup.y * m[col][1]) +\
- (vBackup.z * m[col][2]) +\
- (vBackup.w * m[col][3])) / S3L_FRACTIONS_PER_UNIT
+#define dotCol(col) \
+ ((vBackup.x * m[col][0]) + (vBackup.y * m[col][1]) + \
+ (vBackup.z * m[col][2]) + (vBackup.w * m[col][3])) / \
+ S3L_FRACTIONS_PER_UNIT
- v->x = dotCol(0);
- v->y = dotCol(1);
- v->z = dotCol(2);
- v->w = dotCol(3);
+ v->x = dotCol(0);
+ v->y = dotCol(1);
+ v->z = dotCol(2);
+ v->w = dotCol(3);
}
-void S3L_vec3Xmat4(S3L_Vec4 *v, S3L_Mat4 m)
-{
- S3L_Vec4 vBackup;
+void S3L_vec3Xmat4(S3L_Vec4* v, S3L_Mat4 m) {
+ S3L_Vec4 vBackup;
- #undef dotCol
- #define dotCol(col)\
- (vBackup.x * m[col][0]) / S3L_FRACTIONS_PER_UNIT +\
- (vBackup.y * m[col][1]) / S3L_FRACTIONS_PER_UNIT +\
- (vBackup.z * m[col][2]) / S3L_FRACTIONS_PER_UNIT +\
- m[col][3]
+#undef dotCol
+#define dotCol(col) \
+ (vBackup.x * m[col][0]) / S3L_FRACTIONS_PER_UNIT + \
+ (vBackup.y * m[col][1]) / S3L_FRACTIONS_PER_UNIT + \
+ (vBackup.z * m[col][2]) / S3L_FRACTIONS_PER_UNIT + m[col][3]
- vBackup.x = v->x;
- vBackup.y = v->y;
- vBackup.z = v->z;
- vBackup.w = v->w;
+ vBackup.x = v->x;
+ vBackup.y = v->y;
+ vBackup.z = v->z;
+ vBackup.w = v->w;
- v->x = dotCol(0);
- v->y = dotCol(1);
- v->z = dotCol(2);
- v->w = S3L_FRACTIONS_PER_UNIT;
+ v->x = dotCol(0);
+ v->y = dotCol(1);
+ v->z = dotCol(2);
+ v->w = S3L_FRACTIONS_PER_UNIT;
}
#undef dotCol
-S3L_Unit S3L_abs(S3L_Unit value)
-{
- return value * (((value >= 0) << 1) - 1);
+S3L_Unit S3L_abs(S3L_Unit value) {
+ return value * (((value >= 0) << 1) - 1);
}
-S3L_Unit S3L_min(S3L_Unit v1, S3L_Unit v2)
-{
- return v1 >= v2 ? v2 : v1;
+S3L_Unit S3L_min(S3L_Unit v1, S3L_Unit v2) {
+ return v1 >= v2 ? v2 : v1;
}
-S3L_Unit S3L_max(S3L_Unit v1, S3L_Unit v2)
-{
- return v1 >= v2 ? v1 : v2;
+S3L_Unit S3L_max(S3L_Unit v1, S3L_Unit v2) {
+ return v1 >= v2 ? v1 : v2;
}
-S3L_Unit S3L_clamp(S3L_Unit v, S3L_Unit v1, S3L_Unit v2)
-{
- return v >= v1 ? (v <= v2 ? v : v2) : v1;
+S3L_Unit S3L_clamp(S3L_Unit v, S3L_Unit v1, S3L_Unit v2) {
+ return v >= v1 ? (v <= v2 ? v : v2) : v1;
}
-S3L_Unit S3L_zeroClamp(S3L_Unit value)
-{
- return (value * (value >= 0));
+S3L_Unit S3L_zeroClamp(S3L_Unit value) {
+ return (value * (value >= 0));
}
-S3L_Unit S3L_wrap(S3L_Unit value, S3L_Unit mod)
-{
- return value >= 0 ? (value % mod) : (mod + (value % mod) - 1);
+S3L_Unit S3L_wrap(S3L_Unit value, S3L_Unit mod) {
+ return value >= 0 ? (value % mod) : (mod + (value % mod) - 1);
}
-S3L_Unit S3L_nonZero(S3L_Unit value)
-{
- return (value + (value == 0));
+S3L_Unit S3L_nonZero(S3L_Unit value) {
+ return (value + (value == 0));
}
-S3L_Unit S3L_interpolate(S3L_Unit v1, S3L_Unit v2, S3L_Unit t, S3L_Unit tMax)
-{
- return v1 + ((v2 - v1) * t) / tMax;
+S3L_Unit S3L_interpolate(S3L_Unit v1, S3L_Unit v2, S3L_Unit t, S3L_Unit tMax) {
+ return v1 + ((v2 - v1) * t) / tMax;
}
-S3L_Unit S3L_interpolateByUnit(S3L_Unit v1, S3L_Unit v2, S3L_Unit t)
-{
- return v1 + ((v2 - v1) * t) / S3L_FRACTIONS_PER_UNIT;
+S3L_Unit S3L_interpolateByUnit(S3L_Unit v1, S3L_Unit v2, S3L_Unit t) {
+ return v1 + ((v2 - v1) * t) / S3L_FRACTIONS_PER_UNIT;
}
-S3L_Unit S3L_interpolateByUnitFrom0(S3L_Unit v2, S3L_Unit t)
-{
- return (v2 * t) / S3L_FRACTIONS_PER_UNIT;
+S3L_Unit S3L_interpolateByUnitFrom0(S3L_Unit v2, S3L_Unit t) {
+ return (v2 * t) / S3L_FRACTIONS_PER_UNIT;
}
-S3L_Unit S3L_interpolateFrom0(S3L_Unit v2, S3L_Unit t, S3L_Unit tMax)
-{
- return (v2 * t) / tMax;
+S3L_Unit S3L_interpolateFrom0(S3L_Unit v2, S3L_Unit t, S3L_Unit tMax) {
+ return (v2 * t) / tMax;
}
-S3L_Unit S3L_distanceManhattan(S3L_Vec4 a, S3L_Vec4 b)
-{
- return
- S3L_abs(a.x - b.x) +
- S3L_abs(a.y - b.y) +
- S3L_abs(a.z - b.z);
+S3L_Unit S3L_distanceManhattan(S3L_Vec4 a, S3L_Vec4 b) {
+ return S3L_abs(a.x - b.x) + S3L_abs(a.y - b.y) + S3L_abs(a.z - b.z);
}
-void S3L_mat4Xmat4(S3L_Mat4 m1, S3L_Mat4 m2)
-{
- S3L_Mat4 mat1;
+void S3L_mat4Xmat4(S3L_Mat4 m1, S3L_Mat4 m2) {
+ S3L_Mat4 mat1;
- for (uint16_t row = 0; row < 4; ++row)
- for (uint16_t col = 0; col < 4; ++col)
- mat1[col][row] = m1[col][row];
+ for (uint16_t row = 0; row < 4; ++row)
+ for (uint16_t col = 0; col < 4; ++col)
+ mat1[col][row] = m1[col][row];
- for (uint16_t row = 0; row < 4; ++row)
- for (uint16_t col = 0; col < 4; ++col)
- {
- m1[col][row] = 0;
+ for (uint16_t row = 0; row < 4; ++row)
+ for (uint16_t col = 0; col < 4; ++col) {
+ m1[col][row] = 0;
- for (uint16_t i = 0; i < 4; ++i)
- m1[col][row] +=
- (mat1[i][row] * m2[col][i]) / S3L_FRACTIONS_PER_UNIT;
- }
+ for (uint16_t i = 0; i < 4; ++i)
+ m1[col][row] +=
+ (mat1[i][row] * m2[col][i]) / S3L_FRACTIONS_PER_UNIT;
+ }
}
-S3L_Unit S3L_sin(S3L_Unit x)
-{
- x = S3L_wrap(x / S3L_SIN_TABLE_UNIT_STEP,S3L_SIN_TABLE_LENGTH * 4);
- int8_t positive = 1;
+S3L_Unit S3L_sin(S3L_Unit x) {
+ x = S3L_wrap(x / S3L_SIN_TABLE_UNIT_STEP, S3L_SIN_TABLE_LENGTH * 4);
+ int8_t positive = 1;
- if (x < S3L_SIN_TABLE_LENGTH)
- {
- }
- else if (x < S3L_SIN_TABLE_LENGTH * 2)
- {
- x = S3L_SIN_TABLE_LENGTH * 2 - x - 1;
- }
- else if (x < S3L_SIN_TABLE_LENGTH * 3)
- {
- x = x - S3L_SIN_TABLE_LENGTH * 2;
- positive = 0;
- }
- else
- {
- x = S3L_SIN_TABLE_LENGTH - (x - S3L_SIN_TABLE_LENGTH * 3) - 1;
- positive = 0;
- }
-
- return positive ? S3L_sinTable[x] : -1 * S3L_sinTable[x];
-}
-
-S3L_Unit S3L_asin(S3L_Unit x)
-{
- x = S3L_clamp(x,-S3L_FRACTIONS_PER_UNIT,S3L_FRACTIONS_PER_UNIT);
-
- int8_t sign = 1;
-
- if (x < 0)
- {
- sign = -1;
- x *= -1;
- }
-
- int16_t low = 0;
- int16_t high = S3L_SIN_TABLE_LENGTH -1;
- int16_t middle;
-
- while (low <= high) // binary search
- {
- middle = (low + high) / 2;
-
- S3L_Unit v = S3L_sinTable[middle];
-
- if (v > x)
- high = middle - 1;
- else if (v < x)
- low = middle + 1;
- else
- break;
- }
-
- middle *= S3L_SIN_TABLE_UNIT_STEP;
-
- return sign * middle;
-}
+ if (x < S3L_SIN_TABLE_LENGTH) {
+ } else if (x < S3L_SIN_TABLE_LENGTH * 2) {
+ x = S3L_SIN_TABLE_LENGTH * 2 - x - 1;
+ } else if (x < S3L_SIN_TABLE_LENGTH * 3) {
+ x = x - S3L_SIN_TABLE_LENGTH * 2;
+ positive = 0;
+ } else {
+ x = S3L_SIN_TABLE_LENGTH - (x - S3L_SIN_TABLE_LENGTH * 3) - 1;
+ positive = 0;
+ }
-S3L_Unit S3L_cos(S3L_Unit x)
-{
- return S3L_sin(x + S3L_FRACTIONS_PER_UNIT / 4);
-}
-
-void S3L_correctBarycentricCoords(S3L_Unit barycentric[3])
-{
- barycentric[0] = S3L_clamp(barycentric[0],0,S3L_FRACTIONS_PER_UNIT);
- barycentric[1] = S3L_clamp(barycentric[1],0,S3L_FRACTIONS_PER_UNIT);
-
- S3L_Unit d = S3L_FRACTIONS_PER_UNIT - barycentric[0] - barycentric[1];
-
- if (d < 0)
- {
- barycentric[0] += d;
- barycentric[2] = 0;
- }
- else
- barycentric[2] = d;
-}
-
-void S3L_makeTranslationMat(
- S3L_Unit offsetX,
- S3L_Unit offsetY,
- S3L_Unit offsetZ,
- S3L_Mat4 m)
-{
- #define M(x,y) m[x][y]
- #define S S3L_FRACTIONS_PER_UNIT
-
- M(0,0) = S; M(1,0) = 0; M(2,0) = 0; M(3,0) = 0;
- M(0,1) = 0; M(1,1) = S; M(2,1) = 0; M(3,1) = 0;
- M(0,2) = 0; M(1,2) = 0; M(2,2) = S; M(3,2) = 0;
- M(0,3) = offsetX; M(1,3) = offsetY; M(2,3) = offsetZ; M(3,3) = S;
-
- #undef M
- #undef S
-}
-
-void S3L_makeScaleMatrix(
- S3L_Unit scaleX,
- S3L_Unit scaleY,
- S3L_Unit scaleZ,
- S3L_Mat4 m)
-{
- #define M(x,y) m[x][y]
-
- M(0,0) = scaleX; M(1,0) = 0; M(2,0) = 0; M(3,0) = 0;
- M(0,1) = 0; M(1,1) = scaleY; M(2,1) = 0; M(3,1) = 0;
- M(0,2) = 0; M(1,2) = 0; M(2,2) = scaleZ; M(3,2) = 0;
- M(0,3) = 0; M(1,3) = 0; M(2,3) = 0; M(3,3) = S3L_FRACTIONS_PER_UNIT;
-
- #undef M
+ return positive ? S3L_sinTable[x] : -1 * S3L_sinTable[x];
}
-void S3L_makeRotationMatrixZXY(
- S3L_Unit byX,
- S3L_Unit byY,
- S3L_Unit byZ,
- S3L_Mat4 m)
-{
- byX *= -1;
- byY *= -1;
- byZ *= -1;
+S3L_Unit S3L_asin(S3L_Unit x) {
+ x = S3L_clamp(x, -S3L_FRACTIONS_PER_UNIT, S3L_FRACTIONS_PER_UNIT);
- S3L_Unit sx = S3L_sin(byX);
- S3L_Unit sy = S3L_sin(byY);
- S3L_Unit sz = S3L_sin(byZ);
+ int8_t sign = 1;
- S3L_Unit cx = S3L_cos(byX);
- S3L_Unit cy = S3L_cos(byY);
- S3L_Unit cz = S3L_cos(byZ);
-
- #define M(x,y) m[x][y]
- #define S S3L_FRACTIONS_PER_UNIT
+ if (x < 0) {
+ sign = -1;
+ x *= -1;
+ }
- M(0,0) = (cy * cz) / S + (sy * sx * sz) / (S * S);
- M(1,0) = (cx * sz) / S;
- M(2,0) = (cy * sx * sz) / (S * S) - (cz * sy) / S;
- M(3,0) = 0;
+ int16_t low = 0;
+ int16_t high = S3L_SIN_TABLE_LENGTH - 1;
+ int16_t middle;
- M(0,1) = (cz * sy * sx) / (S * S) - (cy * sz) / S;
- M(1,1) = (cx * cz) / S;
- M(2,1) = (cy * cz * sx) / (S * S) + (sy * sz) / S;
- M(3,1) = 0;
+ while (low <= high) // binary search
+ {
+ middle = (low + high) / 2;
- M(0,2) = (cx * sy) / S;
- M(1,2) = -1 * sx;
- M(2,2) = (cy * cx) / S;
- M(3,2) = 0;
+ S3L_Unit v = S3L_sinTable[middle];
- M(0,3) = 0;
- M(1,3) = 0;
- M(2,3) = 0;
- M(3,3) = S3L_FRACTIONS_PER_UNIT;
+ if (v > x)
+ high = middle - 1;
+ else if (v < x)
+ low = middle + 1;
+ else
+ break;
+ }
- #undef M
- #undef S
-}
-
-S3L_Unit S3L_sqrt(S3L_Unit value)
-{
- int8_t sign = 1;
-
- if (value < 0)
- {
- sign = -1;
- value *= -1;
- }
-
- uint32_t result = 0;
- uint32_t a = value;
- uint32_t b = 1u << 30;
-
- while (b > a)
- b >>= 2;
-
- while (b != 0)
- {
- if (a >= result + b)
- {
- a -= result + b;
- result = result + 2 * b;
+ middle *= S3L_SIN_TABLE_UNIT_STEP;
+
+ return sign * middle;
+}
+
+S3L_Unit S3L_cos(S3L_Unit x) {
+ return S3L_sin(x + S3L_FRACTIONS_PER_UNIT / 4);
+}
+
+void S3L_correctBarycentricCoords(S3L_Unit barycentric[3]) {
+ barycentric[0] = S3L_clamp(barycentric[0], 0, S3L_FRACTIONS_PER_UNIT);
+ barycentric[1] = S3L_clamp(barycentric[1], 0, S3L_FRACTIONS_PER_UNIT);
+
+ S3L_Unit d = S3L_FRACTIONS_PER_UNIT - barycentric[0] - barycentric[1];
+
+ if (d < 0) {
+ barycentric[0] += d;
+ barycentric[2] = 0;
+ } else
+ barycentric[2] = d;
+}
+
+void S3L_makeTranslationMat(S3L_Unit offsetX,
+ S3L_Unit offsetY,
+ S3L_Unit offsetZ,
+ S3L_Mat4 m) {
+#define M(x, y) m[x][y]
+#define S S3L_FRACTIONS_PER_UNIT
+
+ M(0, 0) = S;
+ M(1, 0) = 0;
+ M(2, 0) = 0;
+ M(3, 0) = 0;
+ M(0, 1) = 0;
+ M(1, 1) = S;
+ M(2, 1) = 0;
+ M(3, 1) = 0;
+ M(0, 2) = 0;
+ M(1, 2) = 0;
+ M(2, 2) = S;
+ M(3, 2) = 0;
+ M(0, 3) = offsetX;
+ M(1, 3) = offsetY;
+ M(2, 3) = offsetZ;
+ M(3, 3) = S;
+
+#undef M
+#undef S
+}
+
+void S3L_makeScaleMatrix(S3L_Unit scaleX,
+ S3L_Unit scaleY,
+ S3L_Unit scaleZ,
+ S3L_Mat4 m) {
+#define M(x, y) m[x][y]
+
+ M(0, 0) = scaleX;
+ M(1, 0) = 0;
+ M(2, 0) = 0;
+ M(3, 0) = 0;
+ M(0, 1) = 0;
+ M(1, 1) = scaleY;
+ M(2, 1) = 0;
+ M(3, 1) = 0;
+ M(0, 2) = 0;
+ M(1, 2) = 0;
+ M(2, 2) = scaleZ;
+ M(3, 2) = 0;
+ M(0, 3) = 0;
+ M(1, 3) = 0;
+ M(2, 3) = 0;
+ M(3, 3) = S3L_FRACTIONS_PER_UNIT;
+
+#undef M
+}
+
+void S3L_makeRotationMatrixZXY(S3L_Unit byX,
+ S3L_Unit byY,
+ S3L_Unit byZ,
+ S3L_Mat4 m) {
+ byX *= -1;
+ byY *= -1;
+ byZ *= -1;
+
+ S3L_Unit sx = S3L_sin(byX);
+ S3L_Unit sy = S3L_sin(byY);
+ S3L_Unit sz = S3L_sin(byZ);
+
+ S3L_Unit cx = S3L_cos(byX);
+ S3L_Unit cy = S3L_cos(byY);
+ S3L_Unit cz = S3L_cos(byZ);
+
+#define M(x, y) m[x][y]
+#define S S3L_FRACTIONS_PER_UNIT
+
+ M(0, 0) = (cy * cz) / S + (sy * sx * sz) / (S * S);
+ M(1, 0) = (cx * sz) / S;
+ M(2, 0) = (cy * sx * sz) / (S * S) - (cz * sy) / S;
+ M(3, 0) = 0;
+
+ M(0, 1) = (cz * sy * sx) / (S * S) - (cy * sz) / S;
+ M(1, 1) = (cx * cz) / S;
+ M(2, 1) = (cy * cz * sx) / (S * S) + (sy * sz) / S;
+ M(3, 1) = 0;
+
+ M(0, 2) = (cx * sy) / S;
+ M(1, 2) = -1 * sx;
+ M(2, 2) = (cy * cx) / S;
+ M(3, 2) = 0;
+
+ M(0, 3) = 0;
+ M(1, 3) = 0;
+ M(2, 3) = 0;
+ M(3, 3) = S3L_FRACTIONS_PER_UNIT;
+
+#undef M
+#undef S
+}
+
+S3L_Unit S3L_sqrt(S3L_Unit value) {
+ int8_t sign = 1;
+
+ if (value < 0) {
+ sign = -1;
+ value *= -1;
}
- b >>= 2;
- result >>= 1;
- }
+ uint32_t result = 0;
+ uint32_t a = value;
+ uint32_t b = 1u << 30;
+
+ while (b > a)
+ b >>= 2;
+
+ while (b != 0) {
+ if (a >= result + b) {
+ a -= result + b;
+ result = result + 2 * b;
+ }
- return result * sign;
+ b >>= 2;
+ result >>= 1;
+ }
+
+ return result * sign;
}
-S3L_Unit S3L_vec3Length(S3L_Vec4 v)
-{
- return S3L_sqrt(v.x * v.x + v.y * v.y + v.z * v.z);
+S3L_Unit S3L_vec3Length(S3L_Vec4 v) {
+ return S3L_sqrt(v.x * v.x + v.y * v.y + v.z * v.z);
}
-S3L_Unit S3L_vec2Length(S3L_Vec4 v)
-{
- return S3L_sqrt(v.x * v.x + v.y * v.y);
+S3L_Unit S3L_vec2Length(S3L_Vec4 v) {
+ return S3L_sqrt(v.x * v.x + v.y * v.y);
}
-void S3L_vec3Normalize(S3L_Vec4 *v)
-{
- #define SCALE 16
- #define BOTTOM_LIMIT 16
- #define UPPER_LIMIT 900
+void S3L_vec3Normalize(S3L_Vec4* v) {
+#define SCALE 16
+#define BOTTOM_LIMIT 16
+#define UPPER_LIMIT 900
- /* Here we try to decide if the vector is too small and would cause
- inaccurate result due to very its inaccurate length. If so, we scale
- it up. We can't scale up everything as big vectors overflow in length
- calculations. */
+ /* Here we try to decide if the vector is too small and would cause
+ inaccurate result due to very its inaccurate length. If so, we scale
+ it up. We can't scale up everything as big vectors overflow in length
+ calculations. */
+
+ if (S3L_abs(v->x) <= BOTTOM_LIMIT && S3L_abs(v->y) <= BOTTOM_LIMIT &&
+ S3L_abs(v->z) <= BOTTOM_LIMIT) {
+ v->x *= SCALE;
+ v->y *= SCALE;
+ v->z *= SCALE;
+ } else if (S3L_abs(v->x) > UPPER_LIMIT || S3L_abs(v->y) > UPPER_LIMIT ||
+ S3L_abs(v->z) > UPPER_LIMIT) {
+ v->x /= SCALE;
+ v->y /= SCALE;
+ v->z /= SCALE;
+ }
- if (
- S3L_abs(v->x) <= BOTTOM_LIMIT &&
- S3L_abs(v->y) <= BOTTOM_LIMIT &&
- S3L_abs(v->z) <= BOTTOM_LIMIT)
- {
- v->x *= SCALE;
- v->y *= SCALE;
- v->z *= SCALE;
- }
- else if (
- S3L_abs(v->x) > UPPER_LIMIT ||
- S3L_abs(v->y) > UPPER_LIMIT ||
- S3L_abs(v->z) > UPPER_LIMIT)
- {
- v->x /= SCALE;
- v->y /= SCALE;
- v->z /= SCALE;
- }
-
- #undef SCALE
- #undef BOTTOM_LIMIT
- #undef UPPER_LIMIT
+#undef SCALE
+#undef BOTTOM_LIMIT
+#undef UPPER_LIMIT
- S3L_Unit l = S3L_vec3Length(*v);
+ S3L_Unit l = S3L_vec3Length(*v);
- if (l == 0)
- return;
+ if (l == 0)
+ return;
- v->x = (v->x * S3L_FRACTIONS_PER_UNIT) / l;
- v->y = (v->y * S3L_FRACTIONS_PER_UNIT) / l;
- v->z = (v->z * S3L_FRACTIONS_PER_UNIT) / l;
+ v->x = (v->x * S3L_FRACTIONS_PER_UNIT) / l;
+ v->y = (v->y * S3L_FRACTIONS_PER_UNIT) / l;
+ v->z = (v->z * S3L_FRACTIONS_PER_UNIT) / l;
}
-void S3L_vec3NormalizeFast(S3L_Vec4 *v)
-{
- S3L_Unit l = S3L_vec3Length(*v);
+void S3L_vec3NormalizeFast(S3L_Vec4* v) {
+ S3L_Unit l = S3L_vec3Length(*v);
- if (l == 0)
- return;
+ if (l == 0)
+ return;
- v->x = (v->x * S3L_FRACTIONS_PER_UNIT) / l;
- v->y = (v->y * S3L_FRACTIONS_PER_UNIT) / l;
- v->z = (v->z * S3L_FRACTIONS_PER_UNIT) / l;
+ v->x = (v->x * S3L_FRACTIONS_PER_UNIT) / l;
+ v->y = (v->y * S3L_FRACTIONS_PER_UNIT) / l;
+ v->z = (v->z * S3L_FRACTIONS_PER_UNIT) / l;
}
-void S3L_transform3DInit(S3L_Transform3D *t)
-{
- S3L_vec4Init(&(t->translation));
- S3L_vec4Init(&(t->rotation));
- t->scale.x = S3L_FRACTIONS_PER_UNIT;
- t->scale.y = S3L_FRACTIONS_PER_UNIT;
- t->scale.z = S3L_FRACTIONS_PER_UNIT;
- t->scale.w = 0;
+void S3L_transform3DInit(S3L_Transform3D* t) {
+ S3L_vec4Init(&(t->translation));
+ S3L_vec4Init(&(t->rotation));
+ t->scale.x = S3L_FRACTIONS_PER_UNIT;
+ t->scale.y = S3L_FRACTIONS_PER_UNIT;
+ t->scale.z = S3L_FRACTIONS_PER_UNIT;
+ t->scale.w = 0;
}
/** Performs perspecive division (z-divide). Does NOT check for division by
zero. */
-static inline void S3L_perspectiveDivide(S3L_Vec4 *vector,
- S3L_Unit focalLength)
-{
- vector->x = (vector->x * focalLength) / vector->z;
- vector->y = (vector->y * focalLength) / vector->z;
+static inline void S3L_perspectiveDivide(S3L_Vec4* vector,
+ S3L_Unit focalLength) {
+ vector->x = (vector->x * focalLength) / vector->z;
+ vector->y = (vector->y * focalLength) / vector->z;
+}
+
+void project3DPointToScreen(S3L_Vec4 point,
+ S3L_Camera camera,
+ S3L_Vec4* result) {
+ S3L_Mat4 m;
+ S3L_makeCameraMatrix(camera.transform, m);
+
+ S3L_Unit s = point.w;
+
+ point.w = S3L_FRACTIONS_PER_UNIT;
+
+ S3L_vec3Xmat4(&point, m);
+
+ point.z = S3L_nonZero(point.z);
+
+ S3L_perspectiveDivide(&point, camera.focalLength);
+
+ S3L_ScreenCoord x, y;
+
+ S3L_mapProjectionPlaneToScreen(point, &x, &y);
+
+ result->x = x;
+ result->y = y;
+ result->z = point.z;
+
+ result->w = (point.z <= 0) ? 0
+ : ((s * camera.focalLength * S3L_RESOLUTION_X) /
+ (point.z * S3L_FRACTIONS_PER_UNIT));
+}
+
+void S3L_lookAt(S3L_Vec4 pointTo, S3L_Transform3D* t) {
+ S3L_Vec4 v;
+
+ v.x = pointTo.x - t->translation.x;
+ v.y = pointTo.z - t->translation.z;
+
+ S3L_Unit dx = v.x;
+ S3L_Unit l = S3L_vec2Length(v);
+
+ dx = (v.x * S3L_FRACTIONS_PER_UNIT) / S3L_nonZero(l); // normalize
+
+ t->rotation.y = -1 * S3L_asin(dx);
+
+ if (v.y < 0)
+ t->rotation.y = S3L_FRACTIONS_PER_UNIT / 2 - t->rotation.y;
+
+ v.x = pointTo.y - t->translation.y;
+ v.y = l;
+
+ l = S3L_vec2Length(v);
+
+ dx = (v.x * S3L_FRACTIONS_PER_UNIT) / S3L_nonZero(l);
+
+ t->rotation.x = S3L_asin(dx);
}
-void project3DPointToScreen(
- S3L_Vec4 point,
- S3L_Camera camera,
- S3L_Vec4 *result)
-{
- S3L_Mat4 m;
- S3L_makeCameraMatrix(camera.transform,m);
+void S3L_transform3DSet(S3L_Unit tx,
+ S3L_Unit ty,
+ S3L_Unit tz,
+ S3L_Unit rx,
+ S3L_Unit ry,
+ S3L_Unit rz,
+ S3L_Unit sx,
+ S3L_Unit sy,
+ S3L_Unit sz,
+ S3L_Transform3D* t) {
+ t->translation.x = tx;
+ t->translation.y = ty;
+ t->translation.z = tz;
- S3L_Unit s = point.w;
+ t->rotation.x = rx;
+ t->rotation.y = ry;
+ t->rotation.z = rz;
- point.w = S3L_FRACTIONS_PER_UNIT;
+ t->scale.x = sx;
+ t->scale.y = sy;
+ t->scale.z = sz;
+}
- S3L_vec3Xmat4(&point,m);
+void S3L_cameraInit(S3L_Camera* camera) {
+ camera->focalLength = S3L_FRACTIONS_PER_UNIT;
+ S3L_transform3DInit(&(camera->transform));
+}
- point.z = S3L_nonZero(point.z);
+void S3L_rotationToDirections(S3L_Vec4 rotation,
+ S3L_Unit length,
+ S3L_Vec4* forw,
+ S3L_Vec4* right,
+ S3L_Vec4* up) {
+ S3L_Mat4 m;
- S3L_perspectiveDivide(&point,camera.focalLength);
+ S3L_makeRotationMatrixZXY(rotation.x, rotation.y, rotation.z, m);
- S3L_ScreenCoord x, y;
+ if (forw != 0) {
+ forw->x = 0;
+ forw->y = 0;
+ forw->z = length;
+ S3L_vec3Xmat4(forw, m);
+ }
- S3L_mapProjectionPlaneToScreen(point,&x,&y);
+ if (right != 0) {
+ right->x = length;
+ right->y = 0;
+ right->z = 0;
+ S3L_vec3Xmat4(right, m);
+ }
+
+ if (up != 0) {
+ up->x = 0;
+ up->y = length;
+ up->z = 0;
+ S3L_vec3Xmat4(up, m);
+ }
+}
+
+void S3L_pixelInfoInit(S3L_PixelInfo* p) {
+ p->x = 0;
+ p->y = 0;
+ p->barycentric[0] = S3L_FRACTIONS_PER_UNIT;
+ p->barycentric[1] = 0;
+ p->barycentric[2] = 0;
+ p->modelIndex = 0;
+ p->triangleIndex = 0;
+ p->triangleID = 0;
+ p->depth = 0;
+ p->previousZ = 0;
+}
+
+void S3L_model3DInit(const S3L_Unit* vertices,
+ S3L_Index vertexCount,
+ const S3L_Index* triangles,
+ S3L_Index triangleCount,
+ S3L_Model3D* model) {
+ model->vertices = vertices;
+ model->vertexCount = vertexCount;
+ model->triangles = triangles;
+ model->triangleCount = triangleCount;
+ model->customTransformMatrix = 0;
+
+ S3L_transform3DInit(&(model->transform));
+ S3L_drawConfigInit(&(model->config));
+}
- result->x = x;
- result->y = y;
- result->z = point.z;
-
- result->w =
- (point.z <= 0) ? 0 :
- (
- (s * camera.focalLength * S3L_RESOLUTION_X) /
- (point.z * S3L_FRACTIONS_PER_UNIT)
- );
-}
-
-void S3L_lookAt(S3L_Vec4 pointTo, S3L_Transform3D *t)
-{
- S3L_Vec4 v;
-
- v.x = pointTo.x - t->translation.x;
- v.y = pointTo.z - t->translation.z;
-
- S3L_Unit dx = v.x;
- S3L_Unit l = S3L_vec2Length(v);
-
- dx = (v.x * S3L_FRACTIONS_PER_UNIT) / S3L_nonZero(l); // normalize
-
- t->rotation.y = -1 * S3L_asin(dx);
-
- if (v.y < 0)
- t->rotation.y = S3L_FRACTIONS_PER_UNIT / 2 - t->rotation.y;
-
- v.x = pointTo.y - t->translation.y;
- v.y = l;
-
- l = S3L_vec2Length(v);
-
- dx = (v.x * S3L_FRACTIONS_PER_UNIT) / S3L_nonZero(l);
-
- t->rotation.x = S3L_asin(dx);
-}
-
-void S3L_transform3DSet(
- S3L_Unit tx,
- S3L_Unit ty,
- S3L_Unit tz,
- S3L_Unit rx,
- S3L_Unit ry,
- S3L_Unit rz,
- S3L_Unit sx,
- S3L_Unit sy,
- S3L_Unit sz,
- S3L_Transform3D *t)
-{
- t->translation.x = tx;
- t->translation.y = ty;
- t->translation.z = tz;
-
- t->rotation.x = rx;
- t->rotation.y = ry;
- t->rotation.z = rz;
-
- t->scale.x = sx;
- t->scale.y = sy;
- t->scale.z = sz;
-}
-
-void S3L_cameraInit(S3L_Camera *camera)
-{
- camera->focalLength = S3L_FRACTIONS_PER_UNIT;
- S3L_transform3DInit(&(camera->transform));
-}
-
-void S3L_rotationToDirections(
- S3L_Vec4 rotation,
- S3L_Unit length,
- S3L_Vec4 *forw,
- S3L_Vec4 *right,
- S3L_Vec4 *up)
-{
- S3L_Mat4 m;
-
- S3L_makeRotationMatrixZXY(rotation.x,rotation.y,rotation.z,m);
-
- if (forw != 0)
- {
- forw->x = 0;
- forw->y = 0;
- forw->z = length;
- S3L_vec3Xmat4(forw,m);
- }
-
- if (right != 0)
- {
- right->x = length;
- right->y = 0;
- right->z = 0;
- S3L_vec3Xmat4(right,m);
- }
-
- if (up != 0)
- {
- up->x = 0;
- up->y = length;
- up->z = 0;
- S3L_vec3Xmat4(up,m);
- }
-}
-
-void S3L_pixelInfoInit(S3L_PixelInfo *p)
-{
- p->x = 0;
- p->y = 0;
- p->barycentric[0] = S3L_FRACTIONS_PER_UNIT;
- p->barycentric[1] = 0;
- p->barycentric[2] = 0;
- p->modelIndex = 0;
- p->triangleIndex = 0;
- p->triangleID = 0;
- p->depth = 0;
- p->previousZ = 0;
-}
-
-void S3L_model3DInit(
- const S3L_Unit *vertices,
- S3L_Index vertexCount,
- const S3L_Index *triangles,
- S3L_Index triangleCount,
- S3L_Model3D *model)
-{
- model->vertices = vertices;
- model->vertexCount = vertexCount;
- model->triangles = triangles;
- model->triangleCount = triangleCount;
- model->customTransformMatrix = 0;
-
- S3L_transform3DInit(&(model->transform));
- S3L_drawConfigInit(&(model->config));
-}
-
-void S3L_sceneInit(
- S3L_Model3D *models,
- S3L_Index modelCount,
- S3L_Scene *scene)
-{
- scene->models = models;
- scene->modelCount = modelCount;
- S3L_cameraInit(&(scene->camera));
-}
-
-void S3L_drawConfigInit(S3L_DrawConfig *config)
-{
- config->backfaceCulling = 2;
- config->visible = 1;
+void S3L_sceneInit(S3L_Model3D* models,
+ S3L_Index modelCount,
+ S3L_Scene* scene) {
+ scene->models = models;
+ scene->modelCount = modelCount;
+ S3L_cameraInit(&(scene->camera));
+}
+
+void S3L_drawConfigInit(S3L_DrawConfig* config) {
+ config->backfaceCulling = 2;
+ config->visible = 1;
}
#ifndef S3L_PIXEL_FUNCTION
- #error Pixel rendering function (S3L_PIXEL_FUNCTION) not specified!
+#error Pixel rendering function (S3L_PIXEL_FUNCTION) not specified!
#endif
-static inline void S3L_PIXEL_FUNCTION(S3L_PixelInfo *pixel); // forward decl
+static inline void S3L_PIXEL_FUNCTION(S3L_PixelInfo* pixel); // forward decl
/** Serves to accelerate linear interpolation for performance-critical
code. Functions such as S3L_interpolate require division to compute each
@@ -1818,727 +1701,658 @@ static inline void S3L_PIXEL_FUNCTION(S3L_PixelInfo *pixel); // forward decl
BEWARE! Shifting a negative value is undefined, so handling shifting of
negative values has to be done cleverly. */
-typedef struct
-{
- S3L_Unit valueScaled;
- S3L_Unit stepScaled;
+typedef struct {
+ S3L_Unit valueScaled;
+ S3L_Unit stepScaled;
} S3L_FastLerpState;
-#define S3L_getFastLerpValue(state)\
- (state.valueScaled >> S3L_FAST_LERP_QUALITY)
-
-#define S3L_stepFastLerp(state)\
- state.valueScaled += state.stepScaled
-
-static inline S3L_Unit S3L_interpolateBarycentric(
- S3L_Unit value0,
- S3L_Unit value1,
- S3L_Unit value2,
- S3L_Unit barycentric[3])
-{
- return
- (
- (value0 * barycentric[0]) +
- (value1 * barycentric[1]) +
- (value2 * barycentric[2])
- ) / S3L_FRACTIONS_PER_UNIT;
-}
-
-void S3L_mapProjectionPlaneToScreen(
- S3L_Vec4 point,
- S3L_ScreenCoord *screenX,
- S3L_ScreenCoord *screenY)
-{
- *screenX =
- S3L_HALF_RESOLUTION_X +
- (point.x * S3L_HALF_RESOLUTION_X) / S3L_FRACTIONS_PER_UNIT;
-
- *screenY =
- S3L_HALF_RESOLUTION_Y -
- (point.y * S3L_HALF_RESOLUTION_X) / S3L_FRACTIONS_PER_UNIT;
-}
-
-void S3L_zBufferClear(void)
-{
+#define S3L_getFastLerpValue(state) (state.valueScaled >> S3L_FAST_LERP_QUALITY)
+
+#define S3L_stepFastLerp(state) state.valueScaled += state.stepScaled
+
+static inline S3L_Unit S3L_interpolateBarycentric(S3L_Unit value0,
+ S3L_Unit value1,
+ S3L_Unit value2,
+ S3L_Unit barycentric[3]) {
+ return ((value0 * barycentric[0]) + (value1 * barycentric[1]) +
+ (value2 * barycentric[2])) /
+ S3L_FRACTIONS_PER_UNIT;
+}
+
+void S3L_mapProjectionPlaneToScreen(S3L_Vec4 point,
+ S3L_ScreenCoord* screenX,
+ S3L_ScreenCoord* screenY) {
+ *screenX = S3L_HALF_RESOLUTION_X +
+ (point.x * S3L_HALF_RESOLUTION_X) / S3L_FRACTIONS_PER_UNIT;
+
+ *screenY = S3L_HALF_RESOLUTION_Y -
+ (point.y * S3L_HALF_RESOLUTION_X) / S3L_FRACTIONS_PER_UNIT;
+}
+
+void S3L_zBufferClear(void) {
#if S3L_Z_BUFFER
- for (uint32_t i = 0; i < S3L_RESOLUTION_X * S3L_RESOLUTION_Y; ++i)
- S3L_zBuffer[i] = S3L_MAX_DEPTH;
+ for (uint32_t i = 0; i < S3L_RESOLUTION_X * S3L_RESOLUTION_Y; ++i)
+ S3L_zBuffer[i] = S3L_MAX_DEPTH;
#endif
}
-void S3L_stencilBufferClear(void)
-{
+void S3L_stencilBufferClear(void) {
#if S3L_STENCIL_BUFFER
- for (uint32_t i = 0; i < S3L_STENCIL_BUFFER_SIZE; ++i)
- S3L_stencilBuffer[i] = 0;
+ for (uint32_t i = 0; i < S3L_STENCIL_BUFFER_SIZE; ++i)
+ S3L_stencilBuffer[i] = 0;
#endif
}
-void S3L_newFrame(void)
-{
- S3L_zBufferClear();
- S3L_stencilBufferClear();
+void S3L_newFrame(void) {
+ S3L_zBufferClear();
+ S3L_stencilBufferClear();
}
-/*
+/*
the following serves to communicate info about if the triangle has been split
and how the barycentrics should be remapped.
*/
-uint8_t _S3L_projectedTriangleState = 0; // 0 = normal, 1 = cut, 2 = split
+uint8_t _S3L_projectedTriangleState = 0; // 0 = normal, 1 = cut, 2 = split
#if S3L_NEAR_CROSS_STRATEGY == 3
S3L_Vec4 _S3L_triangleRemapBarycentrics[6];
#endif
-void S3L_drawTriangle(
- S3L_Vec4 point0,
- S3L_Vec4 point1,
- S3L_Vec4 point2,
- S3L_Index modelIndex,
- S3L_Index triangleIndex)
-{
- S3L_PixelInfo p;
- S3L_pixelInfoInit(&p);
- p.modelIndex = modelIndex;
- p.triangleIndex = triangleIndex;
- p.triangleID = (modelIndex << 16) | triangleIndex;
-
- S3L_Vec4 *tPointSS, *lPointSS, *rPointSS; /* points in Screen Space (in
- S3L_Units, normalized by
- S3L_FRACTIONS_PER_UNIT) */
-
- S3L_Unit *barycentric0; // bar. coord that gets higher from L to R
- S3L_Unit *barycentric1; // bar. coord that gets higher from R to L
- S3L_Unit *barycentric2; // bar. coord that gets higher from bottom up
-
- // sort the vertices:
-
- #define assignPoints(t,a,b)\
- {\
- tPointSS = &point##t;\
- barycentric2 = &(p.barycentric[t]);\
- if (S3L_triangleWinding(point##t.x,point##t.y,point##a.x,point##a.y,\
- point##b.x,point##b.y) >= 0)\
- {\
- lPointSS = &point##a; rPointSS = &point##b;\
- barycentric0 = &(p.barycentric[b]);\
- barycentric1 = &(p.barycentric[a]);\
- }\
- else\
- {\
- lPointSS = &point##b; rPointSS = &point##a;\
- barycentric0 = &(p.barycentric[a]);\
- barycentric1 = &(p.barycentric[b]);\
- }\
+void S3L_drawTriangle(S3L_Vec4 point0,
+ S3L_Vec4 point1,
+ S3L_Vec4 point2,
+ S3L_Index modelIndex,
+ S3L_Index triangleIndex) {
+ S3L_PixelInfo p;
+ S3L_pixelInfoInit(&p);
+ p.modelIndex = modelIndex;
+ p.triangleIndex = triangleIndex;
+ p.triangleID = (modelIndex << 16) | triangleIndex;
+
+ S3L_Vec4 *tPointSS, *lPointSS, *rPointSS; /* points in Screen Space (in
+ S3L_Units, normalized by
+ S3L_FRACTIONS_PER_UNIT) */
+
+ S3L_Unit* barycentric0; // bar. coord that gets higher from L to R
+ S3L_Unit* barycentric1; // bar. coord that gets higher from R to L
+ S3L_Unit* barycentric2; // bar. coord that gets higher from bottom up
+
+ // sort the vertices:
+
+#define assignPoints(t, a, b) \
+ { \
+ tPointSS = &point##t; \
+ barycentric2 = &(p.barycentric[t]); \
+ if (S3L_triangleWinding(point##t.x, point##t.y, point##a.x, \
+ point##a.y, point##b.x, point##b.y) >= 0) { \
+ lPointSS = &point##a; \
+ rPointSS = &point##b; \
+ barycentric0 = &(p.barycentric[b]); \
+ barycentric1 = &(p.barycentric[a]); \
+ } else { \
+ lPointSS = &point##b; \
+ rPointSS = &point##a; \
+ barycentric0 = &(p.barycentric[a]); \
+ barycentric1 = &(p.barycentric[b]); \
+ } \
+ }
+
+ if (point0.y <= point1.y) {
+ if (point0.y <= point2.y)
+ assignPoints(0, 1, 2) else assignPoints(2, 0, 1)
+ } else {
+ if (point1.y <= point2.y)
+ assignPoints(1, 0, 2) else assignPoints(2, 0, 1)
}
- if (point0.y <= point1.y)
- {
- if (point0.y <= point2.y)
- assignPoints(0,1,2)
- else
- assignPoints(2,0,1)
- }
- else
- {
- if (point1.y <= point2.y)
- assignPoints(1,0,2)
- else
- assignPoints(2,0,1)
- }
-
- #undef assignPoints
+#undef assignPoints
#if S3L_FLAT
- *barycentric0 = S3L_FRACTIONS_PER_UNIT / 3;
- *barycentric1 = S3L_FRACTIONS_PER_UNIT / 3;
- *barycentric2 = S3L_FRACTIONS_PER_UNIT - 2 * (S3L_FRACTIONS_PER_UNIT / 3);
-#endif
-
- p.triangleSize[0] = rPointSS->x - lPointSS->x;
- p.triangleSize[1] =
- (rPointSS->y > lPointSS->y ? rPointSS->y : lPointSS->y) - tPointSS->y;
-
- // now draw the triangle line by line:
-
- S3L_ScreenCoord splitY; // Y of the vertically middle point of the triangle
- S3L_ScreenCoord endY; // bottom Y of the whole triangle
- int splitOnLeft; /* whether splitY is the y coord. of left or right
- point */
-
- if (rPointSS->y <= lPointSS->y)
- {
- splitY = rPointSS->y;
- splitOnLeft = 0;
- endY = lPointSS->y;
- }
- else
- {
- splitY = lPointSS->y;
- splitOnLeft = 1;
- endY = rPointSS->y;
- }
-
- S3L_ScreenCoord currentY = tPointSS->y;
-
- /* We'll be using an algorithm similar to Bresenham line algorithm. The
- specifics of this algorithm are among others:
-
- - drawing possibly NON-CONTINUOUS line
- - NOT tracing the line exactly, but rather rasterizing one the right
- side of it, according to the pixel CENTERS, INCLUDING the pixel
- centers
-
- The principle is this:
-
- - Move vertically by pixels and accumulate the error (abs(dx/dy)).
- - If the error is greater than one (crossed the next pixel center), keep
- moving horizontally and substracting 1 from the error until it is less
- than 1 again.
- - To make this INTEGER ONLY, scale the case so that distance between
- pixels is equal to dy (instead of 1). This way the error becomes
- dx/dy * dy == dx, and we're comparing the error to (and potentially
- substracting) 1 * dy == dy. */
-
- int16_t
- /* triangle side:
- left right */
- lX, rX, // current x position on the screen
- lDx, rDx, // dx (end point - start point)
- lDy, rDy, // dy (end point - start point)
- lInc, rInc, // direction in which to increment (1 or -1)
- lErr, rErr, // current error (Bresenham)
- lErrCmp, rErrCmp, // helper for deciding comparison (> vs >=)
- lErrAdd, rErrAdd, // error value to add in each Bresenham cycle
- lErrSub, rErrSub; // error value to substract when moving in x direction
-
- S3L_FastLerpState lSideFLS, rSideFLS;
+ *barycentric0 = S3L_FRACTIONS_PER_UNIT / 3;
+ *barycentric1 = S3L_FRACTIONS_PER_UNIT / 3;
+ *barycentric2 = S3L_FRACTIONS_PER_UNIT - 2 * (S3L_FRACTIONS_PER_UNIT / 3);
+#endif
+
+ p.triangleSize[0] = rPointSS->x - lPointSS->x;
+ p.triangleSize[1] =
+ (rPointSS->y > lPointSS->y ? rPointSS->y : lPointSS->y) - tPointSS->y;
+
+ // now draw the triangle line by line:
+
+ S3L_ScreenCoord splitY; // Y of the vertically middle point of the triangle
+ S3L_ScreenCoord endY; // bottom Y of the whole triangle
+ int splitOnLeft; /* whether splitY is the y coord. of left or right
+ point */
+
+ if (rPointSS->y <= lPointSS->y) {
+ splitY = rPointSS->y;
+ splitOnLeft = 0;
+ endY = lPointSS->y;
+ } else {
+ splitY = lPointSS->y;
+ splitOnLeft = 1;
+ endY = rPointSS->y;
+ }
+
+ S3L_ScreenCoord currentY = tPointSS->y;
+
+ /* We'll be using an algorithm similar to Bresenham line algorithm. The
+ specifics of this algorithm are among others:
+
+ - drawing possibly NON-CONTINUOUS line
+ - NOT tracing the line exactly, but rather rasterizing one the right
+ side of it, according to the pixel CENTERS, INCLUDING the pixel
+ centers
+
+ The principle is this:
+
+ - Move vertically by pixels and accumulate the error (abs(dx/dy)).
+ - If the error is greater than one (crossed the next pixel center), keep
+ moving horizontally and substracting 1 from the error until it is less
+ than 1 again.
+ - To make this INTEGER ONLY, scale the case so that distance between
+ pixels is equal to dy (instead of 1). This way the error becomes
+ dx/dy * dy == dx, and we're comparing the error to (and potentially
+ substracting) 1 * dy == dy. */
+
+ int16_t
+ /* triangle side:
+ left right */
+ lX,
+ rX, // current x position on the screen
+ lDx, rDx, // dx (end point - start point)
+ lDy, rDy, // dy (end point - start point)
+ lInc, rInc, // direction in which to increment (1 or -1)
+ lErr, rErr, // current error (Bresenham)
+ lErrCmp, rErrCmp, // helper for deciding comparison (> vs >=)
+ lErrAdd, rErrAdd, // error value to add in each Bresenham cycle
+ lErrSub,
+ rErrSub; // error value to substract when moving in x direction
+
+ S3L_FastLerpState lSideFLS, rSideFLS;
#if S3L_COMPUTE_LERP_DEPTH
- S3L_FastLerpState lDepthFLS, rDepthFLS;
+ S3L_FastLerpState lDepthFLS, rDepthFLS;
- #define initDepthFLS(s,p1,p2)\
- s##DepthFLS.valueScaled = p1##PointSS->z << S3L_FAST_LERP_QUALITY;\
- s##DepthFLS.stepScaled = ((p2##PointSS->z << S3L_FAST_LERP_QUALITY) -\
- s##DepthFLS.valueScaled) / (s##Dy != 0 ? s##Dy : 1);
+#define initDepthFLS(s, p1, p2) \
+ s##DepthFLS.valueScaled = p1##PointSS->z << S3L_FAST_LERP_QUALITY; \
+ s##DepthFLS.stepScaled = ((p2##PointSS->z << S3L_FAST_LERP_QUALITY) - \
+ s##DepthFLS.valueScaled) / \
+ (s##Dy != 0 ? s##Dy : 1);
#else
- #define initDepthFLS(s,p1,p2) ;
-#endif
-
- /* init side for the algorithm, params:
- s - which side (l or r)
- p1 - point from (t, l or r)
- p2 - point to (t, l or r)
- down - whether the side coordinate goes top-down or vice versa */
- #define initSide(s,p1,p2,down)\
- s##X = p1##PointSS->x;\
- s##Dx = p2##PointSS->x - p1##PointSS->x;\
- s##Dy = p2##PointSS->y - p1##PointSS->y;\
- initDepthFLS(s,p1,p2)\
- s##SideFLS.stepScaled = (S3L_FRACTIONS_PER_UNIT << S3L_FAST_LERP_QUALITY)\
- / (s##Dy != 0 ? s##Dy : 1);\
- s##SideFLS.valueScaled = 0;\
- if (!down)\
- {\
- s##SideFLS.valueScaled =\
- S3L_FRACTIONS_PER_UNIT << S3L_FAST_LERP_QUALITY;\
- s##SideFLS.stepScaled *= -1;\
- }\
- s##Inc = s##Dx >= 0 ? 1 : -1;\
- if (s##Dx < 0)\
- {s##Err = 0; s##ErrCmp = 0;}\
- else\
- {s##Err = s##Dy; s##ErrCmp = 1;}\
- s##ErrAdd = S3L_abs(s##Dx);\
- s##ErrSub = s##Dy != 0 ? s##Dy : 1; /* don't allow 0, could lead to an
+#define initDepthFLS(s, p1, p2) ;
+#endif
+
+/* init side for the algorithm, params:
+ s - which side (l or r)
+ p1 - point from (t, l or r)
+ p2 - point to (t, l or r)
+ down - whether the side coordinate goes top-down or vice versa */
+#define initSide(s, p1, p2, down) \
+ s##X = p1##PointSS->x; \
+ s##Dx = p2##PointSS->x - p1##PointSS->x; \
+ s##Dy = p2##PointSS->y - p1##PointSS->y; \
+ initDepthFLS(s, p1, p2) s##SideFLS.stepScaled = \
+ (S3L_FRACTIONS_PER_UNIT << S3L_FAST_LERP_QUALITY) / \
+ (s##Dy != 0 ? s##Dy : 1); \
+ s##SideFLS.valueScaled = 0; \
+ if (!down) { \
+ s##SideFLS.valueScaled = S3L_FRACTIONS_PER_UNIT \
+ << S3L_FAST_LERP_QUALITY; \
+ s##SideFLS.stepScaled *= -1; \
+ } \
+ s##Inc = s##Dx >= 0 ? 1 : -1; \
+ if (s##Dx < 0) { \
+ s##Err = 0; \
+ s##ErrCmp = 0; \
+ } else { \
+ s##Err = s##Dy; \
+ s##ErrCmp = 1; \
+ } \
+ s##ErrAdd = S3L_abs(s##Dx); \
+ s##ErrSub = s##Dy != 0 ? s##Dy : 1; /* don't allow 0, could lead to an \
infinite substracting loop */
- #define stepSide(s)\
- while (s##Err - s##Dy >= s##ErrCmp)\
- {\
- s##X += s##Inc;\
- s##Err -= s##ErrSub;\
- }\
+#define stepSide(s) \
+ while (s##Err - s##Dy >= s##ErrCmp) { \
+ s##X += s##Inc; \
+ s##Err -= s##ErrSub; \
+ } \
s##Err += s##ErrAdd;
- initSide(r,t,r,1)
- initSide(l,t,l,1)
+ initSide(r, t, r, 1) initSide(l, t, l, 1)
#if S3L_PERSPECTIVE_CORRECTION
- /* PC is done by linearly interpolating reciprocals from which the corrected
- velues can be computed. See
- http://www.lysator.liu.se/~mikaelk/doc/perspectivetexture/ */
-
- #if S3L_PERSPECTIVE_CORRECTION == 1
- #define Z_RECIP_NUMERATOR\
- (S3L_FRACTIONS_PER_UNIT * S3L_FRACTIONS_PER_UNIT * S3L_FRACTIONS_PER_UNIT)
- #elif S3L_PERSPECTIVE_CORRECTION == 2
- #define Z_RECIP_NUMERATOR\
- (S3L_FRACTIONS_PER_UNIT * S3L_FRACTIONS_PER_UNIT)
- #endif
- /* ^ This numerator is a number by which we divide values for the
- reciprocals. For PC == 2 it has to be lower because linear interpolation
- scaling would make it overflow -- this results in lower depth precision
- in bigger distance for PC == 2. */
-
- S3L_Unit
- tPointRecipZ, lPointRecipZ, rPointRecipZ, /* Reciprocals of the depth of
- each triangle point. */
- lRecip0, lRecip1, rRecip0, rRecip1; /* Helper variables for swapping
- the above after split. */
-
- tPointRecipZ = Z_RECIP_NUMERATOR / S3L_nonZero(tPointSS->z);
- lPointRecipZ = Z_RECIP_NUMERATOR / S3L_nonZero(lPointSS->z);
- rPointRecipZ = Z_RECIP_NUMERATOR / S3L_nonZero(rPointSS->z);
-
- lRecip0 = tPointRecipZ;
- lRecip1 = lPointRecipZ;
- rRecip0 = tPointRecipZ;
- rRecip1 = rPointRecipZ;
-
- #define manageSplitPerspective(b0,b1)\
- b1##Recip0 = b0##PointRecipZ;\
- b1##Recip1 = b1##PointRecipZ;\
- b0##Recip0 = b0##PointRecipZ;\
+ /* PC is done by linearly interpolating reciprocals from which the corrected
+ velues can be computed. See
+ http://www.lysator.liu.se/~mikaelk/doc/perspectivetexture/ */
+
+#if S3L_PERSPECTIVE_CORRECTION == 1
+#define Z_RECIP_NUMERATOR \
+ (S3L_FRACTIONS_PER_UNIT * S3L_FRACTIONS_PER_UNIT * S3L_FRACTIONS_PER_UNIT)
+#elif S3L_PERSPECTIVE_CORRECTION == 2
+#define Z_RECIP_NUMERATOR (S3L_FRACTIONS_PER_UNIT * S3L_FRACTIONS_PER_UNIT)
+#endif
+ /* ^ This numerator is a number by which we divide values for the
+ reciprocals. For PC == 2 it has to be lower because linear
+ interpolation scaling would make it overflow -- this results in lower
+ depth precision in bigger distance for PC == 2. */
+
+ S3L_Unit tPointRecipZ,
+ lPointRecipZ, rPointRecipZ, /* Reciprocals of the depth of
+ each triangle point. */
+ lRecip0, lRecip1, rRecip0, rRecip1; /* Helper variables for swapping
+ the above after split. */
+
+ tPointRecipZ = Z_RECIP_NUMERATOR / S3L_nonZero(tPointSS->z);
+ lPointRecipZ = Z_RECIP_NUMERATOR / S3L_nonZero(lPointSS->z);
+ rPointRecipZ = Z_RECIP_NUMERATOR / S3L_nonZero(rPointSS->z);
+
+ lRecip0 = tPointRecipZ;
+ lRecip1 = lPointRecipZ;
+ rRecip0 = tPointRecipZ;
+ rRecip1 = rPointRecipZ;
+
+#define manageSplitPerspective(b0, b1) \
+ b1##Recip0 = b0##PointRecipZ; \
+ b1##Recip1 = b1##PointRecipZ; \
+ b0##Recip0 = b0##PointRecipZ; \
b0##Recip1 = tPointRecipZ;
#else
- #define manageSplitPerspective(b0,b1) ;
+#define manageSplitPerspective(b0, b1) ;
#endif
- // clip to the screen in y dimension:
+ // clip to the screen in y dimension:
- endY = S3L_min(endY,S3L_RESOLUTION_Y);
+ endY = S3L_min(endY, S3L_RESOLUTION_Y);
- /* Clipping above the screen (y < 0) can't be easily done here, will be
- handled inside the loop. */
+ /* Clipping above the screen (y < 0) can't be easily done here, will be
+ handled inside the loop. */
- while (currentY < endY) /* draw the triangle from top to bottom -- the
+ while (currentY < endY) /* draw the triangle from top to bottom -- the
bottom-most row is left out because, following
from the rasterization rules (see start of the
file), it is to never be rasterized. */
- {
- if (currentY == splitY) // reached a vertical split of the triangle?
{
- #define manageSplit(b0,b1,s0,s1)\
- S3L_Unit *tmp = barycentric##b0;\
- barycentric##b0 = barycentric##b1;\
- barycentric##b1 = tmp;\
- s0##SideFLS.valueScaled = (S3L_FRACTIONS_PER_UNIT\
- << S3L_FAST_LERP_QUALITY) - s0##SideFLS.valueScaled;\
- s0##SideFLS.stepScaled *= -1;\
- manageSplitPerspective(s0,s1)
-
- if (splitOnLeft)
- {
- initSide(l,l,r,0);
- manageSplit(0,2,r,l)
- }
- else
- {
- initSide(r,r,l,0);
- manageSplit(1,2,l,r)
- }
- }
+ if (currentY == splitY) // reached a vertical split of the triangle?
+ {
+#define manageSplit(b0, b1, s0, s1) \
+ S3L_Unit* tmp = barycentric##b0; \
+ barycentric##b0 = barycentric##b1; \
+ barycentric##b1 = tmp; \
+ s0##SideFLS.valueScaled = \
+ (S3L_FRACTIONS_PER_UNIT << S3L_FAST_LERP_QUALITY) - \
+ s0##SideFLS.valueScaled; \
+ s0##SideFLS.stepScaled *= -1; \
+ manageSplitPerspective(s0, s1)
+
+ if (splitOnLeft) {
+ initSide(l, l, r, 0);
+ manageSplit(0, 2, r, l)
+ } else {
+ initSide(r, r, l, 0);
+ manageSplit(1, 2, l, r)
+ }
+ }
- stepSide(r)
- stepSide(l)
+ stepSide(r) stepSide(l)
- if (currentY >= 0) /* clipping of pixels whose y < 0 (can't be easily done
- outside the loop because of the Bresenham-like
- algorithm steps) */
- {
- p.y = currentY;
+ if (currentY >= 0) /* clipping of pixels whose y < 0 (can't be
+ easily done outside the loop because of the
+ Bresenham-like algorithm steps) */
+ {
+ p.y = currentY;
- // draw the horizontal line
+ // draw the horizontal line
#if !S3L_FLAT
- S3L_Unit rowLength = S3L_nonZero(rX - lX - 1); // prevent zero div
+ S3L_Unit rowLength = S3L_nonZero(rX - lX - 1); // prevent zero div
- #if S3L_PERSPECTIVE_CORRECTION
- S3L_Unit lOverZ, lRecipZ, rOverZ, rRecipZ, lT, rT;
+#if S3L_PERSPECTIVE_CORRECTION
+ S3L_Unit lOverZ, lRecipZ, rOverZ, rRecipZ, lT, rT;
- lT = S3L_getFastLerpValue(lSideFLS);
- rT = S3L_getFastLerpValue(rSideFLS);
+ lT = S3L_getFastLerpValue(lSideFLS);
+ rT = S3L_getFastLerpValue(rSideFLS);
- lOverZ = S3L_interpolateByUnitFrom0(lRecip1,lT);
- lRecipZ = S3L_interpolateByUnit(lRecip0,lRecip1,lT);
+ lOverZ = S3L_interpolateByUnitFrom0(lRecip1, lT);
+ lRecipZ = S3L_interpolateByUnit(lRecip0, lRecip1, lT);
- rOverZ = S3L_interpolateByUnitFrom0(rRecip1,rT);
- rRecipZ = S3L_interpolateByUnit(rRecip0,rRecip1,rT);
- #else
- S3L_FastLerpState b0FLS, b1FLS;
+ rOverZ = S3L_interpolateByUnitFrom0(rRecip1, rT);
+ rRecipZ = S3L_interpolateByUnit(rRecip0, rRecip1, rT);
+#else
+ S3L_FastLerpState b0FLS, b1FLS;
- #if S3L_COMPUTE_LERP_DEPTH
- S3L_FastLerpState depthFLS;
+#if S3L_COMPUTE_LERP_DEPTH
+ S3L_FastLerpState depthFLS;
- depthFLS.valueScaled = lDepthFLS.valueScaled;
- depthFLS.stepScaled =
- (rDepthFLS.valueScaled - lDepthFLS.valueScaled) / rowLength;
- #endif
+ depthFLS.valueScaled = lDepthFLS.valueScaled;
+ depthFLS.stepScaled =
+ (rDepthFLS.valueScaled - lDepthFLS.valueScaled) / rowLength;
+#endif
- b0FLS.valueScaled = 0;
- b1FLS.valueScaled = lSideFLS.valueScaled;
+ b0FLS.valueScaled = 0;
+ b1FLS.valueScaled = lSideFLS.valueScaled;
- b0FLS.stepScaled = rSideFLS.valueScaled / rowLength;
- b1FLS.stepScaled = -1 * lSideFLS.valueScaled / rowLength;
- #endif
+ b0FLS.stepScaled = rSideFLS.valueScaled / rowLength;
+ b1FLS.stepScaled = -1 * lSideFLS.valueScaled / rowLength;
+#endif
#endif
- // clip to the screen in x dimension:
+ // clip to the screen in x dimension:
- S3L_ScreenCoord rXClipped = S3L_min(rX,S3L_RESOLUTION_X),
- lXClipped = lX;
+ S3L_ScreenCoord rXClipped = S3L_min(rX, S3L_RESOLUTION_X),
+ lXClipped = lX;
- if (lXClipped < 0)
- {
- lXClipped = 0;
+ if (lXClipped < 0) {
+ lXClipped = 0;
#if !S3L_PERSPECTIVE_CORRECTION && !S3L_FLAT
- b0FLS.valueScaled -= lX * b0FLS.stepScaled;
- b1FLS.valueScaled -= lX * b1FLS.stepScaled;
+ b0FLS.valueScaled -= lX * b0FLS.stepScaled;
+ b1FLS.valueScaled -= lX * b1FLS.stepScaled;
- #if S3L_COMPUTE_LERP_DEPTH
- depthFLS.valueScaled -= lX * depthFLS.stepScaled;
- #endif
+#if S3L_COMPUTE_LERP_DEPTH
+ depthFLS.valueScaled -= lX * depthFLS.stepScaled;
+#endif
#endif
- }
+ }
#if S3L_PERSPECTIVE_CORRECTION
- S3L_ScreenCoord i = lXClipped - lX; /* helper var to save one
- substraction in the inner
- loop */
+ S3L_ScreenCoord i = lXClipped - lX; /* helper var to save one
+ substraction in the inner
+ loop */
#endif
#if S3L_PERSPECTIVE_CORRECTION == 2
- S3L_FastLerpState
- depthPC, // interpolates depth between row segments
- b0PC, // interpolates barycentric0 between row segments
- b1PC; // interpolates barycentric1 between row segments
-
- /* ^ These interpolate values between row segments (lines of pixels
- of S3L_PC_APPROX_LENGTH length). After each row segment perspective
- correction is recomputed. */
-
- depthPC.valueScaled =
- (Z_RECIP_NUMERATOR /
- S3L_nonZero(S3L_interpolate(lRecipZ,rRecipZ,i,rowLength)))
- << S3L_FAST_LERP_QUALITY;
-
- b0PC.valueScaled =
- (
- S3L_interpolateFrom0(rOverZ,i,rowLength)
- * depthPC.valueScaled
- ) / (Z_RECIP_NUMERATOR / S3L_FRACTIONS_PER_UNIT);
-
- b1PC.valueScaled =
- (
- (lOverZ - S3L_interpolateFrom0(lOverZ,i,rowLength))
- * depthPC.valueScaled
- ) / (Z_RECIP_NUMERATOR / S3L_FRACTIONS_PER_UNIT);
-
- int8_t rowCount = S3L_PC_APPROX_LENGTH;
+ S3L_FastLerpState
+ depthPC, // interpolates depth between row segments
+ b0PC, // interpolates barycentric0 between row segments
+ b1PC; // interpolates barycentric1 between row segments
+
+ /* ^ These interpolate values between row segments (lines of pixels
+ of S3L_PC_APPROX_LENGTH length). After each row segment
+ perspective correction is recomputed. */
+
+ depthPC.valueScaled =
+ (Z_RECIP_NUMERATOR /
+ S3L_nonZero(S3L_interpolate(lRecipZ, rRecipZ, i, rowLength)))
+ << S3L_FAST_LERP_QUALITY;
+
+ b0PC.valueScaled = (S3L_interpolateFrom0(rOverZ, i, rowLength) *
+ depthPC.valueScaled) /
+ (Z_RECIP_NUMERATOR / S3L_FRACTIONS_PER_UNIT);
+
+ b1PC.valueScaled =
+ ((lOverZ - S3L_interpolateFrom0(lOverZ, i, rowLength)) *
+ depthPC.valueScaled) /
+ (Z_RECIP_NUMERATOR / S3L_FRACTIONS_PER_UNIT);
+
+ int8_t rowCount = S3L_PC_APPROX_LENGTH;
#endif
#if S3L_Z_BUFFER
- uint32_t zBufferIndex = p.y * S3L_RESOLUTION_X + lXClipped;
+ uint32_t zBufferIndex = p.y * S3L_RESOLUTION_X + lXClipped;
#endif
- // draw the row -- inner loop:
+ // draw the row -- inner loop:
- for (S3L_ScreenCoord x = lXClipped; x < rXClipped; ++x)
- {
- int8_t testsPassed = 1;
+ for (S3L_ScreenCoord x = lXClipped; x < rXClipped; ++x) {
+ int8_t testsPassed = 1;
#if S3L_STENCIL_BUFFER
- if (!S3L_stencilTest(x,p.y))
- testsPassed = 0;
+ if (!S3L_stencilTest(x, p.y))
+ testsPassed = 0;
#endif
- p.x = x;
+ p.x = x;
#if S3L_COMPUTE_DEPTH
- #if S3L_PERSPECTIVE_CORRECTION == 1
- p.depth = Z_RECIP_NUMERATOR /
- S3L_nonZero(S3L_interpolate(lRecipZ,rRecipZ,i,rowLength));
- #elif S3L_PERSPECTIVE_CORRECTION == 2
- if (rowCount >= S3L_PC_APPROX_LENGTH)
- {
- // init the linear interpolation to the next PC correct value
-
- rowCount = 0;
-
- S3L_Unit nextI = i + S3L_PC_APPROX_LENGTH;
-
- if (nextI < rowLength)
- {
- S3L_Unit nextDepthScaled =
- (
- Z_RECIP_NUMERATOR /
- S3L_nonZero(S3L_interpolate(lRecipZ,rRecipZ,nextI,rowLength))
- ) << S3L_FAST_LERP_QUALITY;
-
- depthPC.stepScaled =
- (nextDepthScaled - depthPC.valueScaled) / S3L_PC_APPROX_LENGTH;
-
- S3L_Unit nextValue =
- (
- S3L_interpolateFrom0(rOverZ,nextI,rowLength)
- * nextDepthScaled
- ) / (Z_RECIP_NUMERATOR / S3L_FRACTIONS_PER_UNIT);
-
- b0PC.stepScaled =
- (nextValue - b0PC.valueScaled) / S3L_PC_APPROX_LENGTH;
-
- nextValue =
- (
- (lOverZ - S3L_interpolateFrom0(lOverZ,nextI,rowLength))
- * nextDepthScaled
- ) / (Z_RECIP_NUMERATOR / S3L_FRACTIONS_PER_UNIT);
-
- b1PC.stepScaled =
- (nextValue - b1PC.valueScaled) / S3L_PC_APPROX_LENGTH;
- }
- else
- {
- /* A special case where we'd be interpolating outside the triangle.
- It seems like a valid approach at first, but it creates a bug
- in a case when the rasaterized triangle is near screen 0 and can
- actually never reach the extrapolated screen position. So we
- have to clamp to the actual end of the triangle here. */
-
- S3L_Unit maxI = S3L_nonZero(rowLength - i);
-
- S3L_Unit nextDepthScaled =
- (
- Z_RECIP_NUMERATOR /
- S3L_nonZero(rRecipZ)
- ) << S3L_FAST_LERP_QUALITY;
-
- depthPC.stepScaled =
- (nextDepthScaled - depthPC.valueScaled) / maxI;
-
- S3L_Unit nextValue =
- (
- rOverZ
- * nextDepthScaled
- ) / (Z_RECIP_NUMERATOR / S3L_FRACTIONS_PER_UNIT);
-
- b0PC.stepScaled =
- (nextValue - b0PC.valueScaled) / maxI;
-
- b1PC.stepScaled =
- -1 * b1PC.valueScaled / maxI;
- }
- }
-
- p.depth = S3L_getFastLerpValue(depthPC);
- #else
- p.depth = S3L_getFastLerpValue(depthFLS);
- S3L_stepFastLerp(depthFLS);
- #endif
-#else // !S3L_COMPUTE_DEPTH
- p.depth = (tPointSS->z + lPointSS->z + rPointSS->z) / 3;
+#if S3L_PERSPECTIVE_CORRECTION == 1
+ p.depth =
+ Z_RECIP_NUMERATOR / S3L_nonZero(S3L_interpolate(
+ lRecipZ, rRecipZ, i, rowLength));
+#elif S3L_PERSPECTIVE_CORRECTION == 2
+ if (rowCount >= S3L_PC_APPROX_LENGTH) {
+ // init the linear interpolation to the next PC correct
+ // value
+
+ rowCount = 0;
+
+ S3L_Unit nextI = i + S3L_PC_APPROX_LENGTH;
+
+ if (nextI < rowLength) {
+ S3L_Unit nextDepthScaled =
+ (Z_RECIP_NUMERATOR /
+ S3L_nonZero(S3L_interpolate(lRecipZ, rRecipZ,
+ nextI, rowLength)))
+ << S3L_FAST_LERP_QUALITY;
+
+ depthPC.stepScaled =
+ (nextDepthScaled - depthPC.valueScaled) /
+ S3L_PC_APPROX_LENGTH;
+
+ S3L_Unit nextValue =
+ (S3L_interpolateFrom0(rOverZ, nextI, rowLength) *
+ nextDepthScaled) /
+ (Z_RECIP_NUMERATOR / S3L_FRACTIONS_PER_UNIT);
+
+ b0PC.stepScaled = (nextValue - b0PC.valueScaled) /
+ S3L_PC_APPROX_LENGTH;
+
+ nextValue =
+ ((lOverZ -
+ S3L_interpolateFrom0(lOverZ, nextI, rowLength)) *
+ nextDepthScaled) /
+ (Z_RECIP_NUMERATOR / S3L_FRACTIONS_PER_UNIT);
+
+ b1PC.stepScaled = (nextValue - b1PC.valueScaled) /
+ S3L_PC_APPROX_LENGTH;
+ } else {
+ /* A special case where we'd be interpolating outside
+ the triangle. It seems like a valid approach at
+ first, but it creates a bug in a case when the
+ rasaterized triangle is near screen 0 and can
+ actually never reach the extrapolated screen
+ position. So we have to clamp to the actual end of
+ the triangle here. */
+
+ S3L_Unit maxI = S3L_nonZero(rowLength - i);
+
+ S3L_Unit nextDepthScaled =
+ (Z_RECIP_NUMERATOR / S3L_nonZero(rRecipZ))
+ << S3L_FAST_LERP_QUALITY;
+
+ depthPC.stepScaled =
+ (nextDepthScaled - depthPC.valueScaled) / maxI;
+
+ S3L_Unit nextValue =
+ (rOverZ * nextDepthScaled) /
+ (Z_RECIP_NUMERATOR / S3L_FRACTIONS_PER_UNIT);
+
+ b0PC.stepScaled = (nextValue - b0PC.valueScaled) / maxI;
+
+ b1PC.stepScaled = -1 * b1PC.valueScaled / maxI;
+ }
+ }
+
+ p.depth = S3L_getFastLerpValue(depthPC);
+#else
+ p.depth = S3L_getFastLerpValue(depthFLS);
+ S3L_stepFastLerp(depthFLS);
+#endif
+#else // !S3L_COMPUTE_DEPTH
+ p.depth = (tPointSS->z + lPointSS->z + rPointSS->z) / 3;
#endif
#if S3L_Z_BUFFER
- p.previousZ = S3L_zBuffer[zBufferIndex];
+ p.previousZ = S3L_zBuffer[zBufferIndex];
- zBufferIndex++;
+ zBufferIndex++;
- if (!S3L_zTest(p.x,p.y,p.depth))
- testsPassed = 0;
+ if (!S3L_zTest(p.x, p.y, p.depth))
+ testsPassed = 0;
#endif
- if (testsPassed)
- {
+ if (testsPassed) {
#if !S3L_FLAT
- #if S3L_PERSPECTIVE_CORRECTION == 0
- *barycentric0 = S3L_getFastLerpValue(b0FLS);
- *barycentric1 = S3L_getFastLerpValue(b1FLS);
- #elif S3L_PERSPECTIVE_CORRECTION == 1
- *barycentric0 =
- (
- S3L_interpolateFrom0(rOverZ,i,rowLength)
- * p.depth
- ) / (Z_RECIP_NUMERATOR / S3L_FRACTIONS_PER_UNIT);
-
- *barycentric1 =
- (
- (lOverZ - S3L_interpolateFrom0(lOverZ,i,rowLength))
- * p.depth
- ) / (Z_RECIP_NUMERATOR / S3L_FRACTIONS_PER_UNIT);
- #elif S3L_PERSPECTIVE_CORRECTION == 2
- *barycentric0 = S3L_getFastLerpValue(b0PC);
- *barycentric1 = S3L_getFastLerpValue(b1PC);
- #endif
-
- *barycentric2 =
- S3L_FRACTIONS_PER_UNIT - *barycentric0 - *barycentric1;
+#if S3L_PERSPECTIVE_CORRECTION == 0
+ *barycentric0 = S3L_getFastLerpValue(b0FLS);
+ *barycentric1 = S3L_getFastLerpValue(b1FLS);
+#elif S3L_PERSPECTIVE_CORRECTION == 1
+ *barycentric0 =
+ (S3L_interpolateFrom0(rOverZ, i, rowLength) * p.depth) /
+ (Z_RECIP_NUMERATOR / S3L_FRACTIONS_PER_UNIT);
+
+ *barycentric1 =
+ ((lOverZ - S3L_interpolateFrom0(lOverZ, i, rowLength)) *
+ p.depth) /
+ (Z_RECIP_NUMERATOR / S3L_FRACTIONS_PER_UNIT);
+#elif S3L_PERSPECTIVE_CORRECTION == 2
+ *barycentric0 = S3L_getFastLerpValue(b0PC);
+ *barycentric1 = S3L_getFastLerpValue(b1PC);
+#endif
+
+ *barycentric2 =
+ S3L_FRACTIONS_PER_UNIT - *barycentric0 - *barycentric1;
#endif
#if S3L_NEAR_CROSS_STRATEGY == 3
-if (_S3L_projectedTriangleState != 0)
-{
- S3L_Unit newBarycentric[3];
+ if (_S3L_projectedTriangleState != 0) {
+ S3L_Unit newBarycentric[3];
- newBarycentric[0] = S3L_interpolateBarycentric(
- _S3L_triangleRemapBarycentrics[0].x,
- _S3L_triangleRemapBarycentrics[1].x,
- _S3L_triangleRemapBarycentrics[2].x,
- p.barycentric);
+ newBarycentric[0] = S3L_interpolateBarycentric(
+ _S3L_triangleRemapBarycentrics[0].x,
+ _S3L_triangleRemapBarycentrics[1].x,
+ _S3L_triangleRemapBarycentrics[2].x, p.barycentric);
- newBarycentric[1] = S3L_interpolateBarycentric(
- _S3L_triangleRemapBarycentrics[0].y,
- _S3L_triangleRemapBarycentrics[1].y,
- _S3L_triangleRemapBarycentrics[2].y,
- p.barycentric);
+ newBarycentric[1] = S3L_interpolateBarycentric(
+ _S3L_triangleRemapBarycentrics[0].y,
+ _S3L_triangleRemapBarycentrics[1].y,
+ _S3L_triangleRemapBarycentrics[2].y, p.barycentric);
- newBarycentric[2] = S3L_interpolateBarycentric(
- _S3L_triangleRemapBarycentrics[0].z,
- _S3L_triangleRemapBarycentrics[1].z,
- _S3L_triangleRemapBarycentrics[2].z,
- p.barycentric);
+ newBarycentric[2] = S3L_interpolateBarycentric(
+ _S3L_triangleRemapBarycentrics[0].z,
+ _S3L_triangleRemapBarycentrics[1].z,
+ _S3L_triangleRemapBarycentrics[2].z, p.barycentric);
- p.barycentric[0] = newBarycentric[0];
- p.barycentric[1] = newBarycentric[1];
- p.barycentric[2] = newBarycentric[2];
-}
+ p.barycentric[0] = newBarycentric[0];
+ p.barycentric[1] = newBarycentric[1];
+ p.barycentric[2] = newBarycentric[2];
+ }
#endif
- S3L_PIXEL_FUNCTION(&p);
- } // tests passed
+ S3L_PIXEL_FUNCTION(&p);
+ } // tests passed
#if !S3L_FLAT
- #if S3L_PERSPECTIVE_CORRECTION
- i++;
- #if S3L_PERSPECTIVE_CORRECTION == 2
- rowCount++;
-
- S3L_stepFastLerp(depthPC);
- S3L_stepFastLerp(b0PC);
- S3L_stepFastLerp(b1PC);
- #endif
- #else
- S3L_stepFastLerp(b0FLS);
- S3L_stepFastLerp(b1FLS);
- #endif
-#endif
- } // inner loop
- } // y clipping
+#if S3L_PERSPECTIVE_CORRECTION
+ i++;
+#if S3L_PERSPECTIVE_CORRECTION == 2
+ rowCount++;
+
+ S3L_stepFastLerp(depthPC);
+ S3L_stepFastLerp(b0PC);
+ S3L_stepFastLerp(b1PC);
+#endif
+#else
+ S3L_stepFastLerp(b0FLS);
+ S3L_stepFastLerp(b1FLS);
+#endif
+#endif
+ } // inner loop
+ } // y clipping
#if !S3L_FLAT
- S3L_stepFastLerp(lSideFLS);
- S3L_stepFastLerp(rSideFLS);
+ S3L_stepFastLerp(lSideFLS);
+ S3L_stepFastLerp(rSideFLS);
- #if S3L_COMPUTE_LERP_DEPTH
- S3L_stepFastLerp(lDepthFLS);
- S3L_stepFastLerp(rDepthFLS);
- #endif
+#if S3L_COMPUTE_LERP_DEPTH
+ S3L_stepFastLerp(lDepthFLS);
+ S3L_stepFastLerp(rDepthFLS);
+#endif
#endif
- ++currentY;
- } // row drawing
+ ++currentY;
+ } // row drawing
- #undef manageSplit
- #undef initPC
- #undef initSide
- #undef stepSide
- #undef Z_RECIP_NUMERATOR
+#undef manageSplit
+#undef initPC
+#undef initSide
+#undef stepSide
+#undef Z_RECIP_NUMERATOR
}
-void S3L_rotate2DPoint(S3L_Unit *x, S3L_Unit *y, S3L_Unit angle)
-{
- if (angle < S3L_SIN_TABLE_UNIT_STEP)
- return; // no visible rotation
+void S3L_rotate2DPoint(S3L_Unit* x, S3L_Unit* y, S3L_Unit angle) {
+ if (angle < S3L_SIN_TABLE_UNIT_STEP)
+ return; // no visible rotation
- S3L_Unit angleSin = S3L_sin(angle);
- S3L_Unit angleCos = S3L_cos(angle);
+ S3L_Unit angleSin = S3L_sin(angle);
+ S3L_Unit angleCos = S3L_cos(angle);
- S3L_Unit xBackup = *x;
+ S3L_Unit xBackup = *x;
- *x =
- (angleCos * (*x)) / S3L_FRACTIONS_PER_UNIT -
- (angleSin * (*y)) / S3L_FRACTIONS_PER_UNIT;
+ *x = (angleCos * (*x)) / S3L_FRACTIONS_PER_UNIT -
+ (angleSin * (*y)) / S3L_FRACTIONS_PER_UNIT;
- *y =
- (angleSin * xBackup) / S3L_FRACTIONS_PER_UNIT +
- (angleCos * (*y)) / S3L_FRACTIONS_PER_UNIT;
+ *y = (angleSin * xBackup) / S3L_FRACTIONS_PER_UNIT +
+ (angleCos * (*y)) / S3L_FRACTIONS_PER_UNIT;
}
-void S3L_makeWorldMatrix(S3L_Transform3D worldTransform, S3L_Mat4 m)
-{
- S3L_makeScaleMatrix(
- worldTransform.scale.x,
- worldTransform.scale.y,
- worldTransform.scale.z,
- m);
+void S3L_makeWorldMatrix(S3L_Transform3D worldTransform, S3L_Mat4 m) {
+ S3L_makeScaleMatrix(worldTransform.scale.x, worldTransform.scale.y,
+ worldTransform.scale.z, m);
- S3L_Mat4 t;
+ S3L_Mat4 t;
- S3L_makeRotationMatrixZXY(
- worldTransform.rotation.x,
- worldTransform.rotation.y,
- worldTransform.rotation.z,
- t);
+ S3L_makeRotationMatrixZXY(worldTransform.rotation.x,
+ worldTransform.rotation.y,
+ worldTransform.rotation.z, t);
- S3L_mat4Xmat4(m,t);
+ S3L_mat4Xmat4(m, t);
- S3L_makeTranslationMat(
- worldTransform.translation.x,
- worldTransform.translation.y,
- worldTransform.translation.z,
- t);
+ S3L_makeTranslationMat(worldTransform.translation.x,
+ worldTransform.translation.y,
+ worldTransform.translation.z, t);
- S3L_mat4Xmat4(m,t);
+ S3L_mat4Xmat4(m, t);
}
-void S3L_mat4Transpose(S3L_Mat4 m)
-{
- S3L_Unit tmp;
+void S3L_mat4Transpose(S3L_Mat4 m) {
+ S3L_Unit tmp;
- for (uint8_t y = 0; y < 3; ++y)
- for (uint8_t x = 1 + y; x < 4; ++x)
- {
- tmp = m[x][y];
- m[x][y] = m[y][x];
- m[y][x] = tmp;
- }
+ for (uint8_t y = 0; y < 3; ++y)
+ for (uint8_t x = 1 + y; x < 4; ++x) {
+ tmp = m[x][y];
+ m[x][y] = m[y][x];
+ m[y][x] = tmp;
+ }
}
-void S3L_makeCameraMatrix(S3L_Transform3D cameraTransform, S3L_Mat4 m)
-{
- S3L_makeTranslationMat(
- -1 * cameraTransform.translation.x,
- -1 * cameraTransform.translation.y,
- -1 * cameraTransform.translation.z,
- m);
+void S3L_makeCameraMatrix(S3L_Transform3D cameraTransform, S3L_Mat4 m) {
+ S3L_makeTranslationMat(-1 * cameraTransform.translation.x,
+ -1 * cameraTransform.translation.y,
+ -1 * cameraTransform.translation.z, m);
- S3L_Mat4 r;
+ S3L_Mat4 r;
- S3L_makeRotationMatrixZXY(
- cameraTransform.rotation.x,
- cameraTransform.rotation.y,
- cameraTransform.rotation.z,
- r);
+ S3L_makeRotationMatrixZXY(cameraTransform.rotation.x,
+ cameraTransform.rotation.y,
+ cameraTransform.rotation.z, r);
- S3L_mat4Transpose(r); // transposing creates an inverse transform
+ S3L_mat4Transpose(r); // transposing creates an inverse transform
- S3L_mat4Xmat4(m,r);
+ S3L_mat4Xmat4(m, r);
}
-int8_t S3L_triangleWinding(
- S3L_ScreenCoord x0,
- S3L_ScreenCoord y0,
- S3L_ScreenCoord x1,
- S3L_ScreenCoord y1,
- S3L_ScreenCoord x2,
- S3L_ScreenCoord y2)
-{
- int32_t winding =
- (y1 - y0) * (x2 - x1) - (x1 - x0) * (y2 - y1);
+int8_t S3L_triangleWinding(S3L_ScreenCoord x0,
+ S3L_ScreenCoord y0,
+ S3L_ScreenCoord x1,
+ S3L_ScreenCoord y1,
+ S3L_ScreenCoord x2,
+ S3L_ScreenCoord y2) {
+ int32_t winding = (y1 - y0) * (x2 - x1) - (x1 - x0) * (y2 - y1);
// ^ cross product for points with z == 0
- return winding > 0 ? 1 : (winding < 0 ? -1 : 0);
+ return winding > 0 ? 1 : (winding < 0 ? -1 : 0);
}
/**
@@ -2546,92 +2360,81 @@ int8_t S3L_triangleWinding(
i.e. returns false if the triangle is either completely outside the frustum
(left, right, top, bottom, near) or is invisible due to backface culling.
*/
-static inline int8_t S3L_triangleIsVisible(
- S3L_Vec4 p0,
- S3L_Vec4 p1,
- S3L_Vec4 p2,
- uint8_t backfaceCulling)
-{
- #define clipTest(c,cmp,v)\
- (p0.c cmp (v) && p1.c cmp (v) && p2.c cmp (v))
-
- if ( // outside frustum?
+static inline int8_t S3L_triangleIsVisible(S3L_Vec4 p0,
+ S3L_Vec4 p1,
+ S3L_Vec4 p2,
+ uint8_t backfaceCulling) {
+#define clipTest(c, cmp, v) (p0.c cmp(v) && p1.c cmp(v) && p2.c cmp(v))
+
+ if ( // outside frustum?
#if S3L_NEAR_CROSS_STRATEGY == 0
- p0.z <= S3L_NEAR || p1.z <= S3L_NEAR || p2.z <= S3L_NEAR ||
- // ^ partially in front of NEAR?
+ p0.z <= S3L_NEAR || p1.z <= S3L_NEAR || p2.z <= S3L_NEAR ||
+ // ^ partially in front of NEAR?
#else
- clipTest(z,<=,S3L_NEAR) || // completely in front of NEAR?
+ clipTest(z, <=, S3L_NEAR) || // completely in front of NEAR?
#endif
- clipTest(x,<,0) ||
- clipTest(x,>=,S3L_RESOLUTION_X) ||
- clipTest(y,<,0) ||
- clipTest(y,>,S3L_RESOLUTION_Y)
- )
- return 0;
+ clipTest(x, <, 0) || clipTest(x, >=, S3L_RESOLUTION_X) ||
+ clipTest(y, <, 0) || clipTest(y, >, S3L_RESOLUTION_Y))
+ return 0;
- #undef clipTest
+#undef clipTest
- if (backfaceCulling != 0)
- {
- int8_t winding =
- S3L_triangleWinding(p0.x,p0.y,p1.x,p1.y,p2.x,p2.y);
+ if (backfaceCulling != 0) {
+ int8_t winding =
+ S3L_triangleWinding(p0.x, p0.y, p1.x, p1.y, p2.x, p2.y);
- if ((backfaceCulling == 1 && winding > 0) ||
- (backfaceCulling == 2 && winding < 0))
- return 0;
- }
+ if ((backfaceCulling == 1 && winding > 0) ||
+ (backfaceCulling == 2 && winding < 0))
+ return 0;
+ }
- return 1;
+ return 1;
}
#if S3L_SORT != 0
-typedef struct
-{
- uint8_t modelIndex;
- S3L_Index triangleIndex;
- uint16_t sortValue;
+typedef struct {
+ uint8_t modelIndex;
+ S3L_Index triangleIndex;
+ uint16_t sortValue;
} _S3L_TriangleToSort;
_S3L_TriangleToSort S3L_sortArray[S3L_MAX_TRIANGES_DRAWN];
uint16_t S3L_sortArrayLength;
#endif
-void _S3L_projectVertex(
- const S3L_Model3D *model,
- S3L_Index triangleIndex,
- uint8_t vertex,
- S3L_Mat4 projectionMatrix,
- S3L_Vec4 *result)
-{
- uint32_t vertexIndex = model->triangles[triangleIndex * 3 + vertex] * 3;
-
- result->x = model->vertices[vertexIndex];
- result->y = model->vertices[vertexIndex + 1];
- result->z = model->vertices[vertexIndex + 2];
- result->w = S3L_FRACTIONS_PER_UNIT; // needed for translation
-
- S3L_vec3Xmat4(result,projectionMatrix);
-
- result->w = result->z;
- /* We'll keep the non-clamped z in w for sorting. */
-}
-
-void _S3L_mapProjectedVertexToScreen(S3L_Vec4 *vertex, S3L_Unit focalLength)
-{
- vertex->z = vertex->z >= S3L_NEAR ? vertex->z : S3L_NEAR;
- /* ^ This firstly prevents zero division in the follwoing z-divide and
- secondly "pushes" vertices that are in front of near a little bit forward,
- which makes them behave a bit better. If all three vertices end up exactly
- on NEAR, the triangle will be culled. */
-
- S3L_perspectiveDivide(vertex,focalLength);
-
- S3L_ScreenCoord sX, sY;
-
- S3L_mapProjectionPlaneToScreen(*vertex,&sX,&sY);
-
- vertex->x = sX;
- vertex->y = sY;
+void _S3L_projectVertex(const S3L_Model3D* model,
+ S3L_Index triangleIndex,
+ uint8_t vertex,
+ S3L_Mat4 projectionMatrix,
+ S3L_Vec4* result) {
+ uint32_t vertexIndex = model->triangles[triangleIndex * 3 + vertex] * 3;
+
+ result->x = model->vertices[vertexIndex];
+ result->y = model->vertices[vertexIndex + 1];
+ result->z = model->vertices[vertexIndex + 2];
+ result->w = S3L_FRACTIONS_PER_UNIT; // needed for translation
+
+ S3L_vec3Xmat4(result, projectionMatrix);
+
+ result->w = result->z;
+ /* We'll keep the non-clamped z in w for sorting. */
+}
+
+void _S3L_mapProjectedVertexToScreen(S3L_Vec4* vertex, S3L_Unit focalLength) {
+ vertex->z = vertex->z >= S3L_NEAR ? vertex->z : S3L_NEAR;
+ /* ^ This firstly prevents zero division in the follwoing z-divide and
+ secondly "pushes" vertices that are in front of near a little bit forward,
+ which makes them behave a bit better. If all three vertices end up exactly
+ on NEAR, the triangle will be culled. */
+
+ S3L_perspectiveDivide(vertex, focalLength);
+
+ S3L_ScreenCoord sX, sY;
+
+ S3L_mapProjectionPlaneToScreen(*vertex, &sX, &sY);
+
+ vertex->x = sX;
+ vertex->y = sY;
}
/**
@@ -2640,306 +2443,301 @@ void _S3L_mapProjectedVertexToScreen(S3L_Vec4 *vertex, S3L_Unit focalLength)
triangles are returned (the info about splitting or cutting the triangle is
passed in global variables, see above).
*/
-void _S3L_projectTriangle(
- const S3L_Model3D *model,
- S3L_Index triangleIndex,
- S3L_Mat4 matrix,
- uint32_t focalLength,
- S3L_Vec4 transformed[6])
-{
- _S3L_projectVertex(model,triangleIndex,0,matrix,&(transformed[0]));
- _S3L_projectVertex(model,triangleIndex,1,matrix,&(transformed[1]));
- _S3L_projectVertex(model,triangleIndex,2,matrix,&(transformed[2]));
-
- _S3L_projectedTriangleState = 0;
+void _S3L_projectTriangle(const S3L_Model3D* model,
+ S3L_Index triangleIndex,
+ S3L_Mat4 matrix,
+ uint32_t focalLength,
+ S3L_Vec4 transformed[6]) {
+ _S3L_projectVertex(model, triangleIndex, 0, matrix, &(transformed[0]));
+ _S3L_projectVertex(model, triangleIndex, 1, matrix, &(transformed[1]));
+ _S3L_projectVertex(model, triangleIndex, 2, matrix, &(transformed[2]));
-#if S3L_NEAR_CROSS_STRATEGY == 2 || S3L_NEAR_CROSS_STRATEGY == 3
- uint8_t infront = 0;
- uint8_t behind = 0;
- uint8_t infrontI[3];
- uint8_t behindI[3];
+ _S3L_projectedTriangleState = 0;
- for (uint8_t i = 0; i < 3; ++i)
- if (transformed[i].z < S3L_NEAR)
- {
- infrontI[infront] = i;
- infront++;
- }
- else
- {
- behindI[behind] = i;
- behind++;
- }
+#if S3L_NEAR_CROSS_STRATEGY == 2 || S3L_NEAR_CROSS_STRATEGY == 3
+ uint8_t infront = 0;
+ uint8_t behind = 0;
+ uint8_t infrontI[3];
+ uint8_t behindI[3];
+
+ for (uint8_t i = 0; i < 3; ++i)
+ if (transformed[i].z < S3L_NEAR) {
+ infrontI[infront] = i;
+ infront++;
+ } else {
+ behindI[behind] = i;
+ behind++;
+ }
#if S3L_NEAR_CROSS_STRATEGY == 3
for (int i = 0; i < 3; ++i)
- S3L_vec4Init(&(_S3L_triangleRemapBarycentrics[i]));
+ S3L_vec4Init(&(_S3L_triangleRemapBarycentrics[i]));
_S3L_triangleRemapBarycentrics[0].x = S3L_FRACTIONS_PER_UNIT;
_S3L_triangleRemapBarycentrics[1].y = S3L_FRACTIONS_PER_UNIT;
_S3L_triangleRemapBarycentrics[2].z = S3L_FRACTIONS_PER_UNIT;
#endif
-#define interpolateVertex \
- S3L_Unit ratio =\
- ((transformed[be].z - S3L_NEAR) * S3L_FRACTIONS_PER_UNIT) /\
- (transformed[be].z - transformed[in].z);\
- transformed[in].x = transformed[be].x - \
- ((transformed[be].x - transformed[in].x) * ratio) /\
- S3L_FRACTIONS_PER_UNIT;\
- transformed[in].y = transformed[be].y -\
- ((transformed[be].y - transformed[in].y) * ratio) /\
- S3L_FRACTIONS_PER_UNIT;\
- transformed[in].z = S3L_NEAR;\
- if (beI != 0) {\
- beI->x = (beI->x * ratio) / S3L_FRACTIONS_PER_UNIT;\
- beI->y = (beI->y * ratio) / S3L_FRACTIONS_PER_UNIT;\
- beI->z = (beI->z * ratio) / S3L_FRACTIONS_PER_UNIT;\
- ratio = S3L_FRACTIONS_PER_UNIT - ratio;\
- beI->x += (beB->x * ratio) / S3L_FRACTIONS_PER_UNIT;\
- beI->y += (beB->y * ratio) / S3L_FRACTIONS_PER_UNIT;\
- beI->z += (beB->z * ratio) / S3L_FRACTIONS_PER_UNIT; }
-
- if (infront == 2)
- {
- // shift the two vertices forward along the edge
- for (uint8_t i = 0; i < 2; ++i)
- {
- uint8_t be = behindI[0], in = infrontI[i];
+#define interpolateVertex \
+ S3L_Unit ratio = \
+ ((transformed[be].z - S3L_NEAR) * S3L_FRACTIONS_PER_UNIT) / \
+ (transformed[be].z - transformed[in].z); \
+ transformed[in].x = transformed[be].x - \
+ ((transformed[be].x - transformed[in].x) * ratio) / \
+ S3L_FRACTIONS_PER_UNIT; \
+ transformed[in].y = transformed[be].y - \
+ ((transformed[be].y - transformed[in].y) * ratio) / \
+ S3L_FRACTIONS_PER_UNIT; \
+ transformed[in].z = S3L_NEAR; \
+ if (beI != 0) { \
+ beI->x = (beI->x * ratio) / S3L_FRACTIONS_PER_UNIT; \
+ beI->y = (beI->y * ratio) / S3L_FRACTIONS_PER_UNIT; \
+ beI->z = (beI->z * ratio) / S3L_FRACTIONS_PER_UNIT; \
+ ratio = S3L_FRACTIONS_PER_UNIT - ratio; \
+ beI->x += (beB->x * ratio) / S3L_FRACTIONS_PER_UNIT; \
+ beI->y += (beB->y * ratio) / S3L_FRACTIONS_PER_UNIT; \
+ beI->z += (beB->z * ratio) / S3L_FRACTIONS_PER_UNIT; \
+ }
+
+ if (infront == 2) {
+ // shift the two vertices forward along the edge
+ for (uint8_t i = 0; i < 2; ++i) {
+ uint8_t be = behindI[0], in = infrontI[i];
#if S3L_NEAR_CROSS_STRATEGY == 3
- S3L_Vec4 *beI = &(_S3L_triangleRemapBarycentrics[in]),
- *beB = &(_S3L_triangleRemapBarycentrics[be]);
+ S3L_Vec4 *beI = &(_S3L_triangleRemapBarycentrics[in]),
+ *beB = &(_S3L_triangleRemapBarycentrics[be]);
#else
- S3L_Vec4 *beI = 0, *beB = 0;
+ S3L_Vec4 *beI = 0, *beB = 0;
#endif
- interpolateVertex
+ interpolateVertex
- _S3L_projectedTriangleState = 1;
- }
- }
- else if (infront == 1)
- {
- // create another triangle and do the shifts
- transformed[3] = transformed[behindI[1]];
- transformed[4] = transformed[infrontI[0]];
- transformed[5] = transformed[infrontI[0]];
+ _S3L_projectedTriangleState = 1;
+ }
+ } else if (infront == 1) {
+ // create another triangle and do the shifts
+ transformed[3] = transformed[behindI[1]];
+ transformed[4] = transformed[infrontI[0]];
+ transformed[5] = transformed[infrontI[0]];
#if S3L_NEAR_CROSS_STRATEGY == 3
- _S3L_triangleRemapBarycentrics[3] =
- _S3L_triangleRemapBarycentrics[behindI[1]];
- _S3L_triangleRemapBarycentrics[4] =
- _S3L_triangleRemapBarycentrics[infrontI[0]];
- _S3L_triangleRemapBarycentrics[5] =
- _S3L_triangleRemapBarycentrics[infrontI[0]];
+ _S3L_triangleRemapBarycentrics[3] =
+ _S3L_triangleRemapBarycentrics[behindI[1]];
+ _S3L_triangleRemapBarycentrics[4] =
+ _S3L_triangleRemapBarycentrics[infrontI[0]];
+ _S3L_triangleRemapBarycentrics[5] =
+ _S3L_triangleRemapBarycentrics[infrontI[0]];
#endif
- for (uint8_t i = 0; i < 2; ++i)
- {
- uint8_t be = behindI[i], in = i + 4;
+ for (uint8_t i = 0; i < 2; ++i) {
+ uint8_t be = behindI[i], in = i + 4;
#if S3L_NEAR_CROSS_STRATEGY == 3
- S3L_Vec4 *beI = &(_S3L_triangleRemapBarycentrics[in]),
- *beB = &(_S3L_triangleRemapBarycentrics[be]);
+ S3L_Vec4 *beI = &(_S3L_triangleRemapBarycentrics[in]),
+ *beB = &(_S3L_triangleRemapBarycentrics[be]);
#else
- S3L_Vec4 *beI = 0, *beB = 0;
+ S3L_Vec4 *beI = 0, *beB = 0;
#endif
- interpolateVertex
- }
+ interpolateVertex
+ }
#if S3L_NEAR_CROSS_STRATEGY == 3
- _S3L_triangleRemapBarycentrics[infrontI[0]] =
- _S3L_triangleRemapBarycentrics[4];
+ _S3L_triangleRemapBarycentrics[infrontI[0]] =
+ _S3L_triangleRemapBarycentrics[4];
#endif
- transformed[infrontI[0]] = transformed[4];
+ transformed[infrontI[0]] = transformed[4];
- _S3L_mapProjectedVertexToScreen(&transformed[3],focalLength);
- _S3L_mapProjectedVertexToScreen(&transformed[4],focalLength);
- _S3L_mapProjectedVertexToScreen(&transformed[5],focalLength);
+ _S3L_mapProjectedVertexToScreen(&transformed[3], focalLength);
+ _S3L_mapProjectedVertexToScreen(&transformed[4], focalLength);
+ _S3L_mapProjectedVertexToScreen(&transformed[5], focalLength);
- _S3L_projectedTriangleState = 2;
- }
+ _S3L_projectedTriangleState = 2;
+ }
#undef interpolateVertex
-#endif // S3L_NEAR_CROSS_STRATEGY == 2
+#endif // S3L_NEAR_CROSS_STRATEGY == 2
- _S3L_mapProjectedVertexToScreen(&transformed[0],focalLength);
- _S3L_mapProjectedVertexToScreen(&transformed[1],focalLength);
- _S3L_mapProjectedVertexToScreen(&transformed[2],focalLength);
+ _S3L_mapProjectedVertexToScreen(&transformed[0], focalLength);
+ _S3L_mapProjectedVertexToScreen(&transformed[1], focalLength);
+ _S3L_mapProjectedVertexToScreen(&transformed[2], focalLength);
}
-void S3L_drawScene(S3L_Scene scene)
-{
- S3L_Mat4 matFinal, matCamera;
- S3L_Vec4 transformed[6]; // transformed triangle coords, for 2 triangles
+void S3L_drawScene(S3L_Scene scene) {
+ S3L_Mat4 matFinal, matCamera;
+ S3L_Vec4 transformed[6]; // transformed triangle coords, for 2 triangles
- const S3L_Model3D *model;
- S3L_Index modelIndex, triangleIndex;
+ const S3L_Model3D* model;
+ S3L_Index modelIndex, triangleIndex;
- S3L_makeCameraMatrix(scene.camera.transform,matCamera);
+ S3L_makeCameraMatrix(scene.camera.transform, matCamera);
#if S3L_SORT != 0
- uint16_t previousModel = 0;
- S3L_sortArrayLength = 0;
+ uint16_t previousModel = 0;
+ S3L_sortArrayLength = 0;
#endif
- for (modelIndex = 0; modelIndex < scene.modelCount; ++modelIndex)
- {
- if (!scene.models[modelIndex].config.visible)
- continue;
+ for (modelIndex = 0; modelIndex < scene.modelCount; ++modelIndex) {
+ if (!scene.models[modelIndex].config.visible)
+ continue;
#if S3L_SORT != 0
- if (S3L_sortArrayLength >= S3L_MAX_TRIANGES_DRAWN)
- break;
+ if (S3L_sortArrayLength >= S3L_MAX_TRIANGES_DRAWN)
+ break;
- previousModel = modelIndex;
+ previousModel = modelIndex;
#endif
- if (scene.models[modelIndex].customTransformMatrix == 0)
- S3L_makeWorldMatrix(scene.models[modelIndex].transform,matFinal);
- else
- {
- S3L_Mat4 *m = scene.models[modelIndex].customTransformMatrix;
+ if (scene.models[modelIndex].customTransformMatrix == 0)
+ S3L_makeWorldMatrix(scene.models[modelIndex].transform, matFinal);
+ else {
+ S3L_Mat4* m = scene.models[modelIndex].customTransformMatrix;
- for (int8_t j = 0; j < 4; ++j)
- for (int8_t i = 0; i < 4; ++i)
- matFinal[i][j] = (*m)[i][j];
- }
+ for (int8_t j = 0; j < 4; ++j)
+ for (int8_t i = 0; i < 4; ++i)
+ matFinal[i][j] = (*m)[i][j];
+ }
- S3L_mat4Xmat4(matFinal,matCamera);
+ S3L_mat4Xmat4(matFinal, matCamera);
- S3L_Index triangleCount = scene.models[modelIndex].triangleCount;
+ S3L_Index triangleCount = scene.models[modelIndex].triangleCount;
- triangleIndex = 0;
-
- model = &(scene.models[modelIndex]);
-
- while (triangleIndex < triangleCount)
- {
- /* Some kind of cache could be used in theory to not project perviously
- already projected vertices, but after some testing this was abandoned,
- no gain was seen. */
+ triangleIndex = 0;
+
+ model = &(scene.models[modelIndex]);
- _S3L_projectTriangle(model,triangleIndex,matFinal,
- scene.camera.focalLength,transformed);
+ while (triangleIndex < triangleCount) {
+ /* Some kind of cache could be used in theory to not project
+ perviously already projected vertices, but after some testing
+ this was abandoned, no gain was seen. */
- if (S3L_triangleIsVisible(transformed[0],transformed[1],transformed[2],
- model->config.backfaceCulling))
- {
+ _S3L_projectTriangle(model, triangleIndex, matFinal,
+ scene.camera.focalLength, transformed);
+
+ if (S3L_triangleIsVisible(transformed[0], transformed[1],
+ transformed[2],
+ model->config.backfaceCulling)) {
#if S3L_SORT == 0
- // without sorting draw right away
- S3L_drawTriangle(transformed[0],transformed[1],transformed[2],modelIndex,
- triangleIndex);
+ // without sorting draw right away
+ S3L_drawTriangle(transformed[0], transformed[1], transformed[2],
+ modelIndex, triangleIndex);
- if (_S3L_projectedTriangleState == 2) // draw potential subtriangle
- {
+ if (_S3L_projectedTriangleState ==
+ 2) // draw potential subtriangle
+ {
#if S3L_NEAR_CROSS_STRATEGY == 3
- _S3L_triangleRemapBarycentrics[0] = _S3L_triangleRemapBarycentrics[3];
- _S3L_triangleRemapBarycentrics[1] = _S3L_triangleRemapBarycentrics[4];
- _S3L_triangleRemapBarycentrics[2] = _S3L_triangleRemapBarycentrics[5];
+ _S3L_triangleRemapBarycentrics[0] =
+ _S3L_triangleRemapBarycentrics[3];
+ _S3L_triangleRemapBarycentrics[1] =
+ _S3L_triangleRemapBarycentrics[4];
+ _S3L_triangleRemapBarycentrics[2] =
+ _S3L_triangleRemapBarycentrics[5];
#endif
- S3L_drawTriangle(transformed[3],transformed[4],transformed[5],
- modelIndex, triangleIndex);
- }
+ S3L_drawTriangle(transformed[3], transformed[4],
+ transformed[5], modelIndex, triangleIndex);
+ }
#else
- if (S3L_sortArrayLength >= S3L_MAX_TRIANGES_DRAWN)
- break;
-
- // with sorting add to a sort list
- S3L_sortArray[S3L_sortArrayLength].modelIndex = modelIndex;
- S3L_sortArray[S3L_sortArrayLength].triangleIndex = triangleIndex;
- S3L_sortArray[S3L_sortArrayLength].sortValue = S3L_zeroClamp(
- transformed[0].w + transformed[1].w + transformed[2].w) >> 2;
- /* ^
- The w component here stores non-clamped z.
-
- As a simple approximation we sort by the triangle center point,
- which is a mean coordinate -- we don't actually have to divide by 3
- (or anything), that is unnecessary for sorting! We shift by 2 just
- as a fast operation to prevent overflow of the sum over uint_16t. */
-
- S3L_sortArrayLength++;
-#endif
- }
-
- triangleIndex++;
+ if (S3L_sortArrayLength >= S3L_MAX_TRIANGES_DRAWN)
+ break;
+
+ // with sorting add to a sort list
+ S3L_sortArray[S3L_sortArrayLength].modelIndex = modelIndex;
+ S3L_sortArray[S3L_sortArrayLength].triangleIndex =
+ triangleIndex;
+ S3L_sortArray[S3L_sortArrayLength].sortValue =
+ S3L_zeroClamp(transformed[0].w + transformed[1].w +
+ transformed[2].w) >>
+ 2;
+ /* ^
+ The w component here stores non-clamped z.
+
+ As a simple approximation we sort by the triangle center
+ point, which is a mean coordinate -- we don't actually have
+ to divide by 3 (or anything), that is unnecessary for
+ sorting! We shift by 2 just as a fast operation to prevent
+ overflow of the sum over uint_16t. */
+
+ S3L_sortArrayLength++;
+#endif
+ }
+
+ triangleIndex++;
+ }
}
- }
#if S3L_SORT != 0
- #if S3L_SORT == 1
- #define cmp <
- #else
- #define cmp >
- #endif
+#if S3L_SORT == 1
+#define cmp <
+#else
+#define cmp >
+#endif
- /* Sort the triangles. We use insertion sort, because it has many advantages,
- especially for smaller arrays (better than bubble sort, in-place, stable,
- simple, ...). */
+ /* Sort the triangles. We use insertion sort, because it has many
+ advantages, especially for smaller arrays (better than bubble sort,
+ in-place, stable, simple, ...). */
- for (int16_t i = 1; i < S3L_sortArrayLength; ++i)
- {
- _S3L_TriangleToSort tmp = S3L_sortArray[i];
-
- int16_t j = i - 1;
+ for (int16_t i = 1; i < S3L_sortArrayLength; ++i) {
+ _S3L_TriangleToSort tmp = S3L_sortArray[i];
- while (j >= 0 && S3L_sortArray[j].sortValue cmp tmp.sortValue)
- {
- S3L_sortArray[j + 1] = S3L_sortArray[j];
- j--;
+ int16_t j = i - 1;
+
+ while (j >= 0 && S3L_sortArray[j].sortValue cmp tmp.sortValue) {
+ S3L_sortArray[j + 1] = S3L_sortArray[j];
+ j--;
+ }
+
+ S3L_sortArray[j + 1] = tmp;
}
- S3L_sortArray[j + 1] = tmp;
- }
+#undef cmp
- #undef cmp
+ for (S3L_Index i = 0; i < S3L_sortArrayLength;
+ ++i) // draw sorted triangles
+ {
+ modelIndex = S3L_sortArray[i].modelIndex;
+ triangleIndex = S3L_sortArray[i].triangleIndex;
- for (S3L_Index i = 0; i < S3L_sortArrayLength; ++i) // draw sorted triangles
- {
- modelIndex = S3L_sortArray[i].modelIndex;
- triangleIndex = S3L_sortArray[i].triangleIndex;
+ model = &(scene.models[modelIndex]);
- model = &(scene.models[modelIndex]);
+ if (modelIndex != previousModel) {
+ // only recompute the matrix when the model has changed
+ S3L_makeWorldMatrix(model->transform, matFinal);
+ S3L_mat4Xmat4(matFinal, matCamera);
+ previousModel = modelIndex;
+ }
- if (modelIndex != previousModel)
- {
- // only recompute the matrix when the model has changed
- S3L_makeWorldMatrix(model->transform,matFinal);
- S3L_mat4Xmat4(matFinal,matCamera);
- previousModel = modelIndex;
- }
+ /* Here we project the points again, which is redundant and slow as
+ they've already been projected above, but saving the projected points
+ would require a lot of memory, which for small resolutions could be
+ even worse than z-bufer. So this seems to be the best way
+ memory-wise. */
- /* Here we project the points again, which is redundant and slow as they've
- already been projected above, but saving the projected points would
- require a lot of memory, which for small resolutions could be even
- worse than z-bufer. So this seems to be the best way memory-wise. */
+ _S3L_projectTriangle(model, triangleIndex, matFinal,
+ scene.camera.focalLength, transformed);
- _S3L_projectTriangle(model,triangleIndex,matFinal,scene.camera.focalLength,
- transformed);
+ S3L_drawTriangle(transformed[0], transformed[1], transformed[2],
+ modelIndex, triangleIndex);
- S3L_drawTriangle(transformed[0],transformed[1],transformed[2],modelIndex,
- triangleIndex);
-
- if (_S3L_projectedTriangleState == 2)
- {
+ if (_S3L_projectedTriangleState == 2) {
#if S3L_NEAR_CROSS_STRATEGY == 3
- _S3L_triangleRemapBarycentrics[0] = _S3L_triangleRemapBarycentrics[3];
- _S3L_triangleRemapBarycentrics[1] = _S3L_triangleRemapBarycentrics[4];
- _S3L_triangleRemapBarycentrics[2] = _S3L_triangleRemapBarycentrics[5];
+ _S3L_triangleRemapBarycentrics[0] =
+ _S3L_triangleRemapBarycentrics[3];
+ _S3L_triangleRemapBarycentrics[1] =
+ _S3L_triangleRemapBarycentrics[4];
+ _S3L_triangleRemapBarycentrics[2] =
+ _S3L_triangleRemapBarycentrics[5];
#endif
- S3L_drawTriangle(transformed[3],transformed[4],transformed[5],
- modelIndex, triangleIndex);
+ S3L_drawTriangle(transformed[3], transformed[4], transformed[5],
+ modelIndex, triangleIndex);
+ }
}
-
- }
#endif
}
-#endif // guard
+#endif // guard