Suspiciously everything worked when changing to floats

This commit is contained in:
2025-08-10 09:00:00 -05:00
parent 24fcf87fb4
commit 26ecf67472
18 changed files with 817 additions and 863 deletions

2
.gitignore vendored
View File

@@ -92,6 +92,6 @@ assets/borrowed
/archive0 /archive0
/archive1 /archive1
/archive # /archive
__pycache__ __pycache__

257
archive/fixed.c Normal file
View File

@@ -0,0 +1,257 @@
/**
* Copyright (c) 2025 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "fixed.h"
#include "assert/assert.h"
float_t fx248Fromi32(const int32_t b) {
return (float_t)b << FIXED248_FRACTION_BITS;
}
float_t fx248Fromu32(const uint32_t b) {
return (float_t)((int32_t)b << FIXED248_FRACTION_BITS);
}
float_t fx248Fromf32(const float_t b) {
return (float_t)(b * (1 << FIXED248_FRACTION_BITS));
}
float_t fx248Fromu16(const uint16_t b) {
return (float_t)((int32_t)b << FIXED248_FRACTION_BITS);
}
float_t fx248Fromu8(const uint8_t b) {
return (float_t)((int32_t)b << FIXED248_FRACTION_BITS);
}
int32_t fx248Toi32(const float_t a) {
return a >> FIXED248_FRACTION_BITS;
}
uint32_t fx248Tou32(const float_t a) {
return (uint32_t)(a >> FIXED248_FRACTION_BITS);
}
float_t fx248Tof32(const float_t a) {
return (float_t)a / (1 << FIXED248_FRACTION_BITS);
}
uint16_t fx248Tou16(const float_t a) {
return (uint16_t)(a >> FIXED248_FRACTION_BITS);
}
uint8_t fx248Tou8(const float_t a) {
return (uint8_t)(a >> FIXED248_FRACTION_BITS);
}
float_t fx248Addfx248(const float_t a, const float_t b) {
return a + b;
}
float_t fx248Addi32(const float_t a, const int32_t b) {
return fx248Addfx248(a, fx248Fromi32(b));
}
float_t fx248Addu32(const float_t a, const uint32_t b) {
return fx248Addfx248(a, fx248Fromu32(b));
}
float_t fx248Addf32(const float_t a, const float_t b) {
return fx248Addfx248(a, fx248Fromf32(b));
}
float_t fx248Subfx248(const float_t a, const float_t b) {
return a - b;
}
float_t fx248Subi32(const float_t a, const int32_t b) {
return fx248Subfx248(a, fx248Fromi32(b));
}
float_t fx248Subu32(const float_t a, const uint32_t b) {
return fx248Subfx248(a, fx248Fromu32(b));
}
float_t fx248Subf32(const float_t a, const float_t b) {
return fx248Subfx248(a, fx248Fromf32(b));
}
float_t fx248Mulfx248(const float_t a, const float_t b) {
return (float_t)(((int64_t)a * (int64_t)b) >> FIXED248_FRACTION_BITS);
}
float_t fx248Muli32(const float_t a, const int32_t b) {
return (float_t)(((int64_t)a * (int64_t)b) >> FIXED248_FRACTION_BITS);
}
float_t fx248Mulu32(const float_t a, const uint32_t b) {
return (float_t)(
((int64_t)a * (int64_t)(int32_t)b
) >> FIXED248_FRACTION_BITS);
}
float_t fx248Mulf32(const float_t a, const float_t b) {
return (float_t)((
(int64_t)a * (int64_t)(b * (1 << FIXED248_FRACTION_BITS))
) >> FIXED248_FRACTION_BITS);
}
float_t fx248Divfx248(const float_t a, const float_t b) {
assertFalse(b == 0, "Division by zero in fx248Divfx248");
return (float_t)(((int64_t)a << FIXED248_FRACTION_BITS) / (int64_t)b);
}
float_t fx248Divi32(const float_t a, const int32_t b) {
assertFalse(b == 0, "Division by zero in fx248Divi32");
return (float_t)(((int64_t)a << FIXED248_FRACTION_BITS) / (int64_t)b);
}
float_t fx248Divu32(const float_t a, const uint32_t b) {
assertFalse(b == 0, "Division by zero in fx248Divu32");
return (float_t)(
((int64_t)a << FIXED248_FRACTION_BITS
) / (int64_t)(int32_t)b);
}
float_t fx248Divf32(const float_t a, const float_t b) {
assertFalse(b == 0, "Division by zero in fx248Divf32");
return (float_t)((
(int64_t)a << FIXED248_FRACTION_BITS
) / (int64_t)(b * (1 << FIXED248_FRACTION_BITS)));
}
float_t fx248Floor(const float_t a) {
return a & ~((1 << FIXED248_FRACTION_BITS) - 1);
}
float_t fx248Ceil(const float_t a) {
if(a & ((1 << FIXED248_FRACTION_BITS) - 1)) {
return (a & ~((1 << FIXED248_FRACTION_BITS) - 1)) + (1 << FIXED248_FRACTION_BITS);
}
return a;
}
float_t fx248Round(const float_t a) {
if(a & ((1 << (FIXED248_FRACTION_BITS - 1)) - 1)) {
return (a & ~((1 << FIXED248_FRACTION_BITS) - 1)) + (1 << FIXED248_FRACTION_BITS);
}
return a & ~((1 << FIXED248_FRACTION_BITS) - 1);
}
uint32_t fx248Flooru32(const float_t a) {
return (uint32_t)((a >> FIXED248_FRACTION_BITS) & 0xFFFFFFFF);
}
uint32_t fx248Ceilu32(const float_t a) {
return (uint32_t)(((a + ((1 << FIXED248_FRACTION_BITS) - 1)) >> FIXED248_FRACTION_BITS) & 0xFFFFFFFF);
}
uint32_t fx248Roundu32(const float_t a) {
return (uint32_t)(((a + (1 << (FIXED248_FRACTION_BITS - 1))) >> FIXED248_FRACTION_BITS) & 0xFFFFFFFF);
}
float_t fx248Sqrt(const float_t a) {
if(a == 0) return 0;
float_t y = a > FIXED248(1, 0) ? a : FIXED248(1, 0);
float_t last = 0;
int max_iter = 16;
while(y != last && max_iter-- > 0) {
last = y;
int32_t div = (int32_t)(((int64_t)a << FIXED248_FRACTION_BITS) / y);
y = (y + div) >> 1;
}
return y;
}
float_t fx248Max(const float_t a, const float_t b) {
return (a > b) ? a : b;
}
float_t fx248Min(const float_t a, const float_t b) {
return (a < b) ? a : b;
}
float_t fx248Clamp(
const float_t a,
const float_t min,
const float_t max
) {
return (a < min) ? min : (a > max) ? max : a;
}
float_t fx248Abs(const float_t a) {
return (a < 0) ? -a : a;
}
float_t fx248Atan2(
const float_t y,
const float_t x
) {
// Handle special cases
if (x == 0) {
if (y > 0) return FX248_HALF_PI;
if (y < 0) return -FX248_HALF_PI;
return 0;
}
// Use absolute values for quadrant correction
float_t abs_y = y;
if (abs_y < 0) abs_y = -abs_y;
float_t angle;
if (abs_y < fx248Abs(x)) {
float_t z = fx248Divfx248(y, x);
float_t z2 = fx248Mulfx248(z, z);
float_t z3 = fx248Mulfx248(z2, z);
float_t z5 = fx248Mulfx248(z3, z2);
angle = fx248Subfx248(
fx248Addfx248(z, fx248Divfx248(z5, fx248Fromi32(5))),
fx248Divfx248(z3, fx248Fromi32(3))
);
if (x < 0) {
if (y < 0) {
angle -= FX248_PI;
} else {
angle += FX248_PI;
}
}
} else {
float_t z = fx248Divfx248(x, y);
float_t z2 = fx248Mulfx248(z, z);
float_t z3 = fx248Mulfx248(z2, z);
float_t z5 = fx248Mulfx248(z3, z2);
angle = fx248Subfx248(
fx248Addfx248(z, fx248Divfx248(z5, fx248Fromi32(5))),
fx248Divfx248(z3, fx248Fromi32(3))
);
if (y > 0) {
angle = FX248_HALF_PI - angle;
} else {
angle = -FX248_HALF_PI - angle;
}
}
return angle;
}

379
archive/fixed.h Normal file
View File

@@ -0,0 +1,379 @@
/**
* Copyright (c) 2025 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "dusk.h"
typedef int32_t float_t;
#define FIXED248_FRACTION_BITS 8
#define FIXED248_HIGH_MULTIPLIER (1 << FIXED248_FRACTION_BITS)
#define FIXED248_MIN INT32_MIN
#define FIXED248_MAX INT32_MAX
#define FIXED248(i, f) ((float_t)( \
((i) << FIXED248_FRACTION_BITS) + \
(((f) * FIXED248_HIGH_MULTIPLIER) / 100) \
))
#define FIXED248_ONE (FIXED248(1, 0))
#define FIXED248_ZERO (FIXED248(0, 0))
#define FX248_PI 804
#define FX248_HALF_PI 402
#define FX248_3PI_4 603
#define FX248_NEG_PI -804
/**
* Convert an int32_t value to a float_t value.
*
* @param b The int32_t value to convert.
* @return The converted float_t value.
*/
float_t fx248Fromi32(const int32_t b);
/**
* Convert a uint32_t value to a float_t value.
*
* @param b The uint32_t value to convert.
* @return The converted float_t value.
*/
float_t fx248Fromu32(const uint32_t b);
/**
* Convert a float_t value to a float_t value.
*
* @param b The float_t value to convert.
* @return The converted float_t value.
*/
float_t fx248Fromf32(const float_t b);
/**
* Convert a uint16_t value to a float_t value.
*
* @param b The uint16_t value to convert.
* @return The converted float_t value.
*/
float_t fx248Fromu16(const uint16_t b);
/**
* Convert a uint8_t value to a float_t value.
*
* @param b The uint8_t value to convert.
* @return The converted float_t value.
*/
float_t fx248Fromu8(const uint8_t b);
/**
* Convert a float_t value to an int32_t value.
*
* @param a The float_t value to convert.
* @return The converted int32_t value.
*/
int32_t fx248Toi32(const float_t a);
/**
* Convert a float_t value to a uint32_t value.
*
* @param a The float_t value to convert.
* @return The converted uint32_t value.
*/
uint32_t fx248Tou32(const float_t a);
/**
* Convert a float_t value to a float_t value.
*
* @param a The float_t value to convert.
* @return The converted float_t value.
*/
float_t fx248Tof32(const float_t a);
/**
* Convert a float_t value to a uint16_t value.
*
* @param a The float_t value to convert.
* @return The converted uint16_t value.
*/
uint16_t fx248Tou16(const float_t a);
/**
* Convert a float_t value to an uint8_t value.
*
* @param a The float_t value to convert.
* @return The converted uint8_t value.
*/
uint8_t fx248Tou8(const float_t a);
/**
* Add a float_t value to another float_t value.
*
* @param a First float_t value.
* @param b Second float_t value to add to the first value.
* @return The result of the addition as a float_t value.
*/
float_t fx248Addfx248(const float_t a, const float_t b);
/**
* Add an int32_t value to a float_t value.
*
* @param a The float_t value to which the int32_t will be added.
* @param b The int32_t value to add to the float_t value.
* @return The result of the addition as a float_t value.
*/
float_t fx248Addi32(const float_t a, const int32_t b);
/**
* Add a uint32_t value to a float_t value.
*
* @param a The float_t value to which the uint32_t will be added.
* @param b The uint32_t value to add to the float_t value.
* @return The result of the addition as a float_t value.
*/
float_t fx248Addu32(const float_t a, const uint32_t b);
/**
* Add a float_t value to a float_t value.
*
* @param a Pointer to the float_t value (will be modified).
* @param b The float_t value to add to the float_t value.
* @return The result of the addition as a float_t value.
*/
float_t fx248Addf32(const float_t a, const float_t b);
/**
* Subtract a float_t value from another float_t value.
*
* @param a First float_t value.
* @param b The float_t value to subtract from the first value.
* @return The result of the subtraction as a float_t value.
*/
float_t fx248Subfx248(const float_t a, const float_t b);
/**
* Subtract an int32_t value from a float_t value.
*
* @param a The float_t value from which the int32_t will be subtracted.
* @param b The int32_t value to subtract from the float_t value.
* @return The result of the subtraction as a float_t value.
*/
float_t fx248Subi32(const float_t a, const int32_t b);
/**
* Subtract a uint32_t value from a float_t value.
*
* @param a The float_t value from which the uint32_t will be subtracted.
* @param b The uint32_t value to subtract from the float_t value.
* @return The result of the subtraction as a float_t value.
*/
float_t fx248Subu32(const float_t a, const uint32_t b);
/**
* Subtract a float_t value from a float_t value.
*
* @param a The float_t value from which the float_t will be subtracted.
* @param b The float_t value to subtract from the float_t value.
* @return The result of the subtraction as a float_t value.
*/
float_t fx248Subf32(const float_t a, const float_t b);
/**
* Multiply two float_t values.
*
* @param a First float_t value.
* @param b Second float_t value to multiply with the first value.
* @return The result of the multiplication as a float_t value.
*/
float_t fx248Mulfx248(const float_t a, const float_t b);
/**
* Multiply a float_t value by an int32_t value.
*
* @param a The float_t value to multiply.
* @param b The int32_t value to multiply with the float_t value.
* @return The result of the multiplication as a float_t value.
*/
float_t fx248Muli32(const float_t a, const int32_t b);
/**
* Multiply a float_t value by a uint32_t value.
*
* @param a The float_t value to multiply.
* @param b The uint32_t value to multiply with the float_t value.
* @return The result of the multiplication as a float_t value.
*/
float_t fx248Mulu32(const float_t a, const uint32_t b);
/**
* Multiply a float_t value by a float_t value.
*
* @param a The float_t value to multiply.
* @param b The float_t value to multiply with the float_t value.
* @return The result of the multiplication as a float_t value.
*/
float_t fx248Mulf32(const float_t a, const float_t b);
/**
* Divide two float_t values.
*
* @param a The float_t value to be divided.
* @param b The float_t value to divide by.
* @return The result of the division as a float_t value.
*/
float_t fx248Divfx248(const float_t a, const float_t b);
/**
* Divide a float_t value by an int32_t value.
*
* @param a The float_t value to be divided.
* @param b The int32_t value to divide by.
* @return The result of the division as a float_t value.
*/
float_t fx248Divi32(const float_t a, const int32_t b);
/**
* Divide a float_t value by a uint32_t value.
*
* @param a The float_t value to be divided.
* @param b The uint32_t value to divide by.
* @return The result of the division as a float_t value.
*/
float_t fx248Divu32(const float_t a, const uint32_t b);
/**
* Divide a float_t value by a float_t value.
*
* @param a The float_t value to be divided.
* @param b The float_t value to divide by.
* @return The result of the division as a float_t value.
*/
float_t fx248Divf32(const float_t a, const float_t b);
/**
* Convert a float_t value to an int32_t value, rounding towards zero.
*
* @param a The float_t value to convert.
* @return The converted int32_t value.
*/
float_t fx248Floor(const float_t a);
/**
* Convert a float_t value to an int32_t value, rounding towards positive
* infinity.
*
* @param a The float_t value to convert.
* @return The converted int32_t value.
*/
float_t fx248Ceil(const float_t a);
/**
* Convert a float_t value to an int32_t value, rounding to the nearest
* integer.
*
* @param a The float_t value to convert.
* @return The converted int32_t value.
*/
float_t fx248Round(const float_t a);
/**
* Convert a float_t value to a uint32_t value, rounding towards zero.
*
* @param a The float_t value to convert.
* @return The converted uint32_t value.
*/
uint32_t fx248Flooru32(const float_t a);
/**
* Convert a float_t value to a uint32_t value, rounding towards positive
* infinity.
*
* @param a The float_t value to convert.
* @return The converted uint32_t value.
*/
uint32_t fx248Ceilu32(const float_t a);
/**
* Convert a float_t value to a uint32_t value, rounding to the nearest
* integer.
*
* @param a The float_t value to convert.
* @return The converted uint32_t value.
*/
uint32_t fx248Roundu32(const float_t a);
/**
* Returns the square root of a float_t value.
*
* @param a The float_t value to calculate the square root of.
*/
float_t fx248Sqrt(const float_t a);
/**
* Returns the maximum of two float_t values.
*
* @param a First float_t value.
* @param b Second float_t value.
* @return The maximum of the two values.
*/
float_t fx248Max(const float_t a, const float_t b);
/**
* Returns the minimum of two float_t values.
*
* @param a First float_t value.
* @param b Second float_t value.
* @return The minimum of the two values.
*/
float_t fx248Min(const float_t a, const float_t b);
/**
* Clamp a float_t value between a minimum and maximum value.
*
* @param a The float_t value to clamp.
* @param min The minimum value to clamp to.
* @param max The maximum value to clamp to.
* @return The clamped float_t value.
*/
float_t fx248Clamp(
const float_t a,
const float_t min,
const float_t max
);
/**
* Returns the absolute value of a float_t value.
*
* @param a The float_t value to calculate the absolute value of.
* @return The absolute value as a float_t value.
*/
float_t fx248Abs(const float_t a);
/**
* Calculate the arctangent of a float_t value.
*
* @param y Y coordinate value.
* @param x X coordinate value.
* @return The arctangent of the value as a float_t value.
*/
float_t fx248Atan2(
const float_t y,
const float_t x
);

