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 = | ||||
| 	    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) | ||||
| 	{ | ||||
| 		printf("stdbi_load() failed: %s\n", stbi_failure_reason()); | ||||
|  | ||||
| @ -58,8 +58,8 @@ void debug_stringUpdateAndRender(Renderer *renderer, Font *font, f32 dt) | ||||
| 	{ | ||||
| 		f32 rotate = 0; | ||||
| 		v4 color   = V4(0, 0, 0, 1); | ||||
| 		renderer_string(renderer, font, GLOBAL_debugState.debugStrings[i], | ||||
| 		                GLOBAL_debugState.stringPos, rotate, color); | ||||
| 		renderer_staticString(renderer, font, GLOBAL_debugState.debugStrings[i], | ||||
| 		                      GLOBAL_debugState.stringPos, rotate, color); | ||||
| 		GLOBAL_debugState.stringPos.y -= | ||||
| 		    (0.9f * GLOBAL_debugState.stringLineGap); | ||||
| 	} | ||||
|  | ||||
| @ -18,50 +18,65 @@ INTERNAL void updateBufferObject(Renderer *const renderer, | ||||
| 	glBindBuffer(GL_ARRAY_BUFFER, 0); | ||||
| } | ||||
| 
 | ||||
| void renderer_string(Renderer *const renderer, Font *const font, | ||||
|                      const char *const string, v2 pos, f32 rotate, | ||||
|                      v4 color) | ||||
| void renderer_string(Renderer *const renderer, v4 cameraBounds, | ||||
|                      Font *const font, const char *const string, v2 pos, | ||||
|                      f32 rotate, v4 color) | ||||
| { | ||||
| 	i32 quadIndex = 0; | ||||
| 	i32 strLen = common_strlen(string); | ||||
| 	RenderQuad *stringQuads = PLATFORM_MEM_ALLOC(strLen, RenderQuad); | ||||
| 
 | ||||
| 	f32 baseline = pos.y; | ||||
| 	for (i32 i = 0; i < strLen; i++) | ||||
| 	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)) | ||||
| 	{ | ||||
| 		// NOTE(doyle): Atlas packs fonts tightly, so offset the codepoint to
 | ||||
| 		// its actual atlas index, i.e. we skip the first 31 glyphs
 | ||||
| 		i32 codepoint = string[i]; | ||||
| 		i32 relativeIndex = codepoint - font->codepointRange.x; | ||||
| 		CharMetrics charMetric = font->charMetrics[relativeIndex]; | ||||
| 		pos.y = baseline - charMetric.offset.y; | ||||
| 		i32 quadIndex           = 0; | ||||
| 		RenderQuad *stringQuads = PLATFORM_MEM_ALLOC(strLen, RenderQuad); | ||||
| 
 | ||||
| 		const v4 charRectOnScreen = getRect( | ||||
| 		    pos, V2(CAST(f32) font->maxSize.w, CAST(f32) font->maxSize.h)); | ||||
| 		v2 offsetFromCamOrigin    = V2(cameraBounds.x, cameraBounds.w); | ||||
| 		v2 entityRelativeToCamera = v2_sub(pos, offsetFromCamOrigin); | ||||
| 
 | ||||
| 		pos.x += charMetric.advance; | ||||
| 		 | ||||
| 		/* Get texture out */ | ||||
| 		v4 charTexRect = font->atlas->texRect[relativeIndex]; | ||||
| 		renderer_flipTexCoord(&charTexRect, FALSE, TRUE); | ||||
| 		pos          = entityRelativeToCamera; | ||||
| 		f32 baseline = pos.y; | ||||
| 		for (i32 i = 0; i < strLen; i++) | ||||
| 		{ | ||||
| 			// NOTE(doyle): Atlas packs fonts tightly, so offset the codepoint
 | ||||
| 			// to
 | ||||
| 			// its actual atlas index, i.e. we skip the first 31 glyphs
 | ||||
| 			i32 codepoint          = string[i]; | ||||
| 			i32 relativeIndex      = codepoint - font->codepointRange.x; | ||||
| 			CharMetrics charMetric = font->charMetrics[relativeIndex]; | ||||
| 			pos.y                  = baseline - charMetric.offset.y; | ||||
| 
 | ||||
| 		RenderQuad charQuad = renderer_createQuad(renderer, charRectOnScreen, | ||||
| 		                                          charTexRect, font->tex); | ||||
| 		stringQuads[quadIndex++] = charQuad; | ||||
| 			const v4 charRectOnScreen = getRect( | ||||
| 			    pos, V2(CAST(f32) font->maxSize.w, CAST(f32) font->maxSize.h)); | ||||
| 
 | ||||
| 			pos.x += charMetric.advance; | ||||
| 
 | ||||
| 			/* Get texture out */ | ||||
| 			v4 charTexRect = font->atlas->texRect[relativeIndex]; | ||||
| 			renderer_flipTexCoord(&charTexRect, FALSE, TRUE); | ||||
| 
 | ||||
| 			RenderQuad charQuad = renderer_createQuad( | ||||
| 			    renderer, charRectOnScreen, charTexRect, font->tex); | ||||
| 			stringQuads[quadIndex++] = charQuad; | ||||
| 		} | ||||
| 
 | ||||
| 		// NOTE(doyle): We render at the renderer's size because we create quads
 | ||||
| 		// relative to the window size, hence we also render at the origin since
 | ||||
| 		// we're rendering a window sized buffer
 | ||||
| 		updateBufferObject(renderer, stringQuads, quadIndex); | ||||
| 		renderer_object(renderer, V2(0.0f, 0.0f), renderer->size, rotate, color, | ||||
| 		                font->tex); | ||||
| 		PLATFORM_MEM_FREE(stringQuads, strLen * sizeof(RenderQuad)); | ||||
| 	} | ||||
| 
 | ||||
