Compare commits
	
		
			1 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 371ece0ce3 | 
| @ -11,7 +11,7 @@ | ||||
| PlatformFlags globalDTRPlatformFlags; | ||||
| 
 | ||||
| // #include <algorithm>
 | ||||
| void CompAssignment(DTRRenderContext renderContext, PlatformInput *const input, | ||||
| void CompAssignment(DTRRenderBuffer *const renderBuffer, PlatformInput *const input, | ||||
|                     PlatformMemory *const memory) | ||||
| { | ||||
| #if 1 | ||||
| @ -835,11 +835,11 @@ void CompAssignment(DTRRenderContext renderContext, PlatformInput *const input, | ||||
| #if 1 | ||||
| 		char pText[32] = {}; | ||||
| 		Dqn_sprintf(pText, "(%1.0f, %1.0f)", origP.x, origP.y); | ||||
| 		DTRRender_Text(renderContext, state->font, | ||||
| 		DTRRender_Text(renderBuffer, state->font, | ||||
| 		               DqnV2_2f(p.x + radius.x + 5, p.y - (state->font.sizeInPt * 0.40f)), pText, | ||||
| 		               textColor); | ||||
| #endif | ||||
| 		DTRRender_Rectangle(renderContext, p - radius, p + radius, pColor); | ||||
| 		DTRRender_Rectangle(renderBuffer, p - radius, p + radius, pColor); | ||||
| 	} | ||||
| 
 | ||||
| 	DqnV2 halfRadius = radius * 0.5f; | ||||
| @ -851,10 +851,10 @@ void CompAssignment(DTRRenderContext renderContext, PlatformInput *const input, | ||||
| 
 | ||||
| 		char pText[32] = {}; | ||||
| 		Dqn_sprintf(pText, "(%1.0f, %1.0f)", origP.x, origP.y); | ||||
| 		DTRRender_Text(renderContext, state->font, | ||||
| 		DTRRender_Text(renderBuffer, state->font, | ||||
| 		               DqnV2_2f(p.x + radius.x + 5, p.y - (state->font.sizeInPt * 0.40f)), pText, | ||||
| 		               textColor); | ||||
| 		DTRRender_Rectangle(renderContext, p - radius, p + radius, pColor); | ||||
| 		DTRRender_Rectangle(renderBuffer, p - radius, p + radius, pColor); | ||||
| 
 | ||||
| 		if (i + 1 <= skyPIndex && i > 0) | ||||
| 		{ | ||||
| @ -863,7 +863,7 @@ void CompAssignment(DTRRenderContext renderContext, PlatformInput *const input, | ||||
| 
 | ||||
| 			DqnV2 pMid     = p + halfRadius; | ||||
| 			DqnV2 prevPMid = prevP + halfRadius; | ||||
| 			DTRRender_Line(renderContext, DqnV2i_V2(prevPMid), DqnV2i_V2(pMid), | ||||
| 			DTRRender_Line(renderBuffer, DqnV2i_V2(prevPMid), DqnV2i_V2(pMid), | ||||
| 			               DqnV4_4f(255, 0, 0, 255)); | ||||
| 		} | ||||
| 	} | ||||
| @ -895,23 +895,18 @@ extern "C" void DTR_Update(PlatformRenderBuffer *const platformRenderBuffer, | ||||
| 		state = (DTRState *)memory->context; | ||||
| 
 | ||||
| 		////////////////////////////////////////////////////////////////////////
 | ||||
| 		// Init
 | ||||
| 		// Init Memory Stacks
 | ||||
| 		////////////////////////////////////////////////////////////////////////
 | ||||
| 		DqnMemStack *const assetStack = &memory->assetStack; | ||||
| 		DqnMemStack *const tempStack  = &memory->tempStack; | ||||
| 		state->renderLock             = input->api.LockInit(&memory->mainStack); | ||||
| 		if (!state->renderLock) | ||||
| 		{ | ||||
| 			// TODO(doyle): Not enough memory die gracefully
 | ||||
| 			DQN_ASSERT(DQN_INVALID_CODE_PATH); | ||||
| 		} | ||||
| 
 | ||||
| 		////////////////////////////////////////////////////////////////////////
 | ||||
| 		// Init Assets
 | ||||
| 		////////////////////////////////////////////////////////////////////////
 | ||||
| 		DTRAsset_InitGlobalState(); | ||||
| 		const f32 FONT_SIZE = 14; | ||||
| 		DTRAsset_LoadFontToBitmap(input->api, &memory->mainStack, tempStack, &state->font, | ||||
| 		                          "Roboto-bold.ttf", DqnV2i_2i(256, 256), DqnV2i_2i(' ', '~'), 12); | ||||
| 		                          "Roboto-bold.ttf", DqnV2i_2i(256, 256), DqnV2i_2i(' ', '~'), FONT_SIZE); | ||||
| 		DTRAsset_LoadBitmap(input->api, assetStack, | ||||
| 		                    tempStack, &state->bitmap, "tree00.bmp"); | ||||
| 
 | ||||
| @ -935,184 +930,148 @@ extern "C" void DTR_Update(PlatformRenderBuffer *const platformRenderBuffer, | ||||
| 		if (DTR_DEBUG) | ||||
| 		{ | ||||
| 			DTRDebug_TestMeshFaceAndVertexParser(&state->mesh); | ||||
| 			bool regionValid; | ||||
| 			auto memRegion = DqnMemStackTempRegionGuard(&memory->tempStack, ®ionValid); | ||||
| 			if (regionValid) | ||||
| 			{ | ||||
| 				DTRBitmap test = {}; | ||||
| 				DTRAsset_LoadBitmap(input->api, assetStack, &memory->tempStack, &test, | ||||
| 				                    "byte_read_check.bmp"); | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 			DqnTempMemStack tmp = DqnMemStack_BeginTempRegion(&memory->tempStack); | ||||
| 			DTRBitmap test      = {}; | ||||
| 			DTRAsset_LoadBitmap(input->api, assetStack, &memory->tempStack, &test, "byte_read_check.bmp"); | ||||
| 			DqnMemStack_EndTempRegion(tmp); | ||||
| 
 | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	{ | ||||
| 		bool regionValid; | ||||
| 		auto tempMemRegion = DqnMemStackTempRegionGuard(&memory->tempStack, ®ionValid); | ||||
| 		if (regionValid) | ||||
| 		{ | ||||
| 			size_t debugSize = DQN_MEGABYTE(1); | ||||
| 			u8 *debugMemory  = (u8 *)DqnMemStack_Push(&memory->tempStack, debugSize); | ||||
| 			DqnMemStack_InitWithFixedMem(&globalDebug.memStack, debugMemory, debugSize); | ||||
| 			DTRDebug_BeginCycleCount("DTR_Update", DTRDebugCycleCount_DTR_Update); | ||||
| 	DqnTempMemStack tempStackMemRegion = DqnMemStack_BeginTempRegion(&memory->tempStack); | ||||
| 
 | ||||
| 			DTRRenderBuffer renderBuffer = {}; | ||||
| 			renderBuffer.width           = platformRenderBuffer->width; | ||||
| 			renderBuffer.height          = platformRenderBuffer->height; | ||||
| 			renderBuffer.bytesPerPixel   = platformRenderBuffer->bytesPerPixel; | ||||
| 			renderBuffer.memory          = (u8 *)platformRenderBuffer->memory; | ||||
| 			renderBuffer.renderLock      = state->renderLock; | ||||
| 	size_t debugSize = DQN_MEGABYTE(1); | ||||
| 	u8 *debugMemory  = (u8 *)DqnMemStack_Push(&memory->tempStack, debugSize); | ||||
| 	DqnMemStack_InitWithFixedMem(&globalDebug.memStack, debugMemory, debugSize); | ||||
| 	DTRDebug_BeginCycleCount("DTR_Update", DTRDebugCycleCount_DTR_Update); | ||||
| 
 | ||||
| 			u32 zBufferSize      = platformRenderBuffer->width * platformRenderBuffer->height; | ||||
| 			renderBuffer.zBuffer = (f32 *)DqnMemStack_Push( | ||||
| 			    &memory->tempStack, zBufferSize * sizeof(*renderBuffer.zBuffer)); | ||||
| 	DTRRenderBuffer renderBuffer = {}; | ||||
| 	renderBuffer.width           = platformRenderBuffer->width; | ||||
| 	renderBuffer.height          = platformRenderBuffer->height; | ||||
| 	renderBuffer.bytesPerPixel   = platformRenderBuffer->bytesPerPixel; | ||||
| 	renderBuffer.memory          = (u8 *)platformRenderBuffer->memory; | ||||
| 
 | ||||
| 			renderBuffer.pixelLockTable = (bool *)DqnMemStack_Push( | ||||
| 			    &memory->tempStack, zBufferSize * sizeof(*renderBuffer.pixelLockTable)); | ||||
| 	u32 zBufferSize = platformRenderBuffer->width * platformRenderBuffer->height; | ||||
| 	renderBuffer.zBuffer = (f32 *)DqnMemStack_Push(&memory->tempStack, | ||||
| 	                                               zBufferSize * sizeof(*renderBuffer.zBuffer)); | ||||
| 
 | ||||
| 			for (u32 i = 0; i < zBufferSize; i++) | ||||
| 			{ | ||||
| 				renderBuffer.zBuffer[i]        = DQN_F32_MIN; | ||||
| 				renderBuffer.pixelLockTable[i] = false; | ||||
| 			} | ||||
| 
 | ||||
| 			DTRRenderContext renderContext = {}; | ||||
| 			renderContext.multithread      = true; | ||||
| 			renderContext.renderBuffer     = &renderBuffer; | ||||
| 			renderContext.tempStack        = &memory->tempStack; | ||||
| 			renderContext.api              = &input->api; | ||||
| 			renderContext.jobQueue         = input->jobQueue; | ||||
| 			////////////////////////////////////////////////////////////////////////////
 | ||||
| 			// Update and Render
 | ||||
| 			////////////////////////////////////////////////////////////////////////////
 | ||||
| 			DTRRender_Clear(renderContext, DqnV3_3f(0.5f, 0.0f, 1.0f)); | ||||
| 	for (u32 i = 0; i < zBufferSize; i++) renderBuffer.zBuffer[i] = DQN_F32_MIN; | ||||
| 	////////////////////////////////////////////////////////////////////////////
 | ||||
| 	// Update and Render
 | ||||
| 	////////////////////////////////////////////////////////////////////////////
 | ||||
| 	DTRRender_Clear(&renderBuffer, DqnV3_3f(0.0f, 0.0f, 0.0f)); | ||||
| 
 | ||||
| #if 1 | ||||
| 			DqnV4 colorRed    = DqnV4_4f(0.8f, 0, 0, 1); | ||||
| 			DqnV2i bufferMidP = DqnV2i_2f(renderBuffer.width * 0.5f, renderBuffer.height * 0.5f); | ||||
| 			f32 rotation      = (f32)input->timeNowInS * 0.25f; | ||||
| 	DqnV4 colorRed    = DqnV4_4f(0.8f, 0, 0, 1); | ||||
| 	DqnV2i bufferMidP = DqnV2i_2f(renderBuffer.width * 0.5f, renderBuffer.height * 0.5f); | ||||
| 	f32 rotation      = (f32)input->timeNowInS * 0.25f; | ||||
| 
 | ||||
| 			// Triangle Drawing
 | ||||
| 			{ | ||||
| 				DqnV4 redTransparent = DqnV4_4f(1, 0, 0, 0.5f); | ||||
| 	// Triangle Drawing
 | ||||
| 	{ | ||||
| 		DqnV4 redTransparent = DqnV4_4f(1, 0, 0, 0.5f); | ||||
| 
 | ||||
| 				i32 boundsOffset = 100; | ||||
| 				DqnV3 t0[3]      = {DqnV3_3i(10, 70, 0), DqnV3_3i(50, 160, 0), DqnV3_3i(70, 80, 0)}; | ||||
| 				DqnV3 t1[3] = {DqnV3_3i(180, 50, 0), DqnV3_3i(150, 1, 0), DqnV3_3i(70, 180, 0)}; | ||||
| 				DqnV3 t2[3] = {DqnV3_3i(180, 150, 0), DqnV3_3i(120, 160, 0), DqnV3_3i(130, 180, 0)}; | ||||
| 				DqnV3 t3[3] = {DqnV3_3i(boundsOffset, boundsOffset, 0), | ||||
| 				               DqnV3_3i(bufferMidP.w, renderBuffer.height - boundsOffset, 0), | ||||
| 				               DqnV3_3i(renderBuffer.width - boundsOffset, boundsOffset, 0)}; | ||||
| 				DqnV3 t4[3] = {DqnV3_3i(100, 150, 0), DqnV3_3i(200, 150, 0), DqnV3_3i(200, 250, 0)}; | ||||
| 				DqnV3 t5[3] = {DqnV3_3i(300, 150, 0), DqnV3_3i(201, 150, 0), DqnV3_3i(200, 250, 0)}; | ||||
| 		i32 boundsOffset = 100; | ||||
| 		DqnV3 t0[3] = {DqnV3_3i(10, 70, 0), DqnV3_3i(50, 160, 0), DqnV3_3i(70, 80, 0)}; | ||||
| 		DqnV3 t1[3] = {DqnV3_3i(180, 50, 0), DqnV3_3i(150, 1, 0), DqnV3_3i(70, 180, 0)}; | ||||
| 		DqnV3 t2[3] = {DqnV3_3i(180, 150, 0), DqnV3_3i(120, 160, 0), DqnV3_3i(130, 180, 0)}; | ||||
| 		DqnV3 t3[3] = {DqnV3_3i(boundsOffset, boundsOffset, 0), | ||||
| 		               DqnV3_3i(bufferMidP.w, renderBuffer.height - boundsOffset, 0), | ||||
| 		               DqnV3_3i(renderBuffer.width - boundsOffset, boundsOffset, 0)}; | ||||
| 		DqnV3 t4[3] = {DqnV3_3i(100, 150, 0), DqnV3_3i(200, 150, 0), DqnV3_3i(200, 250, 0)}; | ||||
| 		DqnV3 t5[3] = {DqnV3_3i(300, 150, 0), DqnV3_3i(201, 150, 0), DqnV3_3i(200, 250, 0)}; | ||||
| 
 | ||||
| 				DTRRenderTransform rotatingXform = DTRRender_DefaultTriangleTransform(); | ||||
| 				rotatingXform.rotation           = rotation; | ||||
| 		if (1) | ||||
| 		{ | ||||
| 
 | ||||
| 				if (0) | ||||
| 				{ | ||||
| 					DTRDebug_BeginCycleCount( | ||||
| 					    "DTR_Update_RenderPrimitiveTriangles", | ||||
| 					    DTRDebugCycleCount_DTR_Update_RenderPrimitiveTriangles); | ||||
| 			DTRRenderTransform rotatingXform = DTRRender_DefaultTriangleTransform(); | ||||
| 			rotatingXform.rotation           = rotation * 0.25f; | ||||
| 
 | ||||
| 					DTRRender_Triangle(renderContext, t0[0], t0[1], t0[2], colorRed); | ||||
| 					DTRRender_Triangle(renderContext, t1[0], t1[1], t1[2], colorRed); | ||||
| 					DTRRender_Triangle(renderContext, t3[0], t3[1], t3[2], colorRed, rotatingXform); | ||||
| 					DTRRender_Triangle(renderContext, t2[0], t2[1], t2[2], colorRed); | ||||
| 					DTRRender_Triangle(renderContext, t4[0], t4[1], t4[2], colorRed); | ||||
| 					DTRRender_Triangle(renderContext, t5[0], t5[1], t5[2], colorRed); | ||||
| 					DTRDebug_EndCycleCount(DTRDebugCycleCount_DTR_Update_RenderPrimitiveTriangles); | ||||
| 				} | ||||
| 			DTRDebug_BeginCycleCount("DTR_Update_RenderPrimitiveTriangles", | ||||
| 			                         DTRDebugCycleCount_DTR_Update_RenderPrimitiveTriangles); | ||||
| 
 | ||||
| 				if (1) | ||||
| 				{ | ||||
| 					LOCAL_PERSIST bool runTinyRendererOnce = false; | ||||
| 					if (1 && runTinyRendererOnce) | ||||
| 					{ | ||||
| 						DTRDebug_RunTinyRenderer(); | ||||
| 						runTinyRendererOnce = false; | ||||
| 					} | ||||
| 
 | ||||
| 					DTRDebug_BeginCycleCount("DTR_Update_RenderModel", | ||||
| 					                         DTRDebugCycleCount_DTR_Update_RenderModel); | ||||
| 					////////////////////////////////////////////////////////////////////////
 | ||||
| 					// Draw Loaded Model
 | ||||
| 					////////////////////////////////////////////////////////////////////////
 | ||||
| 					const DqnV3 LIGHT     = DqnV3_Normalise(DqnV3_3f(1, -1, 1.0f)); | ||||
| 					const f32 MODEL_SCALE = 1; | ||||
| 					DTRMesh *const mesh   = &state->mesh; | ||||
| 					DqnV3 modelP          = DqnV3_3f(0, 0, 0); | ||||
| 
 | ||||
| 					LOCAL_PERSIST f32 modelRotation = 0; | ||||
| 					modelRotation += (input->deltaForFrame * 20.0f); | ||||
| 					DqnV3 axis = DqnV3_3f(0, 1, 0); | ||||
| 
 | ||||
| 					DTRRenderTransform transform = DTRRender_DefaultTransform(); | ||||
| 					transform.scale              = DqnV3_1f(MODEL_SCALE); | ||||
| 					transform.rotation           = modelRotation; | ||||
| 					transform.anchor             = axis; | ||||
| 
 | ||||
| 					DTRRenderLight lighting = {}; | ||||
| 					lighting.mode           = DTRRenderShadingMode_Gouraud; | ||||
| 					lighting.vector         = LIGHT; | ||||
| 					lighting.color          = DqnV4_4f(1, 1, 1, 1); | ||||
| 
 | ||||
| 					DTRRender_Mesh(renderContext, input->jobQueue, mesh, lighting, modelP, | ||||
| 					               transform); | ||||
| 					DTRDebug_EndCycleCount(DTRDebugCycleCount_DTR_Update_RenderModel); | ||||
| 				} | ||||
| 			} | ||||
| 
 | ||||
| 			// Rect drawing
 | ||||
| 			if (0) | ||||
| 			{ | ||||
| 				DTRRenderTransform transform = DTRRender_DefaultTransform(); | ||||
| 				transform.rotation           = rotation + 45; | ||||
| 
 | ||||
| 				DTRRender_Rectangle(renderContext, DqnV2_1f(300.0f), DqnV2_1f(300 + 100.0f), | ||||
| 				                    DqnV4_4f(0, 1.0f, 1.0f, 1.0f), transform); | ||||
| 			} | ||||
| 
 | ||||
| 			// Bitmap drawing
 | ||||
| 			if (0) | ||||
| 			{ | ||||
| 				DTRRenderTransform transform = DTRRender_DefaultTransform(); | ||||
| 				transform.scale              = DqnV3_1f(2.0f); | ||||
| 
 | ||||
| 				LOCAL_PERSIST DqnV2 bitmapP = DqnV2_2f(500, 250); | ||||
| 				bitmapP.x += 2.0f * sinf((f32)input->timeNowInS * 0.5f); | ||||
| 
 | ||||
| 				f32 cAngle = (f32)input->timeNowInS; | ||||
| 				DqnV4 color = | ||||
| 				    DqnV4_4f(0.5f + 0.5f * sinf(cAngle), 0.5f + 0.5f * sinf(2.9f * cAngle), | ||||
| 				             0.5f + 0.5f * cosf(10.0f * cAngle), 1.0f); | ||||
| 				DTRRender_Bitmap(renderContext, &state->bitmap, bitmapP, transform, color); | ||||
| 			} | ||||
| 
 | ||||
| #else | ||||
| // CompAssignment(renderBuffer, input, memory);
 | ||||
| #endif | ||||
| 			DTRDebug_EndCycleCount(DTRDebugCycleCount_DTR_Update); | ||||
| 			DTRDebug_Update(state, renderContext, input, memory); | ||||
| 			DTRRenderTransform scaleXform = DTRRender_DefaultTriangleTransform(); | ||||
| 			scaleXform.scale              = DqnV3_1f(5); | ||||
| 			DTRRender_Triangle(&renderBuffer, t0[0], t0[1], t0[2], colorRed); | ||||
| 			DTRRender_Triangle(&renderBuffer, t1[0], t1[1], t1[2], colorRed); | ||||
| 			DTRRender_Triangle(&renderBuffer, t3[0], t3[1], t3[2], colorRed, rotatingXform); | ||||
| 			DTRRender_Triangle(&renderBuffer, t2[0], t2[1], t2[2], colorRed); | ||||
| 			DTRRender_Triangle(&renderBuffer, t4[0], t4[1], t4[2], colorRed); | ||||
| 			DTRRender_Triangle(&renderBuffer, t5[0], t5[1], t5[2], colorRed); | ||||
| 			DTRDebug_EndCycleCount(DTRDebugCycleCount_DTR_Update_RenderPrimitiveTriangles); | ||||
| 		} | ||||
| 
 | ||||
| 		while (input->api.QueueTryExecuteNextJob(input->jobQueue) || | ||||
| 		       !input->api.QueueAllJobsComplete(input->jobQueue)) | ||||
| 			; | ||||
| 		if (0) | ||||
| 		{ | ||||
| 			LOCAL_PERSIST bool runTinyRendererOnce = false; | ||||
| 			if (1 && runTinyRendererOnce) | ||||
| 			{ | ||||
| 				DTRDebug_RunTinyRenderer(); | ||||
| 				runTinyRendererOnce = false; | ||||
| 			} | ||||
| 
 | ||||
| 			DTRDebug_BeginCycleCount("DTR_Update_RenderModel", DTRDebugCycleCount_DTR_Update_RenderModel); | ||||
| 			////////////////////////////////////////////////////////////////////////
 | ||||
| 			// Draw Loaded Model
 | ||||
| 			////////////////////////////////////////////////////////////////////////
 | ||||
| 			const DqnV3 LIGHT     = DqnV3_Normalise(DqnV3_3f(1, -1, 1.0f)); | ||||
| 			const f32 MODEL_SCALE = 1; | ||||
| 			DTRMesh *const mesh   = &state->mesh; | ||||
| 			DqnV3 modelP          = DqnV3_3f(0, 0, 0); | ||||
| 
 | ||||
| 			LOCAL_PERSIST f32 modelRotation = 0; | ||||
| 			modelRotation += (input->deltaForFrame * 80.0f); | ||||
| 			DqnV3 axis = DqnV3_3f(0, 1, 0); | ||||
| 
 | ||||
| 			DTRRenderTransform transform = DTRRender_DefaultTransform(); | ||||
| 			transform.scale              = DqnV3_1f(MODEL_SCALE); | ||||
| 			transform.rotation           = modelRotation; | ||||
| 			transform.anchor             = axis; | ||||
| 
 | ||||
| 			DTRRenderLight lighting      = {}; | ||||
| 			lighting.mode                = DTRRenderShadingMode_Gouraud; | ||||
| 			lighting.vector              = LIGHT; | ||||
| 			lighting.color               = DqnV4_4f(1, 1, 1, 1); | ||||
| 
 | ||||
| 			DTRRender_Mesh(&renderBuffer, mesh, lighting, modelP, transform); | ||||
| 			DTRDebug_EndCycleCount(DTRDebugCycleCount_DTR_Update_RenderModel); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	// Rect drawing
 | ||||
| 	if (0) | ||||
| 	{ | ||||
| 		DTRRenderTransform transform = DTRRender_DefaultTransform(); | ||||
| 		transform.rotation           = rotation + 45; | ||||
| 
 | ||||
| 		DTRRender_Rectangle(&renderBuffer, DqnV2_1f(300.0f), DqnV2_1f(300 + 100.0f), | ||||
| 		                    DqnV4_4f(0, 1.0f, 1.0f, 1.0f), transform); | ||||
| 	} | ||||
| 
 | ||||
| 	// Bitmap drawing
 | ||||
| 	if (0) | ||||
| 	{ | ||||
| 		DTRRenderTransform transform = DTRRender_DefaultTransform(); | ||||
| 		transform.scale              = DqnV3_1f(2.0f); | ||||
| 
 | ||||
| 		LOCAL_PERSIST DqnV2 bitmapP = DqnV2_2f(500, 250); | ||||
| 		bitmapP.x += 2.0f * sinf((f32)input->timeNowInS * 0.5f); | ||||
| 
 | ||||
| 		f32 cAngle  = (f32)input->timeNowInS; | ||||
| 		DqnV4 color = DqnV4_4f(0.5f + 0.5f * sinf(cAngle), 0.5f + 0.5f * sinf(2.9f * cAngle), | ||||
| 		                       0.5f + 0.5f * cosf(10.0f * cAngle), 1.0f); | ||||
| 		DTRRender_Bitmap(&renderBuffer, &state->bitmap, bitmapP, transform, color); | ||||
| 	} | ||||
| 
 | ||||
| #else | ||||
| 	// CompAssignment(renderBuffer, input, memory);
 | ||||
| #endif | ||||
| 	DTRDebug_EndCycleCount(DTRDebugCycleCount_DTR_Update); | ||||
| 	DTRDebug_Update(state, &renderBuffer, input, memory); | ||||
| 	DqnMemStack_EndTempRegion(tempStackMemRegion); | ||||
| 	////////////////////////////////////////////////////////////////////////////
 | ||||
| 	// End Update
 | ||||
| 	////////////////////////////////////////////////////////////////////////////
 | ||||
| 	if (DTR_DEBUG) | ||||
| 	{ | ||||
| 		DQN_ASSERT(input->api.QueueAllJobsComplete(input->jobQueue)); | ||||
| 		for (i32 i = 0; i < DQN_ARRAY_COUNT(memory->stacks); i++) | ||||
| 		{ | ||||
| 			if (&memory->stacks[i] == &memory->tempStack) continue; | ||||
| 			DQN_ASSERT(memory->stacks[i].tempRegionCount == 0); | ||||
| 		} | ||||
| 		DqnMemStack_ClearCurrBlock(&memory->tempStack, true); | ||||
| 	} | ||||
| 	for (i32 i = 0; i < DQN_ARRAY_COUNT(memory->stacks); i++) | ||||
| 		DQN_ASSERT(memory->stacks[i].tempStackCount == 0); | ||||
| } | ||||
|  | ||||
| @ -13,8 +13,6 @@ typedef struct DTRState | ||||
| 	DTRFont   font; | ||||
| 	DTRBitmap bitmap; | ||||
| 	DTRMesh   mesh; | ||||
| 
 | ||||
| 	struct PlatformLock *renderLock; | ||||
| } DTRState; | ||||
| 
 | ||||
| extern PlatformFlags globalDTRPlatformFlags; | ||||
|  | ||||
| @ -196,26 +196,16 @@ bool DTRAsset_LoadWavefrontObj(const PlatformAPI api, DqnMemStack *const memStac | ||||
| 	if (!api.FileOpen(path, &file, PlatformFilePermissionFlag_Read, PlatformFileAction_OpenOnly)) | ||||
| 		return false; // TODO(doyle): Logging
 | ||||
| 
 | ||||
| 	WavefModel dummy_ = {}; | ||||
| 	WavefModel *obj   = &dummy_; | ||||
| 	bool result                    = false; | ||||
| 	DqnTempMemStack tmpAssetRegion = DqnMemStack_BeginTempRegion(memStack); | ||||
| 	u8 *rawBytes                   = (u8 *)DqnMemStack_Push(memStack, file.size); | ||||
| 	size_t bytesRead               = api.FileRead(&file, rawBytes, file.size); | ||||
| 	size_t fileSize                = file.size; | ||||
| 
 | ||||
| 	DqnMemAPI memAPI   = {}; | ||||
| 	memAPI.callback    = DumbDynamicArrayMemAPICallback; | ||||
| 	memAPI.userContext = memStack; | ||||
| 
 | ||||
| 	bool result = false; | ||||
| 	DqnMemStackTempRegion tmpAssetRegion; | ||||
| 	if (!DqnMemStackTempRegion_Begin(&tmpAssetRegion, memStack)) | ||||
| 	{ | ||||
| 		// TODO(doyle): Logging
 | ||||
| 		DQN_ASSERT(DQN_INVALID_CODE_PATH); | ||||
| 		goto cleanup; | ||||
| 	} | ||||
| 
 | ||||
| 	u8 *rawBytes                         = (u8 *)DqnMemStack_Push(memStack, file.size); | ||||
| 	size_t bytesRead                     = api.FileRead(&file, rawBytes, file.size); | ||||
| 	size_t fileSize                      = file.size; | ||||
| 
 | ||||
| 	enum WavefVertexType { | ||||
| 		WavefVertexType_Invalid, | ||||
| 		WavefVertexType_Geometric, | ||||
| @ -240,6 +230,9 @@ bool DTRAsset_LoadWavefrontObj(const PlatformAPI api, DqnMemStack *const memStac | ||||
| 	// to a new memstack block such that all the data is compacted together in
 | ||||
| 	// memory for locality. Then just throw away the intermediate
 | ||||
| 	// representation.
 | ||||
| 	WavefModel dummy_ = {}; | ||||
| 	WavefModel *obj   = &dummy_; | ||||
| 
 | ||||
| 	if (bytesRead != file.size)       goto cleanup; | ||||
| 	if (!WavefModelInit(obj, memAPI)) goto cleanup; | ||||
| 
 | ||||
| @ -593,7 +586,7 @@ bool DTRAsset_LoadWavefrontObj(const PlatformAPI api, DqnMemStack *const memStac | ||||
| 		DQN_ASSERT(DQN_INVALID_CODE_PATH); | ||||
| 	} | ||||
| 
 | ||||
| 	DqnMemStackTempRegion_End(tmpAssetRegion); | ||||
| 	DqnMemStack_EndTempRegion(tmpAssetRegion); | ||||
| 	if (modelBlock) | ||||
| 	{ | ||||
| 		result = true; | ||||
| @ -606,7 +599,7 @@ bool DTRAsset_LoadWavefrontObj(const PlatformAPI api, DqnMemStack *const memStac | ||||
| 
 | ||||
| cleanup: | ||||
| 	api.FileClose(&file); | ||||
| 	if(!result) DqnMemStackTempRegion_End(tmpAssetRegion); | ||||
| 	if(!result) DqnMemStack_EndTempRegion(tmpAssetRegion); | ||||
| 
 | ||||
| 	return result; | ||||
| } | ||||
| @ -630,22 +623,14 @@ bool DTRAsset_LoadFontToBitmap(const PlatformAPI api, DqnMemStack *const memStac | ||||
| 	if (!api.FileOpen(path, &file, PlatformFilePermissionFlag_Read, PlatformFileAction_OpenOnly)) | ||||
| 		return false; // TODO(doyle): Logging
 | ||||
| 
 | ||||
| 	stbtt_fontinfo fontInfo            = {}; | ||||
| 	stbtt_pack_context fontPackContext = {}; | ||||
| 
 | ||||
| 	bool result       = false; | ||||
| 	bool regionValid; | ||||
| 	auto tmpMemRegion = DqnMemStackTempRegionGuard(tmpMemStack, ®ionValid); | ||||
| 	if (!regionValid) | ||||
| 	{ | ||||
| 		// TODO(doyle): Logging
 | ||||
| 		DQN_ASSERT(DQN_INVALID_CODE_PATH); | ||||
| 		goto cleanup; | ||||
| 	} | ||||
| 
 | ||||
| 	bool result = false; | ||||
| 	DqnTempMemStack tmpMemRegion = DqnMemStack_BeginTempRegion(tmpMemStack); | ||||
| 	u8 *rawBytes                 = (u8 *)DqnMemStack_Push(tmpMemStack, file.size); | ||||
| 	size_t bytesRead             = api.FileRead(&file, rawBytes, file.size); | ||||
| 
 | ||||
| 	stbtt_fontinfo fontInfo            = {}; | ||||
| 	stbtt_pack_context fontPackContext = {}; | ||||
| 
 | ||||
| 	if (bytesRead != file.size || stbtt_InitFont(&fontInfo, rawBytes, 0) == 0) | ||||
| 	{ | ||||
| 		DQN_ASSERT(DQN_INVALID_CODE_PATH); | ||||
| @ -707,6 +692,7 @@ bool DTRAsset_LoadFontToBitmap(const PlatformAPI api, DqnMemStack *const memStac | ||||
| 	*font = loadedFont; | ||||
| 
 | ||||
| cleanup: | ||||
| 	DqnMemStack_EndTempRegion(tmpMemRegion); | ||||
| 	api.FileClose(&file); | ||||
| 
 | ||||
| 	return result; | ||||
| @ -767,9 +753,9 @@ bool DTRAsset_LoadBitmap(const PlatformAPI api, DqnMemStack *const memStack, | ||||
| 	if (!api.FileOpen(path, &file, PlatformFilePermissionFlag_Read, PlatformFileAction_OpenOnly)) | ||||
| 		return result; | ||||
| 
 | ||||
| 	DqnMemStackTempRegionGuard tmpMemRegion = tempStack->TempRegionGuard(); | ||||
| 	u8 *const rawData = (u8 *)DqnMemStack_Push(tempStack, file.size); | ||||
| 	size_t bytesRead  = api.FileRead(&file, rawData, file.size); | ||||
| 	DqnTempMemStack tmpMemRegion = DqnMemStack_BeginTempRegion(tempStack); | ||||
| 	u8 *const rawData            = (u8 *)DqnMemStack_Push     (tempStack, file.size); | ||||
| 	size_t bytesRead             = api.FileRead               (&file, rawData, file.size); | ||||
| 
 | ||||
| 	if (bytesRead != file.size) goto cleanup; | ||||
| 
 | ||||
| @ -844,6 +830,7 @@ bool DTRAsset_LoadBitmap(const PlatformAPI api, DqnMemStack *const memStack, | ||||
| 
 | ||||
| cleanup: | ||||
| 	globalSTBImageAllocator = NULL; | ||||
| 	DqnMemStack_EndTempRegion(tmpMemRegion); | ||||
| 	api.FileClose(&file); | ||||
| 
 | ||||
| 	return result; | ||||
|  | ||||
| @ -77,32 +77,31 @@ void DTRDebug_DumpZBuffer(DTRRenderBuffer *const renderBuffer, DqnMemStack *cons | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		bool regionValid; | ||||
| 		auto memRegion = DqnMemStackTempRegionGuard(tempStack, ®ionValid); | ||||
| 		if (regionValid) | ||||
| 		DqnTempMemStack tmpMemRegion = DqnMemStack_BeginTempRegion(tempStack); | ||||
| 
 | ||||
| 		size_t bufSize = DQN_MEGABYTE(16); | ||||
| 		char *bufString = (char *)DqnMemStack_Push(tempStack, bufSize); | ||||
| 		char *bufPtr    = bufString; | ||||
| 		for (i32 i = 0; i < renderBuffer->width * renderBuffer->height; i++) | ||||
| 		{ | ||||
| 			size_t bufSize  = DQN_MEGABYTE(16); | ||||
| 			char *bufString = (char *)DqnMemStack_Push(tempStack, bufSize); | ||||
| 			char *bufPtr    = bufString; | ||||
| 			for (i32 i = 0; i < renderBuffer->width * renderBuffer->height; i++) | ||||
| 
 | ||||
| 			f32 zValue = renderBuffer->zBuffer[i]; | ||||
| 			if (zValue == DQN_F32_MIN) continue; | ||||
| 			i32 chWritten = Dqn_sprintf(bufPtr, "index %06d: %05.5f\n", i, zValue); | ||||
| 			if ((bufPtr + chWritten) > (bufString + bufSize)) | ||||
| 			{ | ||||
| 
 | ||||
| 				f32 zValue = renderBuffer->zBuffer[i]; | ||||
| 				if (zValue == DQN_F32_MIN) continue; | ||||
| 				i32 chWritten = Dqn_sprintf(bufPtr, "index %06d: %05.5f\n", i, zValue); | ||||
| 				if ((bufPtr + chWritten) > (bufString + bufSize)) | ||||
| 				{ | ||||
| 					size_t bufPtrAddr    = (size_t)(bufPtr + chWritten); | ||||
| 					size_t bufStringAddr = (size_t)(bufString + bufSize); | ||||
| 					DQN_ASSERT(DQN_INVALID_CODE_PATH); | ||||
| 				} | ||||
| 				bufPtr += chWritten; | ||||
| 				size_t bufPtrAddr    = (size_t)(bufPtr + chWritten); | ||||
| 				size_t bufStringAddr = (size_t)(bufString + bufSize); | ||||
| 				DQN_ASSERT(DQN_INVALID_CODE_PATH); | ||||
| 			} | ||||
| 
 | ||||
| 			size_t writeSize    = (size_t)bufPtr - (size_t)bufString; | ||||
| 			size_t bytesWritten = api->FileWrite(&file, (u8 *)bufString, writeSize); | ||||
| 			api->FileClose(&file); | ||||
| 			bufPtr += chWritten; | ||||
| 		} | ||||
| 
 | ||||
| 		size_t writeSize    = (size_t)bufPtr - (size_t)bufString; | ||||
| 		size_t bytesWritten = api->FileWrite(&file, (u8 *)bufString, writeSize); | ||||
| 		api->FileClose(&file); | ||||
| 
 | ||||
| 		DqnMemStack_EndTempRegion(tmpMemRegion); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| @ -119,7 +118,7 @@ void DTRDebug_PushText(const char *const formatStr, ...) | ||||
| 	if (DTR_DEBUG) | ||||
| 	{ | ||||
| 		DTRDebug *const debug = &globalDebug; | ||||
| 		if (!debug->renderContext->renderBuffer) return; | ||||
| 		if (!debug->renderBuffer) return; | ||||
| 
 | ||||
| 		char str[1024] = {}; | ||||
| 
 | ||||
| @ -131,7 +130,7 @@ void DTRDebug_PushText(const char *const formatStr, ...) | ||||
| 		} | ||||
| 		va_end(argList); | ||||
| 
 | ||||
| 		DTRRender_Text(*debug->renderContext, *debug->font, debug->displayP, str, | ||||
| 		DTRRender_Text(debug->renderBuffer, *debug->font, debug->displayP, str, | ||||
| 		               debug->displayColor); | ||||
| 		debug->displayP.y += globalDebug.displayYOffset; | ||||
| 	} | ||||
| @ -200,25 +199,25 @@ FILE_SCOPE void PushMemStackText(const char *const name, const DqnMemStack *cons | ||||
| 		Dqn_sprintf(str, "%s: %d block(s): %_$lld/%_$lld: wasted: %_$lld", name, numBlocks, | ||||
| 		            totalUsed, totalSize, totalWastedKb); | ||||
| 
 | ||||
| 		DTRRender_Text(*globalDebug.renderContext, *globalDebug.font, | ||||
| 		DTRRender_Text(globalDebug.renderBuffer, *globalDebug.font, | ||||
| 		               globalDebug.displayP, str, globalDebug.displayColor); | ||||
| 		globalDebug.displayP.y += globalDebug.displayYOffset; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| void DTRDebug_Update(DTRState *const state, | ||||
|                      DTRRenderContext renderContext, | ||||
|                      DTRRenderBuffer *const renderBuffer, | ||||
|                      PlatformInput *const input, PlatformMemory *const memory) | ||||
| { | ||||
| 	if (DTR_DEBUG) | ||||
| 	{ | ||||
| 		DTRDebug *const debug = &globalDebug; | ||||
| 
 | ||||
| 		debug->renderContext = &renderContext; | ||||
| 		debug->input         = input; | ||||
| 		debug->font          = &state->font; | ||||
| 		debug->displayColor  = DqnV4_4f(1, 1, 1, 1); | ||||
| 		if (debug->font->bitmap && debug->renderContext) | ||||
| 		debug->renderBuffer = renderBuffer; | ||||
| 		debug->input        = input; | ||||
| 		debug->font         = &state->font; | ||||
| 		debug->displayColor = DqnV4_4f(1, 1, 1, 0.85f); | ||||
| 		if (debug->font->bitmap && debug->renderBuffer) | ||||
| 		{ | ||||
| 			debug->displayYOffset = -(i32)(state->font.sizeInPt + 0.5f); | ||||
| 			DQN_ASSERT(globalDebug.displayYOffset < 0); | ||||
| @ -271,7 +270,7 @@ void DTRDebug_Update(DTRState *const state, | ||||
| 		// End Debug Update
 | ||||
| 		////////////////////////////////////////////////////////////////////////
 | ||||
| 		debug->displayP = | ||||
| 		    DqnV2_2i(0, debug->renderContext->renderBuffer->height + globalDebug.displayYOffset); | ||||
| 			DqnV2_2i(0, debug->renderBuffer->height + globalDebug.displayYOffset); | ||||
| 
 | ||||
| 		for (i32 i = 0; i < DQN_ARRAY_COUNT(debug->counter); i++) | ||||
| 			debug->counter[i] = 0; | ||||
|  | ||||
| @ -88,10 +88,10 @@ typedef struct DTRDebugCycles | ||||
| 
 | ||||
| typedef struct DTRDebug | ||||
| { | ||||
| 	struct DTRFont          *font; | ||||
| 	struct DTRRenderContext *renderContext; | ||||
| 	struct PlatformInput    *input; | ||||
| 	DqnMemStack              memStack; | ||||
| 	struct DTRFont         *font; | ||||
| 	struct DTRRenderBuffer *renderBuffer; | ||||
| 	struct PlatformInput   *input; | ||||
| 	DqnMemStack             memStack; | ||||
| 
 | ||||
| 	DqnV4 displayColor; | ||||
| 	DqnV2 displayP; | ||||
|  | ||||
| @ -4,11 +4,6 @@ | ||||
| #include "dqn.h" | ||||
| #include <intrin.h> | ||||
| 
 | ||||
| typedef void PlatformAPI_DieGracefully(); | ||||
| 
 | ||||
| ////////////////////////////////////////////////////////////////////////////////
 | ||||
| // Platform File I/O
 | ||||
| ////////////////////////////////////////////////////////////////////////////////
 | ||||
| enum PlatformFilePermissionFlag | ||||
| { | ||||
| 	PlatformFilePermissionFlag_Read  = (1 << 0), | ||||
| @ -29,71 +24,20 @@ typedef struct PlatformFile | ||||
| 	u32     permissionFlags; | ||||
| } PlatformFile; | ||||
| 
 | ||||
| // File I/O API
 | ||||
| typedef bool   PlatformAPI_FileOpen (const char *const path, PlatformFile *const file, const u32 permissionFlags, const enum PlatformFileAction actionFlags); | ||||
| typedef size_t PlatformAPI_FileRead (PlatformFile *const file, u8 *const buf, const size_t bytesToRead);     // Return bytes read
 | ||||
| typedef size_t PlatformAPI_FileRead (PlatformFile *const file, u8 *const buf, const size_t bytesToRead); // Return bytes read
 | ||||
| typedef size_t PlatformAPI_FileWrite(PlatformFile *const file, u8 *const buf, const size_t numBytesToWrite); // Return bytes read
 | ||||
| typedef void   PlatformAPI_FileClose(PlatformFile *const file); | ||||
| typedef void   PlatformAPI_Print    (const char *const string); | ||||
| 
 | ||||
| ////////////////////////////////////////////////////////////////////////////////
 | ||||
| // Platform Multithreading
 | ||||
| ////////////////////////////////////////////////////////////////////////////////
 | ||||
| // PlatformJobQueue must be implemented in platform code. It simply needs to
 | ||||
| // fullfill the API and be able to accept PlatformJob structs and execute them.
 | ||||
| typedef struct PlatformJobQueue PlatformJobQueue; | ||||
| 
 | ||||
| typedef void   PlatformJob_Callback(PlatformJobQueue *const queue, void *const userData); | ||||
| typedef struct PlatformJob | ||||
| { | ||||
| 	PlatformJob_Callback *callback; | ||||
| 	void                 *userData; | ||||
| } PlatformJob; | ||||
| 
 | ||||
| // Multithreading API
 | ||||
| typedef bool PlatformAPI_QueueAddJob           (PlatformJobQueue *const queue, const PlatformJob job); | ||||
| typedef bool PlatformAPI_QueueTryExecuteNextJob(PlatformJobQueue *const queue); | ||||
| typedef bool PlatformAPI_QueueAllJobsComplete  (PlatformJobQueue *const queue); | ||||
| 
 | ||||
| typedef u32  PlatformAPI_AtomicCompareSwap(u32 volatile *dest, u32 swapVal, u32 compareVal); | ||||
| 
 | ||||
| ////////////////////////////////////////////////////////////////////////////////
 | ||||
| // Platform Locks
 | ||||
| ////////////////////////////////////////////////////////////////////////////////
 | ||||
| typedef struct PlatformLock PlatformLock; | ||||
| 
 | ||||
| typedef PlatformLock *PlatformAPI_LockInit   (DqnMemStack *const stack); | ||||
| typedef void          PlatformAPI_LockAcquire(PlatformLock *const lock); | ||||
| typedef void          PlatformAPI_LockRelease(PlatformLock *const lock); | ||||
| typedef void          PlatformAPI_LockDelete (PlatformLock *const lock); | ||||
| 
 | ||||
| ////////////////////////////////////////////////////////////////////////////////
 | ||||
| // Platform API for Game to Use
 | ||||
| ////////////////////////////////////////////////////////////////////////////////
 | ||||
| typedef struct PlatformAPI | ||||
| { | ||||
| 	PlatformAPI_FileOpen    *FileOpen; | ||||
| 	PlatformAPI_FileRead    *FileRead; | ||||
| 	PlatformAPI_FileWrite   *FileWrite; | ||||
| 	PlatformAPI_FileClose   *FileClose; | ||||
| 	PlatformAPI_Print       *Print; | ||||
| 
 | ||||
| 	PlatformAPI_QueueAddJob            *QueueAddJob; | ||||
| 	PlatformAPI_QueueTryExecuteNextJob *QueueTryExecuteNextJob; | ||||
| 	PlatformAPI_QueueAllJobsComplete   *QueueAllJobsComplete; | ||||
| 	PlatformAPI_AtomicCompareSwap      *AtomicCompareSwap; | ||||
| 
 | ||||
| 	PlatformAPI_LockInit    *LockInit; | ||||
| 	PlatformAPI_LockAcquire *LockAcquire; | ||||
| 	PlatformAPI_LockRelease *LockRelease; | ||||
| 	PlatformAPI_LockDelete  *LockDelete; | ||||
| 
 | ||||
| 	PlatformAPI_DieGracefully *DieGracefully; | ||||
| 	PlatformAPI_FileOpen  *FileOpen; | ||||
| 	PlatformAPI_FileRead  *FileRead; | ||||
| 	PlatformAPI_FileWrite *FileWrite; | ||||
| 	PlatformAPI_FileClose *FileClose; | ||||
| 	PlatformAPI_Print     *Print; | ||||
| } PlatformAPI; | ||||
| 
 | ||||
| ////////////////////////////////////////////////////////////////////////////////
 | ||||
| // Platform Input
 | ||||
| ////////////////////////////////////////////////////////////////////////////////
 | ||||
| enum Key | ||||
| { | ||||
| 	key_up, | ||||
| @ -152,9 +96,8 @@ typedef struct PlatformInput | ||||
| 	f64           timeNowInS; | ||||
| 	PlatformFlags flags; | ||||
| 
 | ||||
| 	PlatformAPI       api; | ||||
| 	PlatformMouse     mouse; | ||||
| 	PlatformJobQueue *jobQueue; | ||||
| 	PlatformAPI   api; | ||||
| 	PlatformMouse mouse; | ||||
| 	union { | ||||
| 		KeyState key[key_count]; | ||||
| 		struct | ||||
| @ -188,9 +131,6 @@ typedef struct PlatformInput | ||||
| 	}; | ||||
| } PlatformInput; | ||||
| 
 | ||||
| ////////////////////////////////////////////////////////////////////////////////
 | ||||
| // Platform Memory
 | ||||
| ////////////////////////////////////////////////////////////////////////////////
 | ||||
| typedef struct PlatformMemory | ||||
| { | ||||
| 	union { | ||||
| @ -206,9 +146,6 @@ typedef struct PlatformMemory | ||||
| 	void *context; | ||||
| } PlatformMemory; | ||||
| 
 | ||||
| ////////////////////////////////////////////////////////////////////////////////
 | ||||
| // Platform Frame Buffer
 | ||||
| ////////////////////////////////////////////////////////////////////////////////
 | ||||
| typedef struct PlatformRenderBuffer | ||||
| { | ||||
| 	i32   width; | ||||
|  | ||||
| @ -121,10 +121,9 @@ inline DqnV4 DTRRender_PreMultiplyAlphaSRGB1WithLinearConversion(DqnV4 color) | ||||
| } | ||||
| 
 | ||||
| // IMPORTANT(doyle): Color is expected to be premultiplied already
 | ||||
| FILE_SCOPE inline void SetPixel(DTRRenderContext context, const i32 x, const i32 y, | ||||
| FILE_SCOPE inline void SetPixel(DTRRenderBuffer *const renderBuffer, const i32 x, const i32 y, | ||||
|                                 DqnV4 color, const enum ColorSpace colorSpace = ColorSpace_SRGB) | ||||
| { | ||||
| 	DTRRenderBuffer *renderBuffer = context.renderBuffer; | ||||
| 	if (!renderBuffer) return; | ||||
| 	if (x < 0 || x > (renderBuffer->width - 1)) return; | ||||
| 	if (y < 0 || y > (renderBuffer->height - 1)) return; | ||||
| @ -190,18 +189,15 @@ FILE_SCOPE inline void SetPixel(DTRRenderContext context, const i32 x, const i32 | ||||
| 	DTRDebug_CounterIncrement(DTRDebugCounter_SetPixels); | ||||
| } | ||||
| 
 | ||||
| void DTRRender_Text(DTRRenderContext context, | ||||
| void DTRRender_Text(DTRRenderBuffer *const renderBuffer, | ||||
|                     const DTRFont font, DqnV2 pos, const char *const text, | ||||
|                     DqnV4 color, i32 len) | ||||
| { | ||||
| 	if (!text) return; | ||||
| 
 | ||||
| 	DTRRenderBuffer *renderBuffer = context.renderBuffer; | ||||
| 	if (!font.bitmap || !font.atlas || !renderBuffer) return; | ||||
| 	DTR_DEBUG_EP_TIMED_FUNCTION(); | ||||
| 
 | ||||
| 
 | ||||
| 	if (len == -1) len = DqnStr_Len(text); | ||||
| 	if (len == -1) len = Dqn_strlen(text); | ||||
| 
 | ||||
| 	i32 index = 0; | ||||
| 	color = DTRRender_SRGB1ToLinearSpaceV4(color); | ||||
| @ -266,7 +262,7 @@ void DTRRender_Text(DTRRenderContext context, | ||||
| 
 | ||||
| 				i32 actualX = (i32)(screenRect.min.x + x); | ||||
| 				i32 actualY = (i32)(screenRect.min.y + y - fontHeightOffset); | ||||
| 				SetPixel(context, actualX, actualY, resultColor, ColorSpace_Linear); | ||||
| 				SetPixel(renderBuffer, actualX, actualY, resultColor, ColorSpace_Linear); | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| @ -291,10 +287,9 @@ FILE_SCOPE void TransformPoints(const DqnV2 origin, DqnV2 *const pList, | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| void DTRRender_Line(DTRRenderContext context, DqnV2i a, | ||||
| void DTRRender_Line(DTRRenderBuffer *const renderBuffer, DqnV2i a, | ||||
|                     DqnV2i b, DqnV4 color) | ||||
| { | ||||
| 	DTRRenderBuffer *renderBuffer = context.renderBuffer; | ||||
| 	if (!renderBuffer) return; | ||||
| 	DTR_DEBUG_EP_TIMED_FUNCTION(); | ||||
| 
 | ||||
| @ -344,7 +339,7 @@ void DTRRender_Line(DTRRenderContext context, DqnV2i a, | ||||
| 	for (i32 iterateX = 0; iterateX < numIterations; iterateX++) | ||||
| 	{ | ||||
| 		newX = a.x + iterateX; | ||||
| 		SetPixel(context, *plotX, *plotY, color, ColorSpace_Linear); | ||||
| 		SetPixel(renderBuffer, *plotX, *plotY, color, ColorSpace_Linear); | ||||
| 
 | ||||
| 		distAccumulator += distFromPixelOrigin; | ||||
|    		if (distAccumulator > run) | ||||
| @ -412,13 +407,10 @@ FILE_SCOPE DqnRect GetBoundingBox(const DqnV2 *const pList, const i32 numP) | ||||
| 	return result; | ||||
| } | ||||
| 
 | ||||
| void DTRRender_Rectangle(DTRRenderContext context, DqnV2 min, DqnV2 max, | ||||
| void DTRRender_Rectangle(DTRRenderBuffer *const renderBuffer, DqnV2 min, DqnV2 max, | ||||
|                          DqnV4 color, const DTRRenderTransform transform) | ||||
| { | ||||
| 	DTR_DEBUG_EP_TIMED_FUNCTION(); | ||||
| 	DTRRenderBuffer *renderBuffer = context.renderBuffer; | ||||
| 	if (!renderBuffer) return; | ||||
| 
 | ||||
| 	////////////////////////////////////////////////////////////////////////////
 | ||||
| 	// Transform vertexes
 | ||||
| 	////////////////////////////////////////////////////////////////////////////
 | ||||
| @ -469,7 +461,7 @@ void DTRRender_Rectangle(DTRRenderContext context, DqnV2 min, DqnV2 max, | ||||
| 					} | ||||
| 				} | ||||
| 
 | ||||
| 				if (pIsInside) SetPixel(context, bufferX, bufferY, color, ColorSpace_Linear); | ||||
| 				if (pIsInside) SetPixel(renderBuffer, bufferX, bufferY, color, ColorSpace_Linear); | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| @ -481,7 +473,7 @@ void DTRRender_Rectangle(DTRRenderContext context, DqnV2 min, DqnV2 max, | ||||
| 			for (i32 x = 0; x < clippedSize.w; x++) | ||||
| 			{ | ||||
| 				i32 bufferX = (i32)clippedRect.min.x + x; | ||||
| 				SetPixel(context, bufferX, bufferY, color, ColorSpace_Linear); | ||||
| 				SetPixel(renderBuffer, bufferX, bufferY, color, ColorSpace_Linear); | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| @ -493,20 +485,20 @@ void DTRRender_Rectangle(DTRRenderContext context, DqnV2 min, DqnV2 max, | ||||
| 	{ | ||||
| 		// Draw Bounding box
 | ||||
| 		{ | ||||
| 			DTRRender_Line(context, DqnV2i_2f(min.x, min.y), DqnV2i_2f(min.x, max.y), color); | ||||
| 			DTRRender_Line(context, DqnV2i_2f(min.x, max.y), DqnV2i_2f(max.x, max.y), color); | ||||
| 			DTRRender_Line(context, DqnV2i_2f(max.x, max.y), DqnV2i_2f(max.x, min.y), color); | ||||
| 			DTRRender_Line(context, DqnV2i_2f(max.x, min.y), DqnV2i_2f(min.x, min.y), color); | ||||
| 			DTRRender_Line(renderBuffer, DqnV2i_2f(min.x, min.y), DqnV2i_2f(min.x, max.y), color); | ||||
| 			DTRRender_Line(renderBuffer, DqnV2i_2f(min.x, max.y), DqnV2i_2f(max.x, max.y), color); | ||||
| 			DTRRender_Line(renderBuffer, DqnV2i_2f(max.x, max.y), DqnV2i_2f(max.x, min.y), color); | ||||
| 			DTRRender_Line(renderBuffer, DqnV2i_2f(max.x, min.y), DqnV2i_2f(min.x, min.y), color); | ||||
| 		} | ||||
| 
 | ||||
| 		// Draw rotating outline
 | ||||
| 		if (transform.rotation > 0) | ||||
| 		{ | ||||
| 			DqnV4 green = DqnV4_4f(0, 1, 0, 1); | ||||
| 			DTRRender_Line(context, DqnV2i_V2(pList[0]), DqnV2i_V2(pList[1]), green); | ||||
| 			DTRRender_Line(context, DqnV2i_V2(pList[1]), DqnV2i_V2(pList[2]), green); | ||||
| 			DTRRender_Line(context, DqnV2i_V2(pList[2]), DqnV2i_V2(pList[3]), green); | ||||
| 			DTRRender_Line(context, DqnV2i_V2(pList[3]), DqnV2i_V2(pList[0]), green); | ||||
| 			DTRRender_Line(renderBuffer, DqnV2i_V2(pList[0]), DqnV2i_V2(pList[1]), green); | ||||
| 			DTRRender_Line(renderBuffer, DqnV2i_V2(pList[1]), DqnV2i_V2(pList[2]), green); | ||||
| 			DTRRender_Line(renderBuffer, DqnV2i_V2(pList[2]), DqnV2i_V2(pList[3]), green); | ||||
| 			DTRRender_Line(renderBuffer, DqnV2i_V2(pList[3]), DqnV2i_V2(pList[0]), green); | ||||
| 		} | ||||
| 
 | ||||
| 	} | ||||
| @ -617,12 +609,10 @@ FILE_SCOPE inline DqnV2 Get2DOriginFromTransformAnchor(const DqnV2 p1, const Dqn | ||||
| } | ||||
| 
 | ||||
| // color: _mm_set_ps(a, b, g, r) ie. 0=r, 1=g, 2=b, 3=a
 | ||||
| FILE_SCOPE inline void SIMDSetPixel(DTRRenderContext context, const i32 x, const i32 y, | ||||
| FILE_SCOPE inline void SIMDSetPixel(DTRRenderBuffer *const renderBuffer, const i32 x, const i32 y, | ||||
|                                      __m128 color, | ||||
|                                      const enum ColorSpace colorSpace = ColorSpace_SRGB) | ||||
| { | ||||
| 
 | ||||
| 	DTRRenderBuffer *renderBuffer = context.renderBuffer; | ||||
| 	if (!renderBuffer) return; | ||||
| 	if (x < 0 || x > (renderBuffer->width - 1)) return; | ||||
| 	if (y < 0 || y > (renderBuffer->height - 1)) return; | ||||
| @ -630,22 +620,22 @@ FILE_SCOPE inline void SIMDSetPixel(DTRRenderContext context, const i32 x, const | ||||
| 	DTR_DEBUG_EP_TIMED_FUNCTION(); | ||||
| 	DebugSIMDAssertColorInRange(color, 0.0f, 1.0f); | ||||
| 
 | ||||
| 	u32 *const bitmapPtr = (u32 *)renderBuffer->memory; | ||||
| 	const u32 pitchInU32 = (renderBuffer->width * renderBuffer->bytesPerPixel) / 4; | ||||
| 
 | ||||
| 	// If some alpha is involved, we need to apply gamma correction, but if the
 | ||||
| 	// new pixel is totally opaque or invisible then we're just flat out
 | ||||
| 	// overwriting/keeping the state of the pixel so we can save cycles by skipping.
 | ||||
| 	f32 alpha = ((f32 *)&color)[3]; | ||||
| 	bool needGammaFix = | ||||
| 	    (alpha > 0.0f || alpha < (1.0f + COLOR_EPSILON)) && (colorSpace == ColorSpace_SRGB); | ||||
| 	bool needGammaFix = (alpha > 0.0f || alpha < (1.0f + COLOR_EPSILON)) && (colorSpace == ColorSpace_SRGB); | ||||
| 	if (needGammaFix) color = SIMDSRGB1ToLinearSpace(color); | ||||
| 
 | ||||
| 	// Format: u32 == (XX, RR, GG, BB)
 | ||||
| 	u32 *const bitmapPtr = (u32 *)renderBuffer->memory; | ||||
| 	const u32 pitchInU32 = (renderBuffer->width * renderBuffer->bytesPerPixel) / 4; | ||||
| 
 | ||||
| 	u32 srcPixel = bitmapPtr[x + (y * pitchInU32)]; | ||||
| 	__m128 src   = _mm_set_ps(0, (f32)((srcPixel >> 0) & 0xFF), | ||||
| 	                             (f32)((srcPixel >> 8) & 0xFF), | ||||
| 	                             (f32)((srcPixel >> 16) & 0xFF)); | ||||
| 	__m128 src = _mm_set_ps(0, | ||||
| 	                        (f32)((srcPixel >> 0) & 0xFF), | ||||
| 	                        (f32)((srcPixel >> 8) & 0xFF), | ||||
| 	                        (f32)((srcPixel >> 16) & 0xFF)); | ||||
| 	src = SIMDSRGB255ToLinearSpace1(src); | ||||
| 
 | ||||
| 	f32 invA       = 1 - alpha; | ||||
| @ -664,10 +654,12 @@ FILE_SCOPE inline void SIMDSetPixel(DTRRenderContext context, const i32 x, const | ||||
| 	f32 destB = ((f32 *)&dest)[2]; | ||||
| 
 | ||||
| 	u32 pixel = // ((u32)(destA) << 24 |
 | ||||
| 	            (u32)(destR) << 16 | | ||||
| 	            (u32)(destG) << 8  | | ||||
| 	            (u32)(destB) << 0; | ||||
| 	             (u32)(destR) << 16 | | ||||
| 	             (u32)(destG) << 8 | | ||||
| 	             (u32)(destB) << 0; | ||||
| 	bitmapPtr[x + (y * pitchInU32)] = pixel; | ||||
| 
 | ||||
| 	DTRDebug_CounterIncrement(DTRDebugCounter_SetPixels); | ||||
| } | ||||
| 
 | ||||
| // colorModulate: _mm_set_ps(a, b, g, r)     ie. 0=r, 1=g, 2=b, 3=a
 | ||||
| @ -716,7 +708,7 @@ FILE_SCOPE __m128 SIMDSampleTextureForTriangle(const DTRBitmap *const texture, c | ||||
| // IMPORTANT: Debug Markers can _NOT_ be used in primitive rendering functions,
 | ||||
| // ie. any render function that is used in this call because it'll call into
 | ||||
| // itself infinitely.
 | ||||
| FILE_SCOPE void DebugRenderMarkers(DTRRenderContext context, const DqnV2 *const pList, | ||||
| FILE_SCOPE void DebugRenderMarkers(DTRRenderBuffer *const renderBuffer, const DqnV2 *const pList, | ||||
|                                    const i32 pListSize, const DTRRenderTransform transform, | ||||
|                                    bool drawBoundingBox, bool drawBasis, bool drawVertexMarkers) | ||||
| { | ||||
| @ -733,10 +725,10 @@ FILE_SCOPE void DebugRenderMarkers(DTRRenderContext context, const DqnV2 *const | ||||
| 	{ | ||||
| 		DqnRect bounds = GetBoundingBox(pList, pListSize); | ||||
| 
 | ||||
| 		DTRRender_Line(context, DqnV2i_2f(bounds.min.x, bounds.min.y), DqnV2i_2f(bounds.min.x, bounds.max.y), red); | ||||
| 		DTRRender_Line(context, DqnV2i_2f(bounds.min.x, bounds.max.y), DqnV2i_2f(bounds.max.x, bounds.max.y), red); | ||||
| 		DTRRender_Line(context, DqnV2i_2f(bounds.max.x, bounds.max.y), DqnV2i_2f(bounds.max.x, bounds.min.y), red); | ||||
| 		DTRRender_Line(context, DqnV2i_2f(bounds.max.x, bounds.min.y), DqnV2i_2f(bounds.min.x, bounds.min.y), red); | ||||
| 		DTRRender_Line(renderBuffer, DqnV2i_2f(bounds.min.x, bounds.min.y), DqnV2i_2f(bounds.min.x, bounds.max.y), red); | ||||
| 		DTRRender_Line(renderBuffer, DqnV2i_2f(bounds.min.x, bounds.max.y), DqnV2i_2f(bounds.max.x, bounds.max.y), red); | ||||
| 		DTRRender_Line(renderBuffer, DqnV2i_2f(bounds.max.x, bounds.max.y), DqnV2i_2f(bounds.max.x, bounds.min.y), red); | ||||
| 		DTRRender_Line(renderBuffer, DqnV2i_2f(bounds.max.x, bounds.min.y), DqnV2i_2f(bounds.min.x, bounds.min.y), red); | ||||
| 	} | ||||
| 
 | ||||
| 	// Draw Coordinate Basis
 | ||||
| @ -751,9 +743,9 @@ FILE_SCOPE void DebugRenderMarkers(DTRRenderContext context, const DqnV2 *const | ||||
| 			DqnV2 yAxis         = DqnV2_2f(-xAxis.y, xAxis.x) * transform.scale.y; | ||||
| 			DqnV4 coordSysColor = DqnV4_4f(0, 1, 1, 1); | ||||
| 			i32 axisLen         = 50; | ||||
| 			DTRRender_Line(context, DqnV2i_V2(origin), | ||||
| 			DTRRender_Line(renderBuffer, DqnV2i_V2(origin), | ||||
| 			               DqnV2i_V2(origin) + DqnV2i_V2(xAxis * axisLen), coordSysColor); | ||||
| 			DTRRender_Line(context, DqnV2i_V2(origin), | ||||
| 			DTRRender_Line(renderBuffer, DqnV2i_V2(origin), | ||||
| 			               DqnV2i_V2(origin) + DqnV2i_V2(yAxis * axisLen), coordSysColor); | ||||
| 		} | ||||
| 	} | ||||
| @ -765,40 +757,11 @@ FILE_SCOPE void DebugRenderMarkers(DTRRenderContext context, const DqnV2 *const | ||||
| 		for (i32 i = 0; i < pListSize; i++) | ||||
| 		{ | ||||
| 			DqnV2 p = pList[i]; | ||||
| 			DTRRender_Rectangle(context, p - DqnV2_1f(5), p + DqnV2_1f(5), colorList[i]); | ||||
| 			DTRRender_Rectangle(renderBuffer, p - DqnV2_1f(5), p + DqnV2_1f(5), colorList[i]); | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| FILE_SCOPE inline f32 GetCurrZDepth(DTRRenderContext context, i32 posX, i32 posY) | ||||
| { | ||||
| 	DTRRenderBuffer *renderBuffer = context.renderBuffer; | ||||
| 	DQN_ASSERT(renderBuffer); | ||||
| 	const u32 zBufferPitch        = renderBuffer->width; | ||||
| 
 | ||||
| 	i32 zBufferIndex = posX + (posY * zBufferPitch); | ||||
| 	DQN_ASSERT(zBufferIndex < (renderBuffer->width * renderBuffer->height)); | ||||
| 
 | ||||
| 	context.api->LockAcquire(renderBuffer->renderLock); | ||||
| 	f32 currZDepth = renderBuffer->zBuffer[zBufferIndex]; | ||||
| 	context.api->LockRelease(renderBuffer->renderLock); | ||||
| 	return currZDepth; | ||||
| } | ||||
| 
 | ||||
| FILE_SCOPE inline void SetCurrZDepth(DTRRenderContext context, i32 posX, i32 posY, f32 newZDepth) | ||||
| { | ||||
| 	DTRRenderBuffer *renderBuffer = context.renderBuffer; | ||||
| 	DQN_ASSERT(renderBuffer); | ||||
| 	const u32 zBufferPitch        = renderBuffer->width; | ||||
| 
 | ||||
| 	i32 zBufferIndex = posX + (posY * zBufferPitch); | ||||
| 	DQN_ASSERT(zBufferIndex < (renderBuffer->width * renderBuffer->height)); | ||||
| 
 | ||||
| 	context.api->LockAcquire(renderBuffer->renderLock); | ||||
| 	renderBuffer->zBuffer[zBufferIndex] = newZDepth; | ||||
| 	context.api->LockRelease(renderBuffer->renderLock); | ||||
| } | ||||
| 
 | ||||
| #define DEBUG_SIMD_AUTO_CHOOSE_BEGIN_CYCLE_COUNT(type)                                             \ | ||||
| 	do                                                                                             \ | ||||
| 	{                                                                                              \ | ||||
| @ -817,18 +780,20 @@ FILE_SCOPE inline void SetCurrZDepth(DTRRenderContext context, i32 posX, i32 pos | ||||
| 			DTRDebug_EndCycleCount(DTRDebugCycleCount_SIMD##type);                                 \ | ||||
| 	} while (0) | ||||
| 
 | ||||
| FILE_SCOPE void | ||||
| SIMDRasteriseTrianglePixel(DTRRenderContext context, const DTRBitmap *const texture, const i32 posX, | ||||
|                            const i32 posY, const i32 maxX, const DqnV2 uv1, const DqnV2 uv2SubUv1, | ||||
|                            const DqnV2 uv3SubUv1, const __m128 simdColor, const __m128 triangleZ, | ||||
|                            const __m128 signedArea, const __m128 invSignedAreaParallelogram_4x, | ||||
|                            const f32 preserveAlpha, const bool ignoreLight, const __m128 p1Light, | ||||
|                            const __m128 p2Light, const __m128 p3Light) | ||||
| FILE_SCOPE void SIMDRasteriseTrianglePixel(DTRRenderBuffer *const renderBuffer, | ||||
|                                            const DTRBitmap *const texture, const i32 posX, | ||||
|                                            const i32 posY, const i32 maxX, const DqnV2 uv1, | ||||
|                                            const DqnV2 uv2SubUv1, const DqnV2 uv3SubUv1, | ||||
|                                            const __m128 simdColor, const __m128 triangleZ, | ||||
|                                            const __m128 signedArea, | ||||
|                                            const __m128 invSignedAreaParallelogram_4x) | ||||
| { | ||||
| 	DTRRenderBuffer *const renderBuffer = context.renderBuffer; | ||||
| 	const __m128 ZERO_4X                = _mm_set_ps1(0.0f); | ||||
| 	const u32 IS_GREATER_MASK           = 0xF; | ||||
| 	const u32 zBufferPitch              = renderBuffer->width; | ||||
| 	const __m128 ZERO_4X      = _mm_set_ps1(0.0f); | ||||
| 	const u32 IS_GREATER_MASK = 0xF; | ||||
| 	const u32 zBufferPitch    = renderBuffer->width; | ||||
| 
 | ||||
| 	// TODO(doyle): Copy lighting work over. But not important since using this
 | ||||
| 	// function causes performance problems.
 | ||||
| 
 | ||||
| 	// Rasterise buffer(X, Y) pixel
 | ||||
| 	{ | ||||
| @ -838,51 +803,32 @@ SIMDRasteriseTrianglePixel(DTRRenderContext context, const DTRBitmap *const text | ||||
| 		if ((isGreaterResult & IS_GREATER_MASK) == IS_GREATER_MASK && posX < maxX) | ||||
| 		{ | ||||
| 			DEBUG_SIMD_AUTO_CHOOSE_BEGIN_CYCLE_COUNT(Triangle_RasterisePixel); | ||||
| 			__m128 barycentric  = _mm_mul_ps(signedArea, invSignedAreaParallelogram_4x); | ||||
| 			__m128 barycentricZ = _mm_mul_ps(triangleZ, barycentric); | ||||
| 
 | ||||
| 			i32 zBufferIndex = posX + (posY * zBufferPitch); | ||||
| 			f32 pixelZValue = | ||||
| 			    ((f32 *)&barycentricZ)[0] + ((f32 *)&barycentricZ)[1] + ((f32 *)&barycentricZ)[2]; | ||||
| 			f32 currZValue = renderBuffer->zBuffer[zBufferIndex]; | ||||
| 			if (pixelZValue > currZValue) | ||||
| 			{ | ||||
| 				__m128 barycentric  = _mm_mul_ps(signedArea, invSignedAreaParallelogram_4x); | ||||
| 				__m128 barycentricZ = _mm_mul_ps(triangleZ, barycentric); | ||||
| 				renderBuffer->zBuffer[zBufferIndex] = pixelZValue; | ||||
| 
 | ||||
| 				f32 pixelZDepth = ((f32 *)&barycentricZ)[0] + ((f32 *)&barycentricZ)[1] + | ||||
| 				                  ((f32 *)&barycentricZ)[2]; | ||||
| 
 | ||||
| 				i32 zBufferIndex  = posX + (posY * zBufferPitch); | ||||
| 				if (pixelZDepth > renderBuffer->zBuffer[zBufferIndex]) | ||||
| 				__m128 finalColor = simdColor; | ||||
| 				if (texture) | ||||
| 				{ | ||||
| 					renderBuffer->zBuffer[zBufferIndex] = pixelZDepth; | ||||
| 					__m128 finalColor                   = simdColor; | ||||
| 					if (!ignoreLight) | ||||
| 					{ | ||||
| 						__m128 barycentricA_4x = _mm_set_ps1(((f32 *)&barycentric)[0]); | ||||
| 						__m128 barycentricB_4x = _mm_set_ps1(((f32 *)&barycentric)[1]); | ||||
| 						__m128 barycentricC_4x = _mm_set_ps1(((f32 *)&barycentric)[2]); | ||||
| 
 | ||||
| 						__m128 barycentricLight1 = _mm_mul_ps(p1Light, barycentricA_4x); | ||||
| 						__m128 barycentricLight2 = _mm_mul_ps(p2Light, barycentricB_4x); | ||||
| 						__m128 barycentricLight3 = _mm_mul_ps(p3Light, barycentricC_4x); | ||||
| 
 | ||||
| 						__m128 light = _mm_add_ps(barycentricLight3, | ||||
| 						                          _mm_add_ps(barycentricLight1, barycentricLight2)); | ||||
| 
 | ||||
| 						finalColor              = _mm_mul_ps(finalColor, light); | ||||
| 						((f32 *)&finalColor)[3] = preserveAlpha; | ||||
| 					} | ||||
| 
 | ||||
| 					if (texture) | ||||
| 					{ | ||||
| 						__m128 texSampledColor = SIMDSampleTextureForTriangle( | ||||
| 						    texture, uv1, uv2SubUv1, uv3SubUv1, barycentric); | ||||
| 						finalColor = _mm_mul_ps(texSampledColor, finalColor); | ||||
| 					} | ||||
| 
 | ||||
| 					SIMDSetPixel(context, posX, posY, finalColor, ColorSpace_Linear); | ||||
| 					__m128 texSampledColor = SIMDSampleTextureForTriangle(texture, uv1, uv2SubUv1, | ||||
| 					                                                      uv3SubUv1, barycentric); | ||||
| 					finalColor = _mm_mul_ps(texSampledColor, simdColor); | ||||
| 				} | ||||
| 				SIMDSetPixel(renderBuffer, posX, posY, finalColor, ColorSpace_Linear); | ||||
| 			} | ||||
| 			DEBUG_SIMD_AUTO_CHOOSE_END_CYCLE_COUNT(Triangle_RasterisePixel); | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| FILE_SCOPE void SIMDTriangle(DTRRenderContext context, const DqnV3 p1, const DqnV3 p2, | ||||
| FILE_SCOPE void SIMDTriangle(DTRRenderBuffer *const renderBuffer, const DqnV3 p1, const DqnV3 p2, | ||||
|                              const DqnV3 p3, const DqnV2 uv1, const DqnV2 uv2, const DqnV2 uv3, | ||||
|                              const f32 lightIntensity1, const f32 lightIntensity2, | ||||
|                              const f32 lightIntensity3, const bool ignoreLight, | ||||
| @ -894,8 +840,6 @@ FILE_SCOPE void SIMDTriangle(DTRRenderContext context, const DqnV3 p1, const Dqn | ||||
| 	DEBUG_SIMD_AUTO_CHOOSE_BEGIN_CYCLE_COUNT(Triangle); | ||||
| 
 | ||||
| 	DEBUG_SIMD_AUTO_CHOOSE_BEGIN_CYCLE_COUNT(Triangle_Preamble); | ||||
| 
 | ||||
| 	DTRRenderBuffer *const renderBuffer = context.renderBuffer; | ||||
| 	////////////////////////////////////////////////////////////////////////////
 | ||||
| 	// Convert color
 | ||||
| 	////////////////////////////////////////////////////////////////////////////
 | ||||
| @ -920,16 +864,16 @@ FILE_SCOPE void SIMDTriangle(DTRRenderContext context, const DqnV3 p1, const Dqn | ||||
| 	////////////////////////////////////////////////////////////////////////////
 | ||||
| 	// Setup SIMD data
 | ||||
| 	////////////////////////////////////////////////////////////////////////////
 | ||||
| 	const u32 NUM_X_PIXELS_TO_SIMD = 1; | ||||
| 	const u32 NUM_X_PIXELS_TO_SIMD = 2; | ||||
| 	const u32 NUM_Y_PIXELS_TO_SIMD = 1; | ||||
| 
 | ||||
| 	// SignedArea: _mm_set_ps(unused, p3, p2, p1) ie 0=p1, 1=p1, 2=p3, 3=unused
 | ||||
| 	__m128 signedAreaPixel1 = _mm_set_ps1(0); | ||||
| 	// __m128 signedAreaPixel2 = _mm_set_ps1(0);
 | ||||
| 	__m128 signedAreaPixel1; | ||||
| 	__m128 signedAreaPixel2; | ||||
| 
 | ||||
| 	__m128 signedAreaPixelDeltaX         = _mm_set_ps1(0); | ||||
| 	__m128 signedAreaPixelDeltaY         = _mm_set_ps1(0); | ||||
| 	__m128 invSignedAreaParallelogram_4x = _mm_set_ps1(0); | ||||
| 	__m128 signedAreaPixelDeltaX; | ||||
| 	__m128 signedAreaPixelDeltaY; | ||||
| 	__m128 invSignedAreaParallelogram_4x; | ||||
| 
 | ||||
| 	__m128 triangleZ = _mm_set_ps(0, p3.z, p2.z, p1.z); | ||||
| 	{ | ||||
| @ -962,7 +906,7 @@ FILE_SCOPE void SIMDTriangle(DTRRenderContext context, const DqnV3 p1, const Dqn | ||||
| 		signedAreaPixelDeltaY = _mm_set_ps(0, signedArea3DeltaY, signedArea2DeltaY, signedArea1DeltaY); | ||||
| 
 | ||||
| 		signedAreaPixel1 = _mm_set_ps(0, signedArea3Start, signedArea2Start, signedArea1Start); | ||||
| 		// signedAreaPixel2 = _mm_add_ps(signedAreaPixel1, signedAreaPixelDeltaX);
 | ||||
| 		signedAreaPixel2 = _mm_add_ps(signedAreaPixel1, signedAreaPixelDeltaX); | ||||
| 
 | ||||
| 		// NOTE: Increase step size to the number of pixels rasterised with SIMD
 | ||||
| 		{ | ||||
| @ -978,9 +922,13 @@ FILE_SCOPE void SIMDTriangle(DTRRenderContext context, const DqnV3 p1, const Dqn | ||||
| 	const DqnV2 uv2SubUv1 = uv2 - uv1; | ||||
| 	const DqnV2 uv3SubUv1 = uv3 - uv1; | ||||
| 
 | ||||
| #define UNROLL_LOOP 1 | ||||
| 	DEBUG_SIMD_AUTO_CHOOSE_END_CYCLE_COUNT(Triangle_Preamble); | ||||
| 
 | ||||
| #if UNROLL_LOOP | ||||
| 	const u32 IS_GREATER_MASK = 0xF; | ||||
| 	const u32 zBufferPitch    = renderBuffer->width; | ||||
| #endif | ||||
| 
 | ||||
| 	////////////////////////////////////////////////////////////////////////////
 | ||||
| 	// Scan and Render
 | ||||
| @ -989,10 +937,11 @@ FILE_SCOPE void SIMDTriangle(DTRRenderContext context, const DqnV3 p1, const Dqn | ||||
| 	for (i32 bufferY = min.y; bufferY < max.y; bufferY += NUM_Y_PIXELS_TO_SIMD) | ||||
| 	{ | ||||
| 		__m128 signedArea1 = signedAreaPixel1; | ||||
| 		// __m128 signedArea2 = signedAreaPixel2;
 | ||||
| 		__m128 signedArea2 = signedAreaPixel2; | ||||
| 
 | ||||
| 		for (i32 bufferX = min.x; bufferX < max.x; bufferX += NUM_X_PIXELS_TO_SIMD) | ||||
| 		{ | ||||
| #if UNROLL_LOOP | ||||
| 			// Rasterise buffer(X, Y) pixel
 | ||||
| 			{ | ||||
| 				__m128 checkArea    = signedArea1; | ||||
| @ -1007,31 +956,20 @@ FILE_SCOPE void SIMDTriangle(DTRRenderContext context, const DqnV3 p1, const Dqn | ||||
| 					__m128 barycentric  = _mm_mul_ps(checkArea, invSignedAreaParallelogram_4x); | ||||
| 					__m128 barycentricZ = _mm_mul_ps(triangleZ, barycentric); | ||||
| 
 | ||||
| 					f32 pixelZDepth  = ((f32 *)&barycentricZ)[0] + | ||||
| 					i32 zBufferIndex = posX + (posY * zBufferPitch); | ||||
| 					f32 pixelZValue  = ((f32 *)&barycentricZ)[0] + | ||||
| 					                   ((f32 *)&barycentricZ)[1] + | ||||
| 					                   ((f32 *)&barycentricZ)[2]; | ||||
| 
 | ||||
| 					i32 zBufferIndex = posX + (posY * zBufferPitch); | ||||
| 					if (context.multithread) | ||||
| 					{ | ||||
| 						bool currLockValue; | ||||
| 						do | ||||
| 						{ | ||||
| 							currLockValue = (bool)context.api->AtomicCompareSwap( | ||||
| 							    (u32 *)&renderBuffer->pixelLockTable[zBufferIndex], (u32) true, | ||||
| 							    (u32) false); | ||||
| 						} while (currLockValue != false); | ||||
| 					} | ||||
| 
 | ||||
| 					if (pixelZDepth > renderBuffer->zBuffer[zBufferIndex]) | ||||
| 					f32 currZValue = renderBuffer->zBuffer[zBufferIndex]; | ||||
| 					if (pixelZValue > currZValue) | ||||
| 					{ | ||||
| 						renderBuffer->zBuffer[zBufferIndex] = pixelZValue; | ||||
| 						__m128 finalColor                   = simdColor; | ||||
| 						renderBuffer->zBuffer[zBufferIndex] = pixelZDepth; | ||||
| 						if (!ignoreLight) | ||||
| 						{ | ||||
| 							__m128 barycentricA_4x = _mm_set_ps1(((f32 *)&barycentric)[0]); | ||||
| 							__m128 barycentricB_4x = _mm_set_ps1(((f32 *)&barycentric)[1]); | ||||
| 							__m128 barycentricC_4x = _mm_set_ps1(((f32 *)&barycentric)[2]); | ||||
| 							__m128 barycentricA_4x   = _mm_set_ps1(((f32 *)&barycentric)[0]); | ||||
| 							__m128 barycentricB_4x   = _mm_set_ps1(((f32 *)&barycentric)[1]); | ||||
| 							__m128 barycentricC_4x   = _mm_set_ps1(((f32 *)&barycentric)[2]); | ||||
| 
 | ||||
| 							__m128 barycentricLight1 = _mm_mul_ps(p1Light, barycentricA_4x); | ||||
| 							__m128 barycentricLight2 = _mm_mul_ps(p2Light, barycentricB_4x); | ||||
| @ -1041,34 +979,91 @@ FILE_SCOPE void SIMDTriangle(DTRRenderContext context, const DqnV3 p1, const Dqn | ||||
| 							    _mm_add_ps(barycentricLight3, | ||||
| 							               _mm_add_ps(barycentricLight1, barycentricLight2)); | ||||
| 
 | ||||
| 							finalColor              = _mm_mul_ps(finalColor, light); | ||||
| 							finalColor = _mm_mul_ps(finalColor, light); | ||||
| 							((f32 *)&finalColor)[3] = preserveAlpha; | ||||
| 						} | ||||
| 
 | ||||
| 						if (texture) | ||||
| 						{ | ||||
| 							__m128 texSampledColor = SIMDSampleTextureForTriangle( | ||||
| 							    texture, uv1, uv2SubUv1, uv3SubUv1, barycentric); | ||||
| 							finalColor = _mm_mul_ps(texSampledColor, finalColor); | ||||
| 							__m128 texSampledColor = SIMDSampleTextureForTriangle(texture, uv1, uv2SubUv1, uv3SubUv1, barycentric); | ||||
| 							finalColor             = _mm_mul_ps(texSampledColor, finalColor); | ||||
| 						} | ||||
| 
 | ||||
| 						SIMDSetPixel(context, posX, posY, finalColor, ColorSpace_Linear); | ||||
| 						SIMDSetPixel(renderBuffer, posX, posY, finalColor, ColorSpace_Linear); | ||||
| 					} | ||||
| 					renderBuffer->pixelLockTable[zBufferIndex] = false; | ||||
| 					DEBUG_SIMD_AUTO_CHOOSE_END_CYCLE_COUNT(Triangle_RasterisePixel); | ||||
| 				} | ||||
| 				signedArea1 = _mm_add_ps(signedArea1, signedAreaPixelDeltaX); | ||||
| 			} | ||||
| 
 | ||||
| 			// Rasterise buffer(X + 1, Y) pixel
 | ||||
| 			{ | ||||
| 				__m128 checkArea    = signedArea2; | ||||
| 				__m128 isGreater    = _mm_cmpge_ps(checkArea, ZERO_4X); | ||||
| 				i32 isGreaterResult = _mm_movemask_ps(isGreater); | ||||
| 				i32 posX            = bufferX + 1; | ||||
| 				i32 posY            = bufferY; | ||||
| 				if ((isGreaterResult & IS_GREATER_MASK) == IS_GREATER_MASK && posX < max.x) | ||||
| 				{ | ||||
| 					__m128 barycentric  = _mm_mul_ps(checkArea, invSignedAreaParallelogram_4x); | ||||
| 					__m128 barycentricZ = _mm_mul_ps(triangleZ, barycentric); | ||||
| 
 | ||||
| 					i32 zBufferIndex = posX + (posY * zBufferPitch); | ||||
| 					f32 pixelZValue  = ((f32 *)&barycentricZ)[0] + | ||||
| 					                    ((f32 *)&barycentricZ)[1] + | ||||
| 					                    ((f32 *)&barycentricZ)[2]; | ||||
| 					f32 currZValue = renderBuffer->zBuffer[zBufferIndex]; | ||||
| 					if (pixelZValue > currZValue) | ||||
| 					{ | ||||
| 						renderBuffer->zBuffer[zBufferIndex] = pixelZValue; | ||||
| 						__m128 finalColor                   = simdColor; | ||||
| 
 | ||||
| 						if (!ignoreLight) | ||||
| 						{ | ||||
| 							__m128 barycentricA_4x   = _mm_set_ps1(((f32 *)&barycentric)[0]); | ||||
| 							__m128 barycentricB_4x   = _mm_set_ps1(((f32 *)&barycentric)[1]); | ||||
| 							__m128 barycentricC_4x   = _mm_set_ps1(((f32 *)&barycentric)[2]); | ||||
| 
 | ||||
| 							__m128 barycentricLight1 = _mm_mul_ps(p1Light, barycentricA_4x); | ||||
| 							__m128 barycentricLight2 = _mm_mul_ps(p2Light, barycentricB_4x); | ||||
| 							__m128 barycentricLight3 = _mm_mul_ps(p3Light, barycentricC_4x); | ||||
| 
 | ||||
| 							__m128 light = | ||||
| 							    _mm_add_ps(barycentricLight3, | ||||
| 							               _mm_add_ps(barycentricLight1, barycentricLight2)); | ||||
| 
 | ||||
| 							finalColor = _mm_mul_ps(finalColor, light); | ||||
| 							((f32 *)&finalColor)[3] = preserveAlpha; | ||||
| 						} | ||||
| 
 | ||||
| 						if (texture) | ||||
| 						{ | ||||
| 							__m128 texSampledColor = SIMDSampleTextureForTriangle(texture, uv1, uv2SubUv1, uv3SubUv1, barycentric); | ||||
| 							finalColor             = _mm_mul_ps(texSampledColor, finalColor); | ||||
| 						} | ||||
| 						SIMDSetPixel(renderBuffer, posX, posY, finalColor, ColorSpace_Linear); | ||||
| 					} | ||||
| 				} | ||||
| 				signedArea2 = _mm_add_ps(signedArea2, signedAreaPixelDeltaX); | ||||
| 			} | ||||
| #else | ||||
| 			SIMDRasteriseTrianglePixel(renderBuffer, texture, bufferX, bufferY, max.x, uv1, uv2SubUv1, | ||||
| 			                           uv3SubUv1, simdColor, triangleZ, signedArea1, | ||||
| 			                           invSignedAreaParallelogram_4x); | ||||
| 			SIMDRasteriseTrianglePixel(renderBuffer, texture, bufferX + 1, bufferY, max.x, uv1, uv2SubUv1, | ||||
| 			                           uv3SubUv1, simdColor, triangleZ, signedArea2, | ||||
| 			                           invSignedAreaParallelogram_4x); | ||||
| 			signedArea1 = _mm_add_ps(signedArea1, signedAreaPixelDeltaX); | ||||
| 			signedArea2 = _mm_add_ps(signedArea2, signedAreaPixelDeltaX); | ||||
| #endif | ||||
| 		} | ||||
| 		signedAreaPixel1 = _mm_add_ps(signedAreaPixel1, signedAreaPixelDeltaY); | ||||
| 		// signedAreaPixel2 = _mm_add_ps(signedAreaPixel2, signedAreaPixelDeltaY);
 | ||||
| 		signedAreaPixel2 = _mm_add_ps(signedAreaPixel2, signedAreaPixelDeltaY); | ||||
| 	} | ||||
| 
 | ||||
| 	DEBUG_SIMD_AUTO_CHOOSE_END_CYCLE_COUNT(Triangle_Rasterise); | ||||
| 	DEBUG_SIMD_AUTO_CHOOSE_END_CYCLE_COUNT(Triangle); | ||||
| } | ||||
| 
 | ||||
| FILE_SCOPE void SlowTriangle(DTRRenderContext context, const DqnV3 p1, const DqnV3 p2, | ||||
| FILE_SCOPE void SlowTriangle(DTRRenderBuffer *const renderBuffer, const DqnV3 p1, const DqnV3 p2, | ||||
|                              const DqnV3 p3, const DqnV2 uv1, const DqnV2 uv2, const DqnV2 uv3, | ||||
|                              const f32 lightIntensity1, const f32 lightIntensity2, | ||||
|                              const f32 lightIntensity3, const bool ignoreLight, | ||||
| @ -1076,6 +1071,7 @@ FILE_SCOPE void SlowTriangle(DTRRenderContext context, const DqnV3 p1, const Dqn | ||||
|                              const DqnV2i max) | ||||
| { | ||||
| 	DTR_DEBUG_EP_TIMED_FUNCTION(); | ||||
| 
 | ||||
| #define DEBUG_SLOW_AUTO_CHOOSE_BEGIN_CYCLE_COUNT(type)                                             \ | ||||
| 	do                                                                                             \ | ||||
| 	{                                                                                              \ | ||||
| @ -1095,9 +1091,8 @@ FILE_SCOPE void SlowTriangle(DTRRenderContext context, const DqnV3 p1, const Dqn | ||||
| 	} while (0) | ||||
| 
 | ||||
| 	DEBUG_SLOW_AUTO_CHOOSE_BEGIN_CYCLE_COUNT(Triangle); | ||||
| 	DEBUG_SLOW_AUTO_CHOOSE_BEGIN_CYCLE_COUNT(Triangle_Preamble); | ||||
| 
 | ||||
| 	DTRRenderBuffer *renderBuffer = context.renderBuffer; | ||||
| 	DEBUG_SLOW_AUTO_CHOOSE_BEGIN_CYCLE_COUNT(Triangle_Preamble); | ||||
| 	////////////////////////////////////////////////////////////////////////////
 | ||||
| 	// Convert Color
 | ||||
| 	////////////////////////////////////////////////////////////////////////////
 | ||||
| @ -1151,39 +1146,75 @@ FILE_SCOPE void SlowTriangle(DTRRenderContext context, const DqnV3 p1, const Dqn | ||||
| 
 | ||||
| 		for (i32 bufferX = min.x; bufferX < max.x; bufferX++) | ||||
| 		{ | ||||
| 			if (signedArea1 >= 0 && signedArea2 >= 0 && signedArea3 >= 0) | ||||
| 			// TODO(doyle): Use signedArea1/2/3 and subsample increments from the signedAreaDeltas
 | ||||
| 			const u32 NUM_SAMPLES_ALONG_AXIS = 2; | ||||
| 			const u32 SAMPLES_PER_PIXEL      = DQN_SQUARED(NUM_SAMPLES_ALONG_AXIS); | ||||
| 			DQN_ASSERT((NUM_SAMPLES_ALONG_AXIS & 1) == 0); | ||||
| 
 | ||||
| 			const f32 SAMPLE_COVERAGE_INCREMENT = 1 / (f32)SAMPLES_PER_PIXEL; | ||||
| 			const f32 SAMPLE_XY_INCREMENT       = 1 / (f32)NUM_SAMPLES_ALONG_AXIS; | ||||
| 
 | ||||
| 			f32 subsampleCoverage = 0; | ||||
| 			for (i32 sampleY = 0; sampleY < NUM_SAMPLES_ALONG_AXIS; sampleY++) | ||||
| 			{ | ||||
| 				for (i32 sampleX = 0; sampleX < NUM_SAMPLES_ALONG_AXIS; sampleX++) | ||||
| 				{ | ||||
| 					f32 granularX = sampleX * SAMPLE_XY_INCREMENT; | ||||
| 					f32 granularY = sampleY * SAMPLE_XY_INCREMENT; | ||||
| 
 | ||||
| 					DqnV2 subsample = DqnV2_2f((f32)bufferX + granularX, (f32)bufferY + granularY); | ||||
| 
 | ||||
| 					f32 subsampleSignedArea1 = Triangle2TimesSignedArea(p2.xy, p3.xy, subsample); | ||||
| 					f32 subsampleSignedArea2 = Triangle2TimesSignedArea(p3.xy, p1.xy, subsample); | ||||
| 					f32 subsampleSignedArea3 = Triangle2TimesSignedArea(p1.xy, p2.xy, subsample); | ||||
| 
 | ||||
| 					if (subsampleSignedArea1 >= 0 && subsampleSignedArea2 >= 0 && | ||||
| 					    subsampleSignedArea3 >= 0) | ||||
| 					{ | ||||
| 						subsampleCoverage += SAMPLE_COVERAGE_INCREMENT; | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
| 			DQN_ASSERT(subsampleCoverage >= 0.0f && subsampleCoverage <= 1.0f); | ||||
| 
 | ||||
| 			// TODO(doyle): Crashes when using meshes, since we are now sampling
 | ||||
| 			// outside the actual specified mesh, (i.e. pixels just before it
 | ||||
| 			// for SSAA) the barycentric coordinates sample outside the texture.
 | ||||
| 			// Naiive workarounds will cause color artifacts or gaps in rendered
 | ||||
| 			// meshes.
 | ||||
| 			if (subsampleCoverage > 0) | ||||
| 			{ | ||||
| 				DEBUG_SLOW_AUTO_CHOOSE_BEGIN_CYCLE_COUNT(Triangle_RasterisePixel); | ||||
| 				f32 barycentricA = signedArea1 * invSignedAreaParallelogram; | ||||
| 				f32 barycentricB = signedArea2 * invSignedAreaParallelogram; | ||||
| 				f32 barycentricC = signedArea3 * invSignedAreaParallelogram; | ||||
| 
 | ||||
| 				i32 zBufferIndex = bufferX + (bufferY * zBufferPitch); | ||||
| 				if (context.multithread) | ||||
| 				{ | ||||
| 					bool currLockValue; | ||||
| 					do | ||||
| 					{ | ||||
| 						currLockValue = (bool)context.api->AtomicCompareSwap( | ||||
| 						    (u32 *)&renderBuffer->pixelLockTable[zBufferIndex], (u32) true, | ||||
| 						    (u32) false); | ||||
| 					} while (currLockValue != false); | ||||
| 				} | ||||
| 				f32 pixelZValue  = p1.z + (barycentricB * (p2SubP1.z)) + (barycentricC * (p3SubP1.z)); | ||||
| 				f32 currZValue   = renderBuffer->zBuffer[zBufferIndex]; | ||||
| 				DQN_ASSERT(zBufferIndex < (renderBuffer->width * renderBuffer->height)); | ||||
| 
 | ||||
| 				f32 pixelZDepth = | ||||
| 				    p1.z + (barycentricB * (p2SubP1.z)) + (barycentricC * (p3SubP1.z)); | ||||
| 				if (pixelZDepth > renderBuffer->zBuffer[zBufferIndex]) | ||||
| 				if (pixelZValue >= currZValue) | ||||
| 				{ | ||||
| 					DqnV4 finalColor = color; | ||||
| 					renderBuffer->zBuffer[zBufferIndex] = pixelZDepth; | ||||
| 					renderBuffer->zBuffer[zBufferIndex] = pixelZValue; | ||||
| 					DqnV4 finalColor                    = color; | ||||
| 					DQN_ASSERT(finalColor.x >= 0); | ||||
| 
 | ||||
| 					// NOTE: Multiply everything by the coverage alpha since
 | ||||
| 					// colors need to be premultiplied alpha.
 | ||||
| 					finalColor *= subsampleCoverage; | ||||
| 					DQN_ASSERT(finalColor.x >= 0); | ||||
| 
 | ||||
| 					if (!ignoreLight) | ||||
| 					{ | ||||
| 						DqnV3 light = (p1Light * barycentricA) + (p2Light * barycentricB) + | ||||
| 						f32 barycentricA = signedArea1 * invSignedAreaParallelogram; | ||||
| 						DqnV3 light      = (p1Light * barycentricA) + (p2Light * barycentricB) + | ||||
| 						              (p3Light * barycentricC); | ||||
| 						finalColor.rgb *= light; | ||||
| 						DQN_ASSERT(finalColor.x >= 0); | ||||
| 					} | ||||
| 
 | ||||
| 					DQN_ASSERT(finalColor.x >= 0); | ||||
| 
 | ||||
| 					if (texture) | ||||
| 					{ | ||||
| 						DqnV2 uv = uv1 + (uv2SubUv1 * barycentricB) + (uv3SubUv1 * barycentricC); | ||||
| @ -1214,11 +1245,14 @@ FILE_SCOPE void SlowTriangle(DTRRenderContext context, const DqnV3 p1, const Dqn | ||||
| 						color1 *= INV_255; | ||||
| 						color1 = DTRRender_SRGB1ToLinearSpaceV4(color1); | ||||
| 						finalColor *= color1; | ||||
| 
 | ||||
| 						DQN_ASSERT(finalColor.x >= 0); | ||||
| 					} | ||||
| 
 | ||||
| 					SetPixel(context, bufferX, bufferY, finalColor, ColorSpace_Linear); | ||||
| 					SetPixel(renderBuffer, bufferX, bufferY, finalColor, ColorSpace_Linear); | ||||
| 
 | ||||
| 					int breakhere = 5; | ||||
| 				} | ||||
| 				renderBuffer->pixelLockTable[zBufferIndex] = false; | ||||
| 				DEBUG_SLOW_AUTO_CHOOSE_END_CYCLE_COUNT(Triangle_RasterisePixel); | ||||
| 			} | ||||
| 
 | ||||
| @ -1262,14 +1296,11 @@ DqnMat4 GLViewport(f32 x, f32 y, f32 width, f32 height) | ||||
| 	return result; | ||||
| } | ||||
| 
 | ||||
| FILE_SCOPE void | ||||
| TexturedTriangleInternal(DTRRenderContext context, RenderLightInternal lighting, DqnV3 p1, DqnV3 p2, | ||||
|                          DqnV3 p3, DqnV2 uv1, DqnV2 uv2, DqnV2 uv3, DTRBitmap *const texture, | ||||
|                          DqnV4 color, | ||||
|                          const DTRRenderTransform transform = DTRRender_DefaultTriangleTransform()) | ||||
| FILE_SCOPE void TexturedTriangleInternal(DTRRenderBuffer *const renderBuffer, | ||||
|                                          RenderLightInternal lighting, DqnV3 p1, DqnV3 p2, DqnV3 p3, | ||||
|                                          DqnV2 uv1, DqnV2 uv2, DqnV2 uv3, DTRBitmap *const texture, | ||||
|                                          DqnV4 color, const DTRRenderTransform transform = DTRRender_DefaultTriangleTransform()) | ||||
| { | ||||
| 	DTRRenderBuffer *renderBuffer = context.renderBuffer; | ||||
| 
 | ||||
| 	////////////////////////////////////////////////////////////////////////////
 | ||||
| 	// Transform vertexes p1, p2, p3 inplace
 | ||||
| 	////////////////////////////////////////////////////////////////////////////
 | ||||
| @ -1324,14 +1355,14 @@ TexturedTriangleInternal(DTRRenderContext context, RenderLightInternal lighting, | ||||
| 	////////////////////////////////////////////////////////////////////////////
 | ||||
| 	// SIMD/Slow Path
 | ||||
| 	////////////////////////////////////////////////////////////////////////////
 | ||||
| 	if (globalDTRPlatformFlags.canUseSSE2) | ||||
| 	if (globalDTRPlatformFlags.canUseSSE2 && 0) | ||||
| 	{ | ||||
| 		SIMDTriangle(context, p1, p2, p3, uv1, uv2, uv3, lightIntensity1, lightIntensity2, | ||||
| 		SIMDTriangle(renderBuffer, p1, p2, p3, uv1, uv2, uv3, lightIntensity1, lightIntensity2, | ||||
| 		             lightIntensity3, ignoreLight, texture, color, min, max); | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		SlowTriangle(context, p1, p2, p3, uv1, uv2, uv3, lightIntensity1, lightIntensity2, | ||||
| 		SlowTriangle(renderBuffer, p1, p2, p3, uv1, uv2, uv3, lightIntensity1, lightIntensity2, | ||||
| 		             lightIntensity3, ignoreLight, texture, color, min, max); | ||||
| 	} | ||||
| 
 | ||||
| @ -1344,7 +1375,7 @@ TexturedTriangleInternal(DTRRenderContext context, RenderLightInternal lighting, | ||||
| 		bool drawBasis       = false; | ||||
| 		bool drawVertexMarkers = false; | ||||
| 
 | ||||
| 		DebugRenderMarkers(context, pList, DQN_ARRAY_COUNT(pList), transform, drawBoundingBox, | ||||
| 		DebugRenderMarkers(renderBuffer, pList, DQN_ARRAY_COUNT(pList), transform, drawBoundingBox, | ||||
| 		                   drawBasis, drawVertexMarkers); | ||||
| 	} | ||||
| } | ||||
| @ -1355,51 +1386,20 @@ FILE_SCOPE RenderLightInternal NullRenderLightInternal() | ||||
| 	return result; | ||||
| } | ||||
| 
 | ||||
| void DTRRender_TexturedTriangle(DTRRenderContext context, | ||||
| void DTRRender_TexturedTriangle(DTRRenderBuffer *const renderBuffer, | ||||
|                                 DqnV3 p1, DqnV3 p2, DqnV3 p3, DqnV2 uv1, DqnV2 uv2, DqnV2 uv3, | ||||
|                                 DTRBitmap *const texture, DqnV4 color, | ||||
|                                 const DTRRenderTransform transform) | ||||
| { | ||||
| 	TexturedTriangleInternal(context, NullRenderLightInternal(), p1, p2, p3, uv1, uv2, uv3, texture, | ||||
| 	TexturedTriangleInternal(renderBuffer, NullRenderLightInternal(), p1, p2, p3, uv1, uv2, uv3, texture, | ||||
| 	                         color, transform); | ||||
| } | ||||
| 
 | ||||
| typedef struct RenderMeshJob | ||||
| void DTRRender_Mesh(DTRRenderBuffer *const renderBuffer, DTRMesh *const mesh, | ||||
|                     DTRRenderLight lighting, const DqnV3 pos, | ||||
|                     const DTRRenderTransform transform) | ||||
| { | ||||
| 	DTRRenderContext context; | ||||
| 	DTRBitmap *tex; | ||||
| 	RenderLightInternal lighting; | ||||
| 
 | ||||
| 	DqnV3 v1; | ||||
| 	DqnV3 v2; | ||||
| 	DqnV3 v3; | ||||
| 	DqnV2 uv1; | ||||
| 	DqnV2 uv2; | ||||
| 	DqnV2 uv3; | ||||
| 	DqnV4 color; | ||||
| } RenderMeshJob; | ||||
| 
 | ||||
| void MultiThreadedRenderMesh(PlatformJobQueue *const queue, void *const userData) | ||||
| { | ||||
| 	if (!queue || !userData) | ||||
| 	{ | ||||
| 		DQN_ASSERT(DQN_INVALID_CODE_PATH); | ||||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
| 	RenderMeshJob *job = (RenderMeshJob *)userData; | ||||
| 	TexturedTriangleInternal(job->context, job->lighting, job->v1, job->v2, job->v3, job->uv1, | ||||
| 	                         job->uv2, job->uv3, job->tex, job->color); | ||||
| } | ||||
| 
 | ||||
| void DTRRender_Mesh(DTRRenderContext context, PlatformJobQueue *const jobQueue, DTRMesh *const mesh, | ||||
|                     DTRRenderLight lighting, const DqnV3 pos, const DTRRenderTransform transform) | ||||
| { | ||||
| 	DqnMemStack *const tempStack        = context.tempStack; | ||||
| 	DTRRenderBuffer *const renderBuffer = context.renderBuffer; | ||||
| 	PlatformAPI *const api              = context.api; | ||||
| 
 | ||||
| 	if (!mesh || !renderBuffer || !tempStack || !api || !jobQueue) return; | ||||
| 	if (!mesh) return; | ||||
| 
 | ||||
| 	DqnMat4 viewPModelViewProjection = {}; | ||||
| 	{ | ||||
| @ -1501,8 +1501,7 @@ void DTRRender_Mesh(DTRRenderContext context, PlatformJobQueue *const jobQueue, | ||||
| 		DqnV2 uv2 = mesh->texUV[uv2Index].xy; | ||||
| 		DqnV2 uv3 = mesh->texUV[uv3Index].xy; | ||||
| 
 | ||||
| 		DqnV4 color = lighting.color; | ||||
| 
 | ||||
| 		DqnV4 color                          = lighting.color; | ||||
| 		RenderLightInternal lightingInternal = {}; | ||||
| 		lightingInternal.mode                = lighting.mode; | ||||
| 		lightingInternal.vector              = lighting.vector; | ||||
| @ -1512,92 +1511,43 @@ void DTRRender_Mesh(DTRRenderContext context, PlatformJobQueue *const jobQueue, | ||||
| 		lightingInternal.numNormals          = 3; | ||||
| 
 | ||||
| 		bool DEBUG_NO_TEX = false; | ||||
| 		if (context.multithread) | ||||
| 		if (DTR_DEBUG && DEBUG_NO_TEX) | ||||
| 		{ | ||||
| 			RenderMeshJob *jobData = (RenderMeshJob *)DqnMemStack_Push(tempStack, sizeof(*jobData)); | ||||
| 			if (jobData) | ||||
| 			{ | ||||
| 				jobData->v1       = v1.xyz; | ||||
| 				jobData->v2       = v2.xyz; | ||||
| 				jobData->v3       = v3.xyz; | ||||
| 				jobData->uv1      = uv1; | ||||
| 				jobData->uv2      = uv2; | ||||
| 				jobData->uv3      = uv3; | ||||
| 				jobData->color    = color; | ||||
| 				jobData->lighting = lightingInternal; | ||||
| 				jobData->context  = context; | ||||
| 
 | ||||
| 				if (DTR_DEBUG && DEBUG_NO_TEX) | ||||
| 				{ | ||||
| 					jobData->tex = NULL; | ||||
| 				} | ||||
| 				else | ||||
| 				{ | ||||
| 					jobData->tex = &mesh->tex; | ||||
| 				} | ||||
| 
 | ||||
| 				PlatformJob renderJob = {}; | ||||
| 				renderJob.callback    = MultiThreadedRenderMesh; | ||||
| 				renderJob.userData    = jobData; | ||||
| 				while (!api->QueueAddJob(jobQueue, renderJob)) | ||||
| 				{ | ||||
| 					api->QueueTryExecuteNextJob(jobQueue); | ||||
| 				} | ||||
| 			} | ||||
| 			else | ||||
| 			{ | ||||
| 				// TODO(doyle): Allocation error
 | ||||
| 				DQN_ASSERT(DQN_INVALID_CODE_PATH); | ||||
| 			} | ||||
| 
 | ||||
| 			TexturedTriangleInternal(renderBuffer, lightingInternal, v1.xyz, v2.xyz, v3.xyz, uv1, | ||||
| 			                         uv2, uv3, NULL, color); | ||||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
| 			if (DTR_DEBUG && DEBUG_NO_TEX) | ||||
| 			{ | ||||
| 				TexturedTriangleInternal(context, lightingInternal, v1.xyz, v2.xyz, v3.xyz, | ||||
| 				                         uv1, uv2, uv3, NULL, color); | ||||
| 			} | ||||
| 			else | ||||
| 			{ | ||||
| 				TexturedTriangleInternal(context, lightingInternal, v1.xyz, v2.xyz, v3.xyz, | ||||
| 				                         uv1, uv2, uv3, &mesh->tex, color); | ||||
| 			} | ||||
| 			TexturedTriangleInternal(renderBuffer, lightingInternal, v1.xyz, v2.xyz, v3.xyz, uv1, | ||||
| 			                         uv2, uv3, &mesh->tex, color); | ||||
| 		} | ||||
| 
 | ||||
| 		bool DEBUG_WIREFRAME = false; | ||||
| 		if (DTR_DEBUG && DEBUG_WIREFRAME) | ||||
| 		{ | ||||
| 			DqnV4 wireColor = DqnV4_4f(1.0f, 1.0f, 1.0f, 0.01f); | ||||
| 			DTRRender_Line(context, DqnV2i_V2(v1.xy), DqnV2i_V2(v2.xy), wireColor); | ||||
| 			DTRRender_Line(context, DqnV2i_V2(v2.xy), DqnV2i_V2(v3.xy), wireColor); | ||||
| 			DTRRender_Line(context, DqnV2i_V2(v3.xy), DqnV2i_V2(v1.xy), wireColor); | ||||
| 			DTRRender_Line(renderBuffer, DqnV2i_V2(v1.xy), DqnV2i_V2(v2.xy), | ||||
| 			               wireColor); | ||||
| 			DTRRender_Line(renderBuffer, DqnV2i_V2(v2.xy), DqnV2i_V2(v3.xy), | ||||
| 			               wireColor); | ||||
| 			DTRRender_Line(renderBuffer, DqnV2i_V2(v3.xy), DqnV2i_V2(v1.xy), | ||||
| 			               wireColor); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	if (context.multithread) | ||||
| 	{ | ||||
| 		// NOTE(doyle): Complete remaining jobs and wait until all jobs finished
 | ||||
| 		// before leaving function.
 | ||||
| 		while (api->QueueTryExecuteNextJob(jobQueue) || !api->QueueAllJobsComplete(jobQueue)) | ||||
| 			; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| void DTRRender_Triangle(DTRRenderContext context, DqnV3 p1, DqnV3 p2, DqnV3 p3, DqnV4 color, | ||||
|                         const DTRRenderTransform transform) | ||||
| void DTRRender_Triangle(DTRRenderBuffer *const renderBuffer, DqnV3 p1, DqnV3 p2, DqnV3 p3, | ||||
|                         DqnV4 color, const DTRRenderTransform transform) | ||||
| { | ||||
| 	const DqnV2 NO_UV       = {}; | ||||
| 	DTRBitmap *const NO_TEX = NULL; | ||||
| 	TexturedTriangleInternal(context, NullRenderLightInternal(), p1, p2, p3, NO_UV, NO_UV, | ||||
| 	TexturedTriangleInternal(renderBuffer, NullRenderLightInternal(), p1, p2, p3, NO_UV, NO_UV, | ||||
| 	                         NO_UV, NO_TEX, color, transform); | ||||
| } | ||||
| 
 | ||||
| void DTRRender_Bitmap(DTRRenderContext context, DTRBitmap *const bitmap, DqnV2 pos, | ||||
| void DTRRender_Bitmap(DTRRenderBuffer *const renderBuffer, DTRBitmap *const bitmap, DqnV2 pos, | ||||
|                       const DTRRenderTransform transform, DqnV4 color) | ||||
| { | ||||
| 	DTRRenderBuffer *renderBuffer = context.renderBuffer; | ||||
| 
 | ||||
| 	if (!bitmap || !bitmap->memory || !renderBuffer) return; | ||||
| 	DTR_DEBUG_EP_TIMED_FUNCTION(); | ||||
| 
 | ||||
| @ -1771,7 +1721,7 @@ void DTRRender_Bitmap(DTRRenderContext context, DTRBitmap *const bitmap, DqnV2 p | ||||
| 					blend.g *= color.g; | ||||
| 					blend.b *= color.b; | ||||
| 
 | ||||
| 					SetPixel(context, bufferX, bufferY, blend, ColorSpace_Linear); | ||||
| 					SetPixel(renderBuffer, bufferX, bufferY, blend, ColorSpace_Linear); | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| @ -1785,14 +1735,14 @@ void DTRRender_Bitmap(DTRRenderContext context, DTRBitmap *const bitmap, DqnV2 p | ||||
| 		bool drawBasis         = true; | ||||
| 		bool drawVertexMarkers = true; | ||||
| 
 | ||||
| 		DebugRenderMarkers(context, pList, RECT_PLIST_SIZE, transform, drawBoundingBox, | ||||
| 		DebugRenderMarkers(renderBuffer, pList, RECT_PLIST_SIZE, transform, drawBoundingBox, | ||||
| 		                   drawBasis, drawVertexMarkers); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| void DTRRender_Clear(DTRRenderContext context, DqnV3 color) | ||||
| void DTRRender_Clear(DTRRenderBuffer *const renderBuffer, | ||||
|                      DqnV3 color) | ||||
| { | ||||
| 	DTRRenderBuffer *renderBuffer = context.renderBuffer; | ||||
| 	if (!renderBuffer) return; | ||||
| 
 | ||||
| 	DQN_ASSERT(color.r >= 0.0f && color.r <= 1.0f); | ||||
| @ -1813,4 +1763,3 @@ void DTRRender_Clear(DTRRenderContext context, DqnV3 color) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -2,10 +2,10 @@ | ||||
| #define DTRENDERER_RENDER_H | ||||
| 
 | ||||
| #include "dqn.h" | ||||
| #include "DTRendererPlatform.h" | ||||
| 
 | ||||
| #define DTRRENDER_INV_255 1.0f/255.0f | ||||
| 
 | ||||
| typedef struct DTRRenderBuffer DTRRenderBuffer; | ||||
| typedef struct DTRBitmap DTRBitmap; | ||||
| 
 | ||||
| ////////////////////////////////////////////////////////////////////////////////////////////////////
 | ||||
| @ -16,11 +16,9 @@ typedef struct DTRRenderBuffer | ||||
| 	i32 width; | ||||
| 	i32 height; | ||||
| 	i32 bytesPerPixel; | ||||
| 	PlatformLock *renderLock; | ||||
| 	volatile u8  *memory;     // Format: XX RR GG BB, and has (width * height * bytesPerPixels) elements
 | ||||
| 	volatile f32 *zBuffer;    // zBuffer has (width * height) elements
 | ||||
| 
 | ||||
| 	volatile bool *pixelLockTable; // has (width * height) elements
 | ||||
| 	u8  *memory;   // Format: XX RR GG BB, and has (width * height * bytesPerPixels) elements
 | ||||
| 	f32 *zBuffer;  // zBuffer has (width * height) elements
 | ||||
| 
 | ||||
| } DTRRenderBuffer; | ||||
| 
 | ||||
| @ -76,25 +74,15 @@ typedef struct DTRRenderLight | ||||
| 	DqnV4 color; | ||||
| } DTRRenderLight; | ||||
| 
 | ||||
| typedef struct DTRRenderContext | ||||
| { | ||||
| 	DTRRenderBuffer  *renderBuffer; | ||||
| 	DqnMemStack      *tempStack; | ||||
| 	PlatformAPI      *api; | ||||
| 	PlatformJobQueue *jobQueue; | ||||
| 
 | ||||
| 	bool multithread; | ||||
| } DTRRenderContext; | ||||
| 
 | ||||
| // NOTE: All colors should be in the range of [0->1] where DqnV4 is a struct with 4 floats, rgba
 | ||||
| // Leaving len = -1 for text will make the system use strlen to determine len.
 | ||||
| void DTRRender_Text            (DTRRenderContext context, const DTRFont font, DqnV2 pos, const char *const text, DqnV4 color = DqnV4_1f(1), i32 len = -1); | ||||
| void DTRRender_Line            (DTRRenderContext context, DqnV2i a, DqnV2i b, DqnV4 color); | ||||
| void DTRRender_Rectangle       (DTRRenderContext context, DqnV2 min, DqnV2 max, DqnV4 color, const DTRRenderTransform transform = DTRRender_DefaultTransform()); | ||||
| void DTRRender_Mesh            (DTRRenderContext context, PlatformJobQueue *const jobQueue, DTRMesh *const mesh, DTRRenderLight lighting, const DqnV3 pos, const DTRRenderTransform transform); | ||||
| void DTRRender_Triangle        (DTRRenderContext context, DqnV3 p1, DqnV3 p2, DqnV3 p3, DqnV4 color, const DTRRenderTransform transform = DTRRender_DefaultTriangleTransform()); | ||||
| void DTRRender_TexturedTriangle(DTRRenderContext context, DqnV3 p1, DqnV3 p2, DqnV3 p3, DqnV2 uv1, DqnV2 uv2, DqnV2 uv3, DTRBitmap *const texture, DqnV4 color, const DTRRenderTransform transform = DTRRender_DefaultTriangleTransform()); | ||||
| void DTRRender_Bitmap          (DTRRenderContext context, DTRBitmap *const bitmap, DqnV2 pos, const DTRRenderTransform transform = DTRRender_DefaultTransform(), DqnV4 color = DqnV4_4f(1, 1, 1, 1)); | ||||
| void DTRRender_Clear           (DTRRenderContext context, DqnV3 color); | ||||
| void DTRRender_Text            (DTRRenderBuffer *const renderBuffer, const DTRFont font, DqnV2 pos, const char *const text, DqnV4 color = DqnV4_1f(1), i32 len = -1); | ||||
| void DTRRender_Line            (DTRRenderBuffer *const renderBuffer, DqnV2i a, DqnV2i b, DqnV4 color); | ||||
| void DTRRender_Rectangle       (DTRRenderBuffer *const renderBuffer, DqnV2 min, DqnV2 max, DqnV4 color, const DTRRenderTransform transform = DTRRender_DefaultTransform()); | ||||
| void DTRRender_Mesh            (DTRRenderBuffer *const renderBuffer, DTRMesh *const mesh, DTRRenderLight lighting, const DqnV3 pos, const DTRRenderTransform transform); | ||||
| void DTRRender_Triangle        (DTRRenderBuffer *const renderBuffer, DqnV3 p1, DqnV3 p2, DqnV3 p3, DqnV4 color, const DTRRenderTransform transform = DTRRender_DefaultTriangleTransform()); | ||||
| void DTRRender_TexturedTriangle(DTRRenderBuffer *const renderBuffer, DqnV3 p1, DqnV3 p2, DqnV3 p3, DqnV2 uv1, DqnV2 uv2, DqnV2 uv3, DTRBitmap *const texture, DqnV4 color, const DTRRenderTransform transform = DTRRender_DefaultTriangleTransform()); | ||||
| void DTRRender_Bitmap          (DTRRenderBuffer *const renderBuffer, DTRBitmap *const bitmap, DqnV2 pos, const DTRRenderTransform transform = DTRRender_DefaultTransform(), DqnV4 color = DqnV4_4f(1, 1, 1, 1)); | ||||
| void DTRRender_Clear           (DTRRenderBuffer *const renderBuffer, DqnV3 color); | ||||
| 
 | ||||
| #endif | ||||
|  | ||||
| @ -1,161 +1,22 @@ | ||||
| #define UNICODE | ||||
| #define _UNICODE | ||||
| 
 | ||||
| #include "DTRenderer.h" | ||||
| #include "DTRendererPlatform.h" | ||||
| 
 | ||||
| #define DQN_WIN32_IMPLEMENTATION | ||||
| #define DQN_IMPLEMENTATION | ||||
| #define DQN_WIN32_IMPLEMENTATION | ||||
| #include "dqn.h" | ||||
| 
 | ||||
| #include <Windows.h> | ||||
| #include <Windowsx.h> // For GET_X|Y_LPARAM(), mouse input
 | ||||
| #include <Psapi.h>    // For win32 GetProcessMemoryInfo()
 | ||||
| #define UNICODE | ||||
| #define _UNICODE | ||||
| 
 | ||||
| FILE_SCOPE PlatformMemory globalPlatformMemory; | ||||
| FILE_SCOPE bool           globalRunning; | ||||
| 
 | ||||
| void Platform_DieGracefully() { globalRunning = false; } | ||||
| const char *const DLL_NAME     = "dtrenderer.dll"; | ||||
| const char *const DLL_TMP_NAME = "dtrenderer_temp.dll"; | ||||
| 
 | ||||
| ////////////////////////////////////////////////////////////////////////////////
 | ||||
| // Platform Atomics
 | ||||
| ////////////////////////////////////////////////////////////////////////////////
 | ||||
| u32 Platform_AtomicCompareSwap(u32 volatile *dest, u32 swapVal, u32 compareVal) | ||||
| { | ||||
| 	// TODO(doyle): Compile time assert
 | ||||
| 	DQN_ASSERT(sizeof(LONG) == sizeof(u32)); | ||||
| 	u32 result = | ||||
| 	    (u32)InterlockedCompareExchange((LONG volatile *)dest, (LONG)swapVal, (LONG)compareVal); | ||||
| 	return result; | ||||
| } | ||||
| 
 | ||||
| ////////////////////////////////////////////////////////////////////////////////
 | ||||
| // Platform Mutex/Lock
 | ||||
| ////////////////////////////////////////////////////////////////////////////////
 | ||||
| typedef struct PlatformLock | ||||
| { | ||||
| 	DqnLock dqnLock; | ||||
| } PlatformLock; | ||||
| 
 | ||||
| PlatformLock *Platform_LockInit(DqnMemStack *const stack) | ||||
| { | ||||
| 	PlatformLock *result = (PlatformLock *)DqnMemStack_Push(stack, sizeof(PlatformLock)); | ||||
| 	if (result) | ||||
| 	{ | ||||
| 		if (!DqnLock_Init(&result->dqnLock)) | ||||
| 		{ | ||||
| 			DqnMemStack_Pop(stack, result, sizeof(PlatformLock)); | ||||
| 			return NULL; | ||||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
| 			return result; | ||||
| 		} | ||||
| 	} | ||||
| 	return NULL; | ||||
| } | ||||
| 
 | ||||
| void Platform_LockAcquire(PlatformLock *const lock) { DqnLock_Acquire(&lock->dqnLock); } | ||||
| void Platform_LockRelease(PlatformLock *const lock) { DqnLock_Release(&lock->dqnLock); } | ||||
| void Platform_LockDelete (PlatformLock *const lock) { DqnLock_Delete(&lock->dqnLock); } | ||||
| 
 | ||||
| ////////////////////////////////////////////////////////////////////////////////
 | ||||
| // Platform Multi Threading
 | ||||
| ////////////////////////////////////////////////////////////////////////////////
 | ||||
| struct PlatformJobQueue | ||||
| { | ||||
| 	PlatformJob *volatile jobList; | ||||
| 	LONG         size; | ||||
| 
 | ||||
| 	// NOTE: Modified by main+worker threads
 | ||||
| 	LONG   volatile jobToExecuteIndex; | ||||
| 	HANDLE volatile win32Semaphore; | ||||
| 	LONG   volatile numJobsToComplete; | ||||
| 
 | ||||
| 	// NOTE: Modified by main thread ONLY
 | ||||
| 	LONG volatile jobInsertIndex; | ||||
| 
 | ||||
| }; | ||||
| 
 | ||||
| bool Platform_QueueAddJob(PlatformJobQueue *const queue, const PlatformJob job) | ||||
| { | ||||
| 	LONG newJobInsertIndex = (queue->jobInsertIndex + 1) % queue->size; | ||||
| 	if (newJobInsertIndex == queue->jobToExecuteIndex) return false; | ||||
| 
 | ||||
| 	queue->jobList[queue->jobInsertIndex] = job; | ||||
| 
 | ||||
| 	InterlockedIncrement(&queue->numJobsToComplete); | ||||
| 	ReleaseSemaphore(queue->win32Semaphore, 1, NULL); | ||||
| 	queue->jobInsertIndex = newJobInsertIndex; | ||||
| 	return true; | ||||
| } | ||||
| 
 | ||||
| bool Platform_QueueTryExecuteNextJob(PlatformJobQueue *const queue) | ||||
| { | ||||
| 	LONG originalJobToExecute = queue->jobToExecuteIndex; | ||||
| 	if (originalJobToExecute != queue->jobInsertIndex) | ||||
| 	{ | ||||
| 		LONG newJobIndexForNextThread = (originalJobToExecute + 1) % queue->size; | ||||
| 		LONG index = InterlockedCompareExchange(&queue->jobToExecuteIndex, newJobIndexForNextThread, | ||||
| 		                                        originalJobToExecute); | ||||
| 
 | ||||
| 		// NOTE: If we weren't successful at the interlock, another thread has
 | ||||
| 		// taken the work and we can't know if there's more work or not. So
 | ||||
| 		// irrespective of that result, return true to let the thread check
 | ||||
| 		// again for more work.
 | ||||
| 		if (index == originalJobToExecute) | ||||
| 		{ | ||||
| 			PlatformJob job = queue->jobList[index]; | ||||
| 			job.callback(queue, job.userData); | ||||
| 			InterlockedDecrement(&queue->numJobsToComplete); | ||||
| 		} | ||||
| 
 | ||||
| 		return true; | ||||
| 	} | ||||
| 
 | ||||
| 	return false; | ||||
| } | ||||
| 
 | ||||
| bool Platform_QueueAllJobsComplete(PlatformJobQueue *const queue) | ||||
| { | ||||
| 	bool result = (queue->numJobsToComplete == 0); | ||||
| 	return result; | ||||
| } | ||||
| 
 | ||||
| FILE_SCOPE u32  volatile globalDebugCounter; | ||||
| FILE_SCOPE bool volatile globalDebugCounterMemoize[2048]; | ||||
| FILE_SCOPE PlatformLock  globalDebugLock; | ||||
| FILE_SCOPE void DebugWin32IncrementCounter(PlatformJobQueue *const queue, void *const userData) | ||||
| { | ||||
| 	Platform_LockAcquire(&globalDebugLock); | ||||
| 	DQN_ASSERT(!globalDebugCounterMemoize[globalDebugCounter]); | ||||
| 	globalDebugCounterMemoize[globalDebugCounter] = true; | ||||
| 	globalDebugCounter++; | ||||
| 	u32 number = globalDebugCounter; | ||||
| 	Platform_LockRelease(&globalDebugLock); | ||||
| 
 | ||||
| 	DqnWin32_OutputDebugString("Thread %d: Incrementing Number: %d\n", GetCurrentThreadId(), | ||||
| 	                           number); | ||||
| } | ||||
| 
 | ||||
| DWORD WINAPI Win32ThreadCallback(void *lpParameter) | ||||
| { | ||||
| 	PlatformJobQueue *queue = (PlatformJobQueue *)lpParameter; | ||||
| 	for (;;) | ||||
| 	{ | ||||
| 		if (!Platform_QueueTryExecuteNextJob(queue)) | ||||
| 		{ | ||||
| 			WaitForSingleObjectEx(queue->win32Semaphore, INFINITE, false); | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| ////////////////////////////////////////////////////////////////////////////////
 | ||||
| // Platform I/O
 | ||||
| // Platform API Implementation
 | ||||
| ////////////////////////////////////////////////////////////////////////////////
 | ||||
| FILE_SCOPE inline PlatformFile DqnFileToPlatformFileInternal(const DqnFile file) | ||||
| { | ||||
| 	PlatformFile result    = {}; | ||||
| 	PlatformFile result = {}; | ||||
| 	result.handle          = file.handle; | ||||
| 	result.size            = file.size; | ||||
| 	result.permissionFlags = file.permissionFlags; | ||||
| @ -176,7 +37,7 @@ FILE_SCOPE inline DqnFile PlatformFileToDqnFileInternal(const PlatformFile file) | ||||
| void Platform_Print(const char *const string) | ||||
| { | ||||
| 	if (!string) return; | ||||
| 	OutputDebugStringA(string); | ||||
| 	OutputDebugString(string); | ||||
| } | ||||
| 
 | ||||
| bool Platform_FileOpen(const char *const path, PlatformFile *const file, const u32 permissionFlags, | ||||
| @ -207,7 +68,7 @@ size_t Platform_FileRead(PlatformFile *const file, u8 *const buf, | ||||
| 	if (!file || !buf) return 0; | ||||
| 
 | ||||
| 	DqnFile dqnFile     = PlatformFileToDqnFileInternal(*file); | ||||
| 	size_t numBytesRead = DqnFile_Read(&dqnFile, buf, bytesToRead); | ||||
| 	size_t numBytesRead = DqnFile_Read(dqnFile, buf, bytesToRead); | ||||
| 
 | ||||
| 	return numBytesRead; | ||||
| } | ||||
| @ -234,9 +95,9 @@ void Platform_FileClose(PlatformFile *const file) | ||||
| ////////////////////////////////////////////////////////////////////////////////
 | ||||
| // Win32 Layer
 | ||||
| ////////////////////////////////////////////////////////////////////////////////
 | ||||
| const char *const DLL_NAME     = "dtrenderer.dll"; | ||||
| const char *const DLL_TMP_NAME = "dtrenderer_temp.dll"; | ||||
| 
 | ||||
| #include <Windows.h> | ||||
| #include <Windowsx.h> // For GET_X|Y_LPARAM(), mouse input
 | ||||
| #include <Psapi.h>    // For win32 GetProcessMemoryInfo()
 | ||||
| typedef struct Win32RenderBitmap | ||||
| { | ||||
| 	BITMAPINFO  info; | ||||
| @ -248,6 +109,8 @@ typedef struct Win32RenderBitmap | ||||
| } Win32RenderBitmap; | ||||
| 
 | ||||
| FILE_SCOPE Win32RenderBitmap globalRenderBitmap; | ||||
| FILE_SCOPE PlatformMemory    globalPlatformMemory; | ||||
| FILE_SCOPE bool              globalRunning; | ||||
| 
 | ||||
| typedef struct Win32ExternalCode | ||||
| { | ||||
| @ -287,7 +150,7 @@ FILETIME Win32GetLastWriteTime(const char *const srcName) | ||||
| { | ||||
| 	FILETIME lastWriteTime               = {}; | ||||
| 	WIN32_FILE_ATTRIBUTE_DATA attribData = {}; | ||||
| 	if (GetFileAttributesExA(srcName, GetFileExInfoStandard, &attribData) != 0) | ||||
| 	if (GetFileAttributesEx(srcName, GetFileExInfoStandard, &attribData) != 0) | ||||
| 	{ | ||||
| 		lastWriteTime = attribData.ftLastWriteTime; | ||||
| 	} | ||||
| @ -301,7 +164,7 @@ FILE_SCOPE Win32ExternalCode Win32LoadExternalDLL(const char *const srcPath, | ||||
| { | ||||
| 	Win32ExternalCode result = {}; | ||||
| 	result.lastWriteTime     = lastWriteTime; | ||||
| 	CopyFileA(srcPath, tmpPath, false); | ||||
| 	CopyFile(srcPath, tmpPath, false); | ||||
| 
 | ||||
| 	DTR_UpdateFunction *updateFunction = NULL; | ||||
| 	result.dll                        = LoadLibraryA(tmpPath); | ||||
| @ -332,10 +195,10 @@ FILE_SCOPE void Win32CreateMenu(HWND window) | ||||
| 	HMENU menuBar  = CreateMenu(); | ||||
| 	{ // File Menu
 | ||||
| 		HMENU menu = CreatePopupMenu(); | ||||
| 		AppendMenuA(menuBar, MF_STRING | MF_POPUP, (UINT_PTR)menu, "File"); | ||||
| 		AppendMenuA(menu, MF_STRING, Win32Menu_FileOpen, "Open"); | ||||
| 		AppendMenuA(menu, MF_STRING, Win32Menu_FileFlushMemory, "Flush Memory"); | ||||
| 		AppendMenuA(menu, MF_STRING, Win32Menu_FileExit, "Exit"); | ||||
| 		AppendMenu(menuBar, MF_STRING | MF_POPUP, (UINT_PTR)menu, "File"); | ||||
| 		AppendMenu(menu, MF_STRING, Win32Menu_FileOpen, "Open"); | ||||
| 		AppendMenu(menu, MF_STRING, Win32Menu_FileFlushMemory, "Flush Memory"); | ||||
| 		AppendMenu(menu, MF_STRING, Win32Menu_FileExit, "Exit"); | ||||
| 	} | ||||
| 	SetMenu(window, menuBar); | ||||
| } | ||||
| @ -549,25 +412,55 @@ FILE_SCOPE void Win32ProcessMessages(HWND window, PlatformInput *input) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nShowCmd) | ||||
| // Return the index of the last slash
 | ||||
| i32 Win32GetModuleDirectory(char *const buf, const u32 bufLen) | ||||
| { | ||||
| 	if (!buf || bufLen == 0) return 0; | ||||
| 	u32 copiedLen = GetModuleFileName(NULL, buf, bufLen); | ||||
| 	if (copiedLen == bufLen) | ||||
| 	{ | ||||
| 		DQN_WIN32_ERROR_BOX( | ||||
| 		    "GetModuleFileName() buffer maxed: Len of copied text is len " | ||||
| 		    "of supplied buffer.", | ||||
| 		    NULL); | ||||
| 		DQN_ASSERT(DQN_INVALID_CODE_PATH); | ||||
| 	} | ||||
| 
 | ||||
| 	// NOTE: Should always work if GetModuleFileName works and we're running an
 | ||||
| 	// executable.
 | ||||
| 	i32 lastSlashIndex = 0; | ||||
| 	for (i32 i = copiedLen; i > 0; i--) | ||||
| 	{ | ||||
| 		if (buf[i] == '\\') | ||||
| 		{ | ||||
| 			lastSlashIndex = i; | ||||
| 			break; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return lastSlashIndex; | ||||
| } | ||||
| 
 | ||||
| int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, | ||||
|                     LPWSTR lpCmdLine, int nShowCmd) | ||||
| { | ||||
| 	////////////////////////////////////////////////////////////////////////////
 | ||||
| 	// Initialise Win32 Window
 | ||||
| 	////////////////////////////////////////////////////////////////////////////
 | ||||
| 	WNDCLASSEXW wc = { | ||||
| 	    sizeof(WNDCLASSEX), | ||||
| 	    CS_HREDRAW | CS_VREDRAW | CS_OWNDC, | ||||
| 	    Win32MainProcCallback, | ||||
| 	    0, // int cbClsExtra
 | ||||
| 	    0, // int cbWndExtra
 | ||||
| 	    hInstance, | ||||
| 	    LoadIcon(NULL, IDI_APPLICATION), | ||||
| 	    LoadCursor(NULL, IDC_ARROW), | ||||
| 	    GetSysColorBrush(COLOR_3DFACE), | ||||
| 	    L"", // LPCTSTR lpszMenuName
 | ||||
| 	    L"DRendererClass", | ||||
| 	    NULL, // HICON hIconSm
 | ||||
| 	WNDCLASSEXW wc = | ||||
| 	{ | ||||
| 		sizeof(WNDCLASSEX), | ||||
| 		CS_HREDRAW | CS_VREDRAW | CS_OWNDC, | ||||
| 		Win32MainProcCallback, | ||||
| 		0, // int cbClsExtra
 | ||||
| 		0, // int cbWndExtra
 | ||||
| 		hInstance, | ||||
| 		LoadIcon(NULL, IDI_APPLICATION), | ||||
| 		LoadCursor(NULL, IDC_ARROW), | ||||
| 		GetSysColorBrush(COLOR_3DFACE), | ||||
| 		L"", // LPCTSTR lpszMenuName
 | ||||
| 		L"DRendererClass", | ||||
| 		NULL, // HICON hIconSm
 | ||||
| 	}; | ||||
| 
 | ||||
| 	if (!RegisterClassExW(&wc)) | ||||
| @ -614,7 +507,7 @@ int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLi | ||||
| 		globalRenderBitmap.width          = header.biWidth; | ||||
| 		globalRenderBitmap.height         = header.biHeight; | ||||
| 		globalRenderBitmap.bytesPerPixel  = header.biBitCount / 8; | ||||
| 		if (!DQN_ASSERT(globalRenderBitmap.bytesPerPixel >= 1)) return -1; | ||||
| 		DQN_ASSERT(globalRenderBitmap.bytesPerPixel >= 1); | ||||
| 
 | ||||
| 		HDC deviceContext         = GetDC(mainWindow); | ||||
| 		globalRenderBitmap.handle = CreateDIBSection( | ||||
| @ -637,130 +530,39 @@ int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLi | ||||
| 	char dllTmpPath[MAX_PATH] = {}; | ||||
| 	{ | ||||
| 		char exeDir[MAX_PATH] = {}; | ||||
| 		i32 lastSlashIndex    = DqnWin32_GetEXEDirectory(exeDir, DQN_ARRAY_COUNT(exeDir)); | ||||
| 		if (DQN_ASSERT_MSG(lastSlashIndex != -1, "Not enough space in buffer for exe path")) | ||||
| 		{ | ||||
| 			exeDir[lastSlashIndex + 1] = 0; | ||||
| 			u32 dllNumCopied           = Dqn_sprintf(dllPath, "%s%s", exeDir, DLL_NAME); | ||||
| 			u32 dllTmpNumCopied        = Dqn_sprintf(dllTmpPath, "%s%s", exeDir, DLL_TMP_NAME); | ||||
| 		i32 lastSlashIndex = | ||||
| 		    Win32GetModuleDirectory(exeDir, DQN_ARRAY_COUNT(exeDir)); | ||||
| 		DQN_ASSERT(lastSlashIndex + 1 < DQN_ARRAY_COUNT(exeDir)); | ||||
| 
 | ||||
| 			if (!DQN_ASSERT_MSG((dllNumCopied    < DQN_ARRAY_COUNT(dllPath)) && | ||||
| 			                    (dllTmpNumCopied < DQN_ARRAY_COUNT(dllPath)), | ||||
| 			                    "Out of space to form DLL path")) | ||||
| 			{ | ||||
| 				Platform_DieGracefully(); | ||||
| 			} | ||||
| 		} | ||||
| 		exeDir[lastSlashIndex + 1] = 0; | ||||
| 		u32 numCopied = Dqn_sprintf(dllPath, "%s%s", exeDir, DLL_NAME); | ||||
| 		DQN_ASSERT(numCopied < DQN_ARRAY_COUNT(dllPath)); | ||||
| 
 | ||||
| 		numCopied = | ||||
| 		    Dqn_sprintf(dllTmpPath, "%s%s", exeDir, DLL_TMP_NAME); | ||||
| 		DQN_ASSERT(numCopied < DQN_ARRAY_COUNT(dllTmpPath)); | ||||
| 	} | ||||
| 
 | ||||
| 	////////////////////////////////////////////////////////////////////////////
 | ||||
| 	// Platform Data Pre-amble
 | ||||
| 	////////////////////////////////////////////////////////////////////////////
 | ||||
| 	bool memoryInitResult = | ||||
| 	    DqnMemStack_Init(&globalPlatformMemory.mainStack, DQN_MEGABYTE(4), true, 4) | | ||||
| 	    DqnMemStack_Init(&globalPlatformMemory.tempStack, DQN_MEGABYTE(4), true, 4) | | ||||
| 	    DqnMemStack_Init(&globalPlatformMemory.assetStack, DQN_MEGABYTE(4), true, 4); | ||||
| 	if (!DQN_ASSERT_MSG(memoryInitResult, "Unable to allocate DTRenderer globalPlatformMemory stacks")) | ||||
| 	{ | ||||
| 		Platform_DieGracefully(); | ||||
| 	} | ||||
| 	DQN_ASSERT(DqnMemStack_Init(&globalPlatformMemory.mainStack, DQN_MEGABYTE(4), true, 4) && | ||||
| 	           DqnMemStack_Init(&globalPlatformMemory.tempStack, DQN_MEGABYTE(4), true, 4) && | ||||
| 	           DqnMemStack_Init(&globalPlatformMemory.assetStack, DQN_MEGABYTE(4), true, 4) | ||||
| 			  ); | ||||
| 
 | ||||
| 	PlatformAPI platformAPI   = {}; | ||||
| 	platformAPI.DieGracefully = Platform_DieGracefully; | ||||
| 
 | ||||
| 	platformAPI.FileOpen  = Platform_FileOpen; | ||||
| 	platformAPI.FileRead  = Platform_FileRead; | ||||
| 	platformAPI.FileWrite = Platform_FileWrite; | ||||
| 	platformAPI.FileClose = Platform_FileClose; | ||||
| 	platformAPI.Print     = Platform_Print; | ||||
| 
 | ||||
| 	platformAPI.QueueAddJob            = Platform_QueueAddJob; | ||||
| 	platformAPI.QueueTryExecuteNextJob = Platform_QueueTryExecuteNextJob; | ||||
| 	platformAPI.QueueAllJobsComplete   = Platform_QueueAllJobsComplete; | ||||
| 
 | ||||
| 	platformAPI.AtomicCompareSwap = Platform_AtomicCompareSwap; | ||||
| 
 | ||||
| 	platformAPI.LockInit    = Platform_LockInit; | ||||
| 	platformAPI.LockAcquire = Platform_LockAcquire; | ||||
| 	platformAPI.LockRelease = Platform_LockRelease; | ||||
| 	platformAPI.LockDelete  = Platform_LockDelete; | ||||
| 
 | ||||
| 	PlatformJobQueue jobQueue = {}; | ||||
| 	PlatformAPI platformAPI = {}; | ||||
| 	platformAPI.FileOpen    = Platform_FileOpen; | ||||
| 	platformAPI.FileRead    = Platform_FileRead; | ||||
| 	platformAPI.FileWrite   = Platform_FileWrite; | ||||
| 	platformAPI.FileClose   = Platform_FileClose; | ||||
| 	platformAPI.Print       = Platform_Print; | ||||
| 
 | ||||
| 	PlatformInput platformInput     = {}; | ||||
| 	platformInput.api               = platformAPI; | ||||
| 	platformInput.jobQueue          = &jobQueue; | ||||
| 	platformInput.flags.canUseSSE2  = IsProcessorFeaturePresent(PF_XMMI64_INSTRUCTIONS_AVAILABLE); | ||||
| 	platformInput.flags.canUseRdtsc = IsProcessorFeaturePresent(PF_RDTSC_INSTRUCTION_AVAILABLE); | ||||
| 
 | ||||
| 	// Threading
 | ||||
| 	PlatformJob jobQueueMemory[512] = {}; | ||||
| 	{ | ||||
| 		DqnMemStackTempRegion memRegion; | ||||
| 		if (!DQN_ASSERT(DqnMemStackTempRegion_Begin(&memRegion, &globalPlatformMemory.tempStack))) | ||||
| 			Platform_DieGracefully(); | ||||
| 
 | ||||
| 		////////////////////////////////////////////////////////////////////////
 | ||||
| 		// Query CPU Cores
 | ||||
| 		////////////////////////////////////////////////////////////////////////
 | ||||
| 		i32 numCores, numThreadsPerCore; | ||||
| 		DqnWin32_GetNumThreadsAndCores(&numCores, &numThreadsPerCore); | ||||
| 
 | ||||
| 		////////////////////////////////////////////////////////////////////////
 | ||||
| 		// Threading
 | ||||
| 		////////////////////////////////////////////////////////////////////////
 | ||||
| 		jobQueue.jobList = jobQueueMemory; | ||||
| 		jobQueue.size    = DQN_ARRAY_COUNT(jobQueueMemory); | ||||
| 
 | ||||
| 		// NOTE: InterlockedIncrement requires things to be on 32bit boundaries.
 | ||||
| 		DQN_ASSERT(((size_t)&jobQueue.jobToExecuteIndex) % 4 == 0); | ||||
| 
 | ||||
| 		// NOTE: (numCores - 1), 1 core is already exclusively for main thread
 | ||||
| 		i32 availableThreads = (numCores - 1) * numThreadsPerCore; | ||||
| 		if (availableThreads <= 0) availableThreads = 1; | ||||
| 		 | ||||
| 		jobQueue.win32Semaphore = CreateSemaphore(NULL, 0, availableThreads, NULL); | ||||
| 		if (jobQueue.win32Semaphore) | ||||
| 		{ | ||||
| 			// Create threads
 | ||||
| 			for (i32 i = 0; i < availableThreads; i++) | ||||
| 			{ | ||||
| 				const i32 USE_DEFAULT_STACK_SIZE = 0; | ||||
| 				void *threadParam                = &jobQueue; | ||||
| 				HANDLE handle = CreateThread(NULL, USE_DEFAULT_STACK_SIZE, Win32ThreadCallback, | ||||
| 				                             threadParam, 0, NULL); | ||||
| 				CloseHandle(handle); | ||||
| 			} | ||||
| 
 | ||||
| #if 1 | ||||
| 			DQN_ASSERT_HARD(DqnLock_Init(&globalDebugLock.dqnLock)); | ||||
| 			for (i32 i = 0; i < DQN_ARRAY_COUNT(globalDebugCounterMemoize); i++) | ||||
| 			{ | ||||
| 				PlatformJob job = {}; | ||||
| 				job.callback    = DebugWin32IncrementCounter; | ||||
| 				while (!Platform_QueueAddJob(&jobQueue, job)) | ||||
| 				{ | ||||
| 					Platform_QueueTryExecuteNextJob(&jobQueue); | ||||
| 				} | ||||
| 			} | ||||
| 
 | ||||
| 			while (Platform_QueueTryExecuteNextJob(&jobQueue)) | ||||
| 				; | ||||
| 
 | ||||
| 			for (i32 i = 0; i < DQN_ARRAY_COUNT(globalDebugCounterMemoize); i++) | ||||
| 				DQN_ASSERT(globalDebugCounterMemoize[i]); | ||||
| 
 | ||||
| 			DqnWin32_OutputDebugString("\nFinal incremented value: %d\n", globalDebugCounter); | ||||
| 			DQN_ASSERT(globalDebugCounter == DQN_ARRAY_COUNT(globalDebugCounterMemoize)); | ||||
| #endif | ||||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
| 			// TODO(doyle): Semaphore failed.
 | ||||
| 			DqnWin32_DisplayLastError("CreateSemaphore() failed"); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	////////////////////////////////////////////////////////////////////////////
 | ||||
| 	// Update Loop
 | ||||
| 	////////////////////////////////////////////////////////////////////////////
 | ||||
| @ -774,7 +576,7 @@ int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLi | ||||
| 		////////////////////////////////////////////////////////////////////////
 | ||||
| 		// Update State
 | ||||
| 		////////////////////////////////////////////////////////////////////////
 | ||||
| 		f64 startFrameTimeInS = DqnTimer_NowInS(); | ||||
| 		f64 startFrameTimeInS = DqnTime_NowInS(); | ||||
| 
 | ||||
| 		FILETIME lastWriteTime = Win32GetLastWriteTime(dllPath); | ||||
| 		if (CompareFileTime(&lastWriteTime, &dllCode.lastWriteTime) != 0) | ||||
| @ -785,7 +587,7 @@ int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLi | ||||
| 		} | ||||
| 
 | ||||
| 		{ | ||||
| 			platformInput.timeNowInS    = DqnTimer_NowInS(); | ||||
| 			platformInput.timeNowInS    = DqnTime_NowInS(); | ||||
| 			platformInput.deltaForFrame = (f32)frameTimeInS; | ||||
| 			Win32ProcessMessages(mainWindow, &platformInput); | ||||
| 
 | ||||
| @ -797,7 +599,8 @@ int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLi | ||||
| 
 | ||||
| 			if (dllCode.DTR_Update) | ||||
| 			{ | ||||
| 				dllCode.DTR_Update(&platformBuffer, &platformInput, &globalPlatformMemory); | ||||
| 				dllCode.DTR_Update(&platformBuffer, &platformInput, | ||||
| 				                   &globalPlatformMemory); | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| @ -823,7 +626,7 @@ int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLi | ||||
| 		// Frame Limiting
 | ||||
| 		////////////////////////////////////////////////////////////////////////
 | ||||
| 		{ | ||||
| 			f64 workTimeInS = DqnTimer_NowInS() - startFrameTimeInS; | ||||
| 			f64 workTimeInS = DqnTime_NowInS() - startFrameTimeInS; | ||||
| 			if (workTimeInS < targetSecondsPerFrame) | ||||
| 			{ | ||||
| 				DWORD remainingTimeInMs = | ||||
| @ -832,7 +635,7 @@ int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLi | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		frameTimeInS        = DqnTimer_NowInS() - startFrameTimeInS; | ||||
| 		frameTimeInS        = DqnTime_NowInS() - startFrameTimeInS; | ||||
| 		f32 msPerFrame      = 1000.0f * (f32)frameTimeInS; | ||||
| 		f32 framesPerSecond = 1.0f / (f32)frameTimeInS; | ||||
| 
 | ||||
|  | ||||
| @ -16,11 +16,6 @@ if %errorlevel%==0 ( | ||||
| 	ctags -R | ||||
| ) | ||||
| 
 | ||||
| where /q gtags | ||||
| if %errorlevel%==0 ( | ||||
| 	gtags | ||||
| ) | ||||
| 
 | ||||
| set ProjectName=dtrenderer | ||||
| ctime -begin ..\src\%ProjectName%.ctm | ||||
| 
 | ||||
| @ -34,6 +29,7 @@ REM EHa-   disable exception handling (currently it's on /EHsc since libraries n | ||||
| REM GR-    disable c runtime type information (we don't use) | ||||
| REM MD     use dynamic runtime library | ||||
| REM MT     use static runtime library, so build and link it into exe | ||||
| REM Od     disables optimisations | ||||
| REM Oi     enable intrinsics optimisation, let us use CPU intrinsics if there is one | ||||
| REM        instead of generating a call to external library (i.e. CRT). | ||||
| REM Zi     enables debug data, Z7 combines the debug files into one. | ||||
| @ -43,47 +39,28 @@ REM wd4100 unused argument parameters | ||||
| REM wd4201 nonstandard extension used: nameless struct/union | ||||
| REM wd4189 local variable is initialised but not referenced | ||||
| REM wd4505 unreferenced local function not used will be removed | ||||
| set CompileFlags=-EHsc -GR- -Oi -MT -Z7 -W4 -wd4100 -wd4201 -wd4189 -wd4505 -FAsc /I..\src\external\ | ||||
| set CompileFlags=-EHsc -GR- -Oi -MT -Z7 -W4 -wd4100 -wd4201 -wd4189 -wd4505 -Od -FAsc /I..\src\external\ | ||||
| set DLLFlags=/Fm%ProjectName% /Fo%ProjectName% /Fa%ProjectName% /Fe%ProjectName% | ||||
| set Win32Flags=/FmWin32DTRenderer /FeWin32DTRenderer | ||||
| 
 | ||||
| REM Link libraries | ||||
| set LinkLibraries=user32.lib kernel32.lib gdi32.lib | ||||
| 
 | ||||
| REM incremental:no,   turn incremental builds off | ||||
| REM opt:ref,          try to remove functions from libs that are not referenced at all | ||||
| set LinkFlags=-incremental:no -opt:ref -subsystem:WINDOWS -machine:x64 -nologo | ||||
| 
 | ||||
| set DebugMode=1 | ||||
| 
 | ||||
| if %DebugMode%==1 goto :DebugFlags | ||||
| goto :ReleaseFlags | ||||
| 
 | ||||
| :DebugFlags | ||||
| REM Od     disables optimisations | ||||
| REM RTC1   runtime error checks, only possible with optimisations disabled | ||||
| set CompileFlags=%CompileFlags% -Od -RTC1 | ||||
| goto compile | ||||
| 
 | ||||
| :ReleaseFlags | ||||
| REM opt:icf,          COMDAT folding for debugging release build | ||||
| REM DEBUG:[FULL|NONE] enforce debugging for release build | ||||
| set CompileFlags=%CompileFlags% -O2 | ||||
| set LinkFlags=%LinkFlags% | ||||
| 
 | ||||
| REM //////////////////////////////////////////////////////////////////////////// | ||||
| REM Compile | ||||
| REM //////////////////////////////////////////////////////////////////////////// | ||||
| :compile | ||||
| REM Clean time necessary for hours <10, which produces  H:MM:SS.SS where the | ||||
| REM first character of time is an empty space. CleanTime will pad a 0 if | ||||
| REM necessary. | ||||
| set CleanTime=%time: =0% | ||||
| set TimeStamp=%date:~10,4%%date:~7,2%%date:~4,2%_%CleanTime:~0,2%%CleanTime:~3,2%%CleanTime:~6,2% | ||||
| 
 | ||||
| REM Link libraries | ||||
| set LinkLibraries=user32.lib kernel32.lib gdi32.lib | ||||
| 
 | ||||
| REM incremental:no, turn incremental builds off | ||||
| REM opt:ref,        try to remove functions from libs that are not referenced at all | ||||
| set LinkFlags=-incremental:no -opt:ref -subsystem:WINDOWS -machine:x64 -nologo | ||||
| 
 | ||||
| REM //////////////////////////////////////////////////////////////////////////// | ||||
| REM Compile | ||||
| REM //////////////////////////////////////////////////////////////////////////// | ||||
| del *.pdb >NUL 2>NUL | ||||
| cl %CompileFlags% %Win32Flags% ..\src\Win32DTRenderer.cpp /link %LinkLibraries% %LinkFlags% | ||||
| REM cl /P ..\src\Win32DTRenderer.cpp | ||||
| REM cl %CompileFlags% %DLLFlags%   ..\src\UnityBuild\UnityBuild.cpp /LD /link ..\src\external\easy\easy_profiler.lib /PDB:%ProjectName%_%TimeStamp%.pdb /export:DTR_Update %LinkFlags% | ||||
| cl %CompileFlags% %DLLFlags%  ..\src\UnityBuild\UnityBuild.cpp /LD /link /PDB:%ProjectName%_%TimeStamp%.pdb /export:DTR_Update %LinkFlags% | ||||
| 
 | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user