mirror of
https://git.coom.tech/drummyfish/raycastlib.git
synced 2024-11-21 20:29:59 +01:00
Add tests
This commit is contained in:
parent
879326c3db
commit
b7d9db3edf
1 changed files with 122 additions and 24 deletions
144
raycastlib.c
144
raycastlib.c
|
@ -14,14 +14,14 @@
|
||||||
|
|
||||||
#define UNITS_PER_SQUARE 1024
|
#define UNITS_PER_SQUARE 1024
|
||||||
|
|
||||||
typedef int64_t Unit; /**< Smallest spatial unit, there is UNITS_PER_SQUARE
|
typedef int32_t Unit; /**< Smallest spatial unit, there is UNITS_PER_SQUARE
|
||||||
units in a square's length. */
|
units in a square's length. */
|
||||||
|
|
||||||
/// Position in 2D space.
|
/// Position in 2D space.
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
Unit y;
|
int32_t y;
|
||||||
Unit x;
|
int32_t x;
|
||||||
} Vector2D;
|
} Vector2D;
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
|
@ -36,19 +36,70 @@ typedef struct
|
||||||
Vector2D position; ///< Exact collision position in Units.
|
Vector2D position; ///< Exact collision position in Units.
|
||||||
Unit distance; /**< Euclidean distance to the hit position, or -1 if
|
Unit distance; /**< Euclidean distance to the hit position, or -1 if
|
||||||
no collision happened. */
|
no collision happened. */
|
||||||
|
Unit textureCoord; /**< Normalized (0 to UNITS_PER_SQUARE - 1) texture
|
||||||
|
coordinate. */
|
||||||
} HitResult;
|
} HitResult;
|
||||||
|
|
||||||
HitResult castRay(Ray ray, int (*collisionFunc)(int, int),
|
|
||||||
unsigned int maxSteps);
|
/**
|
||||||
|
Casts a single ray and returns the first collision result.
|
||||||
|
|
||||||
|
@param Ray Ray to be cast.
|
||||||
|
@param arrayFunc Function that for x and y array coordinates (in squares, NOT
|
||||||
|
Units) returns a type of square (just a number) - transition
|
||||||
|
between two squares of different types (values) is considered
|
||||||
|
a collision).
|
||||||
|
@param maxSteps Maximum number of steps (in squares) to trace the ray.
|
||||||
|
@return The first collision result.
|
||||||
|
*/
|
||||||
|
|
||||||
|
HitResult castRay(Ray ray, int16_t (*arrayFunc)(int16_t, int16_t),
|
||||||
|
uint16_t maxSteps);
|
||||||
|
|
||||||
//=============================================================================
|
//=============================================================================
|
||||||
// privates
|
// privates
|
||||||
|
|
||||||
#define logVector2D(v) printf("[%d,%d]\n",v.x,v.y)
|
#define logVector2D(v) printf("[%d,%d]\n",v.x,v.y)
|
||||||
#define logRay(r) printf("{\n");\
|
#define logRay(r) printf("ray:\n");\
|
||||||
logVector2D(r.start);\
|
printf(" start: "); logVector2D(r.start);\
|
||||||
logVector2D(r.direction);\
|
printf(" dir: "); logVector2D(r.direction);
|
||||||
printf("}\n");
|
#define logHitResult(h) printf("hit:\n");\
|
||||||
|
printf(" sqaure: "); logVector2D(h.square);\
|
||||||
|
printf(" pos: "); logVector2D(h.position);\
|
||||||
|
printf(" dist: %d", h.distance);\
|
||||||
|
printf(" texcoord: %d", h.textureCoord);
|
||||||
|
|
||||||
|
uint16_t sqrtInt(uint32_t value)
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
b >>= 2;
|
||||||
|
result >>= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
Unit dist(Vector2D p1, Vector2D p2)
|
||||||
|
{
|
||||||
|
Unit dx = p2.x - p1.x;
|
||||||
|
Unit dy = p2.y - p1.y;
|
||||||
|
return sqrtInt(((uint16_t) dx * dx) + ((uint16_t) dy * dy));
|
||||||
|
}
|
||||||
|
|
||||||
int8_t pointIsLeftOfRay(Vector2D point, Ray ray)
|
int8_t pointIsLeftOfRay(Vector2D point, Ray ray)
|
||||||
{
|
{
|
||||||
|
@ -123,18 +174,30 @@ void castRaySquare(Ray localRay, Vector2D *nextCellOffset,
|
||||||
#undef helper
|
#undef helper
|
||||||
}
|
}
|
||||||
|
|
||||||
HitResult castRay(Ray ray, int (*collisionFunc)(int, int),
|
HitResult castRay(Ray ray, int16_t (*arrayFunc)(int16_t, int16_t),
|
||||||
unsigned int maxSteps)
|
uint16_t maxSteps)
|
||||||
{
|
{
|
||||||
HitResult result;
|
HitResult result;
|
||||||
|
|
||||||
|
Vector2D initialPos = ray.start;
|
||||||
|
|
||||||
result.distance = -1;
|
result.distance = -1;
|
||||||
result.square.x = ray.start.x / UNITS_PER_SQUARE;
|
result.square.x = ray.start.x / UNITS_PER_SQUARE;
|
||||||
result.square.y = ray.start.y / UNITS_PER_SQUARE;
|
result.square.y = ray.start.y / UNITS_PER_SQUARE;
|
||||||
result.position = ray.start;
|
result.position = ray.start;
|
||||||
|
|
||||||
|
int16_t squareType = arrayFunc(result.square.x,result.square.y);
|
||||||
|
|
||||||
for (uint16_t i = 0; i < maxSteps; ++i)
|
for (uint16_t i = 0; i < maxSteps; ++i)
|
||||||
{
|
{
|
||||||
|
if (arrayFunc(result.square.x,result.square.y) != squareType)
|
||||||
|
{
|
||||||
|
result.distance = dist(initialPos,result.position);
|
||||||
|
//result.textureCoord =
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
ray.start.x = result.position.x % UNITS_PER_SQUARE;
|
ray.start.x = result.position.x % UNITS_PER_SQUARE;
|
||||||
ray.start.y = result.position.y % UNITS_PER_SQUARE;
|
ray.start.y = result.position.y % UNITS_PER_SQUARE;
|
||||||
|
|
||||||
|
@ -152,23 +215,58 @@ HitResult castRay(Ray ray, int (*collisionFunc)(int, int),
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
int aaa(int x, int y)
|
int16_t testArrayFunc(int16_t x, int16_t y)
|
||||||
{
|
{
|
||||||
return (x < 0 || y < 0 || x > 10 || y > 10) ? 1 : 0;
|
return (x < 0 || y < 0 || x > 9 || y > 9) ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Simple automatic test function.
|
||||||
|
*/
|
||||||
|
|
||||||
|
int testSingleRay(Unit startX, Unit startY, Unit dirX, Unit dirY,
|
||||||
|
int16_t expectSquareX, int16_t expectSquareY, int16_t expectPointX,
|
||||||
|
int16_t expectPointY, int16_t tolerateError)
|
||||||
|
{
|
||||||
|
Ray r;
|
||||||
|
|
||||||
|
r.start.x = startX;
|
||||||
|
r.start.y = startY;
|
||||||
|
r.direction.x = dirX;
|
||||||
|
r.direction.y = dirY;
|
||||||
|
|
||||||
|
HitResult h = castRay(r,testArrayFunc,20);
|
||||||
|
|
||||||
|
return
|
||||||
|
h.square.x == expectSquareX &&
|
||||||
|
h.square.y == expectSquareY &&
|
||||||
|
h.position.x <= expectPointX + tolerateError &&
|
||||||
|
h.position.x >= expectPointX - tolerateError &&
|
||||||
|
h.position.y <= expectPointY + tolerateError &&
|
||||||
|
h.position.y >= expectPointY - tolerateError;
|
||||||
|
}
|
||||||
|
|
||||||
|
int test()
|
||||||
|
{
|
||||||
|
if (!testSingleRay(
|
||||||
|
3 * UNITS_PER_SQUARE + UNITS_PER_SQUARE / 2,
|
||||||
|
4 * UNITS_PER_SQUARE + UNITS_PER_SQUARE / 2,
|
||||||
|
100, 50,
|
||||||
|
10, 7,
|
||||||
|
10240, 7936,
|
||||||
|
16))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int main()
|
int main()
|
||||||
{
|
{
|
||||||
Ray r;
|
printf("%d\n",test());
|
||||||
|
|
||||||
r.start.x = 4 * UNITS_PER_SQUARE + UNITS_PER_SQUARE / 2;
|
|
||||||
r.start.y = 4 * UNITS_PER_SQUARE + UNITS_PER_SQUARE / 2;
|
|
||||||
r.direction.x = 100;
|
|
||||||
r.direction.y = 50;
|
|
||||||
|
|
||||||
logRay(r);
|
|
||||||
|
|
||||||
castRay(r,aaa,10);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#undef logVector2D
|
||||||
|
#undef logRay
|
||||||
|
#undef logHitResult
|
||||||
|
|
Loading…
Reference in a new issue