mirror of
https://git.coom.tech/drummyfish/small3dlib.git
synced 2025-04-07 02:06:20 +02:00
Add ortho projection
This commit is contained in:
parent
63a241a0a5
commit
6a2cfb5ce6
3 changed files with 28 additions and 38 deletions
|
@ -55,6 +55,7 @@ PC (SDL, offline rendering, terminal):
|
||||||
- **Extremely portable** due to no dependencies, no float, no build systems, low HW requirements, endian independence etc.
|
- **Extremely portable** due to no dependencies, no float, no build systems, low HW requirements, endian independence etc.
|
||||||
- **Many compile-time options** to tune the performance vs quality.
|
- **Many compile-time options** to tune the performance vs quality.
|
||||||
- **Similar to OpenGL** in principle, but simpler, easier to use, with higher-level features.
|
- **Similar to OpenGL** in principle, but simpler, easier to use, with higher-level features.
|
||||||
|
- **Perspective and orthographic** projections.
|
||||||
- **Tools** (Python scripts) for converting 3D models and textures to C array format used by the library.
|
- **Tools** (Python scripts) for converting 3D models and textures to C array format used by the library.
|
||||||
- **Well commented** and formatted code. Automatic documentation (comments + provided Doxyfile).
|
- **Well commented** and formatted code. Automatic documentation (comments + provided Doxyfile).
|
||||||
- Completely **free of legal restrictions**, public domain, do literally anything you want.
|
- Completely **free of legal restrictions**, public domain, do literally anything you want.
|
||||||
|
|
1
TODO.txt
1
TODO.txt
|
@ -1,4 +1,3 @@
|
||||||
- orthographics projection - did I forget this lol?
|
|
||||||
- Add option to compute sin with Bhaskaras approx instead of using a LUT.
|
- Add option to compute sin with Bhaskaras approx instead of using a LUT.
|
||||||
- camera's focallength attribute could really rather be stored in
|
- camera's focallength attribute could really rather be stored in
|
||||||
transformation.scale.z, while scale.x and scale.y could be used for
|
transformation.scale.z, while scale.x and scale.y could be used for
|
||||||
|
|
64
small3dlib.h
64
small3dlib.h
|
@ -10,7 +10,7 @@
|
||||||
license: CC0 1.0 (public domain)
|
license: CC0 1.0 (public domain)
|
||||||
found at https://creativecommons.org/publicdomain/zero/1.0/
|
found at https://creativecommons.org/publicdomain/zero/1.0/
|
||||||
+ additional waiver of all IP
|
+ additional waiver of all IP
|
||||||
version: 0.904d
|
version: 0.905d
|
||||||
|
|
||||||
Before including the library, define S3L_PIXEL_FUNCTION to the name of the
|
Before including the library, define S3L_PIXEL_FUNCTION to the name of the
|
||||||
function you'll be using to draw single pixels (this function will be called
|
function you'll be using to draw single pixels (this function will be called
|
||||||
|
@ -166,7 +166,6 @@
|
||||||
many rendering bugs and imprecisions happening due to overflows, but this will
|
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
|
also consumer more RAM and may potentially be slower on computers with smaller
|
||||||
native integer. */
|
native integer. */
|
||||||
|
|
||||||
#define S3L_USE_WIDER_TYPES 0
|
#define S3L_USE_WIDER_TYPES 0
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -233,7 +232,6 @@ typedef
|
||||||
3: Perform both geometrical and barycentric correction of triangle crossing
|
3: Perform both geometrical and barycentric correction of triangle crossing
|
||||||
the near plane. This is significantly more expensive but results in
|
the near plane. This is significantly more expensive but results in
|
||||||
correct rendering. */
|
correct rendering. */
|
||||||
|
|
||||||
#define S3L_NEAR_CROSS_STRATEGY 0
|
#define S3L_NEAR_CROSS_STRATEGY 0
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -243,8 +241,7 @@ typedef
|
||||||
for the whole triangle. This can be used to create flat-shaded renders and
|
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
|
will be a lot faster. With this option on you will probably want to use
|
||||||
sorting instead of z-buffer. */
|
sorting instead of z-buffer. */
|
||||||
|
#define S3L_FLAT 0
|
||||||
#define S3L_FLAT 0
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if S3L_FLAT
|
#if S3L_FLAT
|
||||||
|
@ -262,7 +259,6 @@ typedef
|
||||||
2: Approximation (computing only at every S3L_PC_APPROX_LENGTHth pixel).
|
2: Approximation (computing only at every S3L_PC_APPROX_LENGTHth pixel).
|
||||||
Quake-style approximation is used, which only computes the PC after
|
Quake-style approximation is used, which only computes the PC after
|
||||||
S3L_PC_APPROX_LENGTH pixels. This is reasonably accurate and fast. */
|
S3L_PC_APPROX_LENGTH pixels. This is reasonably accurate and fast. */
|
||||||
|
|
||||||
#define S3L_PERSPECTIVE_CORRECTION 0
|
#define S3L_PERSPECTIVE_CORRECTION 0
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -270,7 +266,6 @@ typedef
|
||||||
/** For S3L_PERSPECTIVE_CORRECTION == 2, this specifies after how many pixels
|
/** 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.
|
PC is recomputed. Should be a power of two to keep up the performance.
|
||||||
Smaller is nicer but slower. */
|
Smaller is nicer but slower. */
|
||||||
|
|
||||||
#define S3L_PC_APPROX_LENGTH 32
|
#define S3L_PC_APPROX_LENGTH 32
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -300,13 +295,11 @@ typedef
|
||||||
2: Use reduced-size z-buffer (of bytes). This is fast and somewhat accurate,
|
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
|
but inaccuracies can occur and a considerable amount of memory is
|
||||||
needed. */
|
needed. */
|
||||||
|
|
||||||
#define S3L_Z_BUFFER 0
|
#define S3L_Z_BUFFER 0
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef S3L_REDUCED_Z_BUFFER_GRANULARITY
|
#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
|
#endif
|
||||||
|
|
||||||
|
@ -314,7 +307,6 @@ typedef
|
||||||
/** Whether to use stencil buffer for drawing -- with this a pixel that would
|
/** 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
|
be resterized over an already rasterized pixel (within a frame) will be
|
||||||
discarded. This is mostly for front-to-back sorted drawing. */
|
discarded. This is mostly for front-to-back sorted drawing. */
|
||||||
|
|
||||||
#define S3L_STENCIL_BUFFER 0
|
#define S3L_STENCIL_BUFFER 0
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -336,21 +328,18 @@ typedef
|
||||||
because we prevent computing pixels that will be overwritten by nearer
|
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),
|
ones, but we need a 1b stencil buffer for this (enable S3L_STENCIL_BUFFER),
|
||||||
so a bit more memory is needed. */
|
so a bit more memory is needed. */
|
||||||
|
|
||||||
#define S3L_SORT 0
|
#define S3L_SORT 0
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef S3L_MAX_TRIANGES_DRAWN
|
#ifndef S3L_MAX_TRIANGES_DRAWN
|
||||||
/** Maximum number of triangles that can be drawn in sorted modes. This
|
/** Maximum number of triangles that can be drawn in sorted modes. This
|
||||||
affects the size of the cache used for triangle sorting. */
|
affects the size of the cache used for triangle sorting. */
|
||||||
|
|
||||||
#define S3L_MAX_TRIANGES_DRAWN 128
|
#define S3L_MAX_TRIANGES_DRAWN 128
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef S3L_NEAR
|
#ifndef S3L_NEAR
|
||||||
/** Distance of the near clipping plane. Points in front or EXATLY ON this
|
/** Distance of the near clipping plane. Points in front or EXATLY ON this
|
||||||
plane are considered outside the frustum. This must be >= 0. */
|
plane are considered outside the frustum. This must be >= 0. */
|
||||||
|
|
||||||
#define S3L_NEAR (S3L_F / 4)
|
#define S3L_NEAR (S3L_F / 4)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -361,7 +350,6 @@ typedef
|
||||||
#ifndef S3L_NORMAL_COMPUTE_MAXIMUM_AVERAGE
|
#ifndef S3L_NORMAL_COMPUTE_MAXIMUM_AVERAGE
|
||||||
/** Affects the S3L_computeModelNormals function. See its description for
|
/** Affects the S3L_computeModelNormals function. See its description for
|
||||||
details. */
|
details. */
|
||||||
|
|
||||||
#define S3L_NORMAL_COMPUTE_MAXIMUM_AVERAGE 6
|
#define S3L_NORMAL_COMPUTE_MAXIMUM_AVERAGE 6
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -371,7 +359,6 @@ typedef
|
||||||
higher values can fix this -- in theory all higher values will have the same
|
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
|
speed (it is a shift value), but it mustn't be too high to prevent
|
||||||
overflow. */
|
overflow. */
|
||||||
|
|
||||||
#define S3L_FAST_LERP_QUALITY 11
|
#define S3L_FAST_LERP_QUALITY 11
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -524,7 +511,9 @@ void S3L_mat4Xmat4(S3L_Mat4 m1, S3L_Mat4 m2);
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
S3L_Unit focalLength; ///< Defines the field of view (FOV).
|
S3L_Unit focalLength; /**< Defines the field of view (FOV). 0 sets an
|
||||||
|
orthographics projection (scale is controlled
|
||||||
|
with camera's scale in its transform). */
|
||||||
S3L_Transform3D transform;
|
S3L_Transform3D transform;
|
||||||
} S3L_Camera;
|
} S3L_Camera;
|
||||||
|
|
||||||
|
@ -1669,6 +1658,9 @@ void S3L_transform3DInit(S3L_Transform3D *t)
|
||||||
static inline void S3L_perspectiveDivide(S3L_Vec4 *vector,
|
static inline void S3L_perspectiveDivide(S3L_Vec4 *vector,
|
||||||
S3L_Unit focalLength)
|
S3L_Unit focalLength)
|
||||||
{
|
{
|
||||||
|
if (focalLength == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
vector->x = (vector->x * focalLength) / vector->z;
|
vector->x = (vector->x * focalLength) / vector->z;
|
||||||
vector->y = (vector->y * focalLength) / vector->z;
|
vector->y = (vector->y * focalLength) / vector->z;
|
||||||
}
|
}
|
||||||
|
@ -1719,8 +1711,10 @@ void S3L_project3DPointToScreen(
|
||||||
result->w =
|
result->w =
|
||||||
(point.z <= 0) ? 0 :
|
(point.z <= 0) ? 0 :
|
||||||
(
|
(
|
||||||
|
camera.focalLength > 0 ?(
|
||||||
(s * camera.focalLength * S3L_RESOLUTION_X) /
|
(s * camera.focalLength * S3L_RESOLUTION_X) /
|
||||||
(point.z * S3L_F)
|
(point.z * S3L_F)) :
|
||||||
|
((camera.transform.scale.x * S3L_RESOLUTION_X) / S3L_F)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1945,10 +1939,8 @@ void S3L_newFrame(void)
|
||||||
S3L_stencilBufferClear();
|
S3L_stencilBufferClear();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/* the following serves to communicate info about if the triangle has been split
|
||||||
the following serves to communicate info about if the triangle has been split
|
and how the barycentrics should be remapped. */
|
||||||
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
|
#if S3L_NEAR_CROSS_STRATEGY == 3
|
||||||
|
@ -2585,7 +2577,15 @@ void S3L_makeCameraMatrix(S3L_Transform3D cameraTransform, S3L_Mat4 m)
|
||||||
|
|
||||||
S3L_mat4Transpose(r); // transposing creates an inverse transform
|
S3L_mat4Transpose(r); // transposing creates an inverse transform
|
||||||
|
|
||||||
|
S3L_Mat4 s;
|
||||||
|
|
||||||
|
S3L_makeScaleMatrix(
|
||||||
|
cameraTransform.scale.x,
|
||||||
|
cameraTransform.scale.y,
|
||||||
|
cameraTransform.scale.z,s);
|
||||||
|
|
||||||
S3L_mat4Xmat4(m,r);
|
S3L_mat4Xmat4(m,r);
|
||||||
|
S3L_mat4Xmat4(m,s);
|
||||||
}
|
}
|
||||||
|
|
||||||
int8_t S3L_triangleWinding(
|
int8_t S3L_triangleWinding(
|
||||||
|
@ -2603,11 +2603,9 @@ int8_t S3L_triangleWinding(
|
||||||
return winding > 0 ? 1 : (winding < 0 ? -1 : 0);
|
return winding > 0 ? 1 : (winding < 0 ? -1 : 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** Checks if given triangle (in Screen Space) is at least partially visible,
|
||||||
Checks if given triangle (in Screen Space) is at least partially visible,
|
|
||||||
i.e. returns false if the triangle is either completely outside the frustum
|
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.
|
(left, right, top, bottom, near) or is invisible due to backface culling. */
|
||||||
*/
|
|
||||||
static inline int8_t S3L_triangleIsVisible(
|
static inline int8_t S3L_triangleIsVisible(
|
||||||
S3L_Vec4 p0,
|
S3L_Vec4 p0,
|
||||||
S3L_Vec4 p1,
|
S3L_Vec4 p1,
|
||||||
|
@ -2658,12 +2656,8 @@ _S3L_TriangleToSort S3L_sortArray[S3L_MAX_TRIANGES_DRAWN];
|
||||||
uint16_t S3L_sortArrayLength;
|
uint16_t S3L_sortArrayLength;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void _S3L_projectVertex(
|
void _S3L_projectVertex(const S3L_Model3D *model, S3L_Index triangleIndex,
|
||||||
const S3L_Model3D *model,
|
uint8_t vertex, S3L_Mat4 projectionMatrix, S3L_Vec4 *result)
|
||||||
S3L_Index triangleIndex,
|
|
||||||
uint8_t vertex,
|
|
||||||
S3L_Mat4 projectionMatrix,
|
|
||||||
S3L_Vec4 *result)
|
|
||||||
{
|
{
|
||||||
uint32_t vertexIndex = model->triangles[triangleIndex * 3 + vertex] * 3;
|
uint32_t vertexIndex = model->triangles[triangleIndex * 3 + vertex] * 3;
|
||||||
|
|
||||||
|
@ -2696,12 +2690,10 @@ void _S3L_mapProjectedVertexToScreen(S3L_Vec4 *vertex, S3L_Unit focalLength)
|
||||||
vertex->y = sY;
|
vertex->y = sY;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** Projects a triangle to the screen. If enabled, a triangle can be potentially
|
||||||
Projects a triangle to the screen. If enabled, a triangle can be potentially
|
|
||||||
subdivided into two if it crosses the near plane, in which case two projected
|
subdivided into two if it crosses the near plane, in which case two projected
|
||||||
triangles are returned (the info about splitting or cutting the triangle is
|
triangles are returned (the info about splitting or cutting the triangle is
|
||||||
passed in global variables, see above).
|
passed in global variables, see above). */
|
||||||
*/
|
|
||||||
void _S3L_projectTriangle(
|
void _S3L_projectTriangle(
|
||||||
const S3L_Model3D *model,
|
const S3L_Model3D *model,
|
||||||
S3L_Index triangleIndex,
|
S3L_Index triangleIndex,
|
||||||
|
@ -2712,7 +2704,6 @@ void _S3L_projectTriangle(
|
||||||
_S3L_projectVertex(model,triangleIndex,0,matrix,&(transformed[0]));
|
_S3L_projectVertex(model,triangleIndex,0,matrix,&(transformed[0]));
|
||||||
_S3L_projectVertex(model,triangleIndex,1,matrix,&(transformed[1]));
|
_S3L_projectVertex(model,triangleIndex,1,matrix,&(transformed[1]));
|
||||||
_S3L_projectVertex(model,triangleIndex,2,matrix,&(transformed[2]));
|
_S3L_projectVertex(model,triangleIndex,2,matrix,&(transformed[2]));
|
||||||
|
|
||||||
_S3L_projectedTriangleState = 0;
|
_S3L_projectedTriangleState = 0;
|
||||||
|
|
||||||
#if S3L_NEAR_CROSS_STRATEGY == 2 || S3L_NEAR_CROSS_STRATEGY == 3
|
#if S3L_NEAR_CROSS_STRATEGY == 2 || S3L_NEAR_CROSS_STRATEGY == 3
|
||||||
|
@ -2999,7 +2990,6 @@ void S3L_drawScene(S3L_Scene scene)
|
||||||
S3L_drawTriangle(transformed[3],transformed[4],transformed[5],
|
S3L_drawTriangle(transformed[3],transformed[4],transformed[5],
|
||||||
modelIndex, triangleIndex);
|
modelIndex, triangleIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue