Add resolution changer in options menu

This commit is contained in:
Doyle Thai 2016-11-29 01:41:33 +11:00
parent eb4b0e1714
commit 10891ab56e
13 changed files with 497 additions and 255 deletions

View File

@ -240,15 +240,14 @@ INTERNAL u32 moveEntity(GameWorldState *world, MemoryArena_ *transientArena,
ASSERT(checkEntity->vertexPoints); ASSERT(checkEntity->vertexPoints);
/* Create entity edge lists */ /* Create entity edge lists */
v2 *entityVertexListOffsetToP = entity_generateUpdatedVertexList( v2 *entityVertexListOffsetToP =
transientArena, entity); entity_generateUpdatedVertexList(transientArena, entity);
v2 *checkEntityVertexListOffsetToP = v2 *checkEntityVertexListOffsetToP =
entity_generateUpdatedVertexList(transientArena, entity_generateUpdatedVertexList(transientArena, checkEntity);
checkEntity);
v2 *entityEdgeList = createNormalEdgeList(transientArena, v2 *entityEdgeList =
entityVertexListOffsetToP, createNormalEdgeList(transientArena, entityVertexListOffsetToP,
entity->numVertexPoints); entity->numVertexPoints);
v2 *checkEntityEdgeList = createNormalEdgeList( v2 *checkEntityEdgeList = createNormalEdgeList(
@ -296,7 +295,8 @@ enum AsteroidSize
asteroidsize_count, asteroidsize_count,
}; };
typedef struct { typedef struct
{
v2 pos; v2 pos;
v2 dP; v2 dP;
} AsteroidSpec; } AsteroidSpec;
@ -512,7 +512,7 @@ INTERNAL void addPlayer(GameWorldState *world)
INTERNAL void deleteEntity(GameWorldState *world, i32 entityIndex) INTERNAL void deleteEntity(GameWorldState *world, i32 entityIndex)
{ {
ASSERT(entityIndex > 0); ASSERT(entityIndex > 0);
ASSERT(entityIndex < ARRAY_COUNT(world->entityList)); ASSERT(entityIndex < world->entityListSize);
/* Last entity replaces the entity to delete */ /* Last entity replaces the entity to delete */
world->entityList[entityIndex] = world->entityList[world->entityIndex - 1]; world->entityList[entityIndex] = world->entityList[world->entityIndex - 1];
@ -581,6 +581,10 @@ INTERNAL void gameUpdate(GameState *state, Memory *memory, f32 dt)
world->camera.max = state->renderer.size; world->camera.max = state->renderer.size;
world->size = state->renderer.size; world->size = state->renderer.size;
world->entityListSize = 1024;
world->entityList = MEMORY_PUSH_ARRAY(&world->entityArena,
world->entityListSize, Entity);
{ // Init null entity { // Init null entity
Entity *nullEntity = &world->entityList[world->entityIndex++]; Entity *nullEntity = &world->entityList[world->entityIndex++];
nullEntity->id = world->entityIdCounter++; nullEntity->id = world->entityIdCounter++;
@ -613,7 +617,7 @@ INTERNAL void gameUpdate(GameState *state, Memory *memory, f32 dt)
world->numStarP = 100; world->numStarP = 100;
world->starPList = world->starPList =
MEMORY_PUSH_ARRAY(&state->persistentArena, world->numStarP, v2); MEMORY_PUSH_ARRAY(&world->entityArena, world->numStarP, v2);
for (i32 i = 0; i < world->numStarP; i++) for (i32 i = 0; i < world->numStarP; i++)
{ {
@ -682,8 +686,8 @@ INTERNAL void gameUpdate(GameState *state, Memory *memory, f32 dt)
// TODO(doyle): Atm transient arena is not used, this is // TODO(doyle): Atm transient arena is not used, this is
// just to fill out the arguments // just to fill out the arguments
audio_vorbisPlay(&state->transientArena, audio_vorbisPlay(&state->transientArena,
&state->audioManager, audioRenderer, &state->audioManager, audioRenderer, fire,
fire, 1); 1);
} }
} }
@ -768,11 +772,15 @@ INTERNAL void gameUpdate(GameState *state, Memory *memory, f32 dt)
// direction by extrapolating from it's current dp // direction by extrapolating from it's current dp
else else
{ {
if (entity->dP.x >= 0) localDp.x = 1.0f; if (entity->dP.x >= 0)
else localDp.x = -1.0f; localDp.x = 1.0f;
else
localDp.x = -1.0f;
if (entity->dP.y >= 0) localDp.y = 1.0f; if (entity->dP.y >= 0)
else localDp.y = -1.0f; localDp.y = 1.0f;
else
localDp.y = -1.0f;
} }
/* /*
@ -817,7 +825,6 @@ INTERNAL void gameUpdate(GameState *state, Memory *memory, f32 dt)
f32 maxDp = MAX(entity->dP.x, entity->dP.y); f32 maxDp = MAX(entity->dP.x, entity->dP.y);
entity->color.a = maxDp / divisor; entity->color.a = maxDp / divisor;
} }
/* Loop entity around world */ /* Loop entity around world */
@ -977,11 +984,9 @@ INTERNAL void gameUpdate(GameState *state, Memory *memory, f32 dt)
RenderFlags flags = renderflag_wireframe | renderflag_no_texture; RenderFlags flags = renderflag_wireframe | renderflag_no_texture;
renderer_entity(&state->renderer, &state->transientArena, world->camera, renderer_entity(&state->renderer, &state->transientArena, world->camera,
entity, V2(0, 0), 0, entity, V2(0, 0), 0, collideColor, flags);
collideColor, flags);
} }
for (i32 i = 0; i < world->numAudioRenderers; i++) for (i32 i = 0; i < world->numAudioRenderers; i++)
{ {
AudioRenderer *audioRenderer = &world->audioRenderer[i]; AudioRenderer *audioRenderer = &world->audioRenderer[i];
@ -1000,6 +1005,45 @@ INTERNAL void startMenuUpdate(GameState *state, Memory *memory, f32 dt)
StartMenuState *menuState = StartMenuState *menuState =
GET_STATE_DATA(state, &state->persistentArena, StartMenuState); GET_STATE_DATA(state, &state->persistentArena, StartMenuState);
if (!menuState->init)
{
MemoryArena_ *persistentArena = &state->persistentArena;
OptimalArrayV2 *resolutionArray = inputBuffer->resolutionList;
v2 currRes = renderer->size;
i32 resIndex = -1;
menuState->resStrings = memory_pushBytes(
persistentArena, resolutionArray->index * sizeof(String *));
for (i32 i = 0; i < resolutionArray->index; i++)
{
v2 res = resolutionArray->ptr[i];
if (v2_equals(res, currRes)) resIndex = i;
char widthString[8] = {0};
char heightString[8] = {0};
common_itoa((i32)res.w, widthString, ARRAY_COUNT(widthString));
common_itoa((i32)res.h, heightString, ARRAY_COUNT(heightString));
String *resString = common_stringMake(transientArena, widthString);
resString = common_stringAppend(transientArena, resString, "x", 1);
resString =
common_stringAppend(transientArena, resString, heightString,
ARRAY_COUNT(heightString));
menuState->resStrings[i] = MEMORY_PUSH_ARRAY(
persistentArena, common_stringLen(resString), char);
common_strncpy(menuState->resStrings[i], resString,
common_stringLen(resString));
}
if (resIndex == -1) ASSERT(INVALID_CODE_PATH);
menuState->init = TRUE;
menuState->numResStrings = resolutionArray->index;
menuState->resStringDisplayIndex = resIndex;
}
Font *arial15 = asset_fontGetOrCreateOnDemand( Font *arial15 = asset_fontGetOrCreateOnDemand(
assetManager, &state->persistentArena, transientArena, "Arial", 15); assetManager, &state->persistentArena, transientArena, "Arial", 15);
Font *arial25 = asset_fontGetOrCreateOnDemand( Font *arial25 = asset_fontGetOrCreateOnDemand(
@ -1008,7 +1052,6 @@ INTERNAL void startMenuUpdate(GameState *state, Memory *memory, f32 dt)
v2 screenCenter = v2_scale(renderer->size, 0.5f); v2 screenCenter = v2_scale(renderer->size, 0.5f);
ui_beginState(uiState); ui_beginState(uiState);
if (menuState->optionsShow) if (menuState->optionsShow)
{ {
if (platform_queryKey(&inputBuffer->keys[keycode_o], if (platform_queryKey(&inputBuffer->keys[keycode_o],
@ -1020,39 +1063,78 @@ INTERNAL void startMenuUpdate(GameState *state, Memory *memory, f32 dt)
} }
else else
{ {
f32 textYOffset = arial25->size * 1.5f;; if (platform_queryKey(&inputBuffer->keys[keycode_enter],
readkeytype_one_shot, KEY_DELAY_NONE))
{
OptimalArrayV2 *resolutionArray = inputBuffer->resolutionList;
menuState->newResolutionRequest = TRUE;
v2 newSize =
resolutionArray->ptr[menuState->resStringDisplayIndex];
GameWorldState *world = GET_STATE_DATA(
state, &state->persistentArena, GameWorldState);
renderer_updateSize(renderer, &state->assetManager, newSize);
// TODO(doyle): reset world arena instead of zeroing out struct
common_memset((u8 *)world, 0, sizeof(GameWorldState));
debug_init(newSize, *arial15);
}
else
{
if (platform_queryKey(&inputBuffer->keys[keycode_left],
readkeytype_one_shot, KEY_DELAY_NONE))
{
menuState->resStringDisplayIndex--;
}
else if (platform_queryKey(&inputBuffer->keys[keycode_right],
readkeytype_one_shot,
KEY_DELAY_NONE))
{
menuState->resStringDisplayIndex++;
}
if (menuState->resStringDisplayIndex < 0)
{
menuState->resStringDisplayIndex = 0;
}
else if (menuState->resStringDisplayIndex >=
menuState->numResStrings)
{
menuState->resStringDisplayIndex =
menuState->numResStrings - 1;
}
}
f32 textYOffset = arial25->size * 1.5f;
{ // Options Title String Display
const char *const title = "Options"; const char *const title = "Options";
v2 p = v2_add(screenCenter, V2(0, textYOffset)); v2 p = v2_add(screenCenter, V2(0, textYOffset));
renderer_stringFixedCentered(renderer, transientArena, arial25, renderer_stringFixedCentered(renderer, transientArena, arial25,
title, p, V2(0, 0), 0, V4(1, 0, 1, 1), title, p, V2(0, 0), 0,
0); V4(1, 0, 1, 1), 0);
}
{ // Resolution String Display
/* Draw label */
const char *const resolutionLabel = "Resolution"; const char *const resolutionLabel = "Resolution";
p = v2_add(screenCenter, V2(0, 0));
v2 p = v2_add(screenCenter, V2(0, 0));
renderer_stringFixedCentered(renderer, transientArena, arial25, renderer_stringFixedCentered(renderer, transientArena, arial25,
resolutionLabel, p, V2(0, 0), 0, resolutionLabel, p, V2(0, 0), 0,
V4(1, 0, 1, 1), 0); V4(1, 0, 1, 1), 0);
const char *const resSizeLabel = "< 800x600 >"; /* Draw label value */
char *resStringToDisplay =
menuState->resStrings[menuState->resStringDisplayIndex];
p = v2_add(screenCenter, V2(0, -textYOffset)); p = v2_add(screenCenter, V2(0, -textYOffset));
renderer_stringFixedCentered(renderer, transientArena, arial25, renderer_stringFixedCentered(renderer, transientArena, arial25,
resSizeLabel, p, V2(0, 0), 0, resStringToDisplay, p, V2(0, 0), 0,
V4(1, 0, 1, 1), 0); V4(1, 0, 1, 1), 0);
if (platform_queryKey(&inputBuffer->keys[keycode_enter],
readkeytype_one_shot, KEY_DELAY_NONE))
{
menuState->newResolutionRequest = TRUE;
menuState->newResolution = V2(800, 600);
renderer->size = menuState->newResolution;
GameWorldState *world = GET_STATE_DATA(
state, &state->persistentArena, GameWorldState);
world->size = menuState->newResolution;
world->camera.max = menuState->newResolution;
} }
} }
} }
@ -1086,8 +1168,8 @@ INTERNAL void startMenuUpdate(GameState *state, Memory *memory, f32 dt)
const char *const optionPrompt = "Press [o] for options "; const char *const optionPrompt = "Press [o] for options ";
v2 p = v2_add(screenCenter, V2(0, -120)); v2 p = v2_add(screenCenter, V2(0, -120));
renderer_stringFixedCentered(renderer, transientArena, arial25, renderer_stringFixedCentered(renderer, transientArena, arial25,
optionPrompt, p, V2(0, 0), 0, V4(1, 1, 0, 1), optionPrompt, p, V2(0, 0), 0,
0); V4(1, 1, 0, 1), 0);
} }
if (platform_queryKey(&inputBuffer->keys[keycode_enter], if (platform_queryKey(&inputBuffer->keys[keycode_enter],
@ -1139,7 +1221,7 @@ void asteroid_gameUpdateAndRender(GameState *state, Memory *memory,
&state->persistentArena, windowSize); &state->persistentArena, windowSize);
Font *arial15 = asset_fontGet(&state->assetManager, "Arial", 15); Font *arial15 = asset_fontGet(&state->assetManager, "Arial", 15);
debug_init(&state->persistentArena, windowSize, *arial15); debug_init(windowSize, *arial15);
state->currState = appstate_StartMenuState; state->currState = appstate_StartMenuState;
state->init = TRUE; state->init = TRUE;

View File

@ -1,10 +1,173 @@
#include <stdlib.h>
#include "Dengine/Common.h" #include "Dengine/Common.h"
#include "Dengine/Math.h" #include "Dengine/MemoryArena.h"
void common_optimalArrayV2Create(OptimalArrayV2 *array)
{
array->ptr = array->fastStorage;
array->size = ARRAY_COUNT(array->fastStorage);
}
i32 common_optimalArrayV2Push(OptimalArrayV2 *array, v2 data)
{
if (array->index + 1 > array->size)
{
array->size += ARRAY_COUNT(array->fastStorage);
i32 newSizeInBytes = array->size * sizeof(v2);
/* If first time expanding, we need to manually malloc and copy */
if (array->ptr == array->fastStorage)
{
array->ptr = malloc(newSizeInBytes);
for (i32 i = 0; i < ARRAY_COUNT(array->fastStorage); i++)
{
array->ptr[i] = array->fastStorage[i];
}
}
else
{
array->ptr = realloc(array->ptr, newSizeInBytes);
}
if (!array->ptr) return optimalarrayerror_out_of_memory;
}
array->ptr[array->index++] = data;
return 0;
}
void common_optimalArrayV2Destroy(OptimalArrayV2 *array)
{
if (array->ptr != array->fastStorage)
{
free(array->ptr);
}
}
/*
* +-------------------------------------+
* | Header | C-String | Null Terminator |
* +-------------------------------------+
* |
* +--> Functions return the c-string for compatibility with other
* string libraries
*
* Headers are retrieved using pointer arithmetric from the C string. These
* strings are typechecked by their own typedef char String.
*/
typedef struct StringHeader
{
i32 len;
// NOTE(doyle): A string is stored as one contiguous chunk of memory. We
// don't use a pointer for storing the string as this'd require an extra
// 4 bytes to store the pointer, which we don't need if everything is
// contiguous. The string follows on from the len, and we return the address
// of the string to simulate a pointer.
String string;
} StringHeader;
// TODO(doyle): string capacity- append if already enough space
INTERNAL StringHeader *stringGetHeader(String *const string)
{
StringHeader *result = NULL;
// NOTE(doyle): C-String must be located at end of struct type for offset to
// be correct! We cannot just subtract the string-header since we start at
// the string ptr position
if (string)
{
i32 byteOffsetToHeader = sizeof(StringHeader) - sizeof(String *);
result = CAST(StringHeader *)((CAST(u8 *) string) - byteOffsetToHeader);
}
return result;
}
i32 common_stringLen(String *const string)
{
if (!string) return -1;
StringHeader *header = stringGetHeader(string);
i32 result = header->len;
return result;
}
String *const common_stringAppend(MemoryArena_ *const arena, String *oldString,
char *appendString, i32 appendLen)
{
if (!oldString || !appendString || !arena) return oldString;
/* Calculate size of new string */
StringHeader *oldHeader = stringGetHeader(oldString);
i32 newLen = oldHeader->len + appendLen;
String *newString = common_stringMakeLen(arena, newLen);
/* Append strings together */
String *insertPtr = newString;
common_strncpy(insertPtr, oldString, oldHeader->len);
insertPtr += oldHeader->len;
common_strncpy(insertPtr, appendString, appendLen);
/* Free old string */
common_stringFree(arena, oldString);
return newString;
}
void common_stringFree(MemoryArena_ *arena, String *string)
{
if (!string || !arena) return;
StringHeader *header = stringGetHeader(string);
i32 bytesToFree = sizeof(StringHeader) + header->len;
common_memset((u8 *)header, 0, bytesToFree);
// TODO(doyle): Mem free
// PLATFORM_MEM_FREE(arena, header, bytesToFree);
string = NULL;
}
String *const common_stringMake(MemoryArena_ *const arena, char *string)
{
if (!arena) return NULL;
i32 len = common_strlen(string);
String *result = common_stringMakeLen(arena, len);
common_strncpy(result, string, len);
return result;
}
String *const common_stringMakeLen(MemoryArena_ *const arena, i32 len)
{
if (!arena) return NULL;
// NOTE(doyle): Allocate the string header size plus the len. But _note_
// that StringHeader contains a single String character. This has
// a side-effect of already preallocating a byte for the null-terminating
// character. Whilst the len of a string counts up to the last character
// _not_ including null-terminator.
i32 bytesToAllocate = sizeof(StringHeader) + len;
void *chunk = memory_pushBytes(arena, bytesToAllocate * sizeof(u8));
if (!chunk) return NULL;
StringHeader *header = CAST(StringHeader *) chunk;
header->len = len;
return &header->string;
}
i32 common_strlen(const char *const string) i32 common_strlen(const char *const string)
{ {
i32 result = 0; i32 result = 0;
while (string[result]) result++; while (string[result])
result++;
return result; return result;
} }
@ -12,8 +175,7 @@ i32 common_strcmp(const char *a, const char *b)
{ {
while (*a == *b) while (*a == *b)
{ {
if (!*a) if (!*a) return 0;
return 0;
a++; a++;
b++; b++;
} }
@ -55,8 +217,8 @@ INTERNAL void reverseString(char *const buf, const i32 bufSize)
for (i32 i = 0; i < mid; i++) for (i32 i = 0; i < mid; i++)
{ {
char tmp = buf[i]; char tmp = buf[i];
buf[i] = buf[(bufSize-1) - i]; buf[i] = buf[(bufSize - 1) - i];
buf[(bufSize-1) - i] = tmp; buf[(bufSize - 1) - i] = tmp;
} }
} }
@ -137,9 +299,9 @@ u32 common_murmurHash2(const void *key, i32 len, u32 seed)
// Mix 4 bytes at a time into the hash // Mix 4 bytes at a time into the hash
const unsigned char * data = (const unsigned char *)key; const unsigned char *data = (const unsigned char *)key;
while(len >= 4) while (len >= 4)
{ {
u32 k = *(u32 *)data; u32 k = *(u32 *)data;
@ -156,11 +318,14 @@ u32 common_murmurHash2(const void *key, i32 len, u32 seed)
// Handle the last few bytes of the input array // Handle the last few bytes of the input array
switch(len) switch (len)
{ {
case 3: h ^= data[2] << 16; case 3:
case 2: h ^= data[1] << 8; h ^= data[2] << 16;
case 1: h ^= data[0]; case 2:
h ^= data[1] << 8;
case 1:
h ^= data[0];
h *= m; h *= m;
}; };

View File

@ -9,7 +9,7 @@ typedef struct DebugState
{ {
b32 init; b32 init;
Font font; Font font;
i32 *callCount; i32 callCount[debugcount_num];
f32 stringLineGap; f32 stringLineGap;
/* Debug strings rendered in top left corner */ /* Debug strings rendered in top left corner */
@ -28,11 +28,12 @@ typedef struct DebugState
GLOBAL_VAR DebugState GLOBAL_debug; GLOBAL_VAR DebugState GLOBAL_debug;
void debug_init(MemoryArena_ *arena, v2 windowSize, Font font) void debug_init(v2 windowSize, Font font)
{ {
GLOBAL_debug.font = font; GLOBAL_debug.font = font;
GLOBAL_debug.callCount =
memory_pushBytes(arena, debugcount_num * sizeof(i32)); for (i32 i = 0; i < debugcount_num; i++) GLOBAL_debug.callCount[i] = 0;
GLOBAL_debug.stringLineGap = CAST(f32) font.verticalSpacing; GLOBAL_debug.stringLineGap = CAST(f32) font.verticalSpacing;
/* Init debug string stack */ /* Init debug string stack */
@ -40,8 +41,7 @@ void debug_init(MemoryArena_ *arena, v2 windowSize, Font font)
GLOBAL_debug.stringUpdateTimer = 0.0f; GLOBAL_debug.stringUpdateTimer = 0.0f;
GLOBAL_debug.stringUpdateRate = 0.15f; GLOBAL_debug.stringUpdateRate = 0.15f;
GLOBAL_debug.initialStringP = GLOBAL_debug.initialStringP = V2(0.0f, (windowSize.h - 1.8f * GLOBAL_debug.stringLineGap));
V2(0.0f, (windowSize.h - 1.8f * GLOBAL_debug.stringLineGap));
GLOBAL_debug.currStringP = GLOBAL_debug.initialStringP; GLOBAL_debug.currStringP = GLOBAL_debug.initialStringP;
/* Init gui console */ /* Init gui console */

View File

@ -32,8 +32,7 @@ void shaderUniformSetVec4f(u32 shaderId, const GLchar *name,
void shaderUse(u32 shaderId) { glUseProgram(shaderId); } void shaderUse(u32 shaderId) { glUseProgram(shaderId); }
void renderer_init(Renderer *renderer, AssetManager *assetManager, void renderer_updateSize(Renderer *renderer, AssetManager *assetManager, v2 windowSize)
MemoryArena_ *persistentArena, v2 windowSize)
{ {
renderer->size = windowSize; renderer->size = windowSize;
// NOTE(doyle): Value to map a screen coordinate to NDC coordinate // NOTE(doyle): Value to map a screen coordinate to NDC coordinate
@ -43,6 +42,7 @@ void renderer_init(Renderer *renderer, AssetManager *assetManager,
const mat4 projection = const mat4 projection =
mat4_ortho(0.0f, renderer->size.w, 0.0f, renderer->size.h, 0.0f, 1.0f); mat4_ortho(0.0f, renderer->size.w, 0.0f, renderer->size.h, 0.0f, 1.0f);
for (i32 i = 0; i < shaderlist_count; i++) for (i32 i = 0; i < shaderlist_count; i++)
{ {
renderer->shaderList[i] = asset_shaderGet(assetManager, i); renderer->shaderList[i] = asset_shaderGet(assetManager, i);
@ -54,6 +54,12 @@ void renderer_init(Renderer *renderer, AssetManager *assetManager,
renderer->activeShaderId = renderer->shaderList[shaderlist_default]; renderer->activeShaderId = renderer->shaderList[shaderlist_default];
GL_CHECK_ERROR(); GL_CHECK_ERROR();
}
void renderer_init(Renderer *renderer, AssetManager *assetManager,
MemoryArena_ *persistentArena, v2 windowSize)
{
renderer_updateSize(renderer, assetManager, windowSize);
/* Create buffers */ /* Create buffers */
glGenVertexArrays(ARRAY_COUNT(renderer->vao), renderer->vao); glGenVertexArrays(ARRAY_COUNT(renderer->vao), renderer->vao);

View File

@ -1,120 +1,3 @@
#include "Dengine/String.h" #include "Dengine/String.h"
#include "Dengine/MemoryArena.h" #include "Dengine/MemoryArena.h"
/*
* +-------------------------------------+
* | Header | C-String | Null Terminator |
* +-------------------------------------+
* |
* +--> Functions return the c-string for compatibility with other
* string libraries
*
* Headers are retrieved using pointer arithmetric from the C string. These
* strings are typechecked by their own typedef char String.
*/
typedef struct StringHeader
{
i32 len;
// NOTE(doyle): A string is stored as one contiguous chunk of memory. We
// don't use a pointer for storing the string as this'd require an extra
// 4 bytes to store the pointer, which we don't need if everything is
// contiguous. The string follows on from the len, and we return the address
// of the string to simulate a pointer.
String string;
} StringHeader;
// TODO(doyle): string capacity- append if already enough space
INTERNAL StringHeader *string_getHeader(String *const string)
{
StringHeader *result = NULL;
// NOTE(doyle): C-String must be located at end of struct type for offset to
// be correct! We cannot just subtract the string-header since we start at
// the string ptr position
if (string)
{
i32 byteOffsetToHeader = sizeof(StringHeader) - sizeof(String *);
result = CAST(StringHeader *)((CAST(u8 *) string) - byteOffsetToHeader);
}
return result;
}
i32 string_len(String *const string)
{
if (!string) return -1;
StringHeader *header = string_getHeader(string);
i32 result = header->len;
return result;
}
String *const string_append(MemoryArena_ *const arena, String *oldString,
char *appendString, i32 appendLen)
{
if (!oldString || !appendString || !arena) return oldString;
/* Calculate size of new string */
StringHeader *oldHeader = string_getHeader(oldString);
i32 newLen = oldHeader->len + appendLen;
String *newString = string_makeLen(arena, newLen);
/* Append strings together */
String *insertPtr = newString;
common_strncpy(insertPtr, oldString, oldHeader->len);
insertPtr += oldHeader->len;
common_strncpy(insertPtr, appendString, appendLen);
/* Free old string */
string_free(arena, oldString);
return newString;
}
void string_free(MemoryArena_ *arena, String *string)
{
if (!string || !arena) return;
StringHeader *header = string_getHeader(string);
i32 bytesToFree = sizeof(StringHeader) + header->len;
common_memset((u8 *)header, 0, bytesToFree);
// TODO(doyle): Mem free
// PLATFORM_MEM_FREE(arena, header, bytesToFree);
string = NULL;
}
String *const string_make(MemoryArena_ *const arena, char *string)
{
if (!arena) return NULL;
i32 len = common_strlen(string);
String *result = string_makeLen(arena, len);
common_strncpy(result, string, len);
return result;
}
String *const string_makeLen(MemoryArena_ *const arena, i32 len)
{
if (!arena) return NULL;
// NOTE(doyle): Allocate the string header size plus the len. But _note_
// that StringHeader contains a single String character. This has
// a side-effect of already preallocating a byte for the null-terminating
// character. Whilst the len of a string counts up to the last character
// _not_ including null-terminator.
i32 bytesToAllocate = sizeof(StringHeader) + len;
void *chunk = memory_pushBytes(arena, bytesToAllocate * sizeof(u8));
if (!chunk) return NULL;
StringHeader *header = CAST(StringHeader *) chunk;
header->len = len;
return &header->string;
}

View File

@ -83,7 +83,7 @@ INTERNAL void mouseButtonCallback(GLFWwindow *window, int button, int action,
{ {
GameState *game = CAST(GameState *)(glfwGetWindowUserPointer(window)); GameState *game = CAST(GameState *)(glfwGetWindowUserPointer(window));
switch(button) switch (button)
{ {
case GLFW_MOUSE_BUTTON_LEFT: case GLFW_MOUSE_BUTTON_LEFT:
processKey(&game->input.keys[keycode_mouseLeft], action); processKey(&game->input.keys[keycode_mouseLeft], action);
@ -115,8 +115,73 @@ i32 main(void)
glfwInit(); glfwInit();
setGlfwWindowHints(); setGlfwWindowHints();
i32 windowWidth = 1600; OptimalArrayV2 vidList = {0};
i32 windowHeight = 900; common_optimalArrayV2Create(&vidList);
i32 windowWidth = 0;
i32 windowHeight = 0;
{ // Query Computer Video Resolutions
i32 numMonitors;
GLFWmonitor **monitors = glfwGetMonitors(&numMonitors);
GLFWmonitor *primaryMonitor = monitors[0];
i32 numModes;
const GLFWvidmode *modes = glfwGetVideoModes(primaryMonitor, &numModes);
i32 targetRefreshHz = 60;
f32 targetWindowRatio = 16.0f / 9.0f;
i32 targetPixelDensity = 1280 * 720;
i32 minPixelDensityDelta = 100000000;
printf("== Supported video modes ==\n");
for (i32 i = 0; i < numModes; i++)
{
GLFWvidmode mode = modes[i];
printf("width: %d, height: %d, rgb: %d, %d, %d, refresh: %d\n",
mode.width, mode.height, mode.redBits, mode.greenBits,
mode.blueBits, mode.refreshRate);
if (mode.refreshRate == targetRefreshHz)
{
i32 result = common_optimalArrayV2Push(
&vidList, V2i(mode.width, mode.height));
if (result)
{
printf(
"common_optimalArrayV2Push(): Failed error code %d\n",
result);
ASSERT(INVALID_CODE_PATH);
}
f32 sizeRatio = (f32)mode.width / (f32)mode.height;
f32 delta = targetWindowRatio - sizeRatio;
if (delta < 0.1f)
{
i32 pixelDensity = mode.width * mode.height;
i32 densityDelta = ABS((pixelDensity - targetPixelDensity));
if (densityDelta < minPixelDensityDelta)
{
minPixelDensityDelta = densityDelta;
windowWidth = mode.width;
windowHeight = mode.height;
}
}
}
}
printf("== ==\n");
ASSERT(vidList.index > 0);
}
if (windowWidth == 0 || windowHeight == 0)
{
// NOTE(doyle): In this case just fallback to some value we hope is safe
windowWidth = 800;
windowHeight = 600;
}
GLFWwindow *window = GLFWwindow *window =
glfwCreateWindow(windowWidth, windowHeight, "Dengine", NULL, NULL); glfwCreateWindow(windowWidth, windowHeight, "Dengine", NULL, NULL);
@ -186,7 +251,7 @@ i32 main(void)
glfwSetWindowUserPointer(window, CAST(void *)(gameState)); glfwSetWindowUserPointer(window, CAST(void *)(gameState));
{ { // Load game icon
i32 width, height; i32 width, height;
char *iconPath = "data/textures/Asteroids/icon.png"; char *iconPath = "data/textures/Asteroids/icon.png";
u8 *pixels = asset_imageLoad(&width, &height, NULL, iconPath, FALSE); u8 *pixels = asset_imageLoad(&width, &height, NULL, iconPath, FALSE);
@ -198,6 +263,7 @@ i32 main(void)
asset_imageFree(pixels); asset_imageFree(pixels);
} }
} }
gameState->input.resolutionList = &vidList;
/* /*
******************* *******************
@ -209,7 +275,6 @@ i32 main(void)
#if 0 #if 0
// TODO(doyle): Get actual monitor refresh rate // TODO(doyle): Get actual monitor refresh rate
i32 monitorRefreshHz = 60;
f32 targetSecondsPerFrame = 1.0f / CAST(f32)(monitorRefreshHz); f32 targetSecondsPerFrame = 1.0f / CAST(f32)(monitorRefreshHz);
#else #else
// TODO(doyle): http://gafferongames.com/game-physics/fix-your-timestep/ // TODO(doyle): http://gafferongames.com/game-physics/fix-your-timestep/
@ -234,7 +299,7 @@ i32 main(void)
/* Swap the buffers */ /* Swap the buffers */
glfwSwapBuffers(window); glfwSwapBuffers(window);
f32 endTime = CAST(f32)glfwGetTime(); f32 endTime = CAST(f32) glfwGetTime();
secondsElapsed = endTime - startTime; secondsElapsed = endTime - startTime;
#if 0 #if 0
@ -277,8 +342,11 @@ i32 main(void)
{ {
if (menuState->newResolutionRequest) if (menuState->newResolutionRequest)
{ {
windowSize = menuState->newResolution; i32 index = menuState->resStringDisplayIndex;
windowSize = gameState->input.resolutionList->ptr[index];
glfwSetWindowSize(window, (i32)windowSize.w, (i32)windowSize.h); glfwSetWindowSize(window, (i32)windowSize.w, (i32)windowSize.h);
glViewport(0, 0, (i32)windowSize.w, (i32)windowSize.h);
menuState->newResolutionRequest = FALSE; menuState->newResolutionRequest = FALSE;
} }

View File

@ -24,7 +24,8 @@ typedef struct GameWorldState
MemoryArena_ entityArena; MemoryArena_ entityArena;
v2 *entityVertexListCache[entitytype_count]; v2 *entityVertexListCache[entitytype_count];
Entity entityList[1024]; Entity *entityList;
i32 entityListSize;
i32 entityIndex; i32 entityIndex;
u32 entityIdCounter; u32 entityIdCounter;
@ -54,19 +55,23 @@ typedef struct GameWorldState
typedef struct StartMenuState typedef struct StartMenuState
{ {
b32 init;
f32 startPromptBlinkTimer; f32 startPromptBlinkTimer;
b32 startPromptShow; b32 startPromptShow;
b32 optionsShow; char **resStrings;
i32 numResStrings;
i32 resStringDisplayIndex;
b32 newResolutionRequest; b32 newResolutionRequest;
v2 newResolution;
b32 optionsShow;
} StartMenuState; } StartMenuState;
typedef struct GameState typedef struct GameState
{ {
b32 init; b32 init;
enum AppState currState; enum AppState currState;
void *appStateData[appstate_count]; void *appStateData[appstate_count];
@ -81,8 +86,7 @@ typedef struct GameState
UiState uiState; UiState uiState;
} GameState; } GameState;
#define ASTEROID_GET_STATE_DATA(state, type) \ #define ASTEROID_GET_STATE_DATA(state, type) (type *)asteroid_getStateData_(state, appstate_##type)
(type *)asteroid_getStateData_(state, appstate_##type)
void *asteroid_getStateData_(GameState *state, enum AppState appState); void *asteroid_getStateData_(GameState *state, enum AppState appState);
void asteroid_gameUpdateAndRender(GameState *state, Memory *memory, void asteroid_gameUpdateAndRender(GameState *state, Memory *memory,

View File

@ -15,6 +15,9 @@ typedef float f32;
typedef double f64; typedef double f64;
typedef size_t MemoryIndex; typedef size_t MemoryIndex;
typedef char String;
typedef struct MemoryArena MemoryArena_;
#define TRUE 1 #define TRUE 1
#define FALSE 0 #define FALSE 0
@ -34,6 +37,44 @@ typedef size_t MemoryIndex;
#define DENGINE_DEBUG #define DENGINE_DEBUG
#include "Dengine/Math.h"
/*
NOTE(doyle): Small sized optimised dynamic array that grows as required. The
array uses the stack first, only if it runs out of space does it rely on
memory allocated from the machine.
The array->ptr is initially set to fast storage. Once we are out of space
we allocate space on the heap for the ptr and copy over the elements in
fast storage.
The default behaviour expands the array storage by the size of fastStorage.
*/
enum OptimalArrayError
{
optimalarrayerror_out_of_memory = 1,
optimalarrayerror_count,
};
typedef struct OptimalArrayV2
{
v2 fastStorage[16];
v2 *ptr;
i32 index;
i32 size;
} OptimalArrayV2;
void common_optimalArrayV2Create(OptimalArrayV2 *array);
i32 common_optimalArrayV2Push(OptimalArrayV2 *array, v2 data);
void common_optimalArrayV2Destroy(OptimalArrayV2 *array);
i32 common_stringLen(String *const string);
String *const common_stringAppend(MemoryArena_ *const arena, String *oldString,
String *appendString, i32 appendLen);
void common_stringFree(MemoryArena_ *arena, String *string);
String *const common_stringMake(MemoryArena_ *const arena, char *string);
String *const common_stringMakeLen(MemoryArena_ *const arena, i32 len);
i32 common_strlen(const char *const string); i32 common_strlen(const char *const string);
i32 common_strcmp(const char *a, const char *b); i32 common_strcmp(const char *a, const char *b);
void common_strncat(char *dest, const char *src, i32 numChars); void common_strncat(char *dest, const char *src, i32 numChars);

View File

@ -20,7 +20,7 @@ enum DebugCount
debugcount_num, debugcount_num,
}; };
void debug_init(MemoryArena_ *arena, v2 windowSize, Font font); void debug_init(v2 windowSize, Font font);
#define DEBUG_RECURSIVE_PRINT_XML_TREE(sig) debug_recursivePrintXmlTree(sig, 1) #define DEBUG_RECURSIVE_PRINT_XML_TREE(sig) debug_recursivePrintXmlTree(sig, 1)
void debug_recursivePrintXmlTree(XmlNode *root, i32 levelsDeep); void debug_recursivePrintXmlTree(XmlNode *root, i32 levelsDeep);

View File

@ -2,6 +2,7 @@
#define DENGINE_MATH_H #define DENGINE_MATH_H
#include <math.h> #include <math.h>
#include "Dengine/Common.h" #include "Dengine/Common.h"
#define MATH_PI 3.14159265359f #define MATH_PI 3.14159265359f

View File

@ -143,6 +143,8 @@ typedef struct KeyState
typedef struct InputBuffer typedef struct InputBuffer
{ {
OptimalArrayV2 *resolutionList;
v2 mouseP; v2 mouseP;
KeyState keys[keycode_count]; KeyState keys[keycode_count];
} InputBuffer; } InputBuffer;

View File

@ -84,6 +84,7 @@ typedef struct Renderer
i32 groupCapacity; i32 groupCapacity;
} Renderer; } Renderer;
void renderer_updateSize(Renderer *renderer, AssetManager *assetManager, v2 windowSize);
void renderer_init(Renderer *renderer, AssetManager *assetManager, void renderer_init(Renderer *renderer, AssetManager *assetManager,
MemoryArena_ *persistentArena, v2 windowSize); MemoryArena_ *persistentArena, v2 windowSize);

View File

@ -1,16 +1,5 @@
#ifndef DENGINE_STRING_H #ifndef DENGINE_STRING_H
#define DENGINE_STRING_H #define DENGINE_STRING_H
#include "Dengine/Common.h"
typedef struct MemoryArena MemoryArena_;
typedef char String;
i32 string_len(String *const string);
String *const string_append(MemoryArena_ *const arena, String *oldString,
String *appendString, i32 appendLen);
void string_free(MemoryArena_ *arena, String *string);
String *const string_make(MemoryArena_ *const arena, char *string);
String *const string_makeLen(MemoryArena_ *const arena, i32 len);
#endif #endif