Add new mat4 functions and some external testing
This commit is contained in:
parent
fceac54ecb
commit
65ee7bab4b
211
dqn.h
211
dqn.h
@ -96,24 +96,18 @@ DQN_FILE_SCOPE void DqnMem_Free (void *memory);
|
|||||||
// BeginTempRegion and EndTempRegion functions. Specifically freeing
|
// BeginTempRegion and EndTempRegion functions. Specifically freeing
|
||||||
// individual items is typically not generalisable in this scheme.
|
// individual items is typically not generalisable in this scheme.
|
||||||
|
|
||||||
typedef struct DqnMemStackBlock
|
|
||||||
{
|
|
||||||
u8 *memory;
|
|
||||||
size_t used;
|
|
||||||
size_t size;
|
|
||||||
|
|
||||||
DqnMemStackBlock *prevBlock;
|
|
||||||
} DqnMemStackBlock;
|
|
||||||
|
|
||||||
enum DqnMemStackFlag
|
enum DqnMemStackFlag
|
||||||
{
|
{
|
||||||
DqnMemStackFlag_IsNotExpandable = (1 << 0),
|
DqnMemStackFlag_IsNotExpandable = (1 << 0),
|
||||||
DqnMemStackFlag_IsFixedMemoryFromUser = (1 << 1), // NOTE(doyle): Required to indicate we CAN'T free this memory when free is called.
|
DqnMemStackFlag_IsFixedMemoryFromUser = (1 << 1), // NOTE(doyle): Required to indicate we CAN'T free this memory when free is called.
|
||||||
};
|
};
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Advanced API Structs
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
typedef struct DqnMemStack
|
typedef struct DqnMemStack
|
||||||
{
|
{
|
||||||
DqnMemStackBlock *block;
|
struct DqnMemStackBlock *block;
|
||||||
|
|
||||||
u32 flags;
|
u32 flags;
|
||||||
i32 tempStackCount;
|
i32 tempStackCount;
|
||||||
@ -123,7 +117,7 @@ typedef struct DqnMemStack
|
|||||||
typedef struct DqnTempMemStack
|
typedef struct DqnTempMemStack
|
||||||
{
|
{
|
||||||
DqnMemStack *stack;
|
DqnMemStack *stack;
|
||||||
DqnMemStackBlock *startingBlock;
|
struct DqnMemStackBlock *startingBlock;
|
||||||
size_t used;
|
size_t used;
|
||||||
|
|
||||||
} DqnTempMemStack;
|
} DqnTempMemStack;
|
||||||
@ -132,12 +126,12 @@ DQN_FILE_SCOPE bool DqnMemStack_InitWithFixedMem (DqnMemStack *const stack, u8 *
|
|||||||
DQN_FILE_SCOPE bool DqnMemStack_InitWithFixedSize(DqnMemStack *const stack, size_t size, const bool zeroClear, const u32 byteAlign = 4); // Single allocation from platform, no further allocations, returns NULL of allocate if out of space
|
DQN_FILE_SCOPE bool DqnMemStack_InitWithFixedSize(DqnMemStack *const stack, size_t size, const bool zeroClear, const u32 byteAlign = 4); // Single allocation from platform, no further allocations, returns NULL of allocate if out of space
|
||||||
DQN_FILE_SCOPE bool DqnMemStack_Init (DqnMemStack *const stack, size_t size, const bool zeroClear, const u32 byteAlign = 4); // Allocates from platform dynamically as space runs out
|
DQN_FILE_SCOPE bool DqnMemStack_Init (DqnMemStack *const stack, size_t size, const bool zeroClear, const u32 byteAlign = 4); // Allocates from platform dynamically as space runs out
|
||||||
|
|
||||||
DQN_FILE_SCOPE void *DqnMemStack_Push (DqnMemStack *const stack, size_t size); // Returns NULL if out of space and stack is using fixed memory/size, or platform allocation fails
|
DQN_FILE_SCOPE void *DqnMemStack_Push (DqnMemStack *const stack, size_t size); // Returns NULL if out of space and stack is using fixed memory/size, or platform allocation fails.
|
||||||
DQN_FILE_SCOPE bool DqnMemStack_Pop (DqnMemStack *const stack, void *ptr, size_t size); // Frees the given ptr. It MUST be the last allocated item in the stack
|
DQN_FILE_SCOPE bool DqnMemStack_Pop (DqnMemStack *const stack, void *ptr, size_t size); // Frees the given ptr. It MUST be the last allocated item in the stack.
|
||||||
DQN_FILE_SCOPE void DqnMemStack_Free (DqnMemStack *const stack); // Frees all blocks belonging to this stack
|
DQN_FILE_SCOPE void DqnMemStack_Free (DqnMemStack *const stack); // Frees all blocks belonging to this stack.
|
||||||
DQN_FILE_SCOPE bool DqnMemStack_FreeStackBlock(DqnMemStack *const stack, DqnMemStackBlock *block); // Frees the specified block, returns false if block doesn't belong
|
DQN_FILE_SCOPE bool DqnMemStack_FreeStackBlock(DqnMemStack *const stack, DqnMemStackBlock *block); // Frees the specified block, returns false if block doesn't belong, calls DqnMem_Free().
|
||||||
DQN_FILE_SCOPE bool DqnMemStack_FreeLastBlock (DqnMemStack *const stack); // Frees the last-most memory block. If last block, free that block, next allocate will attach a block.
|
DQN_FILE_SCOPE bool DqnMemStack_FreeLastBlock (DqnMemStack *const stack); // Frees the last-most memory block. If last block, free that block, next allocate will attach a block.
|
||||||
DQN_FILE_SCOPE void DqnMemStack_ClearCurrBlock(DqnMemStack *const stack, const bool zeroClear); // Reset the current memory block usage to 0
|
DQN_FILE_SCOPE void DqnMemStack_ClearCurrBlock(DqnMemStack *const stack, const bool zeroClear); // Reset the current memory block usage to 0.
|
||||||
|
|
||||||
// TempMemStack is only required for the function. Once BeginTempRegion() is called, subsequent allocation calls can be made using the original stack.
|
// TempMemStack is only required for the function. Once BeginTempRegion() is called, subsequent allocation calls can be made using the original stack.
|
||||||
// Upon EndTempRegion() the original stack will free any additional blocks it allocated during the temp region and revert to the original
|
// Upon EndTempRegion() the original stack will free any additional blocks it allocated during the temp region and revert to the original
|
||||||
@ -147,12 +141,26 @@ DQN_FILE_SCOPE void DqnMemStack_ClearCurrBlock(DqnMemStack *const stack, const
|
|||||||
DQN_FILE_SCOPE DqnTempMemStack DqnMemStack_BeginTempRegion(DqnMemStack *const stack);
|
DQN_FILE_SCOPE DqnTempMemStack DqnMemStack_BeginTempRegion(DqnMemStack *const stack);
|
||||||
DQN_FILE_SCOPE void DqnMemStack_EndTempRegion (DqnTempMemStack tempstack);
|
DQN_FILE_SCOPE void DqnMemStack_EndTempRegion (DqnTempMemStack tempstack);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// (OPTIONAL) DqnMemStack Advanced API
|
// (OPTIONAL) DqnMemStack Advanced API
|
||||||
|
// Blocks are freely modifiable if you want fine grained control. Size value and
|
||||||
|
// memory ptr should _NOT_ be modified directly, only indirectly through the
|
||||||
|
// regular API.
|
||||||
|
typedef struct DqnMemStackBlock
|
||||||
|
{
|
||||||
|
u8 *memory;
|
||||||
|
size_t size;
|
||||||
|
size_t used;
|
||||||
|
|
||||||
|
DqnMemStackBlock *prevBlock;
|
||||||
|
} DqnMemStackBlock;
|
||||||
|
|
||||||
// This is useful for forcing a new block to be used. AllocateCompatibleBlock
|
// This is useful for forcing a new block to be used. AllocateCompatibleBlock
|
||||||
// will fail if the supplied stack has flags set such that the stack is not
|
// will fail if the supplied stack has flags set such that the stack is not
|
||||||
// allowed to have new blocks.
|
// allowed to have new blocks.
|
||||||
DQN_FILE_SCOPE DqnMemStackBlock *DqnMemStack_AllocateCompatibleBlock(const DqnMemStack *const stack, size_t size);
|
DQN_FILE_SCOPE DqnMemStackBlock *DqnMemStack_AllocateCompatibleBlock(const DqnMemStack *const stack, size_t size);
|
||||||
DQN_FILE_SCOPE bool DqnMemStack_AttachBlock (DqnMemStack *const stack, DqnMemStackBlock *const newBlock);
|
DQN_FILE_SCOPE bool DqnMemStack_AttachBlock (DqnMemStack *const stack, DqnMemStackBlock *const newBlock);
|
||||||
|
DQN_FILE_SCOPE bool DqnMemStack_DetachBlock (DqnMemStack *const stack, DqnMemStackBlock *const detachBlock);
|
||||||
|
|
||||||
// (IMPORTANT) Should only be used to free blocks that haven't been attached!
|
// (IMPORTANT) Should only be used to free blocks that haven't been attached!
|
||||||
// Attached blocks should be freed using FreeStackBlock().
|
// Attached blocks should be freed using FreeStackBlock().
|
||||||
@ -521,8 +529,9 @@ typedef union DqnV3i
|
|||||||
} DqnV3i;
|
} DqnV3i;
|
||||||
|
|
||||||
// DqnV3
|
// DqnV3
|
||||||
DQN_FILE_SCOPE DqnV3 DqnV3_3i(i32 x, i32 y, i32 z); // Create a vector using ints and typecast to floats
|
DQN_FILE_SCOPE DqnV3 DqnV3_1f(f32 xyz);
|
||||||
DQN_FILE_SCOPE DqnV3 DqnV3_3f(f32 x, f32 y, f32 z);
|
DQN_FILE_SCOPE DqnV3 DqnV3_3f(f32 x, f32 y, f32 z);
|
||||||
|
DQN_FILE_SCOPE DqnV3 DqnV3_3i(i32 x, i32 y, i32 z); // Create a vector using ints and typecast to floats
|
||||||
|
|
||||||
DQN_FILE_SCOPE DqnV3 DqnV3_Add (DqnV3 a, DqnV3 b);
|
DQN_FILE_SCOPE DqnV3 DqnV3_Add (DqnV3 a, DqnV3 b);
|
||||||
DQN_FILE_SCOPE DqnV3 DqnV3_Sub (DqnV3 a, DqnV3 b);
|
DQN_FILE_SCOPE DqnV3 DqnV3_Sub (DqnV3 a, DqnV3 b);
|
||||||
@ -534,12 +543,16 @@ DQN_FILE_SCOPE bool DqnV3_Equals (DqnV3 a, DqnV3 b);
|
|||||||
DQN_FILE_SCOPE DqnV3 DqnV3_Cross (DqnV3 a, DqnV3 b);
|
DQN_FILE_SCOPE DqnV3 DqnV3_Cross (DqnV3 a, DqnV3 b);
|
||||||
|
|
||||||
DQN_FILE_SCOPE DqnV3 DqnV3_Normalise (DqnV3 a);
|
DQN_FILE_SCOPE DqnV3 DqnV3_Normalise (DqnV3 a);
|
||||||
|
DQN_FILE_SCOPE f32 DqnV3_Length (DqnV3 a, DqnV3 b);
|
||||||
|
DQN_FILE_SCOPE f32 DqnV3_LengthSquared(DqnV3 a, DqnV3 b);
|
||||||
|
|
||||||
DQN_FILE_SCOPE inline DqnV3 operator- (DqnV3 a, DqnV3 b) { return DqnV3_Sub (a, b); }
|
DQN_FILE_SCOPE inline DqnV3 operator- (DqnV3 a, DqnV3 b) { return DqnV3_Sub (a, b); }
|
||||||
DQN_FILE_SCOPE inline DqnV3 operator+ (DqnV3 a, DqnV3 b) { return DqnV3_Add (a, b); }
|
DQN_FILE_SCOPE inline DqnV3 operator+ (DqnV3 a, DqnV3 b) { return DqnV3_Add (a, b); }
|
||||||
|
DQN_FILE_SCOPE inline DqnV3 operator+ (DqnV3 a, f32 b) { return DqnV3_Add (a, DqnV3_1f(b)); }
|
||||||
DQN_FILE_SCOPE inline DqnV3 operator* (DqnV3 a, DqnV3 b) { return DqnV3_Hadamard(a, b); }
|
DQN_FILE_SCOPE inline DqnV3 operator* (DqnV3 a, DqnV3 b) { return DqnV3_Hadamard(a, b); }
|
||||||
DQN_FILE_SCOPE inline DqnV3 operator* (DqnV3 a, f32 b) { return DqnV3_Scalef (a, b); }
|
DQN_FILE_SCOPE inline DqnV3 operator* (DqnV3 a, f32 b) { return DqnV3_Scalef (a, b); }
|
||||||
DQN_FILE_SCOPE inline DqnV3 operator* (DqnV3 a, i32 b) { return DqnV3_Scalei (a, b); }
|
DQN_FILE_SCOPE inline DqnV3 operator* (DqnV3 a, i32 b) { return DqnV3_Scalei (a, b); }
|
||||||
|
DQN_FILE_SCOPE inline DqnV3 operator/ (DqnV3 a, f32 b) { return DqnV3_Scalef (a, (1.0f/b)); }
|
||||||
DQN_FILE_SCOPE inline DqnV3 &operator*=(DqnV3 &a, DqnV3 b) { return (a = DqnV3_Hadamard(a, b)); }
|
DQN_FILE_SCOPE inline DqnV3 &operator*=(DqnV3 &a, DqnV3 b) { return (a = DqnV3_Hadamard(a, b)); }
|
||||||
DQN_FILE_SCOPE inline DqnV3 &operator*=(DqnV3 &a, f32 b) { return (a = DqnV3_Scalef (a, b)); }
|
DQN_FILE_SCOPE inline DqnV3 &operator*=(DqnV3 &a, f32 b) { return (a = DqnV3_Scalef (a, b)); }
|
||||||
DQN_FILE_SCOPE inline DqnV3 &operator*=(DqnV3 &a, i32 b) { return (a = DqnV3_Scalei (a, b)); }
|
DQN_FILE_SCOPE inline DqnV3 &operator*=(DqnV3 &a, i32 b) { return (a = DqnV3_Scalei (a, b)); }
|
||||||
@ -572,6 +585,7 @@ typedef union DqnV4 {
|
|||||||
// Create a vector using ints and typecast to floats
|
// Create a vector using ints and typecast to floats
|
||||||
DQN_FILE_SCOPE DqnV4 DqnV4_4i(i32 x, i32 y, i32 z, f32 w);
|
DQN_FILE_SCOPE DqnV4 DqnV4_4i(i32 x, i32 y, i32 z, f32 w);
|
||||||
DQN_FILE_SCOPE DqnV4 DqnV4_4f(f32 x, f32 y, f32 z, f32 w);
|
DQN_FILE_SCOPE DqnV4 DqnV4_4f(f32 x, f32 y, f32 z, f32 w);
|
||||||
|
DQN_FILE_SCOPE DqnV4 DqnV4_V3(DqnV3 a, f32 w);
|
||||||
DQN_FILE_SCOPE DqnV4 DqnV4_1f(f32 xyzw);
|
DQN_FILE_SCOPE DqnV4 DqnV4_1f(f32 xyzw);
|
||||||
|
|
||||||
DQN_FILE_SCOPE DqnV4 DqnV4_Add (DqnV4 a, DqnV4 b);
|
DQN_FILE_SCOPE DqnV4 DqnV4_Add (DqnV4 a, DqnV4 b);
|
||||||
@ -600,13 +614,18 @@ DQN_FILE_SCOPE inline bool operator==(DqnV4 a, DqnV4 b) { return DqnV4_E
|
|||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
typedef union DqnMat4
|
typedef union DqnMat4
|
||||||
{
|
{
|
||||||
|
// TODO(doyle): Row/column instead? More cache friendly since multiplication
|
||||||
|
// prefers rows.
|
||||||
DqnV4 col[4];
|
DqnV4 col[4];
|
||||||
// Column/row
|
f32 e[4][4]; // Column/row
|
||||||
f32 e[4][4];
|
|
||||||
} DqnMat4;
|
} DqnMat4;
|
||||||
|
|
||||||
DQN_FILE_SCOPE DqnMat4 DqnMat4_Identity ();
|
DQN_FILE_SCOPE DqnMat4 DqnMat4_Identity ();
|
||||||
DQN_FILE_SCOPE DqnMat4 DqnMat4_Ortho (f32 left, f32 right, f32 bottom, f32 top, f32 zNear, f32 zFar);
|
|
||||||
|
DQN_FILE_SCOPE DqnMat4 DqnMat4_Orthographic(f32 left, f32 right, f32 bottom, f32 top, f32 zNear, f32 zFar);
|
||||||
|
DQN_FILE_SCOPE DqnMat4 DqnMat4_Perspective (f32 fovYDegrees, f32 aspectRatio, f32 zNear, f32 zFar);
|
||||||
|
DQN_FILE_SCOPE DqnMat4 DqnMat4_LookAt (DqnV3 eye, DqnV3 center, DqnV3 up);
|
||||||
|
|
||||||
DQN_FILE_SCOPE DqnMat4 DqnMat4_Translate (f32 x, f32 y, f32 z);
|
DQN_FILE_SCOPE DqnMat4 DqnMat4_Translate (f32 x, f32 y, f32 z);
|
||||||
DQN_FILE_SCOPE DqnMat4 DqnMat4_Rotate (f32 radians, f32 x, f32 y, f32 z);
|
DQN_FILE_SCOPE DqnMat4 DqnMat4_Rotate (f32 radians, f32 x, f32 y, f32 z);
|
||||||
DQN_FILE_SCOPE DqnMat4 DqnMat4_Scale (f32 x, f32 y, f32 z);
|
DQN_FILE_SCOPE DqnMat4 DqnMat4_Scale (f32 x, f32 y, f32 z);
|
||||||
@ -1394,6 +1413,31 @@ DQN_FILE_SCOPE bool DqnMemStack_AttachBlock(DqnMemStack *const stack,
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DQN_FILE_SCOPE bool DqnMemStack_DetachBlock(DqnMemStack *const stack,
|
||||||
|
DqnMemStackBlock *const detachBlock)
|
||||||
|
{
|
||||||
|
if (!stack || !detachBlock) return false;
|
||||||
|
if (stack->flags & DqnMemStackFlag_IsFixedMemoryFromUser) return false;
|
||||||
|
if (stack->flags & DqnMemStackFlag_IsNotExpandable) return false;
|
||||||
|
|
||||||
|
DqnMemStackBlock **blockPtr = &stack->block;
|
||||||
|
while (*blockPtr && *blockPtr != detachBlock)
|
||||||
|
blockPtr = &((*blockPtr)->prevBlock);
|
||||||
|
|
||||||
|
if (*blockPtr)
|
||||||
|
{
|
||||||
|
*blockPtr = detachBlock->prevBlock;
|
||||||
|
detachBlock->prevBlock = NULL;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
DQN_FILE_SCOPE void DqnMemStack_FreeBlock(DqnMemStackBlock *block)
|
DQN_FILE_SCOPE void DqnMemStack_FreeBlock(DqnMemStackBlock *block)
|
||||||
{
|
{
|
||||||
if (!block) return;
|
if (!block) return;
|
||||||
@ -1406,7 +1450,6 @@ DQN_FILE_SCOPE bool DqnMemStack_InitWithFixedMem(DqnMemStack *const stack,
|
|||||||
const u32 byteAlign)
|
const u32 byteAlign)
|
||||||
{
|
{
|
||||||
if (!stack || !mem) return false;
|
if (!stack || !mem) return false;
|
||||||
DQN_ASSERT(!stack->block);
|
|
||||||
|
|
||||||
// TODO(doyle): Better logging
|
// TODO(doyle): Better logging
|
||||||
if (memSize < sizeof(DqnMemStackBlock))
|
if (memSize < sizeof(DqnMemStackBlock))
|
||||||
@ -1416,6 +1459,7 @@ DQN_FILE_SCOPE bool DqnMemStack_InitWithFixedMem(DqnMemStack *const stack,
|
|||||||
stack->block->memory = mem + sizeof(DqnMemStackBlock);
|
stack->block->memory = mem + sizeof(DqnMemStackBlock);
|
||||||
stack->block->used = 0;
|
stack->block->used = 0;
|
||||||
stack->block->size = memSize - sizeof(DqnMemStackBlock);
|
stack->block->size = memSize - sizeof(DqnMemStackBlock);
|
||||||
|
stack->block->prevBlock = NULL;
|
||||||
stack->flags = (DqnMemStackFlag_IsFixedMemoryFromUser | DqnMemStackFlag_IsNotExpandable);
|
stack->flags = (DqnMemStackFlag_IsFixedMemoryFromUser | DqnMemStackFlag_IsNotExpandable);
|
||||||
|
|
||||||
const u32 DEFAULT_ALIGNMENT = 4;
|
const u32 DEFAULT_ALIGNMENT = 4;
|
||||||
@ -2032,18 +2076,21 @@ DQN_FILE_SCOPE bool DqnV2i_Equals(DqnV2i a, DqnV2i b)
|
|||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// Vec3
|
// Vec3
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
DQN_FILE_SCOPE DqnV3 DqnV3_1f(f32 xyz)
|
||||||
|
{
|
||||||
|
DqnV3 result = {xyz, xyz, xyz};
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
DQN_FILE_SCOPE DqnV3 DqnV3_3f(f32 x, f32 y, f32 z)
|
DQN_FILE_SCOPE DqnV3 DqnV3_3f(f32 x, f32 y, f32 z)
|
||||||
{
|
{
|
||||||
DqnV3 result = {};
|
DqnV3 result = {x, y, z};
|
||||||
result.x = x;
|
|
||||||
result.y = y;
|
|
||||||
result.z = z;
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
DQN_FILE_SCOPE DqnV3 DqnV3_3i(i32 x, i32 y, i32 z)
|
DQN_FILE_SCOPE DqnV3 DqnV3_3i(i32 x, i32 y, i32 z)
|
||||||
{
|
{
|
||||||
DqnV3 result = DqnV3_3f((f32)x, (f32)y, (f32)z);
|
DqnV3 result = {(f32)x, (f32)y, (f32)z};
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2141,6 +2188,24 @@ DQN_FILE_SCOPE DqnV3 DqnV3_Normalise(DqnV3 a)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DQN_FILE_SCOPE f32 DqnV3_LengthSquared(DqnV3 a, DqnV3 b)
|
||||||
|
{
|
||||||
|
f32 x = b.x - a.x;
|
||||||
|
f32 y = b.y - a.y;
|
||||||
|
f32 z = b.z - a.z;
|
||||||
|
f32 result = (DQN_SQUARED(x) + DQN_SQUARED(y) + DQN_SQUARED(z));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
DQN_FILE_SCOPE f32 DqnV3_Length(DqnV3 a, DqnV3 b)
|
||||||
|
{
|
||||||
|
f32 lengthSq = DqnV3_LengthSquared(a, b);
|
||||||
|
if (lengthSq == 0) return 0;
|
||||||
|
|
||||||
|
f32 result = DqnMath_Sqrtf(lengthSq);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
DQN_FILE_SCOPE DqnV3i DqnV3i_3i(i32 x, i32 y, i32 z)
|
DQN_FILE_SCOPE DqnV3i DqnV3i_3i(i32 x, i32 y, i32 z)
|
||||||
{
|
{
|
||||||
DqnV3i result = {x, y, z};
|
DqnV3i result = {x, y, z};
|
||||||
@ -2168,6 +2233,14 @@ DQN_FILE_SCOPE DqnV4 DqnV4_4i(i32 x, i32 y, i32 z, i32 w)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DQN_FILE_SCOPE DqnV4 DqnV4_V3(DqnV3 a, f32 w)
|
||||||
|
{
|
||||||
|
DqnV4 result;
|
||||||
|
result.xyz = a;
|
||||||
|
result.w = w;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
DQN_FILE_SCOPE DqnV4 DqnV4_1f(f32 xyzw)
|
DQN_FILE_SCOPE DqnV4 DqnV4_1f(f32 xyzw)
|
||||||
{
|
{
|
||||||
DqnV4 result = {xyzw, xyzw, xyzw, xyzw};
|
DqnV4 result = {xyzw, xyzw, xyzw, xyzw};
|
||||||
@ -2256,8 +2329,8 @@ DQN_FILE_SCOPE DqnMat4 DqnMat4_Identity()
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
DQN_FILE_SCOPE DqnMat4
|
DQN_FILE_SCOPE DqnMat4 DqnMat4_Orthographic(f32 left, f32 right, f32 bottom, f32 top, f32 zNear,
|
||||||
DqnMat4_Ortho(f32 left, f32 right, f32 bottom, f32 top, f32 zNear, f32 zFar)
|
f32 zFar)
|
||||||
{
|
{
|
||||||
DqnMat4 result = DqnMat4_Identity();
|
DqnMat4 result = DqnMat4_Identity();
|
||||||
result.e[0][0] = +2.0f / (right - left);
|
result.e[0][0] = +2.0f / (right - left);
|
||||||
@ -2271,6 +2344,51 @@ DqnMat4_Ortho(f32 left, f32 right, f32 bottom, f32 top, f32 zNear, f32 zFar)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DQN_FILE_SCOPE DqnMat4 DqnMat4_Perspective(f32 fovYDegrees, f32 aspectRatio, f32 zNear, f32 zFar)
|
||||||
|
{
|
||||||
|
f32 fovYRadians = DQN_DEGREES_TO_RADIANS(fovYDegrees);
|
||||||
|
f32 fovYRadiansOver2 = fovYRadians * 0.5f;
|
||||||
|
f32 tanFovYRadiansOver2 = tanf(fovYRadiansOver2);
|
||||||
|
f32 zNearSubZFar = zNear - zFar;
|
||||||
|
|
||||||
|
DqnMat4 result = DqnMat4_Identity();
|
||||||
|
result.e[0][0] = 1.0f / (tanFovYRadiansOver2 * aspectRatio);
|
||||||
|
result.e[1][1] = 1.0f / tanFovYRadiansOver2;
|
||||||
|
result.e[2][2] = (zNear + zFar) / zNearSubZFar;
|
||||||
|
result.e[2][3] = -1.0f;
|
||||||
|
result.e[3][2] = (2.0f * zNear * zFar) / zNearSubZFar;
|
||||||
|
result.e[3][3] = 0.0f;
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
DQN_FILE_SCOPE DqnMat4 DqnMat4_LookAt(DqnV3 eye, DqnV3 center, DqnV3 up)
|
||||||
|
{
|
||||||
|
DqnMat4 result = {0};
|
||||||
|
|
||||||
|
DqnV3 f = DqnV3_Normalise(DqnV3_Sub(eye, center));
|
||||||
|
DqnV3 s = DqnV3_Normalise(DqnV3_Cross(up, f));
|
||||||
|
DqnV3 u = DqnV3_Cross(f, s);
|
||||||
|
|
||||||
|
result.e[0][0] = s.x;
|
||||||
|
result.e[0][1] = u.x;
|
||||||
|
result.e[0][2] = f.x;
|
||||||
|
|
||||||
|
result.e[1][0] = s.y;
|
||||||
|
result.e[1][1] = u.y;
|
||||||
|
result.e[1][2] = f.y;
|
||||||
|
|
||||||
|
result.e[2][0] = s.z;
|
||||||
|
result.e[2][1] = u.z;
|
||||||
|
result.e[2][2] = f.z;
|
||||||
|
|
||||||
|
result.e[3][0] = DqnV3_Dot(s, eye);
|
||||||
|
result.e[3][1] = DqnV3_Dot(u, eye);
|
||||||
|
result.e[3][2] = -DqnV3_Dot(f, eye);
|
||||||
|
result.e[3][3] = 1.0f;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
DQN_FILE_SCOPE DqnMat4 DqnMat4_Translate(f32 x, f32 y, f32 z)
|
DQN_FILE_SCOPE DqnMat4 DqnMat4_Translate(f32 x, f32 y, f32 z)
|
||||||
{
|
{
|
||||||
DqnMat4 result = DqnMat4_Identity();
|
DqnMat4 result = DqnMat4_Identity();
|
||||||
@ -2285,20 +2403,19 @@ DQN_FILE_SCOPE DqnMat4 DqnMat4_Rotate(f32 radians, f32 x, f32 y, f32 z)
|
|||||||
DqnMat4 result = DqnMat4_Identity();
|
DqnMat4 result = DqnMat4_Identity();
|
||||||
f32 sinVal = sinf(radians);
|
f32 sinVal = sinf(radians);
|
||||||
f32 cosVal = cosf(radians);
|
f32 cosVal = cosf(radians);
|
||||||
|
f32 oneMinusCosVal = 1 - cosVal;
|
||||||
|
|
||||||
result.e[0][0] = (cosVal + (DQN_SQUARED(x) * (1.0f - cosVal)));
|
result.e[0][0] = (DQN_SQUARED(x) * oneMinusCosVal) + cosVal;
|
||||||
result.e[0][1] = ((y * z * (1.0f - cosVal)) + (z * sinVal));
|
result.e[0][1] = (x * y * oneMinusCosVal) + (z * sinVal);
|
||||||
result.e[0][2] = ((z * x * (1.0f - cosVal)) - (y * sinVal));
|
result.e[0][2] = (x * z * oneMinusCosVal) - (y * sinVal);
|
||||||
|
|
||||||
result.e[1][0] = ((x * y * (1.0f - cosVal)) - (z * sinVal));
|
result.e[1][0] = (y * x * oneMinusCosVal) - (z * sinVal);
|
||||||
result.e[1][1] = (cosVal + (DQN_SQUARED(y) * (1.0f - cosVal)));
|
result.e[1][1] = (DQN_SQUARED(y) * oneMinusCosVal) + cosVal;
|
||||||
result.e[1][2] = ((z * y * (1.0f - cosVal)) + (x * sinVal));
|
result.e[1][2] = (y * z * oneMinusCosVal) + (x * sinVal);
|
||||||
|
|
||||||
result.e[2][0] = ((x * z * (1.0f - cosVal)) + (y * sinVal));
|
result.e[2][0] = (z * x * oneMinusCosVal) + (y * sinVal);
|
||||||
result.e[2][1] = ((y * z * (1.0f - cosVal)) - (x * sinVal));
|
result.e[2][1] = (z * y * oneMinusCosVal) - (x * sinVal);
|
||||||
result.e[2][2] = (cosVal + (DQN_SQUARED(z) * (1.0f - cosVal)));
|
result.e[2][2] = (DQN_SQUARED(z) * oneMinusCosVal) + cosVal;
|
||||||
|
|
||||||
result.e[3][3] = 1;
|
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@ -2317,7 +2434,8 @@ DQN_FILE_SCOPE DqnMat4 DqnMat4_Mul(DqnMat4 a, DqnMat4 b)
|
|||||||
{
|
{
|
||||||
DqnMat4 result = {0};
|
DqnMat4 result = {0};
|
||||||
for (i32 j = 0; j < 4; j++) {
|
for (i32 j = 0; j < 4; j++) {
|
||||||
for (i32 i = 0; i < 4; i++) {
|
for (i32 i = 0; i < 4; i++)
|
||||||
|
{
|
||||||
result.e[j][i] = a.e[0][i] * b.e[j][0]
|
result.e[j][i] = a.e[0][i] * b.e[j][0]
|
||||||
+ a.e[1][i] * b.e[j][1]
|
+ a.e[1][i] * b.e[j][1]
|
||||||
+ a.e[2][i] * b.e[j][2]
|
+ a.e[2][i] * b.e[j][2]
|
||||||
@ -2331,15 +2449,10 @@ DQN_FILE_SCOPE DqnMat4 DqnMat4_Mul(DqnMat4 a, DqnMat4 b)
|
|||||||
DQN_FILE_SCOPE DqnV4 DqnMat4_MulV4(DqnMat4 a, DqnV4 b)
|
DQN_FILE_SCOPE DqnV4 DqnMat4_MulV4(DqnMat4 a, DqnV4 b)
|
||||||
{
|
{
|
||||||
DqnV4 result = {0};
|
DqnV4 result = {0};
|
||||||
|
result.x = (a.e[0][0] * b.x) + (a.e[1][0] * b.y) + (a.e[2][0] * b.z) + (a.e[3][0] * b.w);
|
||||||
result.x = (a.e[0][0] * b.x) + (a.e[1][0] * b.y) + (a.e[2][0] * b.z) +
|
result.y = (a.e[0][1] * b.x) + (a.e[1][1] * b.y) + (a.e[2][1] * b.z) + (a.e[3][1] * b.w);
|
||||||
(a.e[3][0] * b.w);
|
result.z = (a.e[0][2] * b.x) + (a.e[1][2] * b.y) + (a.e[2][2] * b.z) + (a.e[3][2] * b.w);
|
||||||
result.y = (a.e[0][1] * b.x) + (a.e[1][1] * b.y) + (a.e[2][1] * b.z) +
|
result.w = (a.e[0][3] * b.x) + (a.e[1][3] * b.y) + (a.e[2][3] * b.z) + (a.e[3][3] * b.w);
|
||||||
(a.e[3][1] * b.w);
|
|
||||||
result.z = (a.e[0][2] * b.x) + (a.e[1][2] * b.y) + (a.e[2][2] * b.z) +
|
|
||||||
(a.e[3][2] * b.w);
|
|
||||||
result.w = (a.e[0][3] * b.x) + (a.e[1][3] * b.y) + (a.e[2][3] * b.z) +
|
|
||||||
(a.e[3][3] * b.w);
|
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,97 @@
|
|||||||
#define DQN_IMPLEMENTATION
|
#define DQN_IMPLEMENTATION
|
||||||
#include "dqn.h"
|
#include "dqn.h"
|
||||||
|
|
||||||
|
#define HANDMADE_MATH_IMPLEMENTATION
|
||||||
|
#define HANDMADE_MATH_CPP_MODE
|
||||||
|
#include "tests/HandmadeMath.h"
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
|
void HandmadeMathVerifyMat4(DqnMat4 dqnMat, hmm_mat4 hmmMat)
|
||||||
|
{
|
||||||
|
f32 *hmmMatf = (f32 *)&hmmMat;
|
||||||
|
f32 *dqnMatf = (f32 *)&dqnMat;
|
||||||
|
|
||||||
|
const u32 EXPECTED_SIZE = 16;
|
||||||
|
u32 totalSize = DQN_ARRAY_COUNT(dqnMat.e) * DQN_ARRAY_COUNT(dqnMat.e[0]);
|
||||||
|
DQN_ASSERT(totalSize == EXPECTED_SIZE);
|
||||||
|
DQN_ASSERT(totalSize == (DQN_ARRAY_COUNT(hmmMat.Elements) * DQN_ARRAY_COUNT(hmmMat.Elements[0])));
|
||||||
|
|
||||||
|
for (i32 i = 0; i < EXPECTED_SIZE; i++)
|
||||||
|
DQN_ASSERT(hmmMatf[i] == dqnMatf[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void HandmadeMathTest()
|
||||||
|
{
|
||||||
|
// Test Perspective/Projection matrix values
|
||||||
|
{
|
||||||
|
f32 aspectRatio = 1;
|
||||||
|
DqnMat4 dqnPerspective = DqnMat4_Perspective(90, aspectRatio, 100, 1000);
|
||||||
|
hmm_mat4 hmmPerspective = HMM_Perspective(90, aspectRatio, 100, 1000);
|
||||||
|
HandmadeMathVerifyMat4(dqnPerspective, hmmPerspective);
|
||||||
|
|
||||||
|
printf("HandmadeMathTest(): Perspective: Completed successfully\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test Mat4 translate * scale
|
||||||
|
{
|
||||||
|
hmm_vec3 hmmVec = HMM_Vec3i(1, 2, 3);
|
||||||
|
DqnV3 dqnVec = DqnV3_3i(1, 2, 3);
|
||||||
|
DqnMat4 dqnTranslate = DqnMat4_Translate(dqnVec.x, dqnVec.y, dqnVec.z);
|
||||||
|
hmm_mat4 hmmTranslate = HMM_Translate(hmmVec);
|
||||||
|
HandmadeMathVerifyMat4(dqnTranslate, hmmTranslate);
|
||||||
|
|
||||||
|
hmm_vec3 hmmAxis = HMM_Vec3(0.5f, 0.2f, 0.7f);
|
||||||
|
DqnV3 dqnAxis = DqnV3_3f(0.5f, 0.2f, 0.7f);
|
||||||
|
f32 rotationInDegrees = 80.0f;
|
||||||
|
|
||||||
|
// TODO(doyle): ?? Handmade Math does it a rotations in a different way
|
||||||
|
// way, they normalise the given axis producing different results.
|
||||||
|
// HandmadeMathVerifyMat4(dqnRotate, hmmRotate);
|
||||||
|
|
||||||
|
dqnVec *= 2;
|
||||||
|
hmmVec *= 2;
|
||||||
|
DqnMat4 dqnScale = DqnMat4_Scale(dqnVec.x, dqnVec.y, dqnVec.z);
|
||||||
|
hmm_mat4 hmmScale = HMM_Scale(hmmVec);
|
||||||
|
HandmadeMathVerifyMat4(dqnScale, hmmScale);
|
||||||
|
|
||||||
|
DqnMat4 dqnTSMatrix = DqnMat4_Mul(dqnTranslate, dqnScale);
|
||||||
|
hmm_mat4 hmmTSMatrix = HMM_MultiplyMat4(hmmTranslate, hmmScale);
|
||||||
|
HandmadeMathVerifyMat4(dqnTSMatrix, hmmTSMatrix);
|
||||||
|
|
||||||
|
|
||||||
|
// Test Mat4 * MulV4
|
||||||
|
{
|
||||||
|
DqnV4 dqnV4 = DqnV4_4f(1, 2, 3, 4);
|
||||||
|
hmm_vec4 hmmV4 = HMM_Vec4(1, 2, 3, 4);
|
||||||
|
|
||||||
|
DqnV4 dqnResult = DqnMat4_MulV4(dqnTSMatrix, dqnV4);
|
||||||
|
hmm_vec4 hmmResult = HMM_MultiplyMat4ByVec4(hmmTSMatrix, hmmV4);
|
||||||
|
|
||||||
|
DQN_ASSERT(dqnResult.x == hmmResult.X);
|
||||||
|
DQN_ASSERT(dqnResult.y == hmmResult.Y);
|
||||||
|
DQN_ASSERT(dqnResult.z == hmmResult.Z);
|
||||||
|
DQN_ASSERT(dqnResult.w == hmmResult.W);
|
||||||
|
|
||||||
|
printf(
|
||||||
|
"HandmadeMathTest(): Mat4 * MulV4: Completed successfully\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("HandmadeMathTest(): Translate/Scale/Rotate Mat4_Mul: Completed successfully\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test LookAt/Camera/View matrix returns same results
|
||||||
|
{
|
||||||
|
DqnMat4 dqnViewMatrix = DqnMat4_LookAt(DqnV3_3f(4, 3, 3), DqnV3_1f(0), DqnV3_3f(0, 1, 0));
|
||||||
|
hmm_mat4 hmmViewMatrix =
|
||||||
|
HMM_LookAt(HMM_Vec3(4, 3, 3), HMM_Vec3(0, 0, 0), HMM_Vec3(0, 1, 0));
|
||||||
|
|
||||||
|
HandmadeMathVerifyMat4(dqnViewMatrix, hmmViewMatrix);
|
||||||
|
printf("HandmadeMathTest(): LookAt: Completed successfully\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
void StringsTest()
|
void StringsTest()
|
||||||
{
|
{
|
||||||
{ // Char Checks
|
{ // Char Checks
|
||||||
@ -1404,6 +1494,7 @@ int main(void)
|
|||||||
StringsTest();
|
StringsTest();
|
||||||
RandomTest();
|
RandomTest();
|
||||||
MathTest();
|
MathTest();
|
||||||
|
HandmadeMathTest();
|
||||||
VecTest();
|
VecTest();
|
||||||
OtherTest();
|
OtherTest();
|
||||||
ArrayTest();
|
ArrayTest();
|
||||||
|
2659
tests/HandmadeMath.h
Normal file
2659
tests/HandmadeMath.h
Normal file
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user