From d42d6ef5bf74b03724682c6028ce4387935faf6c Mon Sep 17 00:00:00 2001 From: Doyle Thai Date: Tue, 23 May 2017 22:42:54 +1000 Subject: [PATCH] Prepare triangle rendering for zbuffer support --- src/DTRenderer.cpp | 227 ++++++++++++++++++++++----------------- src/DTRendererDebug.cpp | 16 +-- src/DTRendererDebug.h | 35 ++++-- src/DTRendererRender.cpp | 61 +++++------ src/DTRendererRender.h | 30 +++--- src/Win32DTRenderer.cpp | 4 +- src/dqn.h | 18 ++-- 7 files changed, 221 insertions(+), 170 deletions(-) diff --git a/src/DTRenderer.cpp b/src/DTRenderer.cpp index a093cce..9e6d670 100644 --- a/src/DTRenderer.cpp +++ b/src/DTRenderer.cpp @@ -52,8 +52,9 @@ FILE_SCOPE bool ObjWavefrontLoad(const PlatformAPI api, PlatformMemory *const me if (!api.FileOpen(path, &file, PlatformFilePermissionFlag_Read)) return false; // TODO(doyle): Logging + // TODO(doyle): Make arrays use given memory not malloc DqnTempMemStack tmpMemRegion = DqnMemStack_BeginTempRegion(&memory->transMemStack); - u8 *rawBytes = (u8 *)DqnMemStack_Allocate(&memory->transMemStack, file.size); + u8 *rawBytes = (u8 *)DqnMemStack_Push(&memory->transMemStack, file.size); size_t bytesRead = api.FileRead(&file, rawBytes, file.size); size_t fileSize = file.size; api.FileClose(&file); @@ -284,7 +285,7 @@ FILE_SCOPE bool ObjWavefrontLoad(const PlatformAPI api, PlatformMemory *const me DQN_ASSERT(obj->model.groupNameIndex + 1 < DQN_ARRAY_COUNT(obj->model.groupName)); DQN_ASSERT(!obj->model.groupName[obj->model.groupNameIndex]); - obj->model.groupName[obj->model.groupNameIndex++] = (char *)DqnMemStack_Allocate( + obj->model.groupName[obj->model.groupNameIndex++] = (char *)DqnMemStack_Push( &memory->permMemStack, (nameLen + 1) * sizeof(char)); for (i32 i = 0; i < nameLen; i++) @@ -371,7 +372,7 @@ FILE_SCOPE bool BitmapFontCreate(const PlatformAPI api, return false; // TODO(doyle): Logging DqnTempMemStack tmpMemRegion = DqnMemStack_BeginTempRegion(&memory->transMemStack); - u8 *fontBuf = (u8 *)DqnMemStack_Allocate(&memory->transMemStack, file.size); + u8 *fontBuf = (u8 *)DqnMemStack_Push(&memory->transMemStack, file.size); size_t bytesRead = api.FileRead(&file, fontBuf, file.size); api.FileClose(&file); if (bytesRead != file.size) @@ -392,7 +393,7 @@ FILE_SCOPE bool BitmapFontCreate(const PlatformAPI api, //////////////////////////////////////////////////////////////////////////// // Pack font data to bitmap //////////////////////////////////////////////////////////////////////////// - loadedFont.bitmap = (u8 *)DqnMemStack_Allocate( + loadedFont.bitmap = (u8 *)DqnMemStack_Push( &memory->permMemStack, (size_t)(loadedFont.bitmapDim.w * loadedFont.bitmapDim.h)); @@ -405,7 +406,7 @@ FILE_SCOPE bool BitmapFontCreate(const PlatformAPI api, i32 numCodepoints = (i32)((codepointRange.max + 1) - codepointRange.min); - loadedFont.atlas = (stbtt_packedchar *)DqnMemStack_Allocate( + loadedFont.atlas = (stbtt_packedchar *)DqnMemStack_Push( &memory->permMemStack, numCodepoints * sizeof(stbtt_packedchar)); stbtt_PackFontRange(&fontPackContext, fontBuf, 0, STBTT_POINT_SIZE(sizeInPt), (i32)codepointRange.min, @@ -463,7 +464,7 @@ FILE_SCOPE bool BitmapLoad(const PlatformAPI api, DTRBitmap *bitmap, DqnTempMemStack tempBuffer = DqnMemStack_BeginTempRegion(transMemStack); { u8 *const rawData = - (u8 *)DqnMemStack_Allocate(transMemStack, file.size); + (u8 *)DqnMemStack_Push(transMemStack, file.size); size_t bytesRead = api.FileRead(&file, rawData, file.size); api.FileClose(&file); @@ -511,7 +512,7 @@ FILE_SCOPE bool BitmapLoad(const PlatformAPI api, DTRBitmap *bitmap, } // #include -void CompAssignment(PlatformRenderBuffer *const renderBuffer, PlatformInput *const input, +void CompAssignment(DTRRenderBuffer *const renderBuffer, PlatformInput *const input, PlatformMemory *const memory) { #if 1 @@ -1441,10 +1442,13 @@ FILE_SCOPE void TestStrToF32Converter() DQN_ASSERT(DQN_ABS(vQ) - DQN_ABS(9.64635e-05) < EPSILON); } -extern "C" void DTR_Update(PlatformRenderBuffer *const renderBuffer, +extern "C" void DTR_Update(PlatformRenderBuffer *const platformRenderBuffer, PlatformInput *const input, PlatformMemory *const memory) { + //////////////////////////////////////////////////////////////////////////// + // Initialisation + //////////////////////////////////////////////////////////////////////////// DTRState *state = (DTRState *)memory->context; if (input->executableReloaded) { @@ -1463,7 +1467,7 @@ extern "C" void DTR_Update(PlatformRenderBuffer *const renderBuffer, memory->isInit = true; memory->context = - DqnMemStack_Allocate(&memory->permMemStack, sizeof(DTRState)); + DqnMemStack_Push(&memory->permMemStack, sizeof(DTRState)); DQN_ASSERT(memory->context); state = (DTRState *)memory->context; @@ -1473,126 +1477,149 @@ extern "C" void DTR_Update(PlatformRenderBuffer *const renderBuffer, &memory->transMemStack); DTRBitmap test = {}; - DqnTempMemStack tmp = DqnMemStack_BeginTempRegion(&memory->permMemStack); + DqnTempMemStack tmp = DqnMemStack_BeginTempRegion(&memory->transMemStack); BitmapLoad(input->api, &test, "byte_read_check.bmp", &memory->transMemStack); DqnMemStack_EndTempRegion(tmp); DQN_ASSERT(ObjWavefrontLoad(input->api, memory, "african_head.obj", &state->obj)); } - DTRRender_Clear(renderBuffer, DqnV3_3f(0.0f, 0.0f, 0.0f)); - const DqnV3 LIGHT = DqnV3_3i(0, 0, -1); - const f32 MODEL_SCALE = DQN_MIN(renderBuffer->width, renderBuffer->height) * 0.5f; - WavefrontObj *const waveObj = &state->obj; - DqnV2 modelP = DqnV2_2f(renderBuffer->width * 0.5f, renderBuffer->height * 0.5f); + DqnTempMemStack transMemTmpRegion = DqnMemStack_BeginTempRegion(&memory->transMemStack); - for (i32 i = 0; i < waveObj->model.faces.count; i++) + DTRRenderBuffer renderBuffer = {}; + renderBuffer.width = platformRenderBuffer->width; + renderBuffer.height = platformRenderBuffer->height; + renderBuffer.bytesPerPixel = platformRenderBuffer->bytesPerPixel; + renderBuffer.memory = (u8 *)platformRenderBuffer->memory; + renderBuffer.zBuffer = (f32 *)DqnMemStack_Push( + &memory->transMemStack, + platformRenderBuffer->width * platformRenderBuffer->height * sizeof(*renderBuffer.zBuffer)); + + //////////////////////////////////////////////////////////////////////////// + // 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; + + // Triangle Drawing { - WavefrontModelFace face = waveObj->model.faces.data[i]; - DQN_ASSERT(face.vertexArray.count == 3); - i32 vertAIndex = face.vertexArray.data[0]; - i32 vertBIndex = face.vertexArray.data[1]; - i32 vertCIndex = face.vertexArray.data[2]; + DqnV4 redTransparent = DqnV4_4f(1, 0, 0, 0.5f); - DqnV4 vertA = waveObj->geometryArray.data[vertAIndex]; - DqnV4 vertB = waveObj->geometryArray.data[vertBIndex]; - DqnV4 vertC = waveObj->geometryArray.data[vertCIndex]; + 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)}; - DqnV4 vertAB = vertB - vertA; - DqnV4 vertAC = vertC - vertA; - DqnV3 normal = DqnV3_Cross(vertAC.xyz, vertAB.xyz); + DTRRenderTransform rotatingXform = DTRRender_DefaultTriangleTransform(); + rotatingXform.rotation = rotation; - f32 intensity = DqnV3_Dot(DqnV3_Normalise(normal), LIGHT); - if (intensity > 0) + 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); + + //////////////////////////////////////////////////////////////////////// + // Draw Loaded Model + //////////////////////////////////////////////////////////////////////// + const DqnV3 LIGHT = DqnV3_3i(0, 0, -1); + const f32 MODEL_SCALE = DQN_MIN(renderBuffer.width, renderBuffer.height) * 0.5f; + WavefrontObj *const waveObj = &state->obj; + DqnV3 modelP = DqnV3_3f(renderBuffer.width * 0.5f, renderBuffer.height * 0.5f, 0); + + for (i32 i = 0; i < waveObj->model.faces.count; i++) { - DqnV4 modelCol = DqnV4_4f(1, 1, 1, 1); - modelCol.rgb *= intensity; + WavefrontModelFace face = waveObj->model.faces.data[i]; + DQN_ASSERT(face.vertexArray.count == 3); + i32 vertAIndex = face.vertexArray.data[0]; + i32 vertBIndex = face.vertexArray.data[1]; + i32 vertCIndex = face.vertexArray.data[2]; - DqnV2 screenVertA = (vertA.xy * MODEL_SCALE) + modelP; - DqnV2 screenVertB = (vertB.xy * MODEL_SCALE) + modelP; - DqnV2 screenVertC = (vertC.xy * MODEL_SCALE) + modelP; + DqnV4 vertA = waveObj->geometryArray.data[vertAIndex]; + DqnV4 vertB = waveObj->geometryArray.data[vertBIndex]; + DqnV4 vertC = waveObj->geometryArray.data[vertCIndex]; - // TODO(doyle): Why do we need rounding here? Maybe it's because - // I don't do any interpolation in the triangle routine for jagged - // edges. - screenVertA.x = (f32)(i32)(screenVertA.x + 0.5f); - screenVertA.y = (f32)(i32)(screenVertA.y + 0.5f); - screenVertB.x = (f32)(i32)(screenVertB.x + 0.5f); - screenVertB.y = (f32)(i32)(screenVertB.y + 0.5f); - screenVertC.x = (f32)(i32)(screenVertC.x + 0.5f); - screenVertC.y = (f32)(i32)(screenVertC.y + 0.5f); + DqnV4 vertAB = vertB - vertA; + DqnV4 vertAC = vertC - vertA; + DqnV3 normal = DqnV3_Cross(vertAC.xyz, vertAB.xyz); - DTRRender_Triangle(renderBuffer, screenVertA, screenVertB, screenVertC, modelCol); + f32 intensity = DqnV3_Dot(DqnV3_Normalise(normal), LIGHT); + if (intensity > 0) + { + DqnV4 modelCol = DqnV4_4f(1, 1, 1, 1); + modelCol.rgb *= intensity; + + DqnV3 screenVA = (vertA.xyz * MODEL_SCALE) + modelP; + DqnV3 screenVB = (vertB.xyz * MODEL_SCALE) + modelP; + DqnV3 screenVC = (vertC.xyz * MODEL_SCALE) + modelP; + + // TODO(doyle): Why do we need rounding here? Maybe it's because + // I don't do any interpolation in the triangle routine for jagged + // edges. + screenVA.x = (f32)(i32)(screenVA.x + 0.5f); + screenVA.y = (f32)(i32)(screenVA.y + 0.5f); + screenVB.x = (f32)(i32)(screenVB.x + 0.5f); + screenVB.y = (f32)(i32)(screenVB.y + 0.5f); + screenVC.x = (f32)(i32)(screenVC.x + 0.5f); + screenVC.y = (f32)(i32)(screenVC.y + 0.5f); + + DTRRender_Triangle(&renderBuffer, screenVA, screenVB, screenVC, modelCol); #if 0 - DqnV4 wireColor = DqnV4_1f(1.0f); - for (i32 j = 0; j < 3; j++) - { - DTRRender_Line(renderBuffer, DqnV2i_V2(screenVertA), DqnV2i_V2(screenVertB), wireColor); - } + DqnV4 wireColor = DqnV4_1f(1.0f); + for (i32 j = 0; j < 3; j++) + { + DTRRender_Line(renderBuffer, DqnV2i_V2(screenVertA), DqnV2i_V2(screenVertB), wireColor); + } #endif + } } } -#if 1 - DqnV4 colorRed = DqnV4_4f(0.8f, 0, 0, 1); - DqnV2i bufferMidP = - DqnV2i_2f(renderBuffer->width * 0.5f, renderBuffer->height * 0.5f); - i32 boundsOffset = 100; - - DqnV2 t0[3] = {DqnV2_2i(10, 70), DqnV2_2i(50, 160), DqnV2_2i(70, 80)}; - DqnV2 t1[3] = {DqnV2_2i(180, 50), DqnV2_2i(150, 1), DqnV2_2i(70, 180)}; - DqnV2 t2[3] = {DqnV2_2i(180, 150), DqnV2_2i(120, 160), DqnV2_2i(130, 180)}; - LOCAL_PERSIST DqnV2 t3[3] = { - DqnV2_2i(boundsOffset, boundsOffset), - DqnV2_2i(bufferMidP.w, renderBuffer->height - boundsOffset), - DqnV2_2i(renderBuffer->width - boundsOffset, boundsOffset)}; - - DTRRender_Triangle(renderBuffer, t0[0], t0[1], t0[2], colorRed); - DTRRender_Triangle(renderBuffer, t1[0], t1[1], t1[2], colorRed); - DTRRender_Triangle(renderBuffer, t2[0], t2[1], t2[2], colorRed); - - DqnV2 t4[3] = {DqnV2_2i(100, 150), DqnV2_2i(200, 150), DqnV2_2i(200, 250)}; - DqnV2 t5[3] = {DqnV2_2i(300, 150), DqnV2_2i(201, 150), DqnV2_2i(200, 250)}; - DTRRender_Triangle(renderBuffer, t4[0], t4[1], t4[2], colorRed); - DTRRender_Triangle(renderBuffer, t5[0], t5[1], t5[2], colorRed); - - DqnV4 colorRedHalfA = DqnV4_4f(1, 0, 0, 0.1f); - LOCAL_PERSIST f32 rotation = 0; - rotation += input->deltaForFrame * 0.25f; - - DTRRenderTransform defaultTransform = DTRRender_DefaultTransform(); - defaultTransform.rotation = rotation + 45; - - DTRRender_Rectangle(renderBuffer, DqnV2_1f(300.0f), DqnV2_1f(300 + 100.0f), DqnV4_4f(0, 1.0f, 1.0f, 1.0f), - defaultTransform); - - // Rotating triangle + // Rect drawing { - DTRRenderTransform triTransform = DTRRender_DefaultTriangleTransform(); - triTransform.rotation = rotation; - DTRRender_Triangle(renderBuffer, t3[0], t3[1], t3[2], colorRedHalfA, triTransform); + 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 + { + DTRRenderTransform transform = DTRRender_DefaultTransform(); + transform.scale = DqnV2_1f(2.0f); - DqnV2 fontP = DqnV2_2i(200, 180); - DTRRender_Text(renderBuffer, state->font, fontP, "hello world!", DqnV4_4f(0, 0, 0, 1)); + LOCAL_PERSIST DqnV2 bitmapP = DqnV2_2f(300, 250); + bitmapP.x += 3.0f * sinf((f32)input->timeNowInS * 0.5f); - DTRRenderTransform transform = DTRRender_DefaultTransform(); - transform.rotation = 0; - transform.scale = DqnV2_1f(2.0f); - - LOCAL_PERSIST DqnV2 bitmapP = DqnV2_2f(300, 250); - bitmapP.x += 3.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); + 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_Update(state, renderBuffer, input, memory); + + DTRDebug_Update(state, &renderBuffer, input, memory); + + //////////////////////////////////////////////////////////////////////////// + // End Update + //////////////////////////////////////////////////////////////////////////// + DqnMemStack_EndTempRegion(transMemTmpRegion); + DQN_ASSERT(memory->transMemStack.tempStackCount == 0); + DQN_ASSERT(memory->permMemStack.tempStackCount == 0); } diff --git a/src/DTRendererDebug.cpp b/src/DTRendererDebug.cpp index f1f7789..edca02e 100644 --- a/src/DTRendererDebug.cpp +++ b/src/DTRendererDebug.cpp @@ -54,8 +54,8 @@ FILE_SCOPE void PushMemStackText(const char *const name, size_t totalWastedKb = totalWasted / 1024; char str[128] = {}; - Dqn_sprintf(str, "%s: %d block(s): %_$lld/%_$lld", name, numBlocks, - totalUsed, totalSize); + Dqn_sprintf(str, "%s: %d block(s): %_$lld/%_$lld: wasted: %_$lld", name, numBlocks, + totalUsed, totalSize, totalWastedKb); DTRRender_Text(globalDebug.renderBuffer, *globalDebug.font, globalDebug.displayP, str, globalDebug.displayColor); @@ -64,7 +64,7 @@ FILE_SCOPE void PushMemStackText(const char *const name, } void DTRDebug_Update(DTRState *const state, - PlatformRenderBuffer *const renderBuffer, + DTRRenderBuffer *const renderBuffer, PlatformInput *const input, PlatformMemory *const memory) { if (DTR_DEBUG) @@ -80,11 +80,13 @@ void DTRDebug_Update(DTRState *const state, DQN_ASSERT(globalDebug.displayYOffset < 0); } - debug->totalSetPixels += debug->setPixelsPerFrame; + debug->totalSetPixels += debug->counter[DTRDebugCounter_SetPixels]; debug->totalSetPixels = DQN_MAX(0, debug->totalSetPixels); DTRDebug_PushText("TotalSetPixels: %'lld", debug->totalSetPixels); - DTRDebug_PushText("SetPixelsPerFrame: %'lld", debug->setPixelsPerFrame); + DTRDebug_PushText("SetPixelsPerFrame: %'lld", debug->counter[DTRDebugCounter_SetPixels]); + DTRDebug_PushText("TrianglesRendered: %'lld", debug->counter[DTRDebugCounter_RenderTriangle]); + DTRDebug_PushText(""); // memory { @@ -94,9 +96,11 @@ void DTRDebug_Update(DTRState *const state, DTRDebug_PushText("SSE2Support: %s", (input->canUseSSE2) ? "true" : "false"); - debug->setPixelsPerFrame = 0; debug->displayP = DqnV2_2i(0, debug->renderBuffer->height + globalDebug.displayYOffset); + + for (i32 i = 0; i < DQN_ARRAY_COUNT(debug->counter); i++) + debug->counter[i] = 0; } } diff --git a/src/DTRendererDebug.h b/src/DTRendererDebug.h index a41f87c..1a446f6 100644 --- a/src/DTRendererDebug.h +++ b/src/DTRendererDebug.h @@ -30,22 +30,29 @@ #endif -typedef struct PlatformRenderBuffer PlatformRenderBuffer; -typedef struct DTRFont DTRFont; -typedef struct DTRState DTRState; -typedef struct PlatformInput PlatformInput; -typedef struct PlatformMemory PlatformMemory; +typedef struct DTRRenderBuffer DTRRenderBuffer; +typedef struct DTRFont DTRFont; +typedef struct DTRState DTRState; +typedef struct PlatformInput PlatformInput; +typedef struct PlatformMemory PlatformMemory; + +enum DTRDebugCounter +{ + DTRDebugCounter_SetPixels, + DTRDebugCounter_RenderTriangle, + DTRDebugCounter_Count, +}; typedef struct DTRDebug { - DTRFont *font; - PlatformRenderBuffer *renderBuffer; + DTRFont *font; + DTRRenderBuffer *renderBuffer; DqnV4 displayColor; DqnV2 displayP; i32 displayYOffset; - u64 setPixelsPerFrame; + u64 counter[DTRDebugCounter_Count]; u64 totalSetPixels; } DTRDebug; @@ -53,6 +60,16 @@ extern DTRDebug globalDebug; void DTRDebug_PushText(const char *const formatStr, ...); void DTRDebug_Update(DTRState *const state, - PlatformRenderBuffer *const renderBuffer, + DTRRenderBuffer *const renderBuffer, PlatformInput *const input, PlatformMemory *const memory); + +void inline DTRDebug_CounterIncrement(enum DTRDebugCounter tag) +{ + if (DTR_DEBUG) + { + DQN_ASSERT(tag >= 0 && tag < DTRDebugCounter_Count); + globalDebug.counter[tag]++; + } +} + #endif diff --git a/src/DTRendererRender.cpp b/src/DTRendererRender.cpp index 2fa5006..a5b7169 100644 --- a/src/DTRendererRender.cpp +++ b/src/DTRendererRender.cpp @@ -99,7 +99,7 @@ inline DqnV4 DTRRender_PreMultiplyAlphaSRGB1WithLinearConversion(DqnV4 color) } // IMPORTANT(doyle): Color is expected to be premultiplied already -FILE_SCOPE inline void SetPixel(PlatformRenderBuffer *const renderBuffer, 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) { if (!renderBuffer) return; @@ -166,10 +166,10 @@ FILE_SCOPE inline void SetPixel(PlatformRenderBuffer *const renderBuffer, const (u32)(destB) << 0; bitmapPtr[x + (y * pitchInU32)] = pixel; - globalDebug.setPixelsPerFrame++; + DTRDebug_CounterIncrement(DTRDebugCounter_SetPixels); } -void DTRRender_Text(PlatformRenderBuffer *const renderBuffer, +void DTRRender_Text(DTRRenderBuffer *const renderBuffer, const DTRFont font, DqnV2 pos, const char *const text, DqnV4 color, i32 len) { @@ -267,7 +267,7 @@ FILE_SCOPE void TransformPoints(const DqnV2 origin, DqnV2 *const pList, } } -void DTRRender_Line(PlatformRenderBuffer *const renderBuffer, DqnV2i a, +void DTRRender_Line(DTRRenderBuffer *const renderBuffer, DqnV2i a, DqnV2i b, DqnV4 color) { if (!renderBuffer) return; @@ -387,7 +387,7 @@ FILE_SCOPE DqnRect GetBoundingBox(const DqnV2 *const pList, const i32 numP) return result; } -void DTRRender_Rectangle(PlatformRenderBuffer *const renderBuffer, DqnV2 min, DqnV2 max, +void DTRRender_Rectangle(DTRRenderBuffer *const renderBuffer, DqnV2 min, DqnV2 max, DqnV4 color, const DTRRenderTransform transform) { DTR_DEBUG_TIMED_FUNCTION(); @@ -484,7 +484,7 @@ void DTRRender_Rectangle(PlatformRenderBuffer *const renderBuffer, DqnV2 min, Dq } } -void DTRRender_Triangle(PlatformRenderBuffer *const renderBuffer, DqnV2 p1, DqnV2 p2, DqnV2 p3, +void DTRRender_Triangle(DTRRenderBuffer *const renderBuffer, DqnV3 p1, DqnV3 p2, DqnV3 p3, DqnV4 color, const DTRRenderTransform transform) { DTR_DEBUG_TIMED_FUNCTION(); @@ -492,17 +492,18 @@ void DTRRender_Triangle(PlatformRenderBuffer *const renderBuffer, DqnV2 p1, DqnV //////////////////////////////////////////////////////////////////////////// // Transform vertexes //////////////////////////////////////////////////////////////////////////// - DqnV2 p1p2 = p2 - p1; - DqnV2 p1p3 = p3 - p1; - DqnV2 p1p2Anchored = p1p2 * transform.anchor; - DqnV2 p1p3Anchored = p1p3 * transform.anchor; + DqnV3 p1p2 = p2 - p1; + DqnV3 p1p3 = p3 - p1; - DqnV2 origin = p1 + p1p2Anchored + p1p3Anchored; - DqnV2 pList[3] = {p1 - origin, p2 - origin, p3 - origin}; + // TODO(doyle): Transform is only in 2d right now + DqnV2 p1p2Anchored = p1p2.xy * transform.anchor; + DqnV2 p1p3Anchored = p1p3.xy * transform.anchor; + DqnV2 origin = p1.xy + p1p2Anchored + p1p3Anchored; + DqnV2 pList[3] = {p1.xy - origin, p2.xy - origin, p3.xy - origin}; TransformPoints(origin, pList, DQN_ARRAY_COUNT(pList), transform.scale, transform.rotation); - p1 = pList[0]; - p2 = pList[1]; - p3 = pList[2]; + p1.xy = pList[0]; + p2.xy = pList[1]; + p3.xy = pList[2]; color = DTRRender_SRGB1ToLinearSpaceV4(color); color = PreMultiplyAlpha1(color); @@ -625,12 +626,12 @@ void DTRRender_Triangle(PlatformRenderBuffer *const renderBuffer, DqnV2 p1, DqnV if (area2Times > 0) { // Clockwise swap any point to make it clockwise - DQN_SWAP(DqnV2, p2, p3); + DQN_SWAP(DqnV3, p2, p3); } - const DqnV2 a = p1; - const DqnV2 b = p2; - const DqnV2 c = p3; + const DqnV3 a = p1; + const DqnV3 b = p2; + const DqnV3 c = p3; DqnV2i startP = min; f32 signedArea1 = ((b.x - a.x) * (startP.y - a.y)) - ((b.y - a.y) * (startP.x - a.x)); @@ -678,6 +679,7 @@ void DTRRender_Triangle(PlatformRenderBuffer *const renderBuffer, DqnV2 p1, DqnV //////////////////////////////////////////////////////////////////////////// // Debug //////////////////////////////////////////////////////////////////////////// + DTRDebug_CounterIncrement(DTRDebugCounter_RenderTriangle); if (DTR_DEBUG_RENDER) { // Draw Bounding box @@ -704,14 +706,14 @@ void DTRRender_Triangle(PlatformRenderBuffer *const renderBuffer, DqnV2 p1, DqnV DqnV4 blue = DqnV4_4f(0, 0, 1, 1); DqnV4 purple = DqnV4_4f(1, 0, 1, 1); - DTRRender_Rectangle(renderBuffer, p1 - DqnV2_1f(5), p1 + DqnV2_1f(5), green); - DTRRender_Rectangle(renderBuffer, p2 - DqnV2_1f(5), p2 + DqnV2_1f(5), blue); - DTRRender_Rectangle(renderBuffer, p3 - DqnV2_1f(5), p3 + DqnV2_1f(5), purple); + DTRRender_Rectangle(renderBuffer, p1.xy - DqnV2_1f(5), p1.xy + DqnV2_1f(5), green); + DTRRender_Rectangle(renderBuffer, p2.xy - DqnV2_1f(5), p2.xy + DqnV2_1f(5), blue); + DTRRender_Rectangle(renderBuffer, p3.xy - DqnV2_1f(5), p3.xy + DqnV2_1f(5), purple); } } } -void DTRRender_Bitmap(PlatformRenderBuffer *const renderBuffer, +void DTRRender_Bitmap(DTRRenderBuffer *const renderBuffer, DTRBitmap *const bitmap, DqnV2 pos, const DTRRenderTransform transform, DqnV4 color) { @@ -723,7 +725,6 @@ void DTRRender_Bitmap(PlatformRenderBuffer *const renderBuffer, //////////////////////////////////////////////////////////////////////////// DqnV2 min = pos; DqnV2 max = min + DqnV2_V2i(bitmap->dim); - DTRDebug_PushText("OldRect: (%5.2f, %5.2f), (%5.2f, %5.2f)", min.x, min.y, max.x, max.y); RectPoints rectPoints = TransformRectPoints(min, max, transform); const DqnV2 *const pList = &rectPoints.pList[0]; @@ -748,16 +749,12 @@ void DTRRender_Bitmap(PlatformRenderBuffer *const renderBuffer, DqnRect clippedDrawRect = DqnRect_ClipRect(drawRect, clip); DqnV2 clippedSize = DqnRect_GetSizeV2(clippedDrawRect); - - DTRDebug_PushText("ClippedRect: (%5.2f, %5.2f), (%5.2f, %5.2f)", clippedDrawRect.min.x, clippedDrawRect.min.y, clippedDrawRect.max.x, clippedDrawRect.max.y); - DTRDebug_PushText("ClippedSize: (%5.2f, %5.2f)", clippedSize.w, clippedSize.h); - DTRDebug_PushText("DrawRect: (%5.2f, %5.2f), (%5.2f, %5.2f)", drawRect.min.x, drawRect.min.y, drawRect.max.x, drawRect.max.y); - const i32 pitch = bitmap->dim.w * bitmap->bytesPerPixel; - u8 *const bitmapPtr = (u8 *)bitmap->memory; - //////////////////////////////////////////////////////////////////////////// // Setup Texture Mapping //////////////////////////////////////////////////////////////////////////// + const i32 pitch = bitmap->dim.w * bitmap->bytesPerPixel; + u8 *const bitmapPtr = (u8 *)bitmap->memory; + const DqnV2 rectBasis = pList[RectPointsIndex_Basis]; const DqnV2 xAxisRelToBasis = pList[RectPointsIndex_XAxis] - rectBasis; const DqnV2 yAxisRelToBasis = pList[RectPointsIndex_YAxis] - rectBasis; @@ -945,7 +942,7 @@ void DTRRender_Bitmap(PlatformRenderBuffer *const renderBuffer, } } -void DTRRender_Clear(PlatformRenderBuffer *const renderBuffer, +void DTRRender_Clear(DTRRenderBuffer *const renderBuffer, DqnV3 color) { if (!renderBuffer) return; diff --git a/src/DTRendererRender.h b/src/DTRendererRender.h index 307cb21..c37d1c8 100644 --- a/src/DTRendererRender.h +++ b/src/DTRendererRender.h @@ -5,12 +5,23 @@ #define DTRRENDER_INV_255 1.0f/255.0f -typedef struct PlatformRenderBuffer PlatformRenderBuffer; +typedef struct DTRRenderBuffer DTRRenderBuffer; typedef struct DTRBitmap DTRBitmap; //////////////////////////////////////////////////////////////////////////////////////////////////// // Utility //////////////////////////////////////////////////////////////////////////////////////////////////// +typedef struct DTRRenderBuffer +{ + i32 width; + i32 height; + i32 bytesPerPixel; + + u8 *memory; // Format: XX RR GG BB, and has (width * height * bytesPerPixels) elements + f32 *zBuffer; // zBuffer has (width * height) elements + +} DTRRenderBuffer; + typedef struct DTRRenderTransform { f32 rotation = 0; // Rotation in degrees @@ -48,16 +59,11 @@ inline DqnV4 DTRRender_PreMultiplyAlphaSRGB1WithLinearConversion(DqnV4 color); //////////////////////////////////////////////////////////////////////////////////////////////////// // 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 (PlatformRenderBuffer *const renderBuffer, const DTRFont font, DqnV2 pos, const char *const text, DqnV4 color = DqnV4_1f(1), i32 len = -1); - -void DTRRender_Line (PlatformRenderBuffer *const renderBuffer, DqnV2i a, DqnV2i b, DqnV4 color); - -void DTRRender_Rectangle(PlatformRenderBuffer *const renderBuffer, DqnV2 min, DqnV2 max, DqnV4 color, const DTRRenderTransform transform = DTRRender_DefaultTransform()); - -void DTRRender_Triangle (PlatformRenderBuffer *const renderBuffer, DqnV2 p1, DqnV2 p2, DqnV2 p3, DqnV4 color, const DTRRenderTransform transform = DTRRender_DefaultTriangleTransform()); - -void DTRRender_Bitmap (PlatformRenderBuffer *const renderBuffer, DTRBitmap *const bitmap, DqnV2 pos, const DTRRenderTransform transform = DTRRender_DefaultTransform(), DqnV4 color = DqnV4_4f(1, 1, 1, 1)); - -void DTRRender_Clear (PlatformRenderBuffer *const renderBuffer, 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_Triangle (DTRRenderBuffer *const renderBuffer, DqnV3 p1, DqnV3 p2, DqnV3 p3, 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 diff --git a/src/Win32DTRenderer.cpp b/src/Win32DTRenderer.cpp index 850e14a..985df9f 100644 --- a/src/Win32DTRenderer.cpp +++ b/src/Win32DTRenderer.cpp @@ -502,8 +502,8 @@ int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, //////////////////////////////////////////////////////////////////////////// // Platform Data Pre-amble //////////////////////////////////////////////////////////////////////////// - DQN_ASSERT(DqnMemStack_Init(&globalPlatformMemory.permMemStack, DQN_MEGABYTE(1), true, 4) && - DqnMemStack_Init(&globalPlatformMemory.transMemStack, DQN_MEGABYTE(1), true, 4)); + DQN_ASSERT(DqnMemStack_Init(&globalPlatformMemory.permMemStack, DQN_MEGABYTE(4), true, 4) && + DqnMemStack_Init(&globalPlatformMemory.transMemStack, DQN_MEGABYTE(4), true, 4)); PlatformAPI platformAPI = {}; platformAPI.FileOpen = Platform_FileOpen; diff --git a/src/dqn.h b/src/dqn.h index 8a005ac..38965dc 100644 --- a/src/dqn.h +++ b/src/dqn.h @@ -75,7 +75,7 @@ DQN_FILE_SCOPE void DqnMem_Free (void *memory); // When an allocation requires a larger amount of memory than available in the // block then the MemStack will allocate a new block of sufficient size for -// you in DqnMemStack_Allocate(..). This _DOES_ mean that there will be wasted +// you in DqnMemStack_Push(..). This _DOES_ mean that there will be wasted // space at the end of each block and is a tradeoff for memory locality against // optimal space usage. @@ -88,7 +88,7 @@ DQN_FILE_SCOPE void DqnMem_Free (void *memory); // - InitWithFixedSize() allows you to to disable dynamic allocations and // sub-allocate from the initial MemStack allocation size only. -// 2. Use DqnMemStack_Allocate(..) to allocate memory for use. +// 2. Use DqnMemStack_Push(..) to allocate memory for use. // - "Freeing" memory is dealt by creating temporary MemStacks or using the // BeginTempRegion and EndTempRegion functions. Specifically freeing // individual items is typically not generalisable in this scheme. @@ -129,12 +129,12 @@ DQN_FILE_SCOPE bool DqnMemStack_InitWithFixedMem (DqnMemStack *const stack, u8 * DQN_FILE_SCOPE bool DqnMemStack_InitWithFixedSize(DqnMemStack *const stack, size_t size, const bool zeroClear, const u32 byteAlign = 4); // Single allocation from platform, no further allocations, returns NULL of allocate if out of space DQN_FILE_SCOPE bool DqnMemStack_Init (DqnMemStack *const stack, size_t size, const bool zeroClear, const u32 byteAlign = 4); // Allocates from platform dynamically as space runs out -DQN_FILE_SCOPE void *DqnMemStack_Allocate (DqnMemStack *const stack, size_t size); // Returns NULL if out of space and stack is using fixed memory/size, or platform allocation fails -DQN_FILE_SCOPE bool DqnMemStack_Pop (DqnMemStack *const stack, void *ptr, size_t size); // Frees the given ptr. It MUST be the last allocated item in the stack -DQN_FILE_SCOPE void DqnMemStack_Free (DqnMemStack *const stack); // Frees all blocks belonging to this stack -DQN_FILE_SCOPE bool DqnMemStack_FreeStackBlock (DqnMemStack *const stack, DqnMemStackBlock *block); // Frees the specified block, returns false if block doesn't belong -DQN_FILE_SCOPE bool DqnMemStack_FreeLastBlock (DqnMemStack *const stack); // Frees the last-most memory block. If last block, free that block, next allocate will attach a block. -DQN_FILE_SCOPE void DqnMemStack_ClearCurrBlock (DqnMemStack *const stack, const bool zeroClear); // Reset the current memory block usage to 0 +DQN_FILE_SCOPE void *DqnMemStack_Push (DqnMemStack *const stack, size_t size); // Returns NULL if out of space and stack is using fixed memory/size, or platform allocation fails +DQN_FILE_SCOPE bool DqnMemStack_Pop (DqnMemStack *const stack, void *ptr, size_t size); // Frees the given ptr. It MUST be the last allocated item in the stack +DQN_FILE_SCOPE void DqnMemStack_Free (DqnMemStack *const stack); // Frees all blocks belonging to this stack +DQN_FILE_SCOPE bool DqnMemStack_FreeStackBlock(DqnMemStack *const stack, DqnMemStackBlock *block); // Frees the specified block, returns false if block doesn't belong +DQN_FILE_SCOPE bool DqnMemStack_FreeLastBlock (DqnMemStack *const stack); // Frees the last-most memory block. If last block, free that block, next allocate will attach a block. +DQN_FILE_SCOPE void DqnMemStack_ClearCurrBlock(DqnMemStack *const stack, const bool zeroClear); // Reset the current memory block usage to 0 // TempMemStack is only required for the function. Once BeginTempRegion() is called, subsequent allocation calls can be made using the original stack. // Upon EndTempRegion() the original stack will free any additional blocks it allocated during the temp region and revert to the original @@ -1453,7 +1453,7 @@ DQN_FILE_SCOPE bool DqnMemStack_InitWithFixedSize(DqnMemStack *const stack, return false; } -DQN_FILE_SCOPE void *DqnMemStack_Allocate(DqnMemStack *const stack, size_t size) +DQN_FILE_SCOPE void *DqnMemStack_Push(DqnMemStack *const stack, size_t size) { if (!stack || size == 0) return NULL;