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++) | ||||
| 	{ | ||||
| 		i32 randValue = rand(); | ||||
| 		 | ||||
| 
 | ||||
| 		// NOTE(doyle): Sin/cos generate values from +-1, we want to create
 | ||||
| 		// vertices that start from 0, 0 (i.e. strictly positive)
 | ||||
| 		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); | ||||
| 
 | ||||
| #if 1 | ||||
| 		f32 displacementDist   = 0.50f * asteroidRadius; | ||||
| 		f32 displacementDist = 0.50f * asteroidRadius; | ||||
| 		i32 vertexDisplacement = | ||||
| 		    randValue % (i32)displacementDist + (i32)(displacementDist * 0.25f); | ||||
| 
 | ||||
| @ -240,16 +240,15 @@ INTERNAL u32 moveEntity(GameWorldState *world, MemoryArena_ *transientArena, | ||||
| 			ASSERT(checkEntity->vertexPoints); | ||||
| 
 | ||||
| 			/* Create entity edge lists */ | ||||
| 			v2 *entityVertexListOffsetToP = entity_generateUpdatedVertexList( | ||||
| 			    transientArena, entity); | ||||
| 			v2 *entityVertexListOffsetToP = | ||||
| 			    entity_generateUpdatedVertexList(transientArena, entity); | ||||
| 
 | ||||
| 			v2 *checkEntityVertexListOffsetToP = | ||||
| 			    entity_generateUpdatedVertexList(transientArena, | ||||
| 			                                     checkEntity); | ||||
| 			    entity_generateUpdatedVertexList(transientArena, checkEntity); | ||||
| 
 | ||||
| 			v2 *entityEdgeList = createNormalEdgeList(transientArena, | ||||
| 			                                          entityVertexListOffsetToP, | ||||
| 			                                          entity->numVertexPoints); | ||||
| 			v2 *entityEdgeList = | ||||
| 			    createNormalEdgeList(transientArena, entityVertexListOffsetToP, | ||||
| 			                         entity->numVertexPoints); | ||||
| 
 | ||||
| 			v2 *checkEntityEdgeList = createNormalEdgeList( | ||||
| 			    transientArena, checkEntityVertexListOffsetToP, | ||||
| @ -296,7 +295,8 @@ enum AsteroidSize | ||||
| 	asteroidsize_count, | ||||
| }; | ||||
| 
 | ||||
| typedef struct { | ||||
| typedef struct | ||||
| { | ||||
| 	v2 pos; | ||||
| 	v2 dP; | ||||
| } AsteroidSpec; | ||||
| @ -377,12 +377,12 @@ INTERNAL void addAsteroidWithSpec(GameWorldState *world, | ||||
| 		{ | ||||
| 			ASSERT(INVALID_CODE_PATH); | ||||
| 		} | ||||
| 		asteroid->pos       = newP; | ||||
| 		asteroid->pos = newP; | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		asteroid->pos       = spec->pos; | ||||
| 		asteroid->dP        = spec->dP; | ||||
| 		asteroid->pos = spec->pos; | ||||
| 		asteroid->dP  = spec->dP; | ||||
| 	} | ||||
| 
 | ||||
| 	asteroid->size            = size; | ||||
| @ -406,7 +406,7 @@ INTERNAL void addAsteroidWithSpec(GameWorldState *world, | ||||
| 	} | ||||
| 
 | ||||
| 	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) | ||||
| @ -456,7 +456,7 @@ INTERNAL AudioRenderer *getFreeAudioRenderer(GameWorldState *world, | ||||
|                                              AudioVorbis *vorbis, | ||||
|                                              i32 maxSimultaneousPlayers) | ||||
| { | ||||
| 	i32 freeIndex = -1; | ||||
| 	i32 freeIndex             = -1; | ||||
| 	i32 sameAudioPlayingCount = 0; | ||||
| 
 | ||||
| 	AudioRenderer *result = NULL; | ||||
| @ -512,13 +512,13 @@ INTERNAL void addPlayer(GameWorldState *world) | ||||
| INTERNAL void deleteEntity(GameWorldState *world, i32 entityIndex) | ||||
| { | ||||
| 	ASSERT(entityIndex > 0); | ||||
| 	ASSERT(entityIndex < ARRAY_COUNT(world->entityList)); | ||||
| 	ASSERT(entityIndex < world->entityListSize); | ||||
| 
 | ||||
| 	/* Last entity replaces the entity to delete */ | ||||
| 	world->entityList[entityIndex] = world->entityList[world->entityIndex - 1]; | ||||
| 
 | ||||
| 	/* Make sure the replaced entity from end of list is cleared out */ | ||||
| 	Entity emptyEntity = {0}; | ||||
| 	Entity emptyEntity                      = {0}; | ||||
| 	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->size       = state->renderer.size; | ||||
| 
 | ||||
| 		world->entityListSize = 1024; | ||||
| 		world->entityList     = MEMORY_PUSH_ARRAY(&world->entityArena, | ||||
| 		                                      world->entityListSize, Entity); | ||||
| 
 | ||||
| 		{ // Init null entity
 | ||||
| 			Entity *nullEntity = &world->entityList[world->entityIndex++]; | ||||
| 			nullEntity->id     = world->entityIdCounter++; | ||||
| @ -613,7 +617,7 @@ INTERNAL void gameUpdate(GameState *state, Memory *memory, f32 dt) | ||||
| 
 | ||||
| 		world->numStarP = 100; | ||||
| 		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++) | ||||
| 		{ | ||||
| @ -630,7 +634,7 @@ INTERNAL void gameUpdate(GameState *state, Memory *memory, f32 dt) | ||||
| 		addAsteroid(world, (rand() % asteroidsize_count)); | ||||
| 
 | ||||
| 	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++) | ||||
| 	{ | ||||
| 		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], | ||||
| 	                 readkeytype_repeat, 0.2f)) | ||||
| 	                      readkeytype_repeat, 0.2f)) | ||||
| 	{ | ||||
| 		addAsteroid(world, (rand() % asteroidsize_count)); | ||||
| 	} | ||||
| @ -673,17 +677,17 @@ INTERNAL void gameUpdate(GameState *state, Memory *memory, f32 dt) | ||||
| 			{ | ||||
| 				addBullet(world, entity); | ||||
| 
 | ||||
| 					AudioVorbis *fire = | ||||
| 					    asset_vorbisGet(&state->assetManager, "fire"); | ||||
| 				    AudioRenderer *audioRenderer = | ||||
| 				        getFreeAudioRenderer(world, fire, 2); | ||||
| 				    if (audioRenderer) | ||||
| 				    { | ||||
| 					    // TODO(doyle): Atm transient arena is not used, this is
 | ||||
| 					    // just to fill out the arguments
 | ||||
| 					    audio_vorbisPlay(&state->transientArena, | ||||
| 					                     &state->audioManager, audioRenderer, | ||||
| 					                     fire, 1); | ||||
| 				AudioVorbis *fire = | ||||
| 				    asset_vorbisGet(&state->assetManager, "fire"); | ||||
| 				AudioRenderer *audioRenderer = | ||||
| 				    getFreeAudioRenderer(world, fire, 2); | ||||
| 				if (audioRenderer) | ||||
| 				{ | ||||
| 					// TODO(doyle): Atm transient arena is not used, this is
 | ||||
| 					// just to fill out the arguments
 | ||||
| 					audio_vorbisPlay(&state->transientArena, | ||||
| 					                 &state->audioManager, audioRenderer, fire, | ||||
| 					                 1); | ||||
| 				} | ||||
| 			} | ||||
| 
 | ||||
| @ -768,11 +772,15 @@ INTERNAL void gameUpdate(GameState *state, Memory *memory, f32 dt) | ||||
| 			// direction by extrapolating from it's current dp
 | ||||
| 			else | ||||
| 			{ | ||||
| 				if (entity->dP.x >= 0) localDp.x = 1.0f; | ||||
| 				else localDp.x = -1.0f; | ||||
| 				if (entity->dP.x >= 0) | ||||
| 					localDp.x = 1.0f; | ||||
| 				else | ||||
| 					localDp.x = -1.0f; | ||||
| 
 | ||||
| 				if (entity->dP.y >= 0) localDp.y = 1.0f; | ||||
| 				else localDp.y = -1.0f; | ||||
| 				if (entity->dP.y >= 0) | ||||
| 					localDp.y = 1.0f; | ||||
| 				else | ||||
| 					localDp.y = -1.0f; | ||||
| 			} | ||||
| 
 | ||||
| 			/*
 | ||||
| @ -814,10 +822,9 @@ INTERNAL void gameUpdate(GameState *state, Memory *memory, f32 dt) | ||||
| 
 | ||||
| 			f32 divisor = | ||||
| 			    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; | ||||
| 
 | ||||
| 		} | ||||
| 
 | ||||
| 		/* 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); | ||||
| 					addAsteroidWithSpec(world, asteroidsize_medium, &spec); | ||||
| 
 | ||||
| 					spec.dP        = v2_perpendicular(spec.dP); | ||||
| 					spec.dP = v2_perpendicular(spec.dP); | ||||
| 					addAsteroidWithSpec(world, asteroidsize_small, &spec); | ||||
| 
 | ||||
| 					spec.dP        = v2_perpendicular(colliderA->dP); | ||||
| 					spec.dP = v2_perpendicular(colliderA->dP); | ||||
| 					addAsteroidWithSpec(world, asteroidsize_small, &spec); | ||||
| 
 | ||||
| 					numParticles = 16; | ||||
| @ -892,8 +899,8 @@ INTERNAL void gameUpdate(GameState *state, Memory *memory, f32 dt) | ||||
| 						    &world->entityList[world->entityIndex++]; | ||||
| 						particle->id = world->entityIdCounter++; | ||||
| 
 | ||||
| 						particle->pos        = colliderA->pos; | ||||
| 						particle->size       = V2(4.0f, 4.0f); | ||||
| 						particle->pos  = colliderA->pos; | ||||
| 						particle->size = V2(4.0f, 4.0f); | ||||
| 
 | ||||
| 						i32 randValue = rand(); | ||||
| 						Radians rotation = | ||||
| @ -977,11 +984,9 @@ INTERNAL void gameUpdate(GameState *state, Memory *memory, f32 dt) | ||||
| 
 | ||||
| 		RenderFlags flags = renderflag_wireframe | renderflag_no_texture; | ||||
| 		renderer_entity(&state->renderer, &state->transientArena, world->camera, | ||||
| 		                entity, V2(0, 0), 0, | ||||
| 		                collideColor, flags); | ||||
| 		                entity, V2(0, 0), 0, collideColor, flags); | ||||
| 	} | ||||
| 
 | ||||
| 
 | ||||
| 	for (i32 i = 0; i < world->numAudioRenderers; i++) | ||||
| 	{ | ||||
| 		AudioRenderer *audioRenderer = &world->audioRenderer[i]; | ||||
| @ -1000,6 +1005,45 @@ INTERNAL void startMenuUpdate(GameState *state, Memory *memory, f32 dt) | ||||
| 	StartMenuState *menuState = | ||||
| 	    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( | ||||
| 	    assetManager, &state->persistentArena, transientArena, "Arial", 15); | ||||
| 	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); | ||||
| 
 | ||||
| 	ui_beginState(uiState); | ||||
| 
 | ||||
| 	if (menuState->optionsShow) | ||||
| 	{ | ||||
| 		if (platform_queryKey(&inputBuffer->keys[keycode_o], | ||||
| @ -1020,39 +1063,78 @@ INTERNAL void startMenuUpdate(GameState *state, Memory *memory, f32 dt) | ||||
| 		} | ||||
| 		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], | ||||
| 			                      readkeytype_one_shot, KEY_DELAY_NONE)) | ||||
| 			{ | ||||
| 				menuState->newResolutionRequest = TRUE; | ||||
| 				menuState->newResolution        = V2(800, 600); | ||||
| 				OptimalArrayV2 *resolutionArray = inputBuffer->resolutionList; | ||||
| 
 | ||||
| 				renderer->size        = menuState->newResolution; | ||||
| 				menuState->newResolutionRequest = TRUE; | ||||
| 				v2 newSize = | ||||
| 				    resolutionArray->ptr[menuState->resStringDisplayIndex]; | ||||
| 
 | ||||
| 				GameWorldState *world = GET_STATE_DATA( | ||||
| 				    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
 | ||||
| 			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, | ||||
| 			                     optionPrompt, p, V2(0, 0), 0, V4(1, 1, 0, 1), | ||||
| 			                     0); | ||||
| 			                             optionPrompt, p, V2(0, 0), 0, | ||||
| 			                             V4(1, 1, 0, 1), 0); | ||||
| 		} | ||||
| 
 | ||||
| 		if (platform_queryKey(&inputBuffer->keys[keycode_enter], | ||||
| @ -1131,7 +1213,7 @@ void asteroid_gameUpdateAndRender(GameState *state, Memory *memory, | ||||
| 		srand((u32)time(NULL)); | ||||
| 		asset_init(&state->assetManager, &state->persistentArena); | ||||
| 		audio_init(&state->audioManager); | ||||
| 		 | ||||
| 
 | ||||
| 		// NOTE(doyle): Load game assets must be before init_renderer so that
 | ||||
| 		// shaders are available for the renderer configuration
 | ||||
| 		loadGameAssets(state); | ||||
| @ -1139,7 +1221,7 @@ void asteroid_gameUpdateAndRender(GameState *state, Memory *memory, | ||||
| 		              &state->persistentArena, windowSize); | ||||
| 
 | ||||
| 		Font *arial15 = asset_fontGet(&state->assetManager, "Arial", 15); | ||||
| 		debug_init(&state->persistentArena, windowSize, *arial15); | ||||
| 		debug_init(windowSize, *arial15); | ||||
| 
 | ||||
| 		state->currState = appstate_StartMenuState; | ||||
| 		state->init      = TRUE; | ||||
|  | ||||
							
								
								
									
										209
									
								
								src/Common.c
									
									
									
									
									
								
							
							
						
						
									
										209
									
								
								src/Common.c
									
									
									
									
									
								
							| @ -1,10 +1,173 @@ | ||||
| #include <stdlib.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 result = 0; | ||||
| 	while (string[result]) result++; | ||||
| 	while (string[result]) | ||||
| 		result++; | ||||
| 	return result; | ||||
| } | ||||
| 
 | ||||
| @ -12,8 +175,7 @@ i32 common_strcmp(const char *a, const char *b) | ||||
| { | ||||
| 	while (*a == *b) | ||||
| 	{ | ||||
| 		if (!*a) | ||||
| 			return 0; | ||||
| 		if (!*a) return 0; | ||||
| 		a++; | ||||
| 		b++; | ||||
| 	} | ||||
| @ -27,13 +189,13 @@ void common_strncat(char *dest, const char *src, i32 numChars) | ||||
| 	while (*stringPtr) | ||||
| 		stringPtr++; | ||||
| 
 | ||||
| 	for (i32 i = 0; i < numChars; i++) | ||||
| 	for (i32 i         = 0; i < numChars; i++) | ||||
| 		*(stringPtr++) = src[i]; | ||||
| } | ||||
| 
 | ||||
| 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]; | ||||
| 
 | ||||
| 	return dest; | ||||
| @ -54,9 +216,9 @@ INTERNAL void reverseString(char *const buf, const i32 bufSize) | ||||
| 
 | ||||
| 	for (i32 i = 0; i < mid; i++) | ||||
| 	{ | ||||
| 		char tmp         = buf[i]; | ||||
| 		buf[i]           = buf[(bufSize-1) - i]; | ||||
| 		buf[(bufSize-1) - i] = tmp; | ||||
| 		char tmp               = buf[i]; | ||||
| 		buf[i]                 = buf[(bufSize - 1) - i]; | ||||
| 		buf[(bufSize - 1) - i] = tmp; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| @ -65,9 +227,9 @@ void common_itoa(i32 value, char *buf, i32 bufSize) | ||||
| 	if (!buf || bufSize == 0) return; | ||||
| 
 | ||||
| 	// NOTE(doyle): Max 32bit integer (+-)2147483647
 | ||||
| 	i32 charIndex   = 0; | ||||
| 	i32 charIndex = 0; | ||||
| 
 | ||||
| 	b32 negative = FALSE; | ||||
| 	b32 negative            = FALSE; | ||||
| 	if (value < 0) negative = TRUE; | ||||
| 
 | ||||
| 	if (negative) buf[charIndex++] = '-'; | ||||
| @ -75,7 +237,7 @@ void common_itoa(i32 value, char *buf, i32 bufSize) | ||||
| 	i32 val = ABS(value); | ||||
| 	while (val != 0 && charIndex < bufSize) | ||||
| 	{ | ||||
| 		i32 rem = val % 10; | ||||
| 		i32 rem          = val % 10; | ||||
| 		buf[charIndex++] = rem + '0'; | ||||
| 		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
 | ||||
| 
 | ||||
| 	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; | ||||
| 
 | ||||
| 		k *= m; | ||||
| 		k ^= k >> r; | ||||
| 		k *= m; | ||||
| 		 | ||||
| 
 | ||||
| 		h *= m; | ||||
| 		h ^= k; | ||||
| 
 | ||||
| 		data += 4; | ||||
| 		len -= 4; | ||||
| 	} | ||||
| 	 | ||||
| 
 | ||||
| 	// Handle the last few bytes of the input array
 | ||||
| 
 | ||||
| 	switch(len) | ||||
| 	switch (len) | ||||
| 	{ | ||||
| 	case 3: h ^= data[2] << 16; | ||||
| 	case 2: h ^= data[1] << 8; | ||||
| 	case 1: h ^= data[0]; | ||||
| 	        h *= m; | ||||
| 	case 3: | ||||
| 		h ^= data[2] << 16; | ||||
| 	case 2: | ||||
| 		h ^= data[1] << 8; | ||||
| 	case 1: | ||||
| 		h ^= data[0]; | ||||
| 		h *= m; | ||||
| 	}; | ||||
| 
 | ||||
| 	// 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; | ||||
| 
 | ||||
| 	return h; | ||||
| }  | ||||
| } | ||||
|  | ||||
							
								
								
									
										22
									
								
								src/Debug.c
									
									
									
									
									
								
							
							
						
						
									
										22
									
								
								src/Debug.c
									
									
									
									
									
								
							| @ -9,7 +9,7 @@ typedef struct DebugState | ||||
| { | ||||
| 	b32 init; | ||||
| 	Font font; | ||||
| 	i32 *callCount; | ||||
| 	i32 callCount[debugcount_num]; | ||||
| 	f32 stringLineGap; | ||||
| 
 | ||||
| 	/* Debug strings rendered in top left corner */ | ||||
| @ -28,11 +28,12 @@ typedef struct DebugState | ||||
| 
 | ||||
| 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.callCount = | ||||
| 	    memory_pushBytes(arena, debugcount_num * sizeof(i32)); | ||||
| 	GLOBAL_debug.font          = font; | ||||
| 
 | ||||
| 	for (i32 i = 0; i < debugcount_num; i++) GLOBAL_debug.callCount[i] = 0; | ||||
| 
 | ||||
| 	GLOBAL_debug.stringLineGap = CAST(f32) font.verticalSpacing; | ||||
| 
 | ||||
| 	/* Init debug string stack */ | ||||
| @ -40,18 +41,17 @@ void debug_init(MemoryArena_ *arena, v2 windowSize, Font font) | ||||
| 	GLOBAL_debug.stringUpdateTimer = 0.0f; | ||||
| 	GLOBAL_debug.stringUpdateRate  = 0.15f; | ||||
| 
 | ||||
| 	GLOBAL_debug.initialStringP = | ||||
| 	    V2(0.0f, (windowSize.h - 1.8f * GLOBAL_debug.stringLineGap)); | ||||
| 	GLOBAL_debug.currStringP = GLOBAL_debug.initialStringP; | ||||
| 	GLOBAL_debug.initialStringP = V2(0.0f, (windowSize.h - 1.8f * GLOBAL_debug.stringLineGap)); | ||||
| 	GLOBAL_debug.currStringP    = GLOBAL_debug.initialStringP; | ||||
| 
 | ||||
| 	/* Init gui console */ | ||||
| 	i32 maxConsoleStrLen = ARRAY_COUNT(GLOBAL_debug.console[0]); | ||||
| 	i32 maxConsoleStrLen      = ARRAY_COUNT(GLOBAL_debug.console[0]); | ||||
| 	GLOBAL_debug.consoleIndex = 0; | ||||
| 
 | ||||
| 	// TODO(doyle): Font max size not entirely correct? using 1 * font.maxSize.w
 | ||||
| 	// reveals around 4 characters ..
 | ||||
| 	f32 consoleXPos = font.maxSize.w * 20; | ||||
| 	f32 consoleYPos = windowSize.h - 1.8f * GLOBAL_debug.stringLineGap; | ||||
| 	f32 consoleXPos              = font.maxSize.w * 20; | ||||
| 	f32 consoleYPos              = windowSize.h - 1.8f * GLOBAL_debug.stringLineGap; | ||||
| 	GLOBAL_debug.initialConsoleP = V2(consoleXPos, consoleYPos); | ||||
| 
 | ||||
| 	GLOBAL_debug.init = TRUE; | ||||
|  | ||||
| @ -32,8 +32,7 @@ void shaderUniformSetVec4f(u32 shaderId, const GLchar *name, | ||||
| 
 | ||||
| void shaderUse(u32 shaderId) { glUseProgram(shaderId); } | ||||
| 
 | ||||
| void renderer_init(Renderer *renderer, AssetManager *assetManager, | ||||
|                    MemoryArena_ *persistentArena, v2 windowSize) | ||||
| void renderer_updateSize(Renderer *renderer, AssetManager *assetManager, v2 windowSize) | ||||
| { | ||||
| 	renderer->size = windowSize; | ||||
| 	// 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 = | ||||
| 	    mat4_ortho(0.0f, renderer->size.w, 0.0f, renderer->size.h, 0.0f, 1.0f); | ||||
| 
 | ||||
| 	for (i32 i = 0; i < shaderlist_count; 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]; | ||||
| 	GL_CHECK_ERROR(); | ||||
| } | ||||
| 
 | ||||
| void renderer_init(Renderer *renderer, AssetManager *assetManager, | ||||
|                    MemoryArena_ *persistentArena, v2 windowSize) | ||||
| { | ||||
| 	renderer_updateSize(renderer, assetManager, windowSize); | ||||
| 
 | ||||
| 	/* Create buffers */ | ||||
| 	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/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)); | ||||
| 
 | ||||
| 	switch(button) | ||||
| 	switch (button) | ||||
| 	{ | ||||
| 	case GLFW_MOUSE_BUTTON_LEFT: | ||||
| 		processKey(&game->input.keys[keycode_mouseLeft], action); | ||||
| @ -115,8 +115,73 @@ i32 main(void) | ||||
| 	glfwInit(); | ||||
| 	setGlfwWindowHints(); | ||||
| 
 | ||||
| 	i32 windowWidth = 1600; | ||||
| 	i32 windowHeight = 900; | ||||
| 	OptimalArrayV2 vidList = {0}; | ||||
| 	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 = | ||||
| 	    glfwCreateWindow(windowWidth, windowHeight, "Dengine", NULL, NULL); | ||||
| @ -168,7 +233,7 @@ i32 main(void) | ||||
| 	 * INITIALISE GAME | ||||
| 	 ******************* | ||||
| 	 */ | ||||
| 	Memory memory = {0}; | ||||
| 	Memory memory              = {0}; | ||||
| 	MemoryIndex persistentSize = MEGABYTES(32); | ||||
| 	MemoryIndex transientSize  = MEGABYTES(64); | ||||
| 
 | ||||
| @ -181,12 +246,12 @@ i32 main(void) | ||||
| 	MemoryArena_ gameArena = {0}; | ||||
| 	memory_arenaInit(&gameArena, memory.persistent, memory.persistentSize); | ||||
| 
 | ||||
| 	GameState *gameState = MEMORY_PUSH_STRUCT(&gameArena, GameState); | ||||
| 	GameState *gameState       = MEMORY_PUSH_STRUCT(&gameArena, GameState); | ||||
| 	gameState->persistentArena = gameArena; | ||||
| 
 | ||||
| 	glfwSetWindowUserPointer(window, CAST(void *)(gameState)); | ||||
| 
 | ||||
| 	{ | ||||
| 	{ // Load game icon
 | ||||
| 		i32 width, height; | ||||
| 		char *iconPath = "data/textures/Asteroids/icon.png"; | ||||
| 		u8 *pixels = asset_imageLoad(&width, &height, NULL, iconPath, FALSE); | ||||
| @ -198,6 +263,7 @@ i32 main(void) | ||||
| 			asset_imageFree(pixels); | ||||
| 		} | ||||
| 	} | ||||
| 	gameState->input.resolutionList = &vidList; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 ******************* | ||||
| @ -209,7 +275,6 @@ i32 main(void) | ||||
| 
 | ||||
| #if 0 | ||||
| 	// TODO(doyle): Get actual monitor refresh rate
 | ||||
| 	i32 monitorRefreshHz      = 60; | ||||
| 	f32 targetSecondsPerFrame = 1.0f / CAST(f32)(monitorRefreshHz); | ||||
| #else | ||||
| 	// TODO(doyle): http://gafferongames.com/game-physics/fix-your-timestep/
 | ||||
| @ -234,7 +299,7 @@ i32 main(void) | ||||
| 		/* Swap the buffers */ | ||||
| 		glfwSwapBuffers(window); | ||||
| 
 | ||||
| 		f32 endTime    = CAST(f32)glfwGetTime(); | ||||
| 		f32 endTime    = CAST(f32) glfwGetTime(); | ||||
| 		secondsElapsed = endTime - startTime; | ||||
| 
 | ||||
| #if 0 | ||||
| @ -277,8 +342,11 @@ i32 main(void) | ||||
| 		{ | ||||
| 			if (menuState->newResolutionRequest) | ||||
| 			{ | ||||
| 				windowSize = menuState->newResolution; | ||||
| 				i32 index  = menuState->resStringDisplayIndex; | ||||
| 				windowSize = gameState->input.resolutionList->ptr[index]; | ||||
| 
 | ||||
| 				glfwSetWindowSize(window, (i32)windowSize.w, (i32)windowSize.h); | ||||
| 				glViewport(0, 0, (i32)windowSize.w, (i32)windowSize.h); | ||||
| 
 | ||||
| 				menuState->newResolutionRequest = FALSE; | ||||
| 			} | ||||
|  | ||||
| @ -24,7 +24,8 @@ typedef struct GameWorldState | ||||
| 	MemoryArena_ entityArena; | ||||
| 
 | ||||
| 	v2 *entityVertexListCache[entitytype_count]; | ||||
| 	Entity entityList[1024]; | ||||
| 	Entity *entityList; | ||||
| 	i32 entityListSize; | ||||
| 	i32 entityIndex; | ||||
| 	u32 entityIdCounter; | ||||
| 
 | ||||
| @ -54,19 +55,23 @@ typedef struct GameWorldState | ||||
| 
 | ||||
| typedef struct StartMenuState | ||||
| { | ||||
| 	b32 init; | ||||
| 
 | ||||
| 	f32 startPromptBlinkTimer; | ||||
| 	b32 startPromptShow; | ||||
| 
 | ||||
| 	b32 optionsShow; | ||||
| 	char **resStrings; | ||||
| 	i32 numResStrings; | ||||
| 	i32 resStringDisplayIndex; | ||||
| 
 | ||||
| 	b32 newResolutionRequest; | ||||
| 	v2 newResolution; | ||||
| 
 | ||||
| 	b32 optionsShow; | ||||
| } StartMenuState; | ||||
| 
 | ||||
| typedef struct GameState | ||||
| { | ||||
| 	b32 init; | ||||
| 
 | ||||
| 	enum AppState currState; | ||||
| 	void *appStateData[appstate_count]; | ||||
| 
 | ||||
| @ -81,8 +86,7 @@ typedef struct GameState | ||||
| 	UiState uiState; | ||||
| } GameState; | ||||
| 
 | ||||
| #define ASTEROID_GET_STATE_DATA(state, type)                                   \ | ||||
| 	(type *)asteroid_getStateData_(state, appstate_##type) | ||||
| #define ASTEROID_GET_STATE_DATA(state, type) (type *)asteroid_getStateData_(state, appstate_##type) | ||||
| void *asteroid_getStateData_(GameState *state, enum AppState appState); | ||||
| 
 | ||||
| void asteroid_gameUpdateAndRender(GameState *state, Memory *memory, | ||||
|  | ||||
| @ -15,6 +15,9 @@ typedef float f32; | ||||
| typedef double f64; | ||||
| 
 | ||||
| typedef size_t MemoryIndex; | ||||
| typedef char String; | ||||
| 
 | ||||
| typedef struct MemoryArena MemoryArena_; | ||||
| 
 | ||||
| #define TRUE 1 | ||||
| #define FALSE 0 | ||||
| @ -34,6 +37,44 @@ typedef size_t MemoryIndex; | ||||
| 
 | ||||
| #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_strcmp(const char *a, const char *b); | ||||
| void common_strncat(char *dest, const char *src, i32 numChars); | ||||
|  | ||||
| @ -20,7 +20,7 @@ enum DebugCount | ||||
| 	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) | ||||
| void debug_recursivePrintXmlTree(XmlNode *root, i32 levelsDeep); | ||||
|  | ||||
| @ -2,6 +2,7 @@ | ||||
| #define DENGINE_MATH_H | ||||
| 
 | ||||
| #include <math.h> | ||||
| 
 | ||||
| #include "Dengine/Common.h" | ||||
| 
 | ||||
| #define MATH_PI 3.14159265359f | ||||
|  | ||||
| @ -143,6 +143,8 @@ typedef struct KeyState | ||||
| 
 | ||||
| typedef struct InputBuffer | ||||
| { | ||||
| 	OptimalArrayV2 *resolutionList; | ||||
| 
 | ||||
| 	v2 mouseP; | ||||
| 	KeyState keys[keycode_count]; | ||||
| } InputBuffer; | ||||
|  | ||||
| @ -84,6 +84,7 @@ typedef struct Renderer | ||||
| 	i32 groupCapacity; | ||||
| } Renderer; | ||||
| 
 | ||||
| void renderer_updateSize(Renderer *renderer, AssetManager *assetManager, v2 windowSize); | ||||
| void renderer_init(Renderer *renderer, AssetManager *assetManager, | ||||
|                    MemoryArena_ *persistentArena, v2 windowSize); | ||||
| 
 | ||||
|  | ||||
| @ -1,16 +1,5 @@ | ||||
| #ifndef 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 | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user