1
0
Fork 0
mirror of https://git.coom.tech/drummyfish/raycastlib.git synced 2024-11-23 20:49:57 +01:00

Update tests

This commit is contained in:
Miloslav Číž 2020-06-21 11:39:52 +02:00
parent 2d5df9fa58
commit 74af704656
5 changed files with 145 additions and 104 deletions

View file

@ -48,7 +48,16 @@ features
- **Pure C99**, tested to run as C++ as well.
- Optional framework **functions that handle the whole rendering**.
- Still **flexible** -- pixels are left for you to draw in any way you want.
- **Tested on multiple platforms** (PC, Arduboy, Pokitto, Gamebuino META).
- **Tested on multiple platforms**:
- PC (little endian, 64bit GNU)
- Emscripten (web browser, JavaScript transpile)
- Arduboy
- Pokitto
- Gamebuino META
- TODO:
- PowerPC emulator (big endian)
- Android
- Windows
- **Many compile-time options** to tune the performance vs quality.
- **Well commented** and formatted code. Automatic documentation (comments + provided Doxyfile).
- Completely **free of legal restrictions**, do literally anything you want.

99
programs/helloWorld.c Normal file
View file

@ -0,0 +1,99 @@
/*
Simple hello world for raycastlib. Renders a single raycasted frame into
terminal as ASCII.
author: Miloslav Ciz
license: CC0 1.0, public domain
*/
#define RCL_PIXEL_FUNCTION pixelFunc /* tell the library the name of our
function with which we write pixels to
the screen */
#define RCL_COMPUTE_FLOOR_DEPTH 0 /* turn off what we don't need, to help
performance */
#define RCL_COMPUTE_CEILING_DEPTH 0
#include "../raycastlib.h" // now include raycastlib itself
#include <stdio.h> // for IO
#define SCREEN_W 80
#define SCREEN_H 40
#define PIXELS_TOTAL ((SCREEN_W + 1) * SCREEN_H + 1)
char screen[(SCREEN_W + 1) * SCREEN_H + 1]; /* our ASCII screen, with extra
space for newlines and
terminating 0 */
/* Function that will tell the library height of square at each coordinates.
We may implement it however we like, it may e.g. read the height out of a
level array. Here we simply compute the height procedurally, without needing
extra data. */
RCL_Unit heightAt(int16_t x, int16_t y)
{
return (x < 0 || x > 10 || y < 0 || y > 10) ?
2 * RCL_UNITS_PER_SQUARE : // two library units, imagine e.g. 2 meters
0;
}
/* This is the function we write pixels to our ASCII screen with. Above we have
told the library it should call this function during rendering. */
void pixelFunc(RCL_PixelInfo *p)
{
char c = ' ';
if (p->isWall)
{
switch (p->hit.direction)
{
case 1:
case 2: c = '#'; break;
case 0:
case 3: c = '/'; break;
default: break;
}
}
else // floor/ceiling
c = p->isFloor ? '.' : ':';
screen[p->position.y * (SCREEN_W + 1) + p->position.x] = c;
}
int main()
{
for (int i = 0; i < PIXELS_TOTAL; ++i) // prefill screen with newlines
screen[i] = '\n';
screen[PIXELS_TOTAL - 1] = 0; // terminate the string
RCL_Camera camera; // camera to specify our view
RCL_initCamera(&camera);
// set up the camera:
camera.position.x = 5 * RCL_UNITS_PER_SQUARE;
camera.position.y = 6 * RCL_UNITS_PER_SQUARE;
camera.direction = 5 * RCL_UNITS_PER_SQUARE / 6; // 4/5 of full angle
camera.resolution.x = SCREEN_W;
camera.resolution.y = SCREEN_H;
RCL_RayConstraints constraints; /* this struct tell the library more
details about how it should cast
rays */
RCL_initRayConstraints(&constraints);
constraints.maxHits = 1; // we don't need more than 1 hit here
constraints.maxSteps = 40; // max squares a ray will travel
/* This will start the rendering itself. The library will start calling our
pixelFunc to render one frame. You can also try to use the complex
rendering function, the result should be practically the same:
RCL_renderComplex(camera,heightAt,0,0,constraints); */
RCL_renderSimple(camera,heightAt,0,0,constraints);
puts(screen); // print out the rendered frame
return 0; // done!
}

