Additional debug string rendering infrastructure
Separate notion of rendering a static string, i.e. for debug display that is absolutely positioned, and rendering of a regular string that moves with the game camera.
This commit is contained in:
		
							parent
							
								
									d82afe49d0
								
							
						
					
					
						commit
						b1875077b7
					
				| @ -48,6 +48,15 @@ const i32 asset_loadTextureImage(AssetManager *assetManager, | |||||||
| 	u8 *image = | 	u8 *image = | ||||||
| 	    stbi_load(path, &imgWidth, &imgHeight, &bytesPerPixel, 0); | 	    stbi_load(path, &imgWidth, &imgHeight, &bytesPerPixel, 0); | ||||||
| 
 | 
 | ||||||
|  | #ifdef DENGINE_DEBUG | ||||||
|  | 	if (imgWidth != imgHeight) | ||||||
|  | 	{ | ||||||
|  | 		printf( | ||||||
|  | 		    "worldTraveller_gameInit() warning: Sprite sheet is not square: " | ||||||
|  | 		    "%dx%dpx\n", imgWidth, imgHeight); | ||||||
|  | 	} | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
| 	if (!image) | 	if (!image) | ||||||
| 	{ | 	{ | ||||||
| 		printf("stdbi_load() failed: %s\n", stbi_failure_reason()); | 		printf("stdbi_load() failed: %s\n", stbi_failure_reason()); | ||||||
|  | |||||||
| @ -58,7 +58,7 @@ void debug_stringUpdateAndRender(Renderer *renderer, Font *font, f32 dt) | |||||||
| 	{ | 	{ | ||||||
| 		f32 rotate = 0; | 		f32 rotate = 0; | ||||||
| 		v4 color   = V4(0, 0, 0, 1); | 		v4 color   = V4(0, 0, 0, 1); | ||||||
| 		renderer_string(renderer, font, GLOBAL_debugState.debugStrings[i], | 		renderer_staticString(renderer, font, GLOBAL_debugState.debugStrings[i], | ||||||
| 		                      GLOBAL_debugState.stringPos, rotate, color); | 		                      GLOBAL_debugState.stringPos, rotate, color); | ||||||
| 		GLOBAL_debugState.stringPos.y -= | 		GLOBAL_debugState.stringPos.y -= | ||||||
| 		    (0.9f * GLOBAL_debugState.stringLineGap); | 		    (0.9f * GLOBAL_debugState.stringLineGap); | ||||||
|  | |||||||
| @ -18,18 +18,33 @@ INTERNAL void updateBufferObject(Renderer *const renderer, | |||||||
| 	glBindBuffer(GL_ARRAY_BUFFER, 0); | 	glBindBuffer(GL_ARRAY_BUFFER, 0); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void renderer_string(Renderer *const renderer, Font *const font, | void renderer_string(Renderer *const renderer, v4 cameraBounds, | ||||||
|                      const char *const string, v2 pos, f32 rotate, |                      Font *const font, const char *const string, v2 pos, | ||||||
|                      v4 color) |                      f32 rotate, v4 color) | ||||||
|  | { | ||||||
|  | 	i32 strLen       = common_strlen(string); | ||||||
|  | 	// TODO(doyle): Slightly incorrect string length in pixels calculation,
 | ||||||
|  | 	// because we use the advance metric of each character for length not
 | ||||||
|  | 	// maximum character size in rendering
 | ||||||
|  | 	v2 rightAlignedP = | ||||||
|  | 	    v2_add(pos, V2((CAST(f32) font->maxSize.w * CAST(f32) strLen), | ||||||
|  | 	                   CAST(f32) font->maxSize.h)); | ||||||
|  | 	v2 leftAlignedP  = pos; | ||||||
|  | 	if ((leftAlignedP.x < cameraBounds.z && rightAlignedP.x >= cameraBounds.x) && | ||||||
|  | 	    (leftAlignedP.y < cameraBounds.y && rightAlignedP.y >= cameraBounds.w)) | ||||||
| 	{ | 	{ | ||||||
| 		i32 quadIndex           = 0; | 		i32 quadIndex           = 0; | ||||||
| 	i32 strLen = common_strlen(string); |  | ||||||
| 		RenderQuad *stringQuads = PLATFORM_MEM_ALLOC(strLen, RenderQuad); | 		RenderQuad *stringQuads = PLATFORM_MEM_ALLOC(strLen, RenderQuad); | ||||||
| 
 | 
 | ||||||
|  | 		v2 offsetFromCamOrigin    = V2(cameraBounds.x, cameraBounds.w); | ||||||
|  | 		v2 entityRelativeToCamera = v2_sub(pos, offsetFromCamOrigin); | ||||||
|  | 
 | ||||||
|  | 		pos          = entityRelativeToCamera; | ||||||
| 		f32 baseline = pos.y; | 		f32 baseline = pos.y; | ||||||
| 		for (i32 i = 0; i < strLen; i++) | 		for (i32 i = 0; i < strLen; i++) | ||||||
| 		{ | 		{ | ||||||
| 		// NOTE(doyle): Atlas packs fonts tightly, so offset the codepoint to
 | 			// NOTE(doyle): Atlas packs fonts tightly, so offset the codepoint
 | ||||||
|  | 			// to
 | ||||||
| 			// its actual atlas index, i.e. we skip the first 31 glyphs
 | 			// its actual atlas index, i.e. we skip the first 31 glyphs
 | ||||||
| 			i32 codepoint          = string[i]; | 			i32 codepoint          = string[i]; | ||||||
| 			i32 relativeIndex      = codepoint - font->codepointRange.x; | 			i32 relativeIndex      = codepoint - font->codepointRange.x; | ||||||
| @ -45,8 +60,8 @@ void renderer_string(Renderer *const renderer, Font *const font, | |||||||
| 			v4 charTexRect = font->atlas->texRect[relativeIndex]; | 			v4 charTexRect = font->atlas->texRect[relativeIndex]; | ||||||
| 			renderer_flipTexCoord(&charTexRect, FALSE, TRUE); | 			renderer_flipTexCoord(&charTexRect, FALSE, TRUE); | ||||||
| 
 | 
 | ||||||
| 		RenderQuad charQuad = renderer_createQuad(renderer, charRectOnScreen, | 			RenderQuad charQuad = renderer_createQuad( | ||||||
| 		                                          charTexRect, font->tex); | 			    renderer, charRectOnScreen, charTexRect, font->tex); | ||||||
| 			stringQuads[quadIndex++] = charQuad; | 			stringQuads[quadIndex++] = charQuad; | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| @ -57,11 +72,11 @@ void renderer_string(Renderer *const renderer, Font *const font, | |||||||
| 		renderer_object(renderer, V2(0.0f, 0.0f), renderer->size, rotate, color, | 		renderer_object(renderer, V2(0.0f, 0.0f), renderer->size, rotate, color, | ||||||
| 		                font->tex); | 		                font->tex); | ||||||
| 		PLATFORM_MEM_FREE(stringQuads, strLen * sizeof(RenderQuad)); | 		PLATFORM_MEM_FREE(stringQuads, strLen * sizeof(RenderQuad)); | ||||||
| 
 | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void renderer_entity(Renderer *renderer, v4 cameraBounds, Entity *entity, f32 dt, f32 rotate, | void renderer_entity(Renderer *renderer, v4 cameraBounds, Entity *entity, | ||||||
|                      v4 color) |                      f32 dt, f32 rotate, v4 color) | ||||||
| { | { | ||||||
| 	// TODO(doyle): Batch into render groups
 | 	// TODO(doyle): Batch into render groups
 | ||||||
| 
 | 
 | ||||||
| @ -101,7 +116,6 @@ void renderer_entity(Renderer *renderer, v4 cameraBounds, Entity *entity, f32 dt | |||||||
| 		renderer_object(renderer, entityRelativeToCamera, entity->size, rotate, | 		renderer_object(renderer, entityRelativeToCamera, entity->size, rotate, | ||||||
| 		                color, entity->tex); | 		                color, entity->tex); | ||||||
| 	} | 	} | ||||||
| 
 |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void renderer_object(Renderer *renderer, v2 pos, v2 size, f32 rotate, v4 color, | void renderer_object(Renderer *renderer, v2 pos, v2 size, f32 rotate, v4 color, | ||||||
|  | |||||||
| @ -201,23 +201,13 @@ void worldTraveller_gameInit(GameState *state, v2i windowSize) | |||||||
| 	heroWalkRects[2]  = V4(849.0f, 1018.0f, 904.0f, 920.0f); | 	heroWalkRects[2]  = V4(849.0f, 1018.0f, 904.0f, 920.0f); | ||||||
| 	addAnim(hero, heroWalkRects, numRects, duration); | 	addAnim(hero, heroWalkRects, numRects, duration); | ||||||
| 
 | 
 | ||||||
| 	Texture *heroSheet = hero->tex; |  | ||||||
| 	v2 sheetSize = V2(CAST(f32) heroSheet->width, CAST(f32) heroSheet->height); |  | ||||||
| 	if (sheetSize.x != sheetSize.y) |  | ||||||
| 	{ |  | ||||||
| 		printf( |  | ||||||
| 		    "worldTraveller_gameInit() warning: Sprite sheet is not square: " |  | ||||||
| 		    "%dx%dpx\n", |  | ||||||
| 		    CAST(i32) sheetSize.w, CAST(i32) sheetSize.h); |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	/* Create a NPC */ | 	/* Create a NPC */ | ||||||
| 	pos         = V2(300.0f, 300.0f); | 	pos         = V2((renderer->size.w / 3.0f), CAST(f32) state->tileSize); | ||||||
| 	size        = hero->size; | 	size        = hero->size; | ||||||
| 	type        = entitytype_hero; | 	type        = entitytype_npc; | ||||||
| 	dir         = direction_null; | 	dir         = direction_null; | ||||||
| 	tex         = hero->tex; | 	tex         = hero->tex; | ||||||
| 	collides    = TRUE; | 	collides    = FALSE; | ||||||
| 	Entity *npc = addEntity(world, pos, size, type, dir, tex, collides); | 	Entity *npc = addEntity(world, pos, size, type, dir, tex, collides); | ||||||
| 
 | 
 | ||||||
| 	/* Add npc waving animation */ | 	/* Add npc waving animation */ | ||||||
| @ -228,6 +218,32 @@ void worldTraveller_gameInit(GameState *state, v2i windowSize) | |||||||
| 	npcWavingRects[1]  = V4(944.0f, 812.0f, 1010.0f, 710.0f); | 	npcWavingRects[1]  = V4(944.0f, 812.0f, 1010.0f, 710.0f); | ||||||
| 	addAnim(npc, npcWavingRects, numRects, duration); | 	addAnim(npc, npcWavingRects, numRects, duration); | ||||||
| 
 | 
 | ||||||
|  | 	/* Create a Mob */ | ||||||
|  | 	pos         = V2(renderer->size.w - (renderer->size.w / 3.0f), | ||||||
|  | 	                 CAST(f32) state->tileSize); | ||||||
|  | 	size        = hero->size; | ||||||
|  | 	type        = entitytype_mob; | ||||||
|  | 	dir         = direction_west; | ||||||
|  | 	tex         = hero->tex; | ||||||
|  | 	collides    = TRUE; | ||||||
|  | 	Entity *mob = addEntity(world, pos, size, type, dir, tex, collides); | ||||||
|  | 
 | ||||||
|  | 	/* Add mob idle animation */ | ||||||
|  | 	duration         = 1.0f; | ||||||
|  | 	numRects         = 1; | ||||||
|  | 	v4 *mobIdleRects = PLATFORM_MEM_ALLOC(numRects, v4); | ||||||
|  | 	mobIdleRects[0]  = heroIdleRects[0]; | ||||||
|  | 	addAnim(mob, mobIdleRects, numRects, duration); | ||||||
|  | 
 | ||||||
|  | 	/* Add mob walking animation */ | ||||||
|  | 	duration         = 0.10f; | ||||||
|  | 	numRects         = 3; | ||||||
|  | 	v4 *mobWalkRects = PLATFORM_MEM_ALLOC(numRects, v4); | ||||||
|  | 	mobWalkRects[0]  = heroWalkRects[0]; | ||||||
|  | 	mobWalkRects[1]  = heroWalkRects[1]; | ||||||
|  | 	mobWalkRects[2]  = heroWalkRects[2]; | ||||||
|  | 	addAnim(mob, mobWalkRects, numRects, duration); | ||||||
|  | 
 | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| INTERNAL void parseInput(GameState *state, const f32 dt) | INTERNAL void parseInput(GameState *state, const f32 dt) | ||||||
| @ -406,18 +422,63 @@ void worldTraveller_gameUpdateAndRender(GameState *state, const f32 dt) | |||||||
| 
 | 
 | ||||||
| 	if (cameraBounds.w <= world->bounds.w) cameraBounds.w = world->bounds.w; | 	if (cameraBounds.w <= world->bounds.w) cameraBounds.w = world->bounds.w; | ||||||
| 
 | 
 | ||||||
|  | 	Font *font = &assetManager->font; | ||||||
| 	for (i32 i = 0; i < world->freeEntityIndex; i++) | 	for (i32 i = 0; i < world->freeEntityIndex; i++) | ||||||
| 	{ | 	{ | ||||||
| 		Entity *const entity = &world->entities[i]; | 		Entity *const entity = &world->entities[i]; | ||||||
| 		renderer_entity(&state->renderer, cameraBounds, entity, dt, 0.0f, | 		renderer_entity(&state->renderer, cameraBounds, entity, dt, 0.0f, | ||||||
| 		                V4(1, 1, 1, 1)); | 		                V4(1, 1, 1, 1)); | ||||||
|  | 
 | ||||||
|  | #ifdef DENGINE_DEBUG | ||||||
|  | 		v4 color = V4(1, 1, 1, 1); | ||||||
|  | 		char *debugString = NULL; | ||||||
|  | 		switch(entity->type) | ||||||
|  | 		{ | ||||||
|  | 			case entitytype_mob: | ||||||
|  | 				color = V4(1, 0, 0, 1); | ||||||
|  | 				debugString = "MOB"; | ||||||
|  | 			    break; | ||||||
|  | 
 | ||||||
|  | 			case entitytype_hero: | ||||||
|  | 				color = V4(0, 0, 1.0f, 1); | ||||||
|  | 				debugString = "HERO"; | ||||||
|  | 			    break; | ||||||
|  | 
 | ||||||
|  | 			case entitytype_npc: | ||||||
|  | 				color = V4(0, 1.0f, 0, 1); | ||||||
|  | 				debugString = "NPC"; | ||||||
|  | 			    break; | ||||||
|  | 
 | ||||||
|  | 			default: | ||||||
|  | 			    break; | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		if (debugString) | ||||||
|  | 		{ | ||||||
|  | 			v2 strPos = v2_add(entity->pos, entity->size); | ||||||
|  | 			i32 indexOfLowerAInMetrics = 'a' - font->codepointRange.x; | ||||||
|  | 			strPos.y += font->charMetrics[indexOfLowerAInMetrics].offset.y; | ||||||
|  | 
 | ||||||
|  | 			renderer_string(&state->renderer, cameraBounds, font, debugString, | ||||||
|  | 			                strPos, 0, color); | ||||||
|  | 
 | ||||||
|  | 			f32 stringLineGap = 1.1f * asset_getVFontSpacing(font->metrics); | ||||||
|  | 			strPos.y -= GLOBAL_debugState.stringLineGap; | ||||||
|  | 
 | ||||||
|  | 			char entityPosStr[256]; | ||||||
|  | 			snprintf(entityPosStr, ARRAY_COUNT(entityPosStr), "%06.2f, %06.2f", | ||||||
|  | 			         entity->pos.x, entity->pos.y); | ||||||
|  | 			renderer_string(&state->renderer, cameraBounds, font, entityPosStr, | ||||||
|  | 			                strPos, 0, color); | ||||||
|  | 		} | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	// TODO(doyle): Clean up lines
 | 	// TODO(doyle): Clean up lines
 | ||||||
| 	// Renderer::~Renderer() { glDeleteVertexArrays(1, &this->quadVAO); }
 | 	// Renderer::~Renderer() { glDeleteVertexArrays(1, &this->quadVAO); }
 | ||||||
| 
 | 
 | ||||||
| #ifdef DENGINE_DEBUG | #ifdef DENGINE_DEBUG | ||||||
| 	Font *font = &assetManager->font; |  | ||||||
| 	Entity *hero = &world->entities[world->heroIndex]; | 	Entity *hero = &world->entities[world->heroIndex]; | ||||||
| 	DEBUG_PUSH_STRING("Hero Pos: %06.2f, %06.2f", &hero->pos, "v2"); | 	DEBUG_PUSH_STRING("Hero Pos: %06.2f, %06.2f", &hero->pos, "v2"); | ||||||
| 	DEBUG_PUSH_STRING("Hero dPos: %06.2f, %06.2f", &hero->dPos, "v2"); | 	DEBUG_PUSH_STRING("Hero dPos: %06.2f, %06.2f", &hero->dPos, "v2"); | ||||||
|  | |||||||
| @ -19,6 +19,7 @@ enum EntityType | |||||||
| 	entitytype_null, | 	entitytype_null, | ||||||
| 	entitytype_hero, | 	entitytype_hero, | ||||||
| 	entitytype_npc, | 	entitytype_npc, | ||||||
|  | 	entitytype_mob, | ||||||
| 	entitytype_tile, | 	entitytype_tile, | ||||||
| 	entitytype_count, | 	entitytype_count, | ||||||
| }; | }; | ||||||
|  | |||||||
| @ -19,8 +19,17 @@ typedef struct RenderQuad | |||||||
| 	v4 vertex[4]; | 	v4 vertex[4]; | ||||||
| } RenderQuad; | } RenderQuad; | ||||||
| 
 | 
 | ||||||
| void renderer_string(Renderer *const renderer, Font *const font, | void renderer_string(Renderer *const renderer, v4 cameraBounds, | ||||||
|                      const char *const string, v2 pos, f32 rotate, v4 color); |                      Font *const font, const char *const string, v2 pos, | ||||||
|  |                      f32 rotate, v4 color); | ||||||
|  | 
 | ||||||
|  | inline void renderer_staticString(Renderer *const renderer, Font *const font, | ||||||
|  |                                   const char *const string, v2 pos, f32 rotate, | ||||||
|  |                                   v4 color) | ||||||
|  | { | ||||||
|  | 	renderer_string(renderer, V4(0, renderer->size.h, renderer->size.w, 0), | ||||||
|  | 	                font, string, pos, rotate, color); | ||||||
|  | } | ||||||
| 
 | 
 | ||||||
| void renderer_entity(Renderer *renderer, v4 cameraBounds, Entity *entity, | void renderer_entity(Renderer *renderer, v4 cameraBounds, Entity *entity, | ||||||
|                      f32 dt, f32 rotate, v4 color); |                      f32 dt, f32 rotate, v4 color); | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user