| 	// NOTE(doyle): We render at the renderer's size because we create quads
 | ||||
| 	// relative to the window size, hence we also render at the origin since
 | ||||
| 	// we're rendering a window sized buffer
 | ||||
| 	updateBufferObject(renderer, stringQuads, quadIndex); | ||||
| 	renderer_object(renderer, V2(0.0f, 0.0f), renderer->size, rotate, color, | ||||
| 	                font->tex); | ||||
| 	PLATFORM_MEM_FREE(stringQuads, strLen * sizeof(RenderQuad)); | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| void renderer_entity(Renderer *renderer, v4 cameraBounds, Entity *entity, f32 dt, f32 rotate, | ||||
|                      v4 color) | ||||
| void renderer_entity(Renderer *renderer, v4 cameraBounds, Entity *entity, | ||||
|                      f32 dt, f32 rotate, v4 color) | ||||
| { | ||||
| 	// 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, | ||||
| 		                color, entity->tex); | ||||
| 	} | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| 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); | ||||
| 	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 */ | ||||
| 	pos         = V2(300.0f, 300.0f); | ||||
| 	pos         = V2((renderer->size.w / 3.0f), CAST(f32) state->tileSize); | ||||
| 	size        = hero->size; | ||||
| 	type        = entitytype_hero; | ||||
| 	type        = entitytype_npc; | ||||
| 	dir         = direction_null; | ||||
| 	tex         = hero->tex; | ||||
| 	collides    = TRUE; | ||||
| 	collides    = FALSE; | ||||
| 	Entity *npc = addEntity(world, pos, size, type, dir, tex, collides); | ||||
| 
 | ||||
| 	/* 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); | ||||
| 	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) | ||||
| @ -406,18 +422,63 @@ void worldTraveller_gameUpdateAndRender(GameState *state, const f32 dt) | ||||
| 
 | ||||
| 	if (cameraBounds.w <= world->bounds.w) cameraBounds.w = world->bounds.w; | ||||
| 
 | ||||
| 	Font *font = &assetManager->font; | ||||
| 	for (i32 i = 0; i < world->freeEntityIndex; i++) | ||||
| 	{ | ||||
| 		Entity *const entity = &world->entities[i]; | ||||
| 		renderer_entity(&state->renderer, cameraBounds, entity, dt, 0.0f, | ||||
| 		                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
 | ||||
| 	// Renderer::~Renderer() { glDeleteVertexArrays(1, &this->quadVAO); }
 | ||||
| 
 | ||||
| #ifdef DENGINE_DEBUG | ||||
| 	Font *font = &assetManager->font; | ||||
| 	Entity *hero = &world->entities[world->heroIndex]; | ||||
| 	DEBUG_PUSH_STRING("Hero Pos: %06.2f, %06.2f", &hero->pos, "v2"); | ||||
| 	DEBUG_PUSH_STRING("Hero dPos: %06.2f, %06.2f", &hero->dPos, "v2"); | ||||
|  | ||||
| @ -19,6 +19,7 @@ enum EntityType | ||||
| 	entitytype_null, | ||||
| 	entitytype_hero, | ||||
| 	entitytype_npc, | ||||
| 	entitytype_mob, | ||||
| 	entitytype_tile, | ||||
| 	entitytype_count, | ||||
| }; | ||||
|  | ||||
| @ -19,8 +19,17 @@ typedef struct RenderQuad | ||||
| 	v4 vertex[4]; | ||||
| } RenderQuad; | ||||
| 
 | ||||
| void renderer_string(Renderer *const renderer, Font *const font, | ||||
|                      const char *const string, v2 pos, f32 rotate, v4 color); | ||||
| void renderer_string(Renderer *const renderer, v4 cameraBounds, | ||||
|                      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, | ||||
|                      f32 dt, f32 rotate, v4 color); | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user