View file

@ -1,5 +1,8 @@
#!/bin/bash
PROGRAM=testSDL
if [ "$#" -ne 1 ]; then
echo "ERROR: expecting one argument, the name of program without extension (e.g. \"helloWorld\")"
exit 0
fi
clear; clear; g++ -x c -g -fmax-errors=5 -pedantic -Wall -Wextra -o $PROGRAM $PROGRAM.c -lSDL2 2>&1 >/dev/null && ./$PROGRAM
clear; clear; g++ -x c -g -fmax-errors=5 -pedantic -Wall -Wextra -o $1 $1.c -lSDL2 2>&1 >/dev/null && ./$1

View file

@ -154,7 +154,7 @@ int main()
camera.position.y += dy * 200;
camera.direction += dr * 10;
camera.height = RCL_UNITS_PER_SQUARE + RCL_sinInt(frame * 16) / 2;
camera.height = RCL_UNITS_PER_SQUARE + RCL_sin(frame * 16) / 2;
usleep(100000);

View file

@ -26,7 +26,7 @@
author: Miloslav "drummyfish" Ciz
license: CC0 1.0
version: 0.905
version: 0.906
*/
#include <stdint.h>
@ -364,13 +364,13 @@ Cos function.
@return RCL_normalized output in RCL_Units (from -RCL_UNITS_PER_SQUARE to
RCL_UNITS_PER_SQUARE)
*/
RCL_Unit RCL_cosInt(RCL_Unit input);
RCL_Unit RCL_cos(RCL_Unit input);
RCL_Unit RCL_sinInt(RCL_Unit input);
RCL_Unit RCL_sin(RCL_Unit input);
RCL_Unit RCL_tanInt(RCL_Unit input);
RCL_Unit RCL_tan(RCL_Unit input);
RCL_Unit RCL_ctgInt(RCL_Unit input);
RCL_Unit RCL_ctg(RCL_Unit input);
/// Normalizes given vector to have RCL_UNITS_PER_SQUARE length.
RCL_Vector2D RCL_normalize(RCL_Vector2D v);
@ -378,7 +378,7 @@ RCL_Vector2D RCL_normalize(RCL_Vector2D v);
/// Computes a cos of an angle between two vectors.
RCL_Unit RCL_vectorsAngleCos(RCL_Vector2D v1, RCL_Vector2D v2);
uint16_t RCL_sqrtInt(RCL_Unit value);
uint16_t RCL_sqrt(RCL_Unit value);
RCL_Unit RCL_dist(RCL_Vector2D p1, RCL_Vector2D p2);
RCL_Unit RCL_len(RCL_Vector2D v);
@ -514,50 +514,8 @@ int16_t _RCL_cameraHeightScreen = 0;
RCL_ArrayFunction _RCL_rollFunction = 0; // says door rolling
RCL_Unit *_RCL_floorPixelDistances = 0;
#ifdef RCL_PROFILE
// function call counters for profiling
uint32_t profile_RCL_sqrtInt = 0;
uint32_t profile_RCL_clamp = 0;
uint32_t profile_RCL_cosInt = 0;
uint32_t profile_RCL_angleToDirection = 0;
uint32_t profile_RCL_dist = 0;
uint32_t profile_RCL_len = 0;
uint32_t profile_RCL_pointIsLeftOfRay = 0;
uint32_t profile_RCL_castRayMultiHit = 0;
uint32_t profile_RCL_castRay = 0;
uint32_t profile_RCL_absVal = 0;
uint32_t profile_RCL_normalize = 0;
uint32_t profile_RCL_vectorsAngleCos = 0;
uint32_t profile_RCL_perspectiveScaleVertical = 0;
uint32_t profile_RCL_wrap = 0;
uint32_t profile_RCL_divRoundDown = 0;
#define RCL_profileCall(c) profile_##c += 1
#define printProfile() {\
printf("profile:\n");\
printf(" RCL_sqrtInt: %d\n",profile_RCL_sqrtInt);\
printf(" RCL_clamp: %d\n",profile_RCL_clamp);\
printf(" RCL_cosInt: %d\n",profile_RCL_cosInt);\
printf(" RCL_angleToDirection: %d\n",profile_RCL_angleToDirection);\
printf(" RCL_dist: %d\n",profile_RCL_dist);\
printf(" RCL_len: %d\n",profile_RCL_len);\
printf(" RCL_pointIsLeftOfRay: %d\n",profile_RCL_pointIsLeftOfRay);\
printf(" RCL_castRayMultiHit : %d\n",profile_RCL_castRayMultiHit);\
printf(" RCL_castRay: %d\n",profile_RCL_castRay);\
printf(" RCL_normalize: %d\n",profile_RCL_normalize);\
printf(" RCL_vectorsAngleCos: %d\n",profile_RCL_vectorsAngleCos);\
printf(" RCL_absVal: %d\n",profile_RCL_absVal);\
printf(" RCL_perspectiveScaleVertical: %d\n",profile_RCL_perspectiveScaleVertical);\
printf(" RCL_wrap: %d\n",profile_RCL_wrap);\
printf(" RCL_divRoundDown: %d\n",profile_RCL_divRoundDown); }
#else
#define RCL_profileCall(c)
#endif
RCL_Unit RCL_clamp(RCL_Unit value, RCL_Unit valueMin, RCL_Unit valueMax)
{
RCL_profileCall(RCL_clamp);
if (value >= valueMin)
{
if (value <= valueMax)
@ -569,17 +527,14 @@ RCL_Unit RCL_clamp(RCL_Unit value, RCL_Unit valueMin, RCL_Unit valueMax)
return valueMin;
}
static inline RCL_Unit RCL_absVal(RCL_Unit value)
static inline RCL_Unit RCL_abs(RCL_Unit value)
{
RCL_profileCall(RCL_absVal);
return value * (((value >= 0) << 1) - 1);
}
/// Like mod, but behaves differently for negative values.
static inline RCL_Unit RCL_wrap(RCL_Unit value, RCL_Unit mod)
{
RCL_profileCall(RCL_wrap);
RCL_Unit cmp = value < 0;
return cmp * mod + (value % mod) - cmp;
}
@ -587,8 +542,6 @@ static inline RCL_Unit RCL_wrap(RCL_Unit value, RCL_Unit mod)
/// Performs division, rounding down, NOT towards zero.
static inline RCL_Unit RCL_divRoundDown(RCL_Unit value, RCL_Unit divisor)
{
RCL_profileCall(RCL_divRoundDown);
return value / divisor - ((value >= 0) ? 0 : 1);
}
@ -628,10 +581,8 @@ const RCL_Unit cosLUT[128] =
};
#endif
RCL_Unit RCL_cosInt(RCL_Unit input)
RCL_Unit RCL_cos(RCL_Unit input)
{
RCL_profileCall(RCL_cosInt);
input = RCL_wrap(input,RCL_UNITS_PER_SQUARE);
#if RCL_USE_COS_LUT == 1
@ -658,37 +609,33 @@ RCL_Unit RCL_cosInt(RCL_Unit input)
#undef trigHelper
RCL_Unit RCL_sinInt(RCL_Unit input)
RCL_Unit RCL_sin(RCL_Unit input)
{
return RCL_cosInt(input - RCL_UNITS_PER_SQUARE / 4);
return RCL_cos(input - RCL_UNITS_PER_SQUARE / 4);
}
RCL_Unit RCL_tanInt(RCL_Unit input)
RCL_Unit RCL_tan(RCL_Unit input)
{
return (RCL_sinInt(input) * RCL_UNITS_PER_SQUARE) / RCL_cosInt(input);
return (RCL_sin(input) * RCL_UNITS_PER_SQUARE) / RCL_cos(input);
}
RCL_Unit RCL_ctgInt(RCL_Unit input)
RCL_Unit RCL_ctg(RCL_Unit input)
{
return (RCL_cosInt(input) * RCL_UNITS_PER_SQUARE) / RCL_sinInt(input);
return (RCL_cos(input) * RCL_UNITS_PER_SQUARE) / RCL_sin(input);
}
RCL_Vector2D RCL_angleToDirection(RCL_Unit angle)
{
RCL_profileCall(RCL_angleToDirection);
RCL_Vector2D result;
result.x = RCL_cosInt(angle);
result.y = -1 * RCL_sinInt(angle);
result.x = RCL_cos(angle);
result.y = -1 * RCL_sin(angle);
return result;
}
uint16_t RCL_sqrtInt(RCL_Unit value)
uint16_t RCL_sqrt(RCL_Unit value)
{
RCL_profileCall(RCL_sqrtInt);
#ifdef RCL_RAYCAST_TINY
uint16_t result = 0;
uint16_t a = value;
@ -719,16 +666,14 @@ uint16_t RCL_sqrtInt(RCL_Unit value)
RCL_Unit RCL_dist(RCL_Vector2D p1, RCL_Vector2D p2)
{
RCL_profileCall(RCL_dist);
RCL_Unit dx = p2.x - p1.x;
RCL_Unit dy = p2.y - p1.y;
#if RCL_USE_DIST_APPROX == 2
// octagonal approximation
dx = RCL_absVal(dx);
dy = RCL_absVal(dy);
dx = RCL_abs(dx);
dy = RCL_abs(dy);
return dy > dx ? dx / 2 + dy : dy / 2 + dx;
#elif RCL_USE_DIST_APPROX == 1
@ -760,14 +705,12 @@ RCL_Unit RCL_dist(RCL_Vector2D p1, RCL_Vector2D p2)
dx = dx * dx;
dy = dy * dy;
return RCL_sqrtInt((RCL_Unit) (dx + dy));
return RCL_sqrt((RCL_Unit) (dx + dy));
#endif
}
RCL_Unit RCL_len(RCL_Vector2D v)
{
RCL_profileCall(RCL_len);
RCL_Vector2D zero;
zero.x = 0;
zero.y = 0;
@ -777,8 +720,6 @@ RCL_Unit RCL_len(RCL_Vector2D v)
static inline int8_t RCL_pointIsLeftOfRay(RCL_Vector2D point, RCL_Ray ray)
{
RCL_profileCall(RCL_pointIsLeftOfRay);
RCL_Unit dX = point.x - ray.start.x;
RCL_Unit dY = point.y - ray.start.y;
return (ray.direction.x * dY - ray.direction.y * dX) > 0;
@ -789,8 +730,6 @@ void RCL_castRayMultiHit(RCL_Ray ray, RCL_ArrayFunction arrayFunc,
RCL_ArrayFunction typeFunc, RCL_HitResult *hitResults,
uint16_t *hitResultsLen, RCL_RayConstraints constraints)
{
RCL_profileCall(RCL_castRayMultiHit);
RCL_Vector2D currentPos = ray.start;
RCL_Vector2D currentSquare;
@ -812,8 +751,8 @@ void RCL_castRayMultiHit(RCL_Ray ray, RCL_ArrayFunction arrayFunc,
RCL_Unit dirVecLengthNorm = RCL_len(ray.direction) * RCL_UNITS_PER_SQUARE;
delta.x = RCL_absVal(dirVecLengthNorm / RCL_nonZero(ray.direction.x));
delta.y = RCL_absVal(dirVecLengthNorm / RCL_nonZero(ray.direction.y));
delta.x = RCL_abs(dirVecLengthNorm / RCL_nonZero(ray.direction.x));
delta.y = RCL_abs(dirVecLengthNorm / RCL_nonZero(ray.direction.y));
// init DDA
@ -991,8 +930,6 @@ void RCL_castRayMultiHit(RCL_Ray ray, RCL_ArrayFunction arrayFunc,
RCL_HitResult RCL_castRay(RCL_Ray ray, RCL_ArrayFunction arrayFunc)
{
RCL_profileCall(RCL_castRay);
RCL_HitResult result;
uint16_t RCL_len;
RCL_RayConstraints c;
@ -1021,7 +958,7 @@ void RCL_castRaysMultiHit(RCL_Camera cam, RCL_ArrayFunction arrayFunc,
/* We scale the side distances so that the middle one is
RCL_UNITS_PER_SQUARE, which has to be this way. */
RCL_Unit cos = RCL_nonZero(RCL_cosInt(RCL_HORIZONTAL_FOV_HALF));
RCL_Unit cos = RCL_nonZero(RCL_cos(RCL_HORIZONTAL_FOV_HALF));
dir1.x = (dir1.x * RCL_UNITS_PER_SQUARE) / cos;
dir1.y = (dir1.y * RCL_UNITS_PER_SQUARE) / cos;
@ -1139,7 +1076,7 @@ static inline int16_t _RCL_drawHorizontalColumn(
{\
if (doDepth) /*constant condition - compiler should optimize it out*/\
{\
depth = pixelInfo->depth + RCL_absVal(verticalOffset) *\
depth = pixelInfo->depth + RCL_abs(verticalOffset) *\
RCL_VERTICAL_DEPTH_MULTIPLY;\
depthIncrement = depthIncrementMultiplier *\
_RCL_horizontalDepthStep;\
@ -1207,15 +1144,15 @@ static inline int16_t _RCL_drawWall(
{
_RCL_UNUSED(height)
height = RCL_absVal(height);
height = RCL_abs(height);
pixelInfo->isWall = 1;
RCL_Unit limit = RCL_clamp(yTo,limit1,limit2);
RCL_Unit wallLength = RCL_nonZero(RCL_absVal(yTo - yFrom - 1));
RCL_Unit wallLength = RCL_nonZero(RCL_abs(yTo - yFrom - 1));
RCL_Unit wallPosition = RCL_absVal(yFrom - yCurrent) - increment;
RCL_Unit wallPosition = RCL_abs(yFrom - yCurrent) - increment;
RCL_Unit heightScaled = height * RCL_TEXTURE_INTERPOLATION_SCALE;
_RCL_UNUSED(heightScaled);
@ -1459,7 +1396,6 @@ void _RCL_columnFunctionSimple(RCL_HitResult *hits, uint16_t hitCount,
RCL_Unit y = 0;
RCL_Unit wallHeightScreen = 0;
RCL_Unit wallStart = _RCL_middleRow;
RCL_Unit heightOffset = 0;
RCL_Unit dist = 1;
@ -1613,7 +1549,7 @@ static inline void _RCL_precomputeFloorDistances(RCL_Camera camera,
for (uint16_t i = startIndex; i < camera.resolution.y; ++i)
dest[i] = RCL_perspectiveScaleVerticalInverse(camHeightScreenSize,
RCL_absVal(i - _RCL_middleRow));
RCL_abs(i - _RCL_middleRow));
}
void RCL_renderComplex(RCL_Camera cam, RCL_ArrayFunction floorHeightFunc,
@ -1692,8 +1628,6 @@ void RCL_renderSimple(RCL_Camera cam, RCL_ArrayFunction floorHeightFunc,
RCL_Vector2D RCL_normalize(RCL_Vector2D v)
{
RCL_profileCall(RCL_normalize);
RCL_Vector2D result;
RCL_Unit l = RCL_len(v);
l = RCL_nonZero(l);
@ -1706,8 +1640,6 @@ RCL_Vector2D RCL_normalize(RCL_Vector2D v)
RCL_Unit RCL_vectorsAngleCos(RCL_Vector2D v1, RCL_Vector2D v2)
{
RCL_profileCall(RCL_vectorsAngleCos);
v1 = RCL_normalize(v1);
v2 = RCL_normalize(v2);
@ -1728,8 +1660,8 @@ RCL_PixelInfo RCL_mapToScreen(RCL_Vector2D worldPosition, RCL_Unit height,
// rotate the point to camera space (y left/right, x forw/backw)
RCL_Unit cos = RCL_cosInt(camera.direction);
RCL_Unit sin = RCL_sinInt(camera.direction);
RCL_Unit cos = RCL_cos(camera.direction);
RCL_Unit sin = RCL_sin(camera.direction);
RCL_Unit tmp = toPoint.x;
@ -1757,8 +1689,6 @@ RCL_Unit RCL_degreesToUnitsAngle(int16_t degrees)
RCL_Unit RCL_perspectiveScaleVertical(RCL_Unit originalSize, RCL_Unit distance)
{
RCL_profileCall(RCL_perspectiveScaleVertical);
return distance != 0 ?
(originalSize * RCL_UNITS_PER_SQUARE) /
((RCL_VERTICAL_FOV_TAN * 2 * distance) / RCL_UNITS_PER_SQUARE)