View File

@@ -15,6 +15,7 @@
#include <errno.h> #include <errno.h>
#include <ctype.h> #include <ctype.h>
#include <stdarg.h> #include <stdarg.h>
#include <float.h>
typedef bool bool_t; typedef bool bool_t;
typedef int int_t; typedef int int_t;

View File

@@ -61,40 +61,29 @@ void entityUpdate(entity_t *entity) {
ENTITY_CALLBACKS[entity->type].update(entity); ENTITY_CALLBACKS[entity->type].update(entity);
if( if(entity->vx == 0.0f && entity->vy == 0.0f) return;
entity->vx == FIXED248(0, 0) &&
entity->vy == FIXED248(0, 0)
) return;
fixed248_t newX = entity->x + entity->vx; float_t newX = entity->x + entity->vx;
fixed248_t newY = entity->y + entity->vy; float_t newY = entity->y + entity->vy;
fixed248_t halfTileWH = FIXED248(TILE_WIDTH_HEIGHT / 2, 0); float_t halfTileWH = TILE_WIDTH_HEIGHT / 2.0f;
// Because all hit detection is done assuming the entity is a circle, with // Because all hit detection is done assuming the entity is a circle, with
// its position centered, we need to precalc these; // its position centered, we need to precalc these;
fixed248_t selfCircX = fx248Addfx248(newX, halfTileWH); float_t selfCircX = newX + halfTileWH;
fixed248_t selfCircY = fx248Addfx248(newY, halfTileWH); float_t selfCircY = newY + halfTileWH;
fixed248_t selfCircR = halfTileWH; float_t selfCircR = halfTileWH;
// Check for collisions with tiles // Check for collisions with tiles
fixed248_t tileStartX = fx248Floor(fx248Divfx248( float_t tileStartX = floorf((newX - halfTileWH) / TILE_WIDTH_HEIGHT);
(newX - halfTileWH), FIXED248(TILE_WIDTH_HEIGHT, 0) float_t tileStartY = floorf((newY - halfTileWH) / TILE_WIDTH_HEIGHT);
)); float_t tileEndX = ceilf((newX + halfTileWH) / TILE_WIDTH_HEIGHT);
fixed248_t tileStartY = fx248Floor(fx248Divfx248( float_t tileEndY = ceilf((newY + halfTileWH) / TILE_WIDTH_HEIGHT);
(newY - halfTileWH), FIXED248(TILE_WIDTH_HEIGHT, 0)
));
fixed248_t tileEndX = fx248Ceil(fx248Divfx248(
(newX + halfTileWH), FIXED248(TILE_WIDTH_HEIGHT, 0)
));
fixed248_t tileEndY = fx248Ceil(fx248Divfx248(
(newY + halfTileWH), FIXED248(TILE_WIDTH_HEIGHT, 0)
));
// For each tile // For each tile
for(fixed248_t y = tileStartY; y <= tileEndY; y += FIXED248_ONE) { for(float_t y = tileStartY; y <= tileEndY; y += 1) {
for(fixed248_t x = tileStartX; x <= tileEndX; x += FIXED248_ONE) { for(float_t x = tileStartX; x <= tileEndX; x += 1) {
uint16_t tileX = fx248Tou16(x); uint16_t tileX = (uint16_t)x;
uint16_t tileY = fx248Tou16(y); uint16_t tileY = (uint16_t)y;
uint16_t chunkX = tileX / CHUNK_WIDTH; uint16_t chunkX = tileX / CHUNK_WIDTH;
uint16_t chunkY = tileY / CHUNK_HEIGHT; uint16_t chunkY = tileY / CHUNK_HEIGHT;
chunk_t *chunk = chunkGetChunkAt(chunkX, chunkY); chunk_t *chunk = chunkGetChunkAt(chunkX, chunkY);
@@ -107,13 +96,9 @@ void entityUpdate(entity_t *entity) {
collisionresult_t collision = physicsCheckCircleTile( collisionresult_t collision = physicsCheckCircleTile(
selfCircX, selfCircY, selfCircR, x, y, tile selfCircX, selfCircY, selfCircR, x, y, tile
); );
if(collision.hit && collision.depth > FIXED248(0, 1)) { if(collision.hit && collision.depth > 0.01f) {
fixed248_t slideX = fx248Mulfx248( float_t slideX = collision.normalX * collision.depth;
collision.normalX, collision.depth float_t slideY = collision.normalY * collision.depth;
);
fixed248_t slideY = fx248Mulfx248(
collision.normalY, collision.depth
);
newX -= slideX; newX -= slideX;
newY -= slideY; newY -= slideY;
} }
@@ -126,7 +111,7 @@ void entityUpdate(entity_t *entity) {
// Skip self and null entities // Skip self and null entities
if(otherEntity == entity || otherEntity->type == ENTITY_TYPE_NULL) continue; if(otherEntity == entity || otherEntity->type == ENTITY_TYPE_NULL) continue;
fixed248_t otherCircR = halfTileWH; float_t otherCircR = halfTileWH;
// We DONT use selfCircX/Y here because the other entity is ALSO a circle. // We DONT use selfCircX/Y here because the other entity is ALSO a circle.
collisionresult_t collision = physicsCheckCircleCircle( collisionresult_t collision = physicsCheckCircleCircle(
@@ -136,8 +121,8 @@ void entityUpdate(entity_t *entity) {
if(!collision.hit) continue; if(!collision.hit) continue;
// Collision with entity detected. Slide out of collision. // Collision with entity detected. Slide out of collision.
fixed248_t slideX = fx248Mulfx248(collision.normalX, collision.depth); float_t slideX = collision.normalX * collision.depth;
fixed248_t slideY = fx248Mulfx248(collision.normalY, collision.depth); float_t slideY = collision.normalY * collision.depth;
newX -= slideX; newX -= slideX;
newY -= slideY; newY -= slideY;
} while(++otherEntity < ENTITIES + ENTITY_COUNT_MAX); } while(++otherEntity < ENTITIES + ENTITY_COUNT_MAX);

View File

@@ -8,7 +8,6 @@
#pragma once #pragma once
#include "player.h" #include "player.h"
#include "npc.h" #include "npc.h"
#include "util/fixed.h"
#define ENTITY_COUNT_MAX 32 #define ENTITY_COUNT_MAX 32
@@ -33,8 +32,8 @@ typedef enum {
typedef struct _entity_t { typedef struct _entity_t {
uint32_t id;// Completely unique ID for this entity. uint32_t id;// Completely unique ID for this entity.
fixed248_t x, y; float_t x, y;
fixed248_t vx, vy; float_t vx, vy;
entitytype_t type; entitytype_t type;
entitydir_t dir; entitydir_t dir;
@@ -69,9 +68,9 @@ void entityLoad(entity_t *entity, const entity_t *source);
void entityUpdate(entity_t *entity); void entityUpdate(entity_t *entity);
/** /**
* Converts an entity direction to an angle in fixed248_t format. * Converts an entity direction to an angle in float_t format.
* *
* @param dir The entity direction to convert. * @param dir The entity direction to convert.
* @return The angle corresponding to the entity direction. * @return The angle corresponding to the entity direction.
*/ */
fixed248_t entityDirToAngle(const entitydir_t dir); float_t entityDirToAngle(const entitydir_t dir);

View File

@@ -114,12 +114,9 @@ void playerEntityUpdate(entity_t *entity) {
continue; continue;
} }
fixed248_t distanceX = fx248Subfx248(other->x, entity->x); float_t distanceX = other->x - entity->x;
fixed248_t distanceY = fx248Subfx248(other->y, entity->y); float_t distanceY = other->y - entity->y;
fixed248_t distance = fx248Sqrt(fx248Addfx248( float_t distance = sqrtf(distanceX * distanceX + distanceY * distanceY);
fx248Mulfx248(distanceX, distanceX),
fx248Mulfx248(distanceY, distanceY)
));
if(distance > PLAYER_INTERACT_RANGE) { if(distance > PLAYER_INTERACT_RANGE) {
other++; other++;
@@ -127,16 +124,16 @@ void playerEntityUpdate(entity_t *entity) {
} }
// Get angle // Get angle
fixed248_t angle = fx248Atan2(distanceY, distanceX); float_t angle = atan2f(distanceY, distanceX);
while(angle < 0) angle += FX248_PI; while(angle < 0) angle += M_PI;
fixed248_t selfAngle = entityDirToAngle(entity->dir); float_t selfAngle = entityDirToAngle(entity->dir);
while(selfAngle < 0) selfAngle += FX248_PI; while(selfAngle < 0) selfAngle += M_PI;
// Check if angle is within range // Check if angle is within range
fixed248_t angleDiff = fx248Subfx248(angle, selfAngle); float_t angleDiff = angle - selfAngle;
if(angleDiff > FX248_HALF_PI) angleDiff -= FX248_PI; if(angleDiff > (M_PI_2)) angleDiff -= M_PI;
if(angleDiff < -FX248_HALF_PI) angleDiff += FX248_PI; if(angleDiff < -M_PI_2) angleDiff += M_PI;
if(fx248Abs(angleDiff) > PLAYER_INTERACT_ANGLE) { if(fabsf(angleDiff) > PLAYER_INTERACT_ANGLE) {
other++; other++;
continue; continue;
} }
@@ -149,12 +146,12 @@ void playerEntityUpdate(entity_t *entity) {
} }
} }
fixed248_t entityDirToAngle(const entitydir_t dir) { float_t entityDirToAngle(const entitydir_t dir) {
switch(dir) { switch(dir) {
case ENTITY_DIR_NORTH: return FX248_HALF_PI; case ENTITY_DIR_NORTH: return (M_PI_2);
case ENTITY_DIR_SOUTH: return -FX248_HALF_PI; case ENTITY_DIR_SOUTH: return -(M_PI_2);
case ENTITY_DIR_EAST: return 0; case ENTITY_DIR_EAST: return 0;
case ENTITY_DIR_WEST: return FX248_PI; case ENTITY_DIR_WEST: return (M_PI);
default: return 0; // Should never happen default: return 0; // Should never happen
} }
} }

View File

@@ -7,7 +7,6 @@
#pragma once #pragma once
#include "dusk.h" #include "dusk.h"
#include "util/fixed.h"
#include "item/inventory.h" #include "item/inventory.h"
typedef struct _entity_t entity_t; typedef struct _entity_t entity_t;
@@ -17,12 +16,10 @@ typedef struct {
} playerentity_t; } playerentity_t;
#define PLAYER_ENTITY_ID (UINT32_MAX-1) #define PLAYER_ENTITY_ID (UINT32_MAX-1)
#define PLAYER_MOVE_SPEED FIXED248(1, 0) #define PLAYER_MOVE_SPEED 1.0f
#define PLAYER_MOVE_SPEED_XY FIXED248(0, 80) #define PLAYER_MOVE_SPEED_XY 0.70710678118f
#define PLAYER_INTERACT_RANGE FIXED248( \ #define PLAYER_INTERACT_RANGE (TILE_WIDTH_HEIGHT + (TILE_WIDTH_HEIGHT / 3))
(TILE_WIDTH_HEIGHT + (TILE_WIDTH_HEIGHT / 3)), 0 \ #define PLAYER_INTERACT_ANGLE 0.68359375f
)
#define PLAYER_INTERACT_ANGLE ((fixed248_t)175)
extern inventory_t PLAYER_INVENTORY; extern inventory_t PLAYER_INVENTORY;

View File

@@ -9,23 +9,20 @@
#include "world/tiledata.h" #include "world/tiledata.h"
collisionresult_t physicsCheckCircleCircle( collisionresult_t physicsCheckCircleCircle(
fixed248_t circle0x, fixed248_t circle0y, fixed248_t circle0r, float_t circle0x, float_t circle0y, float_t circle0r,
fixed248_t circle1x, fixed248_t circle1y, fixed248_t circle1r float_t circle1x, float_t circle1y, float_t circle1r
) { ) {
collisionresult_t result; collisionresult_t result;
// Compute vector between centers // Compute vector between centers
fixed248_t dx = fx248Subfx248(circle1x, circle0x); float_t dx = circle1x - circle0x;
fixed248_t dy = fx248Subfx248(circle1y, circle0y); float_t dy = circle1y - circle0y;
// Distance squared between centers // Distance squared between centers
fixed248_t distSq = fx248Addfx248( float_t distSq = (dx * dx) + (dy * dy);
fx248Mulfx248(dx, dx),
fx248Mulfx248(dy, dy)
);
// Sum of radii // Sum of radii
fixed248_t rSum = fx248Addfx248(circle0r, circle1r); float_t rSum = circle0r + circle1r;
fixed248_t rSumSq = fx248Mulfx248(rSum, rSum); float_t rSumSq = rSum * rSum;
if(distSq > rSumSq) { if(distSq > rSumSq) {
// No collision // No collision
@@ -34,66 +31,66 @@ collisionresult_t physicsCheckCircleCircle(
} }
// Collision: calculate normal and penetration depth // Collision: calculate normal and penetration depth
fixed248_t dist = fx248Sqrt(distSq); float_t dist = sqrtf(distSq);
// If centers are the same, pick arbitrary normal (1,0) // If centers are the same, pick arbitrary normal (1,0)
if(dist == 0) { if(dist == 0) {
result.normalX = FIXED248(1,0); result.normalX = 1;
result.normalY = 0; result.normalY = 0;
result.depth = rSum; result.depth = rSum;
} else { } else {
// Normalized direction from circle0 to circle1 // Normalized direction from circle0 to circle1
result.normalX = fx248Divfx248(dx, dist); result.normalX = dx / dist;
result.normalY = fx248Divfx248(dy, dist); result.normalY = dy / dist;
// Penetration depth = sum of radii - distance // Penetration depth = sum of radii - distance
result.depth = fx248Subfx248(rSum, dist); result.depth = rSum - dist;
} }
result.hit = true; result.hit = true;
return result; return result;
} }
collisionresult_t physicsCheckCircleAABB( collisionresult_t physicsCheckCircleAABB(
fixed248_t circleX, fixed248_t circleY, fixed248_t circleR, float_t circleX, float_t circleY, float_t circleR,
fixed248_t aabbX, fixed248_t aabbY, float_t aabbX, float_t aabbY,
fixed248_t aabbWidth, fixed248_t aabbHeight float_t aabbWidth, float_t aabbHeight
) { ) {
collisionresult_t result; collisionresult_t result;
// Find the closest point on the AABB to the circle center // Find the closest point on the AABB to the circle center
fixed248_t closestX = fx248Max( float_t closestX = fmaxf(
aabbX, fx248Min(circleX, fx248Addfx248(aabbX, aabbWidth)) aabbX, fminf(circleX, aabbX + aabbWidth)
); );
fixed248_t closestY = fx248Max( float_t closestY = fmaxf(
aabbY, fx248Min(circleY, fx248Addfx248(aabbY, aabbHeight)) aabbY, fminf(circleY, aabbY + aabbHeight)
); );
// Vector from circle center to closest point // Vector from circle center to closest point
fixed248_t dx = fx248Subfx248(closestX, circleX); float_t dx = closestX - circleX;
fixed248_t dy = fx248Subfx248(closestY, circleY); float_t dy = closestY - circleY;
// Distance squared from circle center to closest point // Distance squared from circle center to closest point
fixed248_t distSq = fx248Addfx248(fx248Mulfx248(dx, dx), fx248Mulfx248(dy, dy)); float_t distSq = (dx * dx) + (dy * dy);
// Check if distance is less than radius squared // Check if distance is less than radius squared
if(distSq > fx248Mulfx248(circleR, circleR)) { if(distSq > (circleR * circleR)) {
result.hit = false; result.hit = false;
return result; return result;
} }
// Collision: calculate normal and penetration depth // Collision: calculate normal and penetration depth
fixed248_t dist = fx248Sqrt(distSq); float_t dist = sqrtf(distSq);
if(dist <= FIXED248(0, 1)) { if(dist <= 1) {
// Circle center is at the AABB corner // Circle center is at the AABB corner
result.normalX = FIXED248(1,0); result.normalX = 1.0f;
result.normalY = FIXED248(0,1); result.normalY = 0.0f;
result.depth = circleR; result.depth = circleR;
} else { } else {
// Normalized direction from circle center to closest point // Normalized direction from circle center to closest point
result.normalX = fx248Divfx248(dx, dist); result.normalX = dx / dist;
result.normalY = fx248Divfx248(dy, dist); result.normalY = dy / dist;
// Penetration depth = radius - distance // Penetration depth = radius - distance
result.depth = fx248Subfx248(circleR, dist); result.depth = circleR - dist;
} }
result.hit = true; result.hit = true;
@@ -101,116 +98,99 @@ collisionresult_t physicsCheckCircleAABB(
} }
void physicsClosestPointOnSegment( void physicsClosestPointOnSegment(
fixed248_t ax, fixed248_t ay, float_t ax, float_t ay,
fixed248_t bx, fixed248_t by, float_t bx, float_t by,
fixed248_t px, fixed248_t py, float_t px, float_t py,
fixed248_t *outX, fixed248_t *outY float_t *outX, float_t *outY
) { ) {
fixed248_t abx = fx248Subfx248(bx, ax); float_t abx = bx - ax;
fixed248_t aby = fx248Subfx248(by, ay); float_t aby = by - ay;
fixed248_t apx = fx248Subfx248(px, ax); float_t apx = px - ax;
fixed248_t apy = fx248Subfx248(py, ay); float_t apy = py - ay;
fixed248_t abLenSq = fx248Addfx248( float_t abLenSq = (abx * abx) + (aby * aby);
fx248Mulfx248(abx, abx),
fx248Mulfx248(aby, aby)
);
if(abLenSq == FIXED248_ZERO) { if(abLenSq == 0) {
*outX = ax; *outX = ax;
*outY = ay; *outY = ay;
return; return;
} }
fixed248_t t = fx248Divfx248( float_t t = apx * abx + apy * aby;
fx248Addfx248(fx248Mulfx248(apx, abx), fx248Mulfx248(apy, aby)), t /= abLenSq;
abLenSq
);
if(t < FIXED248_ZERO) t = FIXED248_ZERO; if(t < 0) t = 0;
if(t > FIXED248_ONE) t = FIXED248_ONE; if(t > 1) t = 1;
*outX = fx248Addfx248(ax, fx248Mulfx248(abx, t)); *outX = ax + (abx * t);
*outY = fx248Addfx248(ay, fx248Mulfx248(aby, t)); *outY = ay + (aby * t);
} }
bool_t physicsIsPointInTriangle( bool_t physicsIsPointInTriangle(
fixed248_t px, fixed248_t py, float_t px, float_t py,
fixed248_t ax, fixed248_t ay, float_t ax, float_t ay,
fixed248_t bx, fixed248_t by, float_t bx, float_t by,
fixed248_t cx, fixed248_t cy float_t cx, float_t cy
) { ) {
fixed248_t abx = fx248Subfx248(bx, ax); float_t abx = bx - ax;
fixed248_t aby = fx248Subfx248(by, ay); float_t aby = by - ay;
fixed248_t bcx = fx248Subfx248(cx, bx); float_t bcx = cx - bx;
fixed248_t bcy = fx248Subfx248(cy, by); float_t bcy = cy - by;
fixed248_t cax = fx248Subfx248(ax, cx); float_t cax = ax - cx;
fixed248_t cay = fx248Subfx248(ay, cy); float_t cay = ay - cy;
fixed248_t apx = fx248Subfx248(px, ax); float_t apx = px - ax;
fixed248_t apy = fx248Subfx248(py, ay); float_t apy = py - ay;
fixed248_t bpx = fx248Subfx248(px, bx); float_t bpx = px - bx;
fixed248_t bpy = fx248Subfx248(py, by); float_t bpy = py - by;
fixed248_t cpx = fx248Subfx248(px, cx); float_t cpx = px - cx;
fixed248_t cpy = fx248Subfx248(py, cy); float_t cpy = py - cy;
fixed248_t cross1 = fx248Subfx248( float_t cross1 = (abx * apy) - (aby * apx);
fx248Mulfx248(abx, apy), float_t cross2 = (bcx * bpy) - (bcy * bpx);
fx248Mulfx248(aby, apx) float_t cross3 = (cax * cpy) - (cay * cpx);
);
fixed248_t cross2 = fx248Subfx248(
fx248Mulfx248(bcx, bpy),
fx248Mulfx248(bcy, bpx)
);
fixed248_t cross3 = fx248Subfx248(
fx248Mulfx248(cax, cpy),
fx248Mulfx248(cay, cpx)
);
bool_t hasNeg = ( bool_t hasNeg = (
(cross1 < FIXED248_ZERO) || (cross1 < 0) ||
(cross2 < FIXED248_ZERO) || (cross2 < 0) ||
(cross3 < FIXED248_ZERO) (cross3 < 0)
); );
bool_t hasPos = ( bool_t hasPos = (
(cross1 > FIXED248_ZERO) || (cross1 > 0) ||
(cross2 > FIXED248_ZERO) || (cross2 > 0) ||
(cross3 > FIXED248_ZERO) (cross3 > 0)
); );
return !(hasNeg && hasPos); return !(hasNeg && hasPos);
} }
collisionresult_t physicsCheckCircleTriangle( collisionresult_t physicsCheckCircleTriangle(
fixed248_t circleX, fixed248_t circleY, fixed248_t circleR, float_t circleX, float_t circleY, float_t circleR,
fixed248_t triX0, fixed248_t triY0, float_t triX0, float_t triY0,
fixed248_t triX1, fixed248_t triY1, float_t triX1, float_t triY1,
fixed248_t triX2, fixed248_t triY2 float_t triX2, float_t triY2
) { ) {
collisionresult_t result = { .hit = false }; collisionresult_t result = { .hit = false };
fixed248_t vx[3] = { triX0, triX1, triX2 }; float_t vx[3] = { triX0, triX1, triX2 };
fixed248_t vy[3] = { triY0, triY1, triY2 }; float_t vy[3] = { triY0, triY1, triY2 };
fixed248_t closestX = FIXED248_ZERO; float_t closestX = 0;
fixed248_t closestY = FIXED248_ZERO; float_t closestY = 0;
fixed248_t minDistSq = FIXED248_MAX; float_t minDistSq = FLT_MAX;
for(uint8_t i = 0; i < 3; ++i) { for(uint8_t i = 0; i < 3; ++i) {
uint8_t j = (i + 1) % 3; uint8_t j = (i + 1) % 3;
fixed248_t testX, testY; float_t testX, testY;
physicsClosestPointOnSegment( physicsClosestPointOnSegment(
vx[i], vy[i], vx[j], vy[j], vx[i], vy[i], vx[j], vy[j],
circleX, circleY, &testX, &testY circleX, circleY, &testX, &testY
); );
fixed248_t dx = fx248Subfx248(circleX, testX); float_t dx = circleX - testX;
fixed248_t dy = fx248Subfx248(circleY, testY); float_t dy = circleY - testY;
fixed248_t distSq = fx248Addfx248( float_t distSq = (dx * dx) + (dy * dy);
fx248Mulfx248(dx, dx),
fx248Mulfx248(dy, dy)
);
if(distSq < minDistSq) { if(distSq < minDistSq) {
minDistSq = distSq; minDistSq = distSq;
@@ -221,44 +201,44 @@ collisionresult_t physicsCheckCircleTriangle(
} }
} }
fixed248_t dist = fx248Sqrt(minDistSq); float_t dist = sqrtf(minDistSq);
fixed248_t invDist = ( float_t invDist = (
(dist != FIXED248_ZERO) ? (dist != 0) ?
fx248Divfx248(FIXED248_ONE, dist) : (1.0f / dist) :
FIXED248_ONE 1.0f
); );
result.normalX = fx248Mulfx248(-result.normalX, invDist); result.normalX = -result.normalX * invDist;
result.normalY = fx248Mulfx248(-result.normalY, invDist); result.normalY = -result.normalY * invDist;
if(physicsIsPointInTriangle( if(physicsIsPointInTriangle(
circleX, circleY, vx[0], vy[0], vx[1], vy[1], vx[2], vy[2] circleX, circleY, vx[0], vy[0], vx[1], vy[1], vx[2], vy[2]
)) { )) {
result.hit = true; result.hit = true;
result.depth = fx248Subfx248(circleR, dist); result.depth = circleR - dist;
return result; return result;
} }
if(dist < circleR) { if(dist < circleR) {
result.hit = true; result.hit = true;
result.depth = fx248Subfx248(circleR, dist); result.depth = circleR - dist;
} }
return result; return result;
} }
collisionresult_t physicsCheckCircleTile( collisionresult_t physicsCheckCircleTile(
fixed248_t circleX, fixed248_t circleY, fixed248_t circleR, float_t circleX, float_t circleY, float_t circleR,
fixed248_t tileX, fixed248_t tileY, tile_t tile float_t tileX, float_t tileY, tile_t tile
) { ) {
collisionresult_t result; collisionresult_t result;
#define tw FIXED248(TILE_WIDTH_HEIGHT, 0) #define tw (TILE_WIDTH_HEIGHT)
#define th FIXED248(TILE_WIDTH_HEIGHT, 0) #define th (TILE_WIDTH_HEIGHT)
#define lx fx248Mulfx248(tileX, tw) #define lx (tileX * tw)
#define ty fx248Mulfx248(tileY, th) #define ty (tileY * th)
#define rx fx248Addfx248(lx, tw) #define rx (lx + tw)
#define by fx248Addfx248(ty, th) #define by (ty + th)
switch(TILE_META_DATA[tile].solidType) { switch(TILE_META_DATA[tile].solidType) {
case TILE_SOLID_FULL: case TILE_SOLID_FULL:

View File

@@ -6,13 +6,12 @@
*/ */
#pragma once #pragma once
#include "util/fixed.h"
#include "world/tile.h" #include "world/tile.h"
typedef struct { typedef struct {
bool_t hit; bool_t hit;
fixed248_t normalX, normalY; float_t normalX, normalY;
fixed248_t depth; float_t depth;
} collisionresult_t; } collisionresult_t;
/** /**
@@ -27,8 +26,8 @@ typedef struct {
* @return A collisionresult_t structure containing collision information. * @return A collisionresult_t structure containing collision information.
*/ */
collisionresult_t physicsCheckCircleCircle( collisionresult_t physicsCheckCircleCircle(
fixed248_t circle0x, fixed248_t circle0y, fixed248_t circle0r, float_t circle0x, float_t circle0y, float_t circle0r,
fixed248_t circle1x, fixed248_t circle1y, fixed248_t circle1r float_t circle1x, float_t circle1y, float_t circle1r
); );
/** /**
@@ -44,9 +43,9 @@ collisionresult_t physicsCheckCircleCircle(
* @return A collisionresult_t structure containing collision information. * @return A collisionresult_t structure containing collision information.
*/ */
collisionresult_t physicsCheckCircleAABB( collisionresult_t physicsCheckCircleAABB(
fixed248_t circleX, fixed248_t circleY, fixed248_t circleR, float_t circleX, float_t circleY, float_t circleR,
fixed248_t aabb, fixed248_t aabbY, float_t aabb, float_t aabbY,
fixed248_t aabbWidth, fixed248_t aabbHeight float_t aabbWidth, float_t aabbHeight
); );
/** /**
@@ -62,10 +61,10 @@ collisionresult_t physicsCheckCircleAABB(
* @param outY Pointer to store the Y coordinate of the closest point. * @param outY Pointer to store the Y coordinate of the closest point.
*/ */
void physicsClosestPointOnSegment( void physicsClosestPointOnSegment(
fixed248_t ax, fixed248_t ay, float_t ax, float_t ay,
fixed248_t bx, fixed248_t by, float_t bx, float_t by,
fixed248_t px, fixed248_t py, float_t px, float_t py,
fixed248_t *outX, fixed248_t *outY float_t *outX, float_t *outY
); );
/** /**
@@ -82,10 +81,10 @@ void physicsClosestPointOnSegment(
* @return true if the point is inside the triangle, false otherwise. * @return true if the point is inside the triangle, false otherwise.
*/ */
bool_t physicsIsPointInTriangle( bool_t physicsIsPointInTriangle(
fixed248_t px, fixed248_t py, float_t px, float_t py,
fixed248_t x0, fixed248_t y0, float_t x0, float_t y0,
fixed248_t x1, fixed248_t y1, float_t x1, float_t y1,
fixed248_t x2, fixed248_t y2 float_t x2, float_t y2
); );
/** /**
@@ -103,10 +102,10 @@ bool_t physicsIsPointInTriangle(
* @return A collisionresult_t structure containing collision information. * @return A collisionresult_t structure containing collision information.
*/ */
collisionresult_t physicsCheckCircleTriangle( collisionresult_t physicsCheckCircleTriangle(
fixed248_t circleX, fixed248_t circleY, fixed248_t circleR, float_t circleX, float_t circleY, float_t circleR,
fixed248_t triX0, fixed248_t triY0, float_t triX0, float_t triY0,
fixed248_t triX1, fixed248_t triY1, float_t triX1, float_t triY1,
fixed248_t triX2, fixed248_t triY2 float_t triX2, float_t triY2
); );
/** /**
@@ -121,6 +120,6 @@ collisionresult_t physicsCheckCircleTriangle(
* @return A collisionresult_t structure containing collision information. * @return A collisionresult_t structure containing collision information.
*/ */
collisionresult_t physicsCheckCircleTile( collisionresult_t physicsCheckCircleTile(
fixed248_t circleX, fixed248_t circleY, fixed248_t circleR, float_t circleX, float_t circleY, float_t circleR,
fixed248_t tileX, fixed248_t tileY, tile_t tile float_t tileX, float_t tileY, tile_t tile
); );

View File

@@ -6,7 +6,6 @@
# Sources # Sources
target_sources(${DUSK_TARGET_NAME} target_sources(${DUSK_TARGET_NAME}
PRIVATE PRIVATE
fixed.c
memory.c memory.c
string.c string.c
) )

View File

@@ -1,257 +0,0 @@
/**
* Copyright (c) 2025 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "fixed.h"
#include "assert/assert.h"
fixed248_t fx248Fromi32(const int32_t b) {
return (fixed248_t)b << FIXED248_FRACTION_BITS;
}
fixed248_t fx248Fromu32(const uint32_t b) {
return (fixed248_t)((int32_t)b << FIXED248_FRACTION_BITS);
}
fixed248_t fx248Fromf32(const float_t b) {
return (fixed248_t)(b * (1 << FIXED248_FRACTION_BITS));
}
fixed248_t fx248Fromu16(const uint16_t b) {
return (fixed248_t)((int32_t)b << FIXED248_FRACTION_BITS);
}
fixed248_t fx248Fromu8(const uint8_t b) {
return (fixed248_t)((int32_t)b << FIXED248_FRACTION_BITS);
}
int32_t fx248Toi32(const fixed248_t a) {
return a >> FIXED248_FRACTION_BITS;
}
uint32_t fx248Tou32(const fixed248_t a) {
return (uint32_t)(a >> FIXED248_FRACTION_BITS);
}
float_t fx248Tof32(const fixed248_t a) {
return (float_t)a / (1 << FIXED248_FRACTION_BITS);
}
uint16_t fx248Tou16(const fixed248_t a) {
return (uint16_t)(a >> FIXED248_FRACTION_BITS);
}
uint8_t fx248Tou8(const fixed248_t a) {
return (uint8_t)(a >> FIXED248_FRACTION_BITS);
}
fixed248_t fx248Addfx248(const fixed248_t a, const fixed248_t b) {
return a + b;
}
fixed248_t fx248Addi32(const fixed248_t a, const int32_t b) {
return fx248Addfx248(a, fx248Fromi32(b));
}
fixed248_t fx248Addu32(const fixed248_t a, const uint32_t b) {
return fx248Addfx248(a, fx248Fromu32(b));
}
fixed248_t fx248Addf32(const fixed248_t a, const float_t b) {
return fx248Addfx248(a, fx248Fromf32(b));
}
fixed248_t fx248Subfx248(const fixed248_t a, const fixed248_t b) {
return a - b;
}
fixed248_t fx248Subi32(const fixed248_t a, const int32_t b) {
return fx248Subfx248(a, fx248Fromi32(b));
}
fixed248_t fx248Subu32(const fixed248_t a, const uint32_t b) {
return fx248Subfx248(a, fx248Fromu32(b));
}
fixed248_t fx248Subf32(const fixed248_t a, const float_t b) {
return fx248Subfx248(a, fx248Fromf32(b));
}
fixed248_t fx248Mulfx248(const fixed248_t a, const fixed248_t b) {
return (fixed248_t)(((int64_t)a * (int64_t)b) >> FIXED248_FRACTION_BITS);
}
fixed248_t fx248Muli32(const fixed248_t a, const int32_t b) {
return (fixed248_t)(((int64_t)a * (int64_t)b) >> FIXED248_FRACTION_BITS);
}
fixed248_t fx248Mulu32(const fixed248_t a, const uint32_t b) {
return (fixed248_t)(
((int64_t)a * (int64_t)(int32_t)b
) >> FIXED248_FRACTION_BITS);
}
fixed248_t fx248Mulf32(const fixed248_t a, const float_t b) {
return (fixed248_t)((
(int64_t)a * (int64_t)(b * (1 << FIXED248_FRACTION_BITS))
) >> FIXED248_FRACTION_BITS);
}
fixed248_t fx248Divfx248(const fixed248_t a, const fixed248_t b) {
assertFalse(b == 0, "Division by zero in fx248Divfx248");
return (fixed248_t)(((int64_t)a << FIXED248_FRACTION_BITS) / (int64_t)b);
}
fixed248_t fx248Divi32(const fixed248_t a, const int32_t b) {
assertFalse(b == 0, "Division by zero in fx248Divi32");
return (fixed248_t)(((int64_t)a << FIXED248_FRACTION_BITS) / (int64_t)b);
}
fixed248_t fx248Divu32(const fixed248_t a, const uint32_t b) {
assertFalse(b == 0, "Division by zero in fx248Divu32");
return (fixed248_t)(
((int64_t)a << FIXED248_FRACTION_BITS
) / (int64_t)(int32_t)b);
}
fixed248_t fx248Divf32(const fixed248_t a, const float_t b) {
assertFalse(b == 0, "Division by zero in fx248Divf32");
return (fixed248_t)((
(int64_t)a << FIXED248_FRACTION_BITS
) / (int64_t)(b * (1 << FIXED248_FRACTION_BITS)));
}
fixed248_t fx248Floor(const fixed248_t a) {
return a & ~((1 << FIXED248_FRACTION_BITS) - 1);
}
fixed248_t fx248Ceil(const fixed248_t a) {
if(a & ((1 << FIXED248_FRACTION_BITS) - 1)) {
return (a & ~((1 << FIXED248_FRACTION_BITS) - 1)) + (1 << FIXED248_FRACTION_BITS);
}
return a;
}
fixed248_t fx248Round(const fixed248_t a) {
if(a & ((1 << (FIXED248_FRACTION_BITS - 1)) - 1)) {
return (a & ~((1 << FIXED248_FRACTION_BITS) - 1)) + (1 << FIXED248_FRACTION_BITS);
}
return a & ~((1 << FIXED248_FRACTION_BITS) - 1);
}
uint32_t fx248Flooru32(const fixed248_t a) {
return (uint32_t)((a >> FIXED248_FRACTION_BITS) & 0xFFFFFFFF);
}
uint32_t fx248Ceilu32(const fixed248_t a) {
return (uint32_t)(((a + ((1 << FIXED248_FRACTION_BITS) - 1)) >> FIXED248_FRACTION_BITS) & 0xFFFFFFFF);
}
uint32_t fx248Roundu32(const fixed248_t a) {
return (uint32_t)(((a + (1 << (FIXED248_FRACTION_BITS - 1))) >> FIXED248_FRACTION_BITS) & 0xFFFFFFFF);
}
fixed248_t fx248Sqrt(const fixed248_t a) {
if(a == 0) return 0;
fixed248_t y = a > FIXED248(1, 0) ? a : FIXED248(1, 0);
fixed248_t last = 0;
int max_iter = 16;
while(y != last && max_iter-- > 0) {
last = y;
int32_t div = (int32_t)(((int64_t)a << FIXED248_FRACTION_BITS) / y);
y = (y + div) >> 1;
}
return y;
}
fixed248_t fx248Max(const fixed248_t a, const fixed248_t b) {
return (a > b) ? a : b;
}
fixed248_t fx248Min(const fixed248_t a, const fixed248_t b) {
return (a < b) ? a : b;
}
fixed248_t fx248Clamp(
const fixed248_t a,
const fixed248_t min,
const fixed248_t max
) {
return (a < min) ? min : (a > max) ? max : a;
}
fixed248_t fx248Abs(const fixed248_t a) {
return (a < 0) ? -a : a;
}
fixed248_t fx248Atan2(
const fixed248_t y,
const fixed248_t x
) {
// Handle special cases
if (x == 0) {
if (y > 0) return FX248_HALF_PI;
if (y < 0) return -FX248_HALF_PI;
return 0;
}
// Use absolute values for quadrant correction
fixed248_t abs_y = y;
if (abs_y < 0) abs_y = -abs_y;
fixed248_t angle;
if (abs_y < fx248Abs(x)) {
fixed248_t z = fx248Divfx248(y, x);
fixed248_t z2 = fx248Mulfx248(z, z);
fixed248_t z3 = fx248Mulfx248(z2, z);
fixed248_t z5 = fx248Mulfx248(z3, z2);
angle = fx248Subfx248(
fx248Addfx248(z, fx248Divfx248(z5, fx248Fromi32(5))),
fx248Divfx248(z3, fx248Fromi32(3))
);
if (x < 0) {
if (y < 0) {
angle -= FX248_PI;
} else {
angle += FX248_PI;
}
}
} else {
fixed248_t z = fx248Divfx248(x, y);
fixed248_t z2 = fx248Mulfx248(z, z);
fixed248_t z3 = fx248Mulfx248(z2, z);
fixed248_t z5 = fx248Mulfx248(z3, z2);
angle = fx248Subfx248(
fx248Addfx248(z, fx248Divfx248(z5, fx248Fromi32(5))),
fx248Divfx248(z3, fx248Fromi32(3))
);
if (y > 0) {
angle = FX248_HALF_PI - angle;
} else {
angle = -FX248_HALF_PI - angle;
}
}
return angle;
}

View File

@@ -1,379 +0,0 @@
/**
* Copyright (c) 2025 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "dusk.h"
typedef int32_t fixed248_t;
#define FIXED248_FRACTION_BITS 8
#define FIXED248_HIGH_MULTIPLIER (1 << FIXED248_FRACTION_BITS)
#define FIXED248_MIN INT32_MIN
#define FIXED248_MAX INT32_MAX
#define FIXED248(i, f) ((fixed248_t)( \
((i) << FIXED248_FRACTION_BITS) + \
(((f) * FIXED248_HIGH_MULTIPLIER) / 100) \
))
#define FIXED248_ONE (FIXED248(1, 0))
#define FIXED248_ZERO (FIXED248(0, 0))
#define FX248_PI 804
#define FX248_HALF_PI 402
#define FX248_3PI_4 603
#define FX248_NEG_PI -804
/**
* Convert an int32_t value to a fixed248_t value.
*
* @param b The int32_t value to convert.
* @return The converted fixed248_t value.
*/
fixed248_t fx248Fromi32(const int32_t b);
/**
* Convert a uint32_t value to a fixed248_t value.
*
* @param b The uint32_t value to convert.
* @return The converted fixed248_t value.
*/
fixed248_t fx248Fromu32(const uint32_t b);
/**
* Convert a float_t value to a fixed248_t value.
*
* @param b The float_t value to convert.
* @return The converted fixed248_t value.
*/
fixed248_t fx248Fromf32(const float_t b);
/**
* Convert a uint16_t value to a fixed248_t value.
*
* @param b The uint16_t value to convert.
* @return The converted fixed248_t value.
*/
fixed248_t fx248Fromu16(const uint16_t b);
/**
* Convert a uint8_t value to a fixed248_t value.
*
* @param b The uint8_t value to convert.
* @return The converted fixed248_t value.
*/
fixed248_t fx248Fromu8(const uint8_t b);
/**
* Convert a fixed248_t value to an int32_t value.
*
* @param a The fixed248_t value to convert.
* @return The converted int32_t value.
*/
int32_t fx248Toi32(const fixed248_t a);
/**
* Convert a fixed248_t value to a uint32_t value.
*
* @param a The fixed248_t value to convert.
* @return The converted uint32_t value.
*/
uint32_t fx248Tou32(const fixed248_t a);
/**
* Convert a fixed248_t value to a float_t value.
*
* @param a The fixed248_t value to convert.
* @return The converted float_t value.
*/
float_t fx248Tof32(const fixed248_t a);
/**
* Convert a fixed248_t value to a uint16_t value.
*
* @param a The fixed248_t value to convert.
* @return The converted uint16_t value.
*/
uint16_t fx248Tou16(const fixed248_t a);
/**
* Convert a fixed248_t value to an uint8_t value.
*
* @param a The fixed248_t value to convert.
* @return The converted uint8_t value.
*/
uint8_t fx248Tou8(const fixed248_t a);
/**
* Add a fixed248_t value to another fixed248_t value.
*
* @param a First fixed248_t value.
* @param b Second fixed248_t value to add to the first value.
* @return The result of the addition as a fixed248_t value.
*/
fixed248_t fx248Addfx248(const fixed248_t a, const fixed248_t b);
/**
* Add an int32_t value to a fixed248_t value.
*
* @param a The fixed248_t value to which the int32_t will be added.
* @param b The int32_t value to add to the fixed248_t value.
* @return The result of the addition as a fixed248_t value.
*/
fixed248_t fx248Addi32(const fixed248_t a, const int32_t b);
/**
* Add a uint32_t value to a fixed248_t value.
*
* @param a The fixed248_t value to which the uint32_t will be added.
* @param b The uint32_t value to add to the fixed248_t value.
* @return The result of the addition as a fixed248_t value.
*/
fixed248_t fx248Addu32(const fixed248_t a, const uint32_t b);
/**
* Add a float_t value to a fixed248_t value.
*
* @param a Pointer to the fixed248_t value (will be modified).
* @param b The float_t value to add to the fixed248_t value.
* @return The result of the addition as a fixed248_t value.
*/
fixed248_t fx248Addf32(const fixed248_t a, const float_t b);
/**
* Subtract a fixed248_t value from another fixed248_t value.
*
* @param a First fixed248_t value.
* @param b The fixed248_t value to subtract from the first value.
* @return The result of the subtraction as a fixed248_t value.
*/
fixed248_t fx248Subfx248(const fixed248_t a, const fixed248_t b);
/**
* Subtract an int32_t value from a fixed248_t value.
*
* @param a The fixed248_t value from which the int32_t will be subtracted.
* @param b The int32_t value to subtract from the fixed248_t value.
* @return The result of the subtraction as a fixed248_t value.
*/
fixed248_t fx248Subi32(const fixed248_t a, const int32_t b);
/**
* Subtract a uint32_t value from a fixed248_t value.
*
* @param a The fixed248_t value from which the uint32_t will be subtracted.
* @param b The uint32_t value to subtract from the fixed248_t value.
* @return The result of the subtraction as a fixed248_t value.
*/
fixed248_t fx248Subu32(const fixed248_t a, const uint32_t b);
/**
* Subtract a float_t value from a fixed248_t value.
*
* @param a The fixed248_t value from which the float_t will be subtracted.
* @param b The float_t value to subtract from the fixed248_t value.
* @return The result of the subtraction as a fixed248_t value.
*/
fixed248_t fx248Subf32(const fixed248_t a, const float_t b);
/**
* Multiply two fixed248_t values.
*
* @param a First fixed248_t value.
* @param b Second fixed248_t value to multiply with the first value.
* @return The result of the multiplication as a fixed248_t value.
*/
fixed248_t fx248Mulfx248(const fixed248_t a, const fixed248_t b);
/**
* Multiply a fixed248_t value by an int32_t value.
*
* @param a The fixed248_t value to multiply.
* @param b The int32_t value to multiply with the fixed248_t value.
* @return The result of the multiplication as a fixed248_t value.
*/
fixed248_t fx248Muli32(const fixed248_t a, const int32_t b);
/**
* Multiply a fixed248_t value by a uint32_t value.
*
* @param a The fixed248_t value to multiply.
* @param b The uint32_t value to multiply with the fixed248_t value.
* @return The result of the multiplication as a fixed248_t value.
*/
fixed248_t fx248Mulu32(const fixed248_t a, const uint32_t b);
/**
* Multiply a fixed248_t value by a float_t value.
*
* @param a The fixed248_t value to multiply.
* @param b The float_t value to multiply with the fixed248_t value.
* @return The result of the multiplication as a fixed248_t value.
*/
fixed248_t fx248Mulf32(const fixed248_t a, const float_t b);
/**
* Divide two fixed248_t values.
*
* @param a The fixed248_t value to be divided.
* @param b The fixed248_t value to divide by.
* @return The result of the division as a fixed248_t value.
*/
fixed248_t fx248Divfx248(const fixed248_t a, const fixed248_t b);
/**
* Divide a fixed248_t value by an int32_t value.
*
* @param a The fixed248_t value to be divided.
* @param b The int32_t value to divide by.
* @return The result of the division as a fixed248_t value.
*/
fixed248_t fx248Divi32(const fixed248_t a, const int32_t b);
/**
* Divide a fixed248_t value by a uint32_t value.
*
* @param a The fixed248_t value to be divided.
* @param b The uint32_t value to divide by.
* @return The result of the division as a fixed248_t value.
*/
fixed248_t fx248Divu32(const fixed248_t a, const uint32_t b);
/**
* Divide a fixed248_t value by a float_t value.
*
* @param a The fixed248_t value to be divided.
* @param b The float_t value to divide by.
* @return The result of the division as a fixed248_t value.
*/
fixed248_t fx248Divf32(const fixed248_t a, const float_t b);
/**
* Convert a fixed248_t value to an int32_t value, rounding towards zero.
*
* @param a The fixed248_t value to convert.
* @return The converted int32_t value.
*/
fixed248_t fx248Floor(const fixed248_t a);
/**
* Convert a fixed248_t value to an int32_t value, rounding towards positive
* infinity.
*
* @param a The fixed248_t value to convert.
* @return The converted int32_t value.
*/
fixed248_t fx248Ceil(const fixed248_t a);
/**
* Convert a fixed248_t value to an int32_t value, rounding to the nearest
* integer.
*
* @param a The fixed248_t value to convert.
* @return The converted int32_t value.
*/
fixed248_t fx248Round(const fixed248_t a);
/**
* Convert a fixed248_t value to a uint32_t value, rounding towards zero.
*
* @param a The fixed248_t value to convert.
* @return The converted uint32_t value.
*/
uint32_t fx248Flooru32(const fixed248_t a);
/**
* Convert a fixed248_t value to a uint32_t value, rounding towards positive
* infinity.
*
* @param a The fixed248_t value to convert.
* @return The converted uint32_t value.
*/
uint32_t fx248Ceilu32(const fixed248_t a);
/**
* Convert a fixed248_t value to a uint32_t value, rounding to the nearest
* integer.
*
* @param a The fixed248_t value to convert.
* @return The converted uint32_t value.
*/
uint32_t fx248Roundu32(const fixed248_t a);
/**
* Returns the square root of a fixed248_t value.
*
* @param a The fixed248_t value to calculate the square root of.
*/
fixed248_t fx248Sqrt(const fixed248_t a);
/**
* Returns the maximum of two fixed248_t values.
*
* @param a First fixed248_t value.
* @param b Second fixed248_t value.
* @return The maximum of the two values.
*/
fixed248_t fx248Max(const fixed248_t a, const fixed248_t b);
/**
* Returns the minimum of two fixed248_t values.
*
* @param a First fixed248_t value.
* @param b Second fixed248_t value.
* @return The minimum of the two values.
*/
fixed248_t fx248Min(const fixed248_t a, const fixed248_t b);
/**
* Clamp a fixed248_t value between a minimum and maximum value.
*
* @param a The fixed248_t value to clamp.
* @param min The minimum value to clamp to.
* @param max The maximum value to clamp to.
* @return The clamped fixed248_t value.
*/
fixed248_t fx248Clamp(
const fixed248_t a,
const fixed248_t min,
const fixed248_t max
);
/**
* Returns the absolute value of a fixed248_t value.
*
* @param a The fixed248_t value to calculate the absolute value of.
* @return The absolute value as a fixed248_t value.
*/
fixed248_t fx248Abs(const fixed248_t a);
/**
* Calculate the arctangent of a fixed248_t value.
*
* @param y Y coordinate value.
* @param x X coordinate value.
* @return The arctangent of the value as a fixed248_t value.
*/
fixed248_t fx248Atan2(
const fixed248_t y,
const fixed248_t x
);

View File

@@ -292,10 +292,10 @@ void chunkUnload(chunk_t *chunk) {
// If the entity is still within our chunk bounds, it's getting unloaded // If the entity is still within our chunk bounds, it's getting unloaded
if( if(
fx248Flooru32(entity->x) >= chunk->x * CHUNK_WIDTH * TILE_WIDTH_HEIGHT && floorf(entity->x) >= chunk->x * CHUNK_WIDTH * TILE_WIDTH_HEIGHT &&
fx248Ceilu32(entity->x) < (chunk->x + 1) * CHUNK_WIDTH * TILE_WIDTH_HEIGHT && ceilf(entity->x) < (chunk->x + 1) * CHUNK_WIDTH * TILE_WIDTH_HEIGHT &&
fx248Flooru32(entity->y) >= chunk->y * CHUNK_HEIGHT * TILE_WIDTH_HEIGHT && floorf(entity->y) >= chunk->y * CHUNK_HEIGHT * TILE_WIDTH_HEIGHT &&
fx248Ceilu32(entity->y) < (chunk->y + 1) * CHUNK_HEIGHT * TILE_WIDTH_HEIGHT ceilf(entity->y) < (chunk->y + 1) * CHUNK_HEIGHT * TILE_WIDTH_HEIGHT
) { ) {
shouldUnload = true; shouldUnload = true;
} else { } else {

View File

@@ -47,8 +47,8 @@ void overworldUpdate() {
entity->type == ENTITY_TYPE_PLAYER, entity->type == ENTITY_TYPE_PLAYER,
"First entity must be player" "First entity must be player"
); );
OVERWORLD_CAMERA_X = fx248Flooru32(entity->x); OVERWORLD_CAMERA_X = (uint32_t)floorf(entity->x);
OVERWORLD_CAMERA_Y = fx248Flooru32(entity->y); OVERWORLD_CAMERA_Y = (uint32_t)floorf(entity->y);
uint16_t x, y; uint16_t x, y;
uint16_t halfWidth, halfHeight; uint16_t halfWidth, halfHeight;

View File

@@ -113,8 +113,8 @@ void drawOverworldDrawEntity(const entity_t *entity) {
assertNotNull(entity, "Entity pointer cannot be NULL"); assertNotNull(entity, "Entity pointer cannot be NULL");
if(entity->type == ENTITY_TYPE_NULL) return; // Skip null entities if(entity->type == ENTITY_TYPE_NULL) return; // Skip null entities
uint32_t x = fx248Tou32(entity->x); uint32_t x = (uint32_t)(entity->x);
uint32_t y = fx248Tou32(entity->y); uint32_t y = (uint32_t)(entity->y);
uint32_t row = 0; uint32_t row = 0;
uint32_t col = entity->dir; uint32_t col = entity->dir;

View File

@@ -1,5 +1,2 @@
def floatToFixed248(value): def floatToFixed248(value):
# Converts a float to the fixed248_t used internally. return value;
high24 = int(value) & 0xFFFFFF
low8 = int((value * 256.0 - high24) * 256.0) & 0xFF
return f'((fixed248_t){(high24 << 8) | low8})'

View File

@@ -128,8 +128,8 @@ with open(headerPath, 'w') as f:
f.write(f"#define WORLD_HEIGHT {worldHeight}\n") f.write(f"#define WORLD_HEIGHT {worldHeight}\n")
# Write out other global variables. # Write out other global variables.
f.write(f"#define WORLD_PLAYER_SPAWN_X ((fixed248_t){floatToFixed248(mapData['playerSpawnX'])})\n") f.write(f"#define WORLD_PLAYER_SPAWN_X ((float_t){floatToFixed248(mapData['playerSpawnX'])})\n")
f.write(f"#define WORLD_PLAYER_SPAWN_Y ((fixed248_t){floatToFixed248(mapData['playerSpawnY'])})\n") f.write(f"#define WORLD_PLAYER_SPAWN_Y ((float_t){floatToFixed248(mapData['playerSpawnY'])})\n")
f.write("\n") f.write("\n")