Add helper V4 functions, change allocate to push

This commit is contained in:
Doyle Thai 2017-05-26 01:10:32 +10:00
parent 25744855ee
commit fceac54ecb
2 changed files with 55 additions and 35 deletions

64
dqn.h
View File

@ -20,6 +20,7 @@
#endif
#include <stdint.h> // For standard types
#include <float.h>
#define LOCAL_PERSIST static
#define FILE_SCOPE static
@ -35,6 +36,8 @@ typedef int16_t i16;
typedef double f64;
typedef float f32;
#define DQN_F32_MIN -FLT_MAX
#define DQN_TERABYTE(val) (DQN_GIGABYTE(val) * 1024LL)
#define DQN_GIGABYTE(val) (DQN_MEGABYTE(val) * 1024LL)
#define DQN_MEGABYTE(val) (DQN_KILOBYTE(val) * 1024LL)
@ -75,7 +78,7 @@ DQN_FILE_SCOPE void DqnMem_Free (void *memory);
// When an allocation requires a larger amount of memory than available in the
// block then the MemStack will allocate a new block of sufficient size for
// you in DqnMemStack_Allocate(..). This _DOES_ mean that there will be wasted
// you in DqnMemStack_Push(..). This _DOES_ mean that there will be wasted
// space at the end of each block and is a tradeoff for memory locality against
// optimal space usage.
@ -88,7 +91,7 @@ DQN_FILE_SCOPE void DqnMem_Free (void *memory);
// - InitWithFixedSize() allows you to to disable dynamic allocations and
// sub-allocate from the initial MemStack allocation size only.
// 2. Use DqnMemStack_Allocate(..) to allocate memory for use.
// 2. Use DqnMemStack_Push(..) to allocate memory for use.
// - "Freeing" memory is dealt by creating temporary MemStacks or using the
// BeginTempRegion and EndTempRegion functions. Specifically freeing
// individual items is typically not generalisable in this scheme.
@ -129,12 +132,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_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_Allocate (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 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_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_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 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_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
// 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
@ -504,6 +507,8 @@ DQN_FILE_SCOPE inline bool operator==(DqnV2i a, DqnV2i b) { return DqnV
typedef union DqnV3
{
struct { f32 x, y, z; };
DqnV2 xy;
struct { f32 r, g, b; };
f32 e[3];
} DqnV3;
@ -528,6 +533,8 @@ DQN_FILE_SCOPE f32 DqnV3_Dot (DqnV3 a, DqnV3 b);
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_Normalise(DqnV3 a);
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_Hadamard(a, b); }
@ -548,8 +555,12 @@ DQN_FILE_SCOPE DqnV3i DqnV3i_3f(f32 x, f32 y, f32 z);
// Vec4
////////////////////////////////////////////////////////////////////////////////
typedef union DqnV4 {
struct { f32 x, y, z, w; };
struct
{
f32 x, y, z, w;
};
DqnV3 xyz;
DqnV2 xy;
struct { f32 r, g, b, a; };
DqnV3 rgb;
@ -571,17 +582,18 @@ DQN_FILE_SCOPE DqnV4 DqnV4_Hadamard(DqnV4 a, DqnV4 b);
DQN_FILE_SCOPE f32 DqnV4_Dot (DqnV4 a, DqnV4 b);
DQN_FILE_SCOPE bool DqnV4_Equals (DqnV4 a, DqnV4 b);
DQN_FILE_SCOPE inline DqnV4 operator- (DqnV4 a, DqnV4 b) { return DqnV4_Sub (a, b); }
DQN_FILE_SCOPE inline DqnV4 operator+ (DqnV4 a, DqnV4 b) { return DqnV4_Add (a, b); }
DQN_FILE_SCOPE inline DqnV4 operator* (DqnV4 a, DqnV4 b) { return DqnV4_Hadamard(a, b); }
DQN_FILE_SCOPE inline DqnV4 operator* (DqnV4 a, f32 b) { return DqnV4_Scalef (a, b); }
DQN_FILE_SCOPE inline DqnV4 operator* (DqnV4 a, i32 b) { return DqnV4_Scalei (a, b); }
DQN_FILE_SCOPE inline DqnV4 &operator*=(DqnV4 &a, DqnV4 b) { return (a = DqnV4_Hadamard(a, b)); }
DQN_FILE_SCOPE inline DqnV4 &operator*=(DqnV4 &a, f32 b) { return (a = DqnV4_Scalef (a, b)); }
DQN_FILE_SCOPE inline DqnV4 &operator*=(DqnV4 &a, i32 b) { return (a = DqnV4_Scalei (a, b)); }
DQN_FILE_SCOPE inline DqnV4 &operator-=(DqnV4 &a, DqnV4 b) { return (a = DqnV4_Sub (a, b)); }
DQN_FILE_SCOPE inline DqnV4 &operator+=(DqnV4 &a, DqnV4 b) { return (a = DqnV4_Add (a, b)); }
DQN_FILE_SCOPE inline bool operator==(DqnV4 a, DqnV4 b) { return DqnV4_Equals (a, b); }
DQN_FILE_SCOPE inline DqnV4 operator- (DqnV4 a, DqnV4 b) { return DqnV4_Sub (a, b); }
DQN_FILE_SCOPE inline DqnV4 operator+ (DqnV4 a, DqnV4 b) { return DqnV4_Add (a, b); }
DQN_FILE_SCOPE inline DqnV4 operator+ (DqnV4 a, f32 b) { return DqnV4_Add (a, DqnV4_1f(b)); }
DQN_FILE_SCOPE inline DqnV4 operator* (DqnV4 a, DqnV4 b) { return DqnV4_Hadamard(a, b); }
DQN_FILE_SCOPE inline DqnV4 operator* (DqnV4 a, f32 b) { return DqnV4_Scalef (a, b); }
DQN_FILE_SCOPE inline DqnV4 operator* (DqnV4 a, i32 b) { return DqnV4_Scalei (a, b); }
DQN_FILE_SCOPE inline DqnV4 &operator*=(DqnV4 &a, DqnV4 b) { return (a = DqnV4_Hadamard(a, b)); }
DQN_FILE_SCOPE inline DqnV4 &operator*=(DqnV4 &a, f32 b) { return (a = DqnV4_Scalef (a, b)); }
DQN_FILE_SCOPE inline DqnV4 &operator*=(DqnV4 &a, i32 b) { return (a = DqnV4_Scalei (a, b)); }
DQN_FILE_SCOPE inline DqnV4 &operator-=(DqnV4 &a, DqnV4 b) { return (a = DqnV4_Sub (a, b)); }
DQN_FILE_SCOPE inline DqnV4 &operator+=(DqnV4 &a, DqnV4 b) { return (a = DqnV4_Add (a, b)); }
DQN_FILE_SCOPE inline bool operator==(DqnV4 a, DqnV4 b) { return DqnV4_Equals (a, b); }
////////////////////////////////////////////////////////////////////////////////
// 4D Matrix Mat4
@ -754,7 +766,6 @@ DQN_FILE_SCOPE i32 DqnRnd_PCGRange(DqnRandPCGState *pcg, i32 min, i32 max);
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
#define DQN_WIN32_ERROR_BOX(text, title) MessageBoxA(NULL, text, title, MB_OK);
// Out is a pointer to the buffer to receive the characters.
// outLen is the length/capacity of the out buffer
@ -1444,7 +1455,7 @@ DQN_FILE_SCOPE bool DqnMemStack_InitWithFixedSize(DqnMemStack *const stack,
return false;
}
DQN_FILE_SCOPE void *DqnMemStack_Allocate(DqnMemStack *const stack, size_t size)
DQN_FILE_SCOPE void *DqnMemStack_Push(DqnMemStack *const stack, size_t size)
{
if (!stack || size == 0) return NULL;
@ -2121,6 +2132,15 @@ DQN_FILE_SCOPE DqnV3 DqnV3_Cross(DqnV3 a, DqnV3 b)
return result;
}
DQN_FILE_SCOPE DqnV3 DqnV3_Normalise(DqnV3 a)
{
f32 length = DqnMath_Sqrtf(DQN_SQUARED(a.x) + DQN_SQUARED(a.y) + DQN_SQUARED(a.z));
f32 invLength = 1 / length;
DqnV3 result = a * invLength;
return result;
}
DQN_FILE_SCOPE DqnV3i DqnV3i_3i(i32 x, i32 y, i32 z)
{
DqnV3i result = {x, y, z};

View File

@ -1052,7 +1052,7 @@ void MemStackTest()
// Alocate A
size_t sizeA = (size_t)(allocSize * 0.5f);
void *resultA = DqnMemStack_Allocate(&stack, sizeA);
void *resultA = DqnMemStack_Push(&stack, sizeA);
u64 resultAddrA = *((u64 *)resultA);
DQN_ASSERT(resultAddrA % ALIGNMENT == 0);
DQN_ASSERT(stack.block && stack.block->memory);
@ -1068,7 +1068,7 @@ void MemStackTest()
DqnMemStackBlock *blockA = stack.block;
// Alocate B
size_t sizeB = (size_t)(allocSize * 2.0f);
void *resultB = DqnMemStack_Allocate(&stack, sizeB);
void *resultB = DqnMemStack_Push(&stack, sizeB);
u64 resultAddrB = *((u64 *)resultB);
DQN_ASSERT(resultAddrB % ALIGNMENT == 0);
DQN_ASSERT(stack.block && stack.block->memory);
@ -1094,7 +1094,7 @@ void MemStackTest()
// Check temp regions work
DqnTempMemStack tempBuffer = DqnMemStack_BeginTempRegion(&stack);
size_t sizeC = 1024 + 1;
void *resultC = DqnMemStack_Allocate(tempBuffer.stack, sizeC);
void *resultC = DqnMemStack_Push(tempBuffer.stack, sizeC);
u64 resultAddrC = *((u64 *)resultC);
DQN_ASSERT(resultAddrC % ALIGNMENT == 0);
DQN_ASSERT(stack.block != blockB && stack.block != blockA);
@ -1166,7 +1166,7 @@ void MemStackTest()
DQN_ASSERT(stack.byteAlign == ALIGNMENT);
// Allocation larger than stack mem size should fail
DQN_ASSERT(!DqnMemStack_Allocate(&stack, DQN_ARRAY_COUNT(memory) * 2));
DQN_ASSERT(!DqnMemStack_Push(&stack, DQN_ARRAY_COUNT(memory) * 2));
// Check free does nothing
DqnMemStack_Free(&stack);
@ -1190,11 +1190,11 @@ void MemStackTest()
DQN_ASSERT(stack.block->used == 0);
DQN_ASSERT(stack.byteAlign == ALIGNMENT);
void *result = DqnMemStack_Allocate(&stack, (size_t)(0.5f * allocSize));
void *result = DqnMemStack_Push(&stack, (size_t)(0.5f * allocSize));
DQN_ASSERT(result);
// Allocating more should fail
DQN_ASSERT(!DqnMemStack_Allocate(&stack, allocSize));
DQN_ASSERT(!DqnMemStack_Push(&stack, allocSize));
// Freeing should work
DqnMemStack_Free(&stack);
@ -1212,7 +1212,7 @@ void MemStackTest()
u8 *first = NULL;
{
u32 allocate40Bytes = 40;
u8 *data = (u8 *)DqnMemStack_Allocate(&stack, allocate40Bytes);
u8 *data = (u8 *)DqnMemStack_Push(&stack, allocate40Bytes);
// Test that the allocation got aligned to 16 byte boundary
DQN_ASSERT(data);
@ -1232,7 +1232,7 @@ void MemStackTest()
DQN_ASSERT(stack.block->size == firstBlockSize);
// Reallocate the data
data = (u8 *)DqnMemStack_Allocate(&stack, firstBlockSize);
data = (u8 *)DqnMemStack_Push(&stack, firstBlockSize);
DQN_ASSERT(stack.block->size == firstBlockSize);
DQN_ASSERT((size_t)data % ALIGNMENT == 0);
@ -1253,7 +1253,7 @@ void MemStackTest()
DQN_ASSERT(stack.block->size == firstBlockSize);
// Write out data to current block
data = (u8 *)DqnMemStack_Allocate(&stack, firstBlockSize);
data = (u8 *)DqnMemStack_Push(&stack, firstBlockSize);
for (u32 i = 0; i < firstBlockSize; i++)
data[i] = 'c';
@ -1262,19 +1262,19 @@ void MemStackTest()
// Force it to allocate three new blocks and write out data to each
size_t secondBlockSize = DQN_KILOBYTE(2);
u8 *second = (u8 *)DqnMemStack_Allocate(&stack, secondBlockSize);
u8 *second = (u8 *)DqnMemStack_Push(&stack, secondBlockSize);
DqnMemStackBlock *secondBlock = stack.block;
for (u32 i = 0; i < secondBlockSize; i++)
second[i] = 'd';
size_t thirdBlockSize = DQN_KILOBYTE(3);
u8 *third = (u8 *)DqnMemStack_Allocate(&stack, thirdBlockSize);
u8 *third = (u8 *)DqnMemStack_Push(&stack, thirdBlockSize);
DqnMemStackBlock *thirdBlock = stack.block;
for (u32 i = 0; i < thirdBlockSize; i++)
third[i] = 'e';
size_t fourthBlockSize = DQN_KILOBYTE(4);
u8 *fourth = (u8 *)DqnMemStack_Allocate(&stack, fourthBlockSize);
u8 *fourth = (u8 *)DqnMemStack_Push(&stack, fourthBlockSize);
DqnMemStackBlock *fourthBlock = stack.block;
for (u32 i = 0; i < fourthBlockSize; i++)
fourth[i] = 'f';
@ -1391,7 +1391,7 @@ void MemStackTest()
DqnMemStack_Init(&stack, DQN_KILOBYTE(1), true);
size_t allocSize = 512;
void *alloc = DqnMemStack_Allocate(&stack, allocSize);
void *alloc = DqnMemStack_Push(&stack, allocSize);
DQN_ASSERT(stack.block->used == allocSize);
DQN_ASSERT(DqnMemStack_Pop(&stack, alloc, allocSize));