Add resolution changer in options menu
This commit is contained in:
parent
eb4b0e1714
commit
10891ab56e
234
src/Asteroid.c
234
src/Asteroid.c
@ -82,7 +82,7 @@ INTERNAL v2 *createAsteroidVertexList(MemoryArena_ *arena, i32 iterations,
|
|||||||
for (i32 i = 0; i < iterations; i++)
|
for (i32 i = 0; i < iterations; i++)
|
||||||
{
|
{
|
||||||
i32 randValue = rand();
|
i32 randValue = rand();
|
||||||
|
|
||||||
// NOTE(doyle): Sin/cos generate values from +-1, we want to create
|
// NOTE(doyle): Sin/cos generate values from +-1, we want to create
|
||||||
// vertices that start from 0, 0 (i.e. strictly positive)
|
// vertices that start from 0, 0 (i.e. strictly positive)
|
||||||
result[i] = V2(((math_cosf(iterationAngle * i) + 1) * asteroidRadius),
|
result[i] = V2(((math_cosf(iterationAngle * i) + 1) * asteroidRadius),
|
||||||
@ -91,7 +91,7 @@ INTERNAL v2 *createAsteroidVertexList(MemoryArena_ *arena, i32 iterations,
|
|||||||
ASSERT(result[i].x >= 0 && result[i].y >= 0);
|
ASSERT(result[i].x >= 0 && result[i].y >= 0);
|
||||||
|
|
||||||
#if 1
|
#if 1
|
||||||
f32 displacementDist = 0.50f * asteroidRadius;
|
f32 displacementDist = 0.50f * asteroidRadius;
|
||||||
i32 vertexDisplacement =
|
i32 vertexDisplacement =
|
||||||
randValue % (i32)displacementDist + (i32)(displacementDist * 0.25f);
|
randValue % (i32)displacementDist + (i32)(displacementDist * 0.25f);
|
||||||
|
|
||||||
@ -240,16 +240,15 @@ 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(
|
||||||
transientArena, checkEntityVertexListOffsetToP,
|
transientArena, checkEntityVertexListOffsetToP,
|
||||||
@ -296,7 +295,8 @@ enum AsteroidSize
|
|||||||
asteroidsize_count,
|
asteroidsize_count,
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct {
|
typedef struct
|
||||||
|
{
|
||||||
v2 pos;
|
v2 pos;
|
||||||
v2 dP;
|
v2 dP;
|
||||||
} AsteroidSpec;
|
} AsteroidSpec;
|
||||||
@ -377,12 +377,12 @@ INTERNAL void addAsteroidWithSpec(GameWorldState *world,
|
|||||||
{
|
{
|
||||||
ASSERT(INVALID_CODE_PATH);
|
ASSERT(INVALID_CODE_PATH);
|
||||||
}
|
}
|
||||||
asteroid->pos = newP;
|
asteroid->pos = newP;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
asteroid->pos = spec->pos;
|
asteroid->pos = spec->pos;
|
||||||
asteroid->dP = spec->dP;
|
asteroid->dP = spec->dP;
|
||||||
}
|
}
|
||||||
|
|
||||||
asteroid->size = size;
|
asteroid->size = size;
|
||||||
@ -406,7 +406,7 @@ INTERNAL void addAsteroidWithSpec(GameWorldState *world,
|
|||||||
}
|
}
|
||||||
|
|
||||||
asteroid->vertexPoints = vertexCache[cacheIndex];
|
asteroid->vertexPoints = vertexCache[cacheIndex];
|
||||||
asteroid->color = V4(1.0f, 1.0f, 1.0f, 1.0f);
|
asteroid->color = V4(1.0f, 1.0f, 1.0f, 1.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
INTERNAL void addAsteroid(GameWorldState *world, enum AsteroidSize asteroidSize)
|
INTERNAL void addAsteroid(GameWorldState *world, enum AsteroidSize asteroidSize)
|
||||||
@ -456,7 +456,7 @@ INTERNAL AudioRenderer *getFreeAudioRenderer(GameWorldState *world,
|
|||||||
AudioVorbis *vorbis,
|
AudioVorbis *vorbis,
|
||||||
i32 maxSimultaneousPlayers)
|
i32 maxSimultaneousPlayers)
|
||||||
{
|
{
|
||||||
i32 freeIndex = -1;
|
i32 freeIndex = -1;
|
||||||
i32 sameAudioPlayingCount = 0;
|
i32 sameAudioPlayingCount = 0;
|
||||||
|
|
||||||
AudioRenderer *result = NULL;
|
AudioRenderer *result = NULL;
|
||||||
@ -512,13 +512,13 @@ 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];
|
||||||
|
|
||||||
/* Make sure the replaced entity from end of list is cleared out */
|
/* Make sure the replaced entity from end of list is cleared out */
|
||||||
Entity emptyEntity = {0};
|
Entity emptyEntity = {0};
|
||||||
world->entityList[--world->entityIndex] = emptyEntity;
|
world->entityList[--world->entityIndex] = emptyEntity;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -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++)
|
||||||
{
|
{
|
||||||
@ -630,7 +634,7 @@ INTERNAL void gameUpdate(GameState *state, Memory *memory, f32 dt)
|
|||||||
addAsteroid(world, (rand() % asteroidsize_count));
|
addAsteroid(world, (rand() % asteroidsize_count));
|
||||||
|
|
||||||
Radians starRotation = DEGREES_TO_RADIANS(45.0f);
|
Radians starRotation = DEGREES_TO_RADIANS(45.0f);
|
||||||
v2 starSize = V2(2, 2);
|
v2 starSize = V2(2, 2);
|
||||||
for (i32 i = 0; i < world->numStarP; i++)
|
for (i32 i = 0; i < world->numStarP; i++)
|
||||||
{
|
{
|
||||||
renderer_rect(&state->renderer, world->camera, world->starPList[i],
|
renderer_rect(&state->renderer, world->camera, world->starPList[i],
|
||||||
@ -640,7 +644,7 @@ INTERNAL void gameUpdate(GameState *state, Memory *memory, f32 dt)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (platform_queryKey(&state->input.keys[keycode_left_square_bracket],
|
if (platform_queryKey(&state->input.keys[keycode_left_square_bracket],
|
||||||
readkeytype_repeat, 0.2f))
|
readkeytype_repeat, 0.2f))
|
||||||
{
|
{
|
||||||
addAsteroid(world, (rand() % asteroidsize_count));
|
addAsteroid(world, (rand() % asteroidsize_count));
|
||||||
}
|
}
|
||||||
@ -673,17 +677,17 @@ INTERNAL void gameUpdate(GameState *state, Memory *memory, f32 dt)
|
|||||||
{
|
{
|
||||||
addBullet(world, entity);
|
addBullet(world, entity);
|
||||||
|
|
||||||
AudioVorbis *fire =
|
AudioVorbis *fire =
|
||||||
asset_vorbisGet(&state->assetManager, "fire");
|
asset_vorbisGet(&state->assetManager, "fire");
|
||||||
AudioRenderer *audioRenderer =
|
AudioRenderer *audioRenderer =
|
||||||
getFreeAudioRenderer(world, fire, 2);
|
getFreeAudioRenderer(world, fire, 2);
|
||||||
if (audioRenderer)
|
if (audioRenderer)
|
||||||
{
|
{
|
||||||
// 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -814,10 +822,9 @@ INTERNAL void gameUpdate(GameState *state, Memory *memory, f32 dt)
|
|||||||
|
|
||||||
f32 divisor =
|
f32 divisor =
|
||||||
MAX(entity->particleInitDp.x, entity->particleInitDp.y);
|
MAX(entity->particleInitDp.x, entity->particleInitDp.y);
|
||||||
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 */
|
||||||
@ -876,10 +883,10 @@ INTERNAL void gameUpdate(GameState *state, Memory *memory, f32 dt)
|
|||||||
spec.dP = v2_scale(colliderA->dP, -4.0f);
|
spec.dP = v2_scale(colliderA->dP, -4.0f);
|
||||||
addAsteroidWithSpec(world, asteroidsize_medium, &spec);
|
addAsteroidWithSpec(world, asteroidsize_medium, &spec);
|
||||||
|
|
||||||
spec.dP = v2_perpendicular(spec.dP);
|
spec.dP = v2_perpendicular(spec.dP);
|
||||||
addAsteroidWithSpec(world, asteroidsize_small, &spec);
|
addAsteroidWithSpec(world, asteroidsize_small, &spec);
|
||||||
|
|
||||||
spec.dP = v2_perpendicular(colliderA->dP);
|
spec.dP = v2_perpendicular(colliderA->dP);
|
||||||
addAsteroidWithSpec(world, asteroidsize_small, &spec);
|
addAsteroidWithSpec(world, asteroidsize_small, &spec);
|
||||||
|
|
||||||
numParticles = 16;
|
numParticles = 16;
|
||||||
@ -892,8 +899,8 @@ INTERNAL void gameUpdate(GameState *state, Memory *memory, f32 dt)
|
|||||||
&world->entityList[world->entityIndex++];
|
&world->entityList[world->entityIndex++];
|
||||||
particle->id = world->entityIdCounter++;
|
particle->id = world->entityIdCounter++;
|
||||||
|
|
||||||
particle->pos = colliderA->pos;
|
particle->pos = colliderA->pos;
|
||||||
particle->size = V2(4.0f, 4.0f);
|
particle->size = V2(4.0f, 4.0f);
|
||||||
|
|
||||||
i32 randValue = rand();
|
i32 randValue = rand();
|
||||||
Radians rotation =
|
Radians rotation =
|
||||||
@ -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;;
|
|
||||||
const char *const title = "Options";
|
|
||||||
v2 p = v2_add(screenCenter, V2(0, textYOffset));
|
|
||||||
renderer_stringFixedCentered(renderer, transientArena, arial25,
|
|
||||||
title, p, V2(0, 0), 0, V4(1, 0, 1, 1),
|
|
||||||
0);
|
|
||||||
|
|
||||||
const char *const resolutionLabel = "Resolution";
|
|
||||||
p = v2_add(screenCenter, V2(0, 0));
|
|
||||||
|
|
||||||
renderer_stringFixedCentered(renderer, transientArena, arial25,
|
|
||||||
resolutionLabel, p, V2(0, 0), 0,
|
|
||||||
V4(1, 0, 1, 1), 0);
|
|
||||||
|
|
||||||
const char *const resSizeLabel = "< 800x600 >";
|
|
||||||
p = v2_add(screenCenter, V2(0, -textYOffset));
|
|
||||||
|
|
||||||
renderer_stringFixedCentered(renderer, transientArena, arial25,
|
|
||||||
resSizeLabel, p, V2(0, 0), 0,
|
|
||||||
V4(1, 0, 1, 1), 0);
|
|
||||||
|
|
||||||
if (platform_queryKey(&inputBuffer->keys[keycode_enter],
|
if (platform_queryKey(&inputBuffer->keys[keycode_enter],
|
||||||
readkeytype_one_shot, KEY_DELAY_NONE))
|
readkeytype_one_shot, KEY_DELAY_NONE))
|
||||||
{
|
{
|
||||||
menuState->newResolutionRequest = TRUE;
|
OptimalArrayV2 *resolutionArray = inputBuffer->resolutionList;
|
||||||
menuState->newResolution = V2(800, 600);
|
|
||||||
|
|
||||||
renderer->size = menuState->newResolution;
|
menuState->newResolutionRequest = TRUE;
|
||||||
|
v2 newSize =
|
||||||
|
resolutionArray->ptr[menuState->resStringDisplayIndex];
|
||||||
|
|
||||||
GameWorldState *world = GET_STATE_DATA(
|
GameWorldState *world = GET_STATE_DATA(
|
||||||
state, &state->persistentArena, GameWorldState);
|
state, &state->persistentArena, GameWorldState);
|
||||||
world->size = menuState->newResolution;
|
|
||||||
world->camera.max = menuState->newResolution;
|
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";
|
||||||
|
|
||||||
|
v2 p = v2_add(screenCenter, V2(0, textYOffset));
|
||||||
|
renderer_stringFixedCentered(renderer, transientArena, arial25,
|
||||||
|
title, p, V2(0, 0), 0,
|
||||||
|
V4(1, 0, 1, 1), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
{ // Resolution String Display
|
||||||
|
|
||||||
|
/* Draw label */
|
||||||
|
const char *const resolutionLabel = "Resolution";
|
||||||
|
|
||||||
|
v2 p = v2_add(screenCenter, V2(0, 0));
|
||||||
|
renderer_stringFixedCentered(renderer, transientArena, arial25,
|
||||||
|
resolutionLabel, p, V2(0, 0), 0,
|
||||||
|
V4(1, 0, 1, 1), 0);
|
||||||
|
|
||||||
|
/* Draw label value */
|
||||||
|
char *resStringToDisplay =
|
||||||
|
menuState->resStrings[menuState->resStringDisplayIndex];
|
||||||
|
|
||||||
|
p = v2_add(screenCenter, V2(0, -textYOffset));
|
||||||
|
renderer_stringFixedCentered(renderer, transientArena, arial25,
|
||||||
|
resStringToDisplay, p, V2(0, 0), 0,
|
||||||
|
V4(1, 0, 1, 1), 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1084,10 +1166,10 @@ INTERNAL void startMenuUpdate(GameState *state, Memory *memory, f32 dt)
|
|||||||
|
|
||||||
{ // Draw show options prompt
|
{ // Draw show options prompt
|
||||||
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],
|
||||||
@ -1131,7 +1213,7 @@ void asteroid_gameUpdateAndRender(GameState *state, Memory *memory,
|
|||||||
srand((u32)time(NULL));
|
srand((u32)time(NULL));
|
||||||
asset_init(&state->assetManager, &state->persistentArena);
|
asset_init(&state->assetManager, &state->persistentArena);
|
||||||
audio_init(&state->audioManager);
|
audio_init(&state->audioManager);
|
||||||
|
|
||||||
// NOTE(doyle): Load game assets must be before init_renderer so that
|
// NOTE(doyle): Load game assets must be before init_renderer so that
|
||||||
// shaders are available for the renderer configuration
|
// shaders are available for the renderer configuration
|
||||||
loadGameAssets(state);
|
loadGameAssets(state);
|
||||||
@ -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;
|
||||||
|
209
src/Common.c
209
src/Common.c
@ -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++;
|
||||||
}
|
}
|
||||||
@ -27,13 +189,13 @@ void common_strncat(char *dest, const char *src, i32 numChars)
|
|||||||
while (*stringPtr)
|
while (*stringPtr)
|
||||||
stringPtr++;
|
stringPtr++;
|
||||||
|
|
||||||
for (i32 i = 0; i < numChars; i++)
|
for (i32 i = 0; i < numChars; i++)
|
||||||
*(stringPtr++) = src[i];
|
*(stringPtr++) = src[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
char *common_strncpy(char *dest, const char *src, i32 numChars)
|
char *common_strncpy(char *dest, const char *src, i32 numChars)
|
||||||
{
|
{
|
||||||
for (i32 i = 0; i < numChars; i++)
|
for (i32 i = 0; i < numChars; i++)
|
||||||
dest[i] = src[i];
|
dest[i] = src[i];
|
||||||
|
|
||||||
return dest;
|
return dest;
|
||||||
@ -54,9 +216,9 @@ 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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -65,9 +227,9 @@ void common_itoa(i32 value, char *buf, i32 bufSize)
|
|||||||
if (!buf || bufSize == 0) return;
|
if (!buf || bufSize == 0) return;
|
||||||
|
|
||||||
// NOTE(doyle): Max 32bit integer (+-)2147483647
|
// NOTE(doyle): Max 32bit integer (+-)2147483647
|
||||||
i32 charIndex = 0;
|
i32 charIndex = 0;
|
||||||
|
|
||||||
b32 negative = FALSE;
|
b32 negative = FALSE;
|
||||||
if (value < 0) negative = TRUE;
|
if (value < 0) negative = TRUE;
|
||||||
|
|
||||||
if (negative) buf[charIndex++] = '-';
|
if (negative) buf[charIndex++] = '-';
|
||||||
@ -75,7 +237,7 @@ void common_itoa(i32 value, char *buf, i32 bufSize)
|
|||||||
i32 val = ABS(value);
|
i32 val = ABS(value);
|
||||||
while (val != 0 && charIndex < bufSize)
|
while (val != 0 && charIndex < bufSize)
|
||||||
{
|
{
|
||||||
i32 rem = val % 10;
|
i32 rem = val % 10;
|
||||||
buf[charIndex++] = rem + '0';
|
buf[charIndex++] = rem + '0';
|
||||||
val /= 10;
|
val /= 10;
|
||||||
}
|
}
|
||||||
@ -137,31 +299,34 @@ 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;
|
||||||
|
|
||||||
k *= m;
|
k *= m;
|
||||||
k ^= k >> r;
|
k ^= k >> r;
|
||||||
k *= m;
|
k *= m;
|
||||||
|
|
||||||
h *= m;
|
h *= m;
|
||||||
h ^= k;
|
h ^= k;
|
||||||
|
|
||||||
data += 4;
|
data += 4;
|
||||||
len -= 4;
|
len -= 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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 *= m;
|
h ^= data[1] << 8;
|
||||||
|
case 1:
|
||||||
|
h ^= data[0];
|
||||||
|
h *= m;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Do a few final mixes of the hash to ensure the last few
|
// Do a few final mixes of the hash to ensure the last few
|
||||||
@ -172,4 +337,4 @@ u32 common_murmurHash2(const void *key, i32 len, u32 seed)
|
|||||||
h ^= h >> 15;
|
h ^= h >> 15;
|
||||||
|
|
||||||
return h;
|
return h;
|
||||||
}
|
}
|
||||||
|
22
src/Debug.c
22
src/Debug.c
@ -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,18 +41,17 @@ 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 */
|
||||||
i32 maxConsoleStrLen = ARRAY_COUNT(GLOBAL_debug.console[0]);
|
i32 maxConsoleStrLen = ARRAY_COUNT(GLOBAL_debug.console[0]);
|
||||||
GLOBAL_debug.consoleIndex = 0;
|
GLOBAL_debug.consoleIndex = 0;
|
||||||
|
|
||||||
// TODO(doyle): Font max size not entirely correct? using 1 * font.maxSize.w
|
// TODO(doyle): Font max size not entirely correct? using 1 * font.maxSize.w
|
||||||
// reveals around 4 characters ..
|
// reveals around 4 characters ..
|
||||||
f32 consoleXPos = font.maxSize.w * 20;
|
f32 consoleXPos = font.maxSize.w * 20;
|
||||||
f32 consoleYPos = windowSize.h - 1.8f * GLOBAL_debug.stringLineGap;
|
f32 consoleYPos = windowSize.h - 1.8f * GLOBAL_debug.stringLineGap;
|
||||||
GLOBAL_debug.initialConsoleP = V2(consoleXPos, consoleYPos);
|
GLOBAL_debug.initialConsoleP = V2(consoleXPos, consoleYPos);
|
||||||
|
|
||||||
GLOBAL_debug.init = TRUE;
|
GLOBAL_debug.init = TRUE;
|
||||||
|
@ -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);
|
||||||
|
117
src/String.c
117
src/String.c
@ -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;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
@ -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);
|
||||||
@ -168,7 +233,7 @@ i32 main(void)
|
|||||||
* INITIALISE GAME
|
* INITIALISE GAME
|
||||||
*******************
|
*******************
|
||||||
*/
|
*/
|
||||||
Memory memory = {0};
|
Memory memory = {0};
|
||||||
MemoryIndex persistentSize = MEGABYTES(32);
|
MemoryIndex persistentSize = MEGABYTES(32);
|
||||||
MemoryIndex transientSize = MEGABYTES(64);
|
MemoryIndex transientSize = MEGABYTES(64);
|
||||||
|
|
||||||
@ -181,12 +246,12 @@ i32 main(void)
|
|||||||
MemoryArena_ gameArena = {0};
|
MemoryArena_ gameArena = {0};
|
||||||
memory_arenaInit(&gameArena, memory.persistent, memory.persistentSize);
|
memory_arenaInit(&gameArena, memory.persistent, memory.persistentSize);
|
||||||
|
|
||||||
GameState *gameState = MEMORY_PUSH_STRUCT(&gameArena, GameState);
|
GameState *gameState = MEMORY_PUSH_STRUCT(&gameArena, GameState);
|
||||||
gameState->persistentArena = gameArena;
|
gameState->persistentArena = gameArena;
|
||||||
|
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
@ -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,
|
||||||
|
@ -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);
|
||||||
|
@ -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);
|
||||||
|
@ -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
|
||||||
|
@ -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;
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
Loading…
Reference in New Issue
Block a user