Compare commits
1 Commits
Author | SHA1 | Date | |
---|---|---|---|
371ece0ce3 |
@ -11,7 +11,7 @@
|
|||||||
PlatformFlags globalDTRPlatformFlags;
|
PlatformFlags globalDTRPlatformFlags;
|
||||||
|
|
||||||
// #include <algorithm>
|
// #include <algorithm>
|
||||||
void CompAssignment(DTRRenderContext renderContext, PlatformInput *const input,
|
void CompAssignment(DTRRenderBuffer *const renderBuffer, PlatformInput *const input,
|
||||||
PlatformMemory *const memory)
|
PlatformMemory *const memory)
|
||||||
{
|
{
|
||||||
#if 1
|
#if 1
|
||||||
@ -835,11 +835,11 @@ void CompAssignment(DTRRenderContext renderContext, PlatformInput *const input,
|
|||||||
#if 1
|
#if 1
|
||||||
char pText[32] = {};
|
char pText[32] = {};
|
||||||
Dqn_sprintf(pText, "(%1.0f, %1.0f)", origP.x, origP.y);
|
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,
|
DqnV2_2f(p.x + radius.x + 5, p.y - (state->font.sizeInPt * 0.40f)), pText,
|
||||||
textColor);
|
textColor);
|
||||||
#endif
|
#endif
|
||||||
DTRRender_Rectangle(renderContext, p - radius, p + radius, pColor);
|
DTRRender_Rectangle(renderBuffer, p - radius, p + radius, pColor);
|
||||||
}
|
}
|
||||||
|
|
||||||
DqnV2 halfRadius = radius * 0.5f;
|
DqnV2 halfRadius = radius * 0.5f;
|
||||||
@ -851,10 +851,10 @@ void CompAssignment(DTRRenderContext renderContext, PlatformInput *const input,
|
|||||||
|
|
||||||
char pText[32] = {};
|
char pText[32] = {};
|
||||||
Dqn_sprintf(pText, "(%1.0f, %1.0f)", origP.x, origP.y);
|
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,
|
DqnV2_2f(p.x + radius.x + 5, p.y - (state->font.sizeInPt * 0.40f)), pText,
|
||||||
textColor);
|
textColor);
|
||||||
DTRRender_Rectangle(renderContext, p - radius, p + radius, pColor);
|
DTRRender_Rectangle(renderBuffer, p - radius, p + radius, pColor);
|
||||||
|
|
||||||
if (i + 1 <= skyPIndex && i > 0)
|
if (i + 1 <= skyPIndex && i > 0)
|
||||||
{
|
{
|
||||||
@ -863,7 +863,7 @@ void CompAssignment(DTRRenderContext renderContext, PlatformInput *const input,
|
|||||||
|
|
||||||
DqnV2 pMid = p + halfRadius;
|
DqnV2 pMid = p + halfRadius;
|
||||||
DqnV2 prevPMid = prevP + 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));
|
DqnV4_4f(255, 0, 0, 255));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -895,23 +895,18 @@ extern "C" void DTR_Update(PlatformRenderBuffer *const platformRenderBuffer,
|
|||||||
state = (DTRState *)memory->context;
|
state = (DTRState *)memory->context;
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////
|
||||||
// Init
|
// Init Memory Stacks
|
||||||
////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////
|
||||||
DqnMemStack *const assetStack = &memory->assetStack;
|
DqnMemStack *const assetStack = &memory->assetStack;
|
||||||
DqnMemStack *const tempStack = &memory->tempStack;
|
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
|
// Init Assets
|
||||||
////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////
|
||||||
DTRAsset_InitGlobalState();
|
DTRAsset_InitGlobalState();
|
||||||
|
const f32 FONT_SIZE = 14;
|
||||||
DTRAsset_LoadFontToBitmap(input->api, &memory->mainStack, tempStack, &state->font,
|
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,
|
DTRAsset_LoadBitmap(input->api, assetStack,
|
||||||
tempStack, &state->bitmap, "tree00.bmp");
|
tempStack, &state->bitmap, "tree00.bmp");
|
||||||
|
|
||||||
@ -935,23 +930,17 @@ extern "C" void DTR_Update(PlatformRenderBuffer *const platformRenderBuffer,
|
|||||||
if (DTR_DEBUG)
|
if (DTR_DEBUG)
|
||||||
{
|
{
|
||||||
DTRDebug_TestMeshFaceAndVertexParser(&state->mesh);
|
DTRDebug_TestMeshFaceAndVertexParser(&state->mesh);
|
||||||
bool regionValid;
|
|
||||||
auto memRegion = DqnMemStackTempRegionGuard(&memory->tempStack, ®ionValid);
|
DqnTempMemStack tmp = DqnMemStack_BeginTempRegion(&memory->tempStack);
|
||||||
if (regionValid)
|
|
||||||
{
|
|
||||||
DTRBitmap test = {};
|
DTRBitmap test = {};
|
||||||
DTRAsset_LoadBitmap(input->api, assetStack, &memory->tempStack, &test,
|
DTRAsset_LoadBitmap(input->api, assetStack, &memory->tempStack, &test, "byte_read_check.bmp");
|
||||||
"byte_read_check.bmp");
|
DqnMemStack_EndTempRegion(tmp);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
DqnTempMemStack tempStackMemRegion = DqnMemStack_BeginTempRegion(&memory->tempStack);
|
||||||
|
|
||||||
{
|
|
||||||
bool regionValid;
|
|
||||||
auto tempMemRegion = DqnMemStackTempRegionGuard(&memory->tempStack, ®ionValid);
|
|
||||||
if (regionValid)
|
|
||||||
{
|
|
||||||
size_t debugSize = DQN_MEGABYTE(1);
|
size_t debugSize = DQN_MEGABYTE(1);
|
||||||
u8 *debugMemory = (u8 *)DqnMemStack_Push(&memory->tempStack, debugSize);
|
u8 *debugMemory = (u8 *)DqnMemStack_Push(&memory->tempStack, debugSize);
|
||||||
DqnMemStack_InitWithFixedMem(&globalDebug.memStack, debugMemory, debugSize);
|
DqnMemStack_InitWithFixedMem(&globalDebug.memStack, debugMemory, debugSize);
|
||||||
@ -962,31 +951,16 @@ extern "C" void DTR_Update(PlatformRenderBuffer *const platformRenderBuffer,
|
|||||||
renderBuffer.height = platformRenderBuffer->height;
|
renderBuffer.height = platformRenderBuffer->height;
|
||||||
renderBuffer.bytesPerPixel = platformRenderBuffer->bytesPerPixel;
|
renderBuffer.bytesPerPixel = platformRenderBuffer->bytesPerPixel;
|
||||||
renderBuffer.memory = (u8 *)platformRenderBuffer->memory;
|
renderBuffer.memory = (u8 *)platformRenderBuffer->memory;
|
||||||
renderBuffer.renderLock = state->renderLock;
|
|
||||||
|
|
||||||
u32 zBufferSize = platformRenderBuffer->width * platformRenderBuffer->height;
|
u32 zBufferSize = platformRenderBuffer->width * platformRenderBuffer->height;
|
||||||
renderBuffer.zBuffer = (f32 *)DqnMemStack_Push(
|
renderBuffer.zBuffer = (f32 *)DqnMemStack_Push(&memory->tempStack,
|
||||||
&memory->tempStack, zBufferSize * sizeof(*renderBuffer.zBuffer));
|
zBufferSize * sizeof(*renderBuffer.zBuffer));
|
||||||
|
|
||||||
renderBuffer.pixelLockTable = (bool *)DqnMemStack_Push(
|
for (u32 i = 0; i < zBufferSize; i++) renderBuffer.zBuffer[i] = DQN_F32_MIN;
|
||||||
&memory->tempStack, zBufferSize * sizeof(*renderBuffer.pixelLockTable));
|
|
||||||
|
|
||||||
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
|
// Update and Render
|
||||||
////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////
|
||||||
DTRRender_Clear(renderContext, DqnV3_3f(0.5f, 0.0f, 1.0f));
|
DTRRender_Clear(&renderBuffer, DqnV3_3f(0.0f, 0.0f, 0.0f));
|
||||||
|
|
||||||
#if 1
|
#if 1
|
||||||
DqnV4 colorRed = DqnV4_4f(0.8f, 0, 0, 1);
|
DqnV4 colorRed = DqnV4_4f(0.8f, 0, 0, 1);
|
||||||
@ -1007,25 +981,27 @@ extern "C" void DTR_Update(PlatformRenderBuffer *const platformRenderBuffer,
|
|||||||
DqnV3 t4[3] = {DqnV3_3i(100, 150, 0), DqnV3_3i(200, 150, 0), DqnV3_3i(200, 250, 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)};
|
DqnV3 t5[3] = {DqnV3_3i(300, 150, 0), DqnV3_3i(201, 150, 0), DqnV3_3i(200, 250, 0)};
|
||||||
|
|
||||||
DTRRenderTransform rotatingXform = DTRRender_DefaultTriangleTransform();
|
if (1)
|
||||||
rotatingXform.rotation = rotation;
|
|
||||||
|
|
||||||
if (0)
|
|
||||||
{
|
{
|
||||||
DTRDebug_BeginCycleCount(
|
|
||||||
"DTR_Update_RenderPrimitiveTriangles",
|
DTRRenderTransform rotatingXform = DTRRender_DefaultTriangleTransform();
|
||||||
|
rotatingXform.rotation = rotation * 0.25f;
|
||||||
|
|
||||||
|
DTRDebug_BeginCycleCount("DTR_Update_RenderPrimitiveTriangles",
|
||||||
DTRDebugCycleCount_DTR_Update_RenderPrimitiveTriangles);
|
DTRDebugCycleCount_DTR_Update_RenderPrimitiveTriangles);
|
||||||
|
|
||||||
DTRRender_Triangle(renderContext, t0[0], t0[1], t0[2], colorRed);
|
DTRRenderTransform scaleXform = DTRRender_DefaultTriangleTransform();
|
||||||
DTRRender_Triangle(renderContext, t1[0], t1[1], t1[2], colorRed);
|
scaleXform.scale = DqnV3_1f(5);
|
||||||
DTRRender_Triangle(renderContext, t3[0], t3[1], t3[2], colorRed, rotatingXform);
|
DTRRender_Triangle(&renderBuffer, t0[0], t0[1], t0[2], colorRed);
|
||||||
DTRRender_Triangle(renderContext, t2[0], t2[1], t2[2], colorRed);
|
DTRRender_Triangle(&renderBuffer, t1[0], t1[1], t1[2], colorRed);
|
||||||
DTRRender_Triangle(renderContext, t4[0], t4[1], t4[2], colorRed);
|
DTRRender_Triangle(&renderBuffer, t3[0], t3[1], t3[2], colorRed, rotatingXform);
|
||||||
DTRRender_Triangle(renderContext, t5[0], t5[1], t5[2], colorRed);
|
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);
|
DTRDebug_EndCycleCount(DTRDebugCycleCount_DTR_Update_RenderPrimitiveTriangles);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (1)
|
if (0)
|
||||||
{
|
{
|
||||||
LOCAL_PERSIST bool runTinyRendererOnce = false;
|
LOCAL_PERSIST bool runTinyRendererOnce = false;
|
||||||
if (1 && runTinyRendererOnce)
|
if (1 && runTinyRendererOnce)
|
||||||
@ -1034,8 +1010,7 @@ extern "C" void DTR_Update(PlatformRenderBuffer *const platformRenderBuffer,
|
|||||||
runTinyRendererOnce = false;
|
runTinyRendererOnce = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
DTRDebug_BeginCycleCount("DTR_Update_RenderModel",
|
DTRDebug_BeginCycleCount("DTR_Update_RenderModel", DTRDebugCycleCount_DTR_Update_RenderModel);
|
||||||
DTRDebugCycleCount_DTR_Update_RenderModel);
|
|
||||||
////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////
|
||||||
// Draw Loaded Model
|
// Draw Loaded Model
|
||||||
////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////
|
||||||
@ -1045,7 +1020,7 @@ extern "C" void DTR_Update(PlatformRenderBuffer *const platformRenderBuffer,
|
|||||||
DqnV3 modelP = DqnV3_3f(0, 0, 0);
|
DqnV3 modelP = DqnV3_3f(0, 0, 0);
|
||||||
|
|
||||||
LOCAL_PERSIST f32 modelRotation = 0;
|
LOCAL_PERSIST f32 modelRotation = 0;
|
||||||
modelRotation += (input->deltaForFrame * 20.0f);
|
modelRotation += (input->deltaForFrame * 80.0f);
|
||||||
DqnV3 axis = DqnV3_3f(0, 1, 0);
|
DqnV3 axis = DqnV3_3f(0, 1, 0);
|
||||||
|
|
||||||
DTRRenderTransform transform = DTRRender_DefaultTransform();
|
DTRRenderTransform transform = DTRRender_DefaultTransform();
|
||||||
@ -1058,8 +1033,7 @@ extern "C" void DTR_Update(PlatformRenderBuffer *const platformRenderBuffer,
|
|||||||
lighting.vector = LIGHT;
|
lighting.vector = LIGHT;
|
||||||
lighting.color = DqnV4_4f(1, 1, 1, 1);
|
lighting.color = DqnV4_4f(1, 1, 1, 1);
|
||||||
|
|
||||||
DTRRender_Mesh(renderContext, input->jobQueue, mesh, lighting, modelP,
|
DTRRender_Mesh(&renderBuffer, mesh, lighting, modelP, transform);
|
||||||
transform);
|
|
||||||
DTRDebug_EndCycleCount(DTRDebugCycleCount_DTR_Update_RenderModel);
|
DTRDebug_EndCycleCount(DTRDebugCycleCount_DTR_Update_RenderModel);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1070,7 +1044,7 @@ extern "C" void DTR_Update(PlatformRenderBuffer *const platformRenderBuffer,
|
|||||||
DTRRenderTransform transform = DTRRender_DefaultTransform();
|
DTRRenderTransform transform = DTRRender_DefaultTransform();
|
||||||
transform.rotation = rotation + 45;
|
transform.rotation = rotation + 45;
|
||||||
|
|
||||||
DTRRender_Rectangle(renderContext, DqnV2_1f(300.0f), DqnV2_1f(300 + 100.0f),
|
DTRRender_Rectangle(&renderBuffer, DqnV2_1f(300.0f), DqnV2_1f(300 + 100.0f),
|
||||||
DqnV4_4f(0, 1.0f, 1.0f, 1.0f), transform);
|
DqnV4_4f(0, 1.0f, 1.0f, 1.0f), transform);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1084,35 +1058,20 @@ extern "C" void DTR_Update(PlatformRenderBuffer *const platformRenderBuffer,
|
|||||||
bitmapP.x += 2.0f * sinf((f32)input->timeNowInS * 0.5f);
|
bitmapP.x += 2.0f * sinf((f32)input->timeNowInS * 0.5f);
|
||||||
|
|
||||||
f32 cAngle = (f32)input->timeNowInS;
|
f32 cAngle = (f32)input->timeNowInS;
|
||||||
DqnV4 color =
|
DqnV4 color = DqnV4_4f(0.5f + 0.5f * sinf(cAngle), 0.5f + 0.5f * sinf(2.9f * cAngle),
|
||||||
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);
|
0.5f + 0.5f * cosf(10.0f * cAngle), 1.0f);
|
||||||
DTRRender_Bitmap(renderContext, &state->bitmap, bitmapP, transform, color);
|
DTRRender_Bitmap(&renderBuffer, &state->bitmap, bitmapP, transform, color);
|
||||||
}
|
}
|
||||||
|
|
||||||
#else
|
#else
|
||||||
// CompAssignment(renderBuffer, input, memory);
|
// CompAssignment(renderBuffer, input, memory);
|
||||||
#endif
|
#endif
|
||||||
DTRDebug_EndCycleCount(DTRDebugCycleCount_DTR_Update);
|
DTRDebug_EndCycleCount(DTRDebugCycleCount_DTR_Update);
|
||||||
DTRDebug_Update(state, renderContext, input, memory);
|
DTRDebug_Update(state, &renderBuffer, input, memory);
|
||||||
}
|
DqnMemStack_EndTempRegion(tempStackMemRegion);
|
||||||
|
|
||||||
while (input->api.QueueTryExecuteNextJob(input->jobQueue) ||
|
|
||||||
!input->api.QueueAllJobsComplete(input->jobQueue))
|
|
||||||
;
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////
|
||||||
// End Update
|
// End Update
|
||||||
////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////
|
||||||
if (DTR_DEBUG)
|
|
||||||
{
|
|
||||||
DQN_ASSERT(input->api.QueueAllJobsComplete(input->jobQueue));
|
|
||||||
for (i32 i = 0; i < DQN_ARRAY_COUNT(memory->stacks); i++)
|
for (i32 i = 0; i < DQN_ARRAY_COUNT(memory->stacks); i++)
|
||||||
{
|
DQN_ASSERT(memory->stacks[i].tempStackCount == 0);
|
||||||
if (&memory->stacks[i] == &memory->tempStack) continue;
|
|
||||||
DQN_ASSERT(memory->stacks[i].tempRegionCount == 0);
|
|
||||||
}
|
|
||||||
DqnMemStack_ClearCurrBlock(&memory->tempStack, true);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -13,8 +13,6 @@ typedef struct DTRState
|
|||||||
DTRFont font;
|
DTRFont font;
|
||||||
DTRBitmap bitmap;
|
DTRBitmap bitmap;
|
||||||
DTRMesh mesh;
|
DTRMesh mesh;
|
||||||
|
|
||||||
struct PlatformLock *renderLock;
|
|
||||||
} DTRState;
|
} DTRState;
|
||||||
|
|
||||||
extern PlatformFlags globalDTRPlatformFlags;
|
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))
|
if (!api.FileOpen(path, &file, PlatformFilePermissionFlag_Read, PlatformFileAction_OpenOnly))
|
||||||
return false; // TODO(doyle): Logging
|
return false; // TODO(doyle): Logging
|
||||||
|
|
||||||
WavefModel dummy_ = {};
|
bool result = false;
|
||||||
WavefModel *obj = &dummy_;
|
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 = {};
|
DqnMemAPI memAPI = {};
|
||||||
memAPI.callback = DumbDynamicArrayMemAPICallback;
|
memAPI.callback = DumbDynamicArrayMemAPICallback;
|
||||||
memAPI.userContext = memStack;
|
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 {
|
enum WavefVertexType {
|
||||||
WavefVertexType_Invalid,
|
WavefVertexType_Invalid,
|
||||||
WavefVertexType_Geometric,
|
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
|
// to a new memstack block such that all the data is compacted together in
|
||||||
// memory for locality. Then just throw away the intermediate
|
// memory for locality. Then just throw away the intermediate
|
||||||
// representation.
|
// representation.
|
||||||
|
WavefModel dummy_ = {};
|
||||||
|
WavefModel *obj = &dummy_;
|
||||||
|
|
||||||
if (bytesRead != file.size) goto cleanup;
|
if (bytesRead != file.size) goto cleanup;
|
||||||
if (!WavefModelInit(obj, memAPI)) 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);
|
DQN_ASSERT(DQN_INVALID_CODE_PATH);
|
||||||
}
|
}
|
||||||
|
|
||||||
DqnMemStackTempRegion_End(tmpAssetRegion);
|
DqnMemStack_EndTempRegion(tmpAssetRegion);
|
||||||
if (modelBlock)
|
if (modelBlock)
|
||||||
{
|
{
|
||||||
result = true;
|
result = true;
|
||||||
@ -606,7 +599,7 @@ bool DTRAsset_LoadWavefrontObj(const PlatformAPI api, DqnMemStack *const memStac
|
|||||||
|
|
||||||
cleanup:
|
cleanup:
|
||||||
api.FileClose(&file);
|
api.FileClose(&file);
|
||||||
if(!result) DqnMemStackTempRegion_End(tmpAssetRegion);
|
if(!result) DqnMemStack_EndTempRegion(tmpAssetRegion);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@ -630,22 +623,14 @@ bool DTRAsset_LoadFontToBitmap(const PlatformAPI api, DqnMemStack *const memStac
|
|||||||
if (!api.FileOpen(path, &file, PlatformFilePermissionFlag_Read, PlatformFileAction_OpenOnly))
|
if (!api.FileOpen(path, &file, PlatformFilePermissionFlag_Read, PlatformFileAction_OpenOnly))
|
||||||
return false; // TODO(doyle): Logging
|
return false; // TODO(doyle): Logging
|
||||||
|
|
||||||
stbtt_fontinfo fontInfo = {};
|
|
||||||
stbtt_pack_context fontPackContext = {};
|
|
||||||
|
|
||||||
bool result = false;
|
bool result = false;
|
||||||
bool regionValid;
|
DqnTempMemStack tmpMemRegion = DqnMemStack_BeginTempRegion(tmpMemStack);
|
||||||
auto tmpMemRegion = DqnMemStackTempRegionGuard(tmpMemStack, ®ionValid);
|
|
||||||
if (!regionValid)
|
|
||||||
{
|
|
||||||
// TODO(doyle): Logging
|
|
||||||
DQN_ASSERT(DQN_INVALID_CODE_PATH);
|
|
||||||
goto cleanup;
|
|
||||||
}
|
|
||||||
|
|
||||||
u8 *rawBytes = (u8 *)DqnMemStack_Push(tmpMemStack, file.size);
|
u8 *rawBytes = (u8 *)DqnMemStack_Push(tmpMemStack, file.size);
|
||||||
size_t bytesRead = api.FileRead(&file, rawBytes, 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)
|
if (bytesRead != file.size || stbtt_InitFont(&fontInfo, rawBytes, 0) == 0)
|
||||||
{
|
{
|
||||||
DQN_ASSERT(DQN_INVALID_CODE_PATH);
|
DQN_ASSERT(DQN_INVALID_CODE_PATH);
|
||||||
@ -707,6 +692,7 @@ bool DTRAsset_LoadFontToBitmap(const PlatformAPI api, DqnMemStack *const memStac
|
|||||||
*font = loadedFont;
|
*font = loadedFont;
|
||||||
|
|
||||||
cleanup:
|
cleanup:
|
||||||
|
DqnMemStack_EndTempRegion(tmpMemRegion);
|
||||||
api.FileClose(&file);
|
api.FileClose(&file);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
@ -767,7 +753,7 @@ bool DTRAsset_LoadBitmap(const PlatformAPI api, DqnMemStack *const memStack,
|
|||||||
if (!api.FileOpen(path, &file, PlatformFilePermissionFlag_Read, PlatformFileAction_OpenOnly))
|
if (!api.FileOpen(path, &file, PlatformFilePermissionFlag_Read, PlatformFileAction_OpenOnly))
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
DqnMemStackTempRegionGuard tmpMemRegion = tempStack->TempRegionGuard();
|
DqnTempMemStack tmpMemRegion = DqnMemStack_BeginTempRegion(tempStack);
|
||||||
u8 *const rawData = (u8 *)DqnMemStack_Push (tempStack, file.size);
|
u8 *const rawData = (u8 *)DqnMemStack_Push (tempStack, file.size);
|
||||||
size_t bytesRead = api.FileRead (&file, rawData, file.size);
|
size_t bytesRead = api.FileRead (&file, rawData, file.size);
|
||||||
|
|
||||||
@ -844,6 +830,7 @@ bool DTRAsset_LoadBitmap(const PlatformAPI api, DqnMemStack *const memStack,
|
|||||||
|
|
||||||
cleanup:
|
cleanup:
|
||||||
globalSTBImageAllocator = NULL;
|
globalSTBImageAllocator = NULL;
|
||||||
|
DqnMemStack_EndTempRegion(tmpMemRegion);
|
||||||
api.FileClose(&file);
|
api.FileClose(&file);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
@ -77,10 +77,8 @@ void DTRDebug_DumpZBuffer(DTRRenderBuffer *const renderBuffer, DqnMemStack *cons
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool regionValid;
|
DqnTempMemStack tmpMemRegion = DqnMemStack_BeginTempRegion(tempStack);
|
||||||
auto memRegion = DqnMemStackTempRegionGuard(tempStack, ®ionValid);
|
|
||||||
if (regionValid)
|
|
||||||
{
|
|
||||||
size_t bufSize = DQN_MEGABYTE(16);
|
size_t bufSize = DQN_MEGABYTE(16);
|
||||||
char *bufString = (char *)DqnMemStack_Push(tempStack, bufSize);
|
char *bufString = (char *)DqnMemStack_Push(tempStack, bufSize);
|
||||||
char *bufPtr = bufString;
|
char *bufPtr = bufString;
|
||||||
@ -102,7 +100,8 @@ void DTRDebug_DumpZBuffer(DTRRenderBuffer *const renderBuffer, DqnMemStack *cons
|
|||||||
size_t writeSize = (size_t)bufPtr - (size_t)bufString;
|
size_t writeSize = (size_t)bufPtr - (size_t)bufString;
|
||||||
size_t bytesWritten = api->FileWrite(&file, (u8 *)bufString, writeSize);
|
size_t bytesWritten = api->FileWrite(&file, (u8 *)bufString, writeSize);
|
||||||
api->FileClose(&file);
|
api->FileClose(&file);
|
||||||
}
|
|
||||||
|
DqnMemStack_EndTempRegion(tmpMemRegion);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -119,7 +118,7 @@ void DTRDebug_PushText(const char *const formatStr, ...)
|
|||||||
if (DTR_DEBUG)
|
if (DTR_DEBUG)
|
||||||
{
|
{
|
||||||
DTRDebug *const debug = &globalDebug;
|
DTRDebug *const debug = &globalDebug;
|
||||||
if (!debug->renderContext->renderBuffer) return;
|
if (!debug->renderBuffer) return;
|
||||||
|
|
||||||
char str[1024] = {};
|
char str[1024] = {};
|
||||||
|
|
||||||
@ -131,7 +130,7 @@ void DTRDebug_PushText(const char *const formatStr, ...)
|
|||||||
}
|
}
|
||||||
va_end(argList);
|
va_end(argList);
|
||||||
|
|
||||||
DTRRender_Text(*debug->renderContext, *debug->font, debug->displayP, str,
|
DTRRender_Text(debug->renderBuffer, *debug->font, debug->displayP, str,
|
||||||
debug->displayColor);
|
debug->displayColor);
|
||||||
debug->displayP.y += globalDebug.displayYOffset;
|
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,
|
Dqn_sprintf(str, "%s: %d block(s): %_$lld/%_$lld: wasted: %_$lld", name, numBlocks,
|
||||||
totalUsed, totalSize, totalWastedKb);
|
totalUsed, totalSize, totalWastedKb);
|
||||||
|
|
||||||
DTRRender_Text(*globalDebug.renderContext, *globalDebug.font,
|
DTRRender_Text(globalDebug.renderBuffer, *globalDebug.font,
|
||||||
globalDebug.displayP, str, globalDebug.displayColor);
|
globalDebug.displayP, str, globalDebug.displayColor);
|
||||||
globalDebug.displayP.y += globalDebug.displayYOffset;
|
globalDebug.displayP.y += globalDebug.displayYOffset;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DTRDebug_Update(DTRState *const state,
|
void DTRDebug_Update(DTRState *const state,
|
||||||
DTRRenderContext renderContext,
|
DTRRenderBuffer *const renderBuffer,
|
||||||
PlatformInput *const input, PlatformMemory *const memory)
|
PlatformInput *const input, PlatformMemory *const memory)
|
||||||
{
|
{
|
||||||
if (DTR_DEBUG)
|
if (DTR_DEBUG)
|
||||||
{
|
{
|
||||||
DTRDebug *const debug = &globalDebug;
|
DTRDebug *const debug = &globalDebug;
|
||||||
|
|
||||||
debug->renderContext = &renderContext;
|
debug->renderBuffer = renderBuffer;
|
||||||
debug->input = input;
|
debug->input = input;
|
||||||
debug->font = &state->font;
|
debug->font = &state->font;
|
||||||
debug->displayColor = DqnV4_4f(1, 1, 1, 1);
|
debug->displayColor = DqnV4_4f(1, 1, 1, 0.85f);
|
||||||
if (debug->font->bitmap && debug->renderContext)
|
if (debug->font->bitmap && debug->renderBuffer)
|
||||||
{
|
{
|
||||||
debug->displayYOffset = -(i32)(state->font.sizeInPt + 0.5f);
|
debug->displayYOffset = -(i32)(state->font.sizeInPt + 0.5f);
|
||||||
DQN_ASSERT(globalDebug.displayYOffset < 0);
|
DQN_ASSERT(globalDebug.displayYOffset < 0);
|
||||||
@ -271,7 +270,7 @@ void DTRDebug_Update(DTRState *const state,
|
|||||||
// End Debug Update
|
// End Debug Update
|
||||||
////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////
|
||||||
debug->displayP =
|
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++)
|
for (i32 i = 0; i < DQN_ARRAY_COUNT(debug->counter); i++)
|
||||||
debug->counter[i] = 0;
|
debug->counter[i] = 0;
|
||||||
|
@ -89,7 +89,7 @@ typedef struct DTRDebugCycles
|
|||||||
typedef struct DTRDebug
|
typedef struct DTRDebug
|
||||||
{
|
{
|
||||||
struct DTRFont *font;
|
struct DTRFont *font;
|
||||||
struct DTRRenderContext *renderContext;
|
struct DTRRenderBuffer *renderBuffer;
|
||||||
struct PlatformInput *input;
|
struct PlatformInput *input;
|
||||||
DqnMemStack memStack;
|
DqnMemStack memStack;
|
||||||
|
|
||||||
|
@ -4,11 +4,6 @@
|
|||||||
#include "dqn.h"
|
#include "dqn.h"
|
||||||
#include <intrin.h>
|
#include <intrin.h>
|
||||||
|
|
||||||
typedef void PlatformAPI_DieGracefully();
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// Platform File I/O
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
enum PlatformFilePermissionFlag
|
enum PlatformFilePermissionFlag
|
||||||
{
|
{
|
||||||
PlatformFilePermissionFlag_Read = (1 << 0),
|
PlatformFilePermissionFlag_Read = (1 << 0),
|
||||||
@ -29,47 +24,11 @@ typedef struct PlatformFile
|
|||||||
u32 permissionFlags;
|
u32 permissionFlags;
|
||||||
} PlatformFile;
|
} PlatformFile;
|
||||||
|
|
||||||
// File I/O API
|
|
||||||
typedef bool PlatformAPI_FileOpen (const char *const path, PlatformFile *const file, const u32 permissionFlags, const enum PlatformFileAction actionFlags);
|
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 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_FileClose(PlatformFile *const file);
|
||||||
typedef void PlatformAPI_Print (const char *const string);
|
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
|
typedef struct PlatformAPI
|
||||||
{
|
{
|
||||||
PlatformAPI_FileOpen *FileOpen;
|
PlatformAPI_FileOpen *FileOpen;
|
||||||
@ -77,23 +36,8 @@ typedef struct PlatformAPI
|
|||||||
PlatformAPI_FileWrite *FileWrite;
|
PlatformAPI_FileWrite *FileWrite;
|
||||||
PlatformAPI_FileClose *FileClose;
|
PlatformAPI_FileClose *FileClose;
|
||||||
PlatformAPI_Print *Print;
|
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;
|
} PlatformAPI;
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// Platform Input
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
enum Key
|
enum Key
|
||||||
{
|
{
|
||||||
key_up,
|
key_up,
|
||||||
@ -154,7 +98,6 @@ typedef struct PlatformInput
|
|||||||
|
|
||||||
PlatformAPI api;
|
PlatformAPI api;
|
||||||
PlatformMouse mouse;
|
PlatformMouse mouse;
|
||||||
PlatformJobQueue *jobQueue;
|
|
||||||
union {
|
union {
|
||||||
KeyState key[key_count];
|
KeyState key[key_count];
|
||||||
struct
|
struct
|
||||||
@ -188,9 +131,6 @@ typedef struct PlatformInput
|
|||||||
};
|
};
|
||||||
} PlatformInput;
|
} PlatformInput;
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// Platform Memory
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
typedef struct PlatformMemory
|
typedef struct PlatformMemory
|
||||||
{
|
{
|
||||||
union {
|
union {
|
||||||
@ -206,9 +146,6 @@ typedef struct PlatformMemory
|
|||||||
void *context;
|
void *context;
|
||||||
} PlatformMemory;
|
} PlatformMemory;
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// Platform Frame Buffer
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
typedef struct PlatformRenderBuffer
|
typedef struct PlatformRenderBuffer
|
||||||
{
|
{
|
||||||
i32 width;
|
i32 width;
|
||||||
|
@ -121,10 +121,9 @@ inline DqnV4 DTRRender_PreMultiplyAlphaSRGB1WithLinearConversion(DqnV4 color)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// IMPORTANT(doyle): Color is expected to be premultiplied already
|
// 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)
|
DqnV4 color, const enum ColorSpace colorSpace = ColorSpace_SRGB)
|
||||||
{
|
{
|
||||||
DTRRenderBuffer *renderBuffer = context.renderBuffer;
|
|
||||||
if (!renderBuffer) return;
|
if (!renderBuffer) return;
|
||||||
if (x < 0 || x > (renderBuffer->width - 1)) return;
|
if (x < 0 || x > (renderBuffer->width - 1)) return;
|
||||||
if (y < 0 || y > (renderBuffer->height - 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);
|
DTRDebug_CounterIncrement(DTRDebugCounter_SetPixels);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DTRRender_Text(DTRRenderContext context,
|
void DTRRender_Text(DTRRenderBuffer *const renderBuffer,
|
||||||
const DTRFont font, DqnV2 pos, const char *const text,
|
const DTRFont font, DqnV2 pos, const char *const text,
|
||||||
DqnV4 color, i32 len)
|
DqnV4 color, i32 len)
|
||||||
{
|
{
|
||||||
if (!text) return;
|
if (!text) return;
|
||||||
|
|
||||||
DTRRenderBuffer *renderBuffer = context.renderBuffer;
|
|
||||||
if (!font.bitmap || !font.atlas || !renderBuffer) return;
|
if (!font.bitmap || !font.atlas || !renderBuffer) return;
|
||||||
DTR_DEBUG_EP_TIMED_FUNCTION();
|
DTR_DEBUG_EP_TIMED_FUNCTION();
|
||||||
|
|
||||||
|
if (len == -1) len = Dqn_strlen(text);
|
||||||
if (len == -1) len = DqnStr_Len(text);
|
|
||||||
|
|
||||||
i32 index = 0;
|
i32 index = 0;
|
||||||
color = DTRRender_SRGB1ToLinearSpaceV4(color);
|
color = DTRRender_SRGB1ToLinearSpaceV4(color);
|
||||||
@ -266,7 +262,7 @@ void DTRRender_Text(DTRRenderContext context,
|
|||||||
|
|
||||||
i32 actualX = (i32)(screenRect.min.x + x);
|
i32 actualX = (i32)(screenRect.min.x + x);
|
||||||
i32 actualY = (i32)(screenRect.min.y + y - fontHeightOffset);
|
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)
|
DqnV2i b, DqnV4 color)
|
||||||
{
|
{
|
||||||
DTRRenderBuffer *renderBuffer = context.renderBuffer;
|
|
||||||
if (!renderBuffer) return;
|
if (!renderBuffer) return;
|
||||||
DTR_DEBUG_EP_TIMED_FUNCTION();
|
DTR_DEBUG_EP_TIMED_FUNCTION();
|
||||||
|
|
||||||
@ -344,7 +339,7 @@ void DTRRender_Line(DTRRenderContext context, DqnV2i a,
|
|||||||
for (i32 iterateX = 0; iterateX < numIterations; iterateX++)
|
for (i32 iterateX = 0; iterateX < numIterations; iterateX++)
|
||||||
{
|
{
|
||||||
newX = a.x + iterateX;
|
newX = a.x + iterateX;
|
||||||
SetPixel(context, *plotX, *plotY, color, ColorSpace_Linear);
|
SetPixel(renderBuffer, *plotX, *plotY, color, ColorSpace_Linear);
|
||||||
|
|
||||||
distAccumulator += distFromPixelOrigin;
|
distAccumulator += distFromPixelOrigin;
|
||||||
if (distAccumulator > run)
|
if (distAccumulator > run)
|
||||||
@ -412,13 +407,10 @@ FILE_SCOPE DqnRect GetBoundingBox(const DqnV2 *const pList, const i32 numP)
|
|||||||
return result;
|
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)
|
DqnV4 color, const DTRRenderTransform transform)
|
||||||
{
|
{
|
||||||
DTR_DEBUG_EP_TIMED_FUNCTION();
|
DTR_DEBUG_EP_TIMED_FUNCTION();
|
||||||
DTRRenderBuffer *renderBuffer = context.renderBuffer;
|
|
||||||
if (!renderBuffer) return;
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////
|
||||||
// Transform vertexes
|
// 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++)
|
for (i32 x = 0; x < clippedSize.w; x++)
|
||||||
{
|
{
|
||||||
i32 bufferX = (i32)clippedRect.min.x + 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
|
// Draw Bounding box
|
||||||
{
|
{
|
||||||
DTRRender_Line(context, DqnV2i_2f(min.x, min.y), DqnV2i_2f(min.x, max.y), color);
|
DTRRender_Line(renderBuffer, 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(renderBuffer, 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(renderBuffer, 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(max.x, min.y), DqnV2i_2f(min.x, min.y), color);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Draw rotating outline
|
// Draw rotating outline
|
||||||
if (transform.rotation > 0)
|
if (transform.rotation > 0)
|
||||||
{
|
{
|
||||||
DqnV4 green = DqnV4_4f(0, 1, 0, 1);
|
DqnV4 green = DqnV4_4f(0, 1, 0, 1);
|
||||||
DTRRender_Line(context, DqnV2i_V2(pList[0]), DqnV2i_V2(pList[1]), green);
|
DTRRender_Line(renderBuffer, DqnV2i_V2(pList[0]), DqnV2i_V2(pList[1]), green);
|
||||||
DTRRender_Line(context, DqnV2i_V2(pList[1]), DqnV2i_V2(pList[2]), green);
|
DTRRender_Line(renderBuffer, DqnV2i_V2(pList[1]), DqnV2i_V2(pList[2]), green);
|
||||||
DTRRender_Line(context, DqnV2i_V2(pList[2]), DqnV2i_V2(pList[3]), green);
|
DTRRender_Line(renderBuffer, 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[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
|
// 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,
|
__m128 color,
|
||||||
const enum ColorSpace colorSpace = ColorSpace_SRGB)
|
const enum ColorSpace colorSpace = ColorSpace_SRGB)
|
||||||
{
|
{
|
||||||
|
|
||||||
DTRRenderBuffer *renderBuffer = context.renderBuffer;
|
|
||||||
if (!renderBuffer) return;
|
if (!renderBuffer) return;
|
||||||
if (x < 0 || x > (renderBuffer->width - 1)) return;
|
if (x < 0 || x > (renderBuffer->width - 1)) return;
|
||||||
if (y < 0 || y > (renderBuffer->height - 1)) return;
|
if (y < 0 || y > (renderBuffer->height - 1)) return;
|
||||||
@ -630,20 +620,20 @@ FILE_SCOPE inline void SIMDSetPixel(DTRRenderContext context, const i32 x, const
|
|||||||
DTR_DEBUG_EP_TIMED_FUNCTION();
|
DTR_DEBUG_EP_TIMED_FUNCTION();
|
||||||
DebugSIMDAssertColorInRange(color, 0.0f, 1.0f);
|
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
|
// 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
|
// 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.
|
// overwriting/keeping the state of the pixel so we can save cycles by skipping.
|
||||||
f32 alpha = ((f32 *)&color)[3];
|
f32 alpha = ((f32 *)&color)[3];
|
||||||
bool needGammaFix =
|
bool needGammaFix = (alpha > 0.0f || alpha < (1.0f + COLOR_EPSILON)) && (colorSpace == ColorSpace_SRGB);
|
||||||
(alpha > 0.0f || alpha < (1.0f + COLOR_EPSILON)) && (colorSpace == ColorSpace_SRGB);
|
|
||||||
if (needGammaFix) color = SIMDSRGB1ToLinearSpace(color);
|
if (needGammaFix) color = SIMDSRGB1ToLinearSpace(color);
|
||||||
|
|
||||||
// Format: u32 == (XX, RR, GG, BB)
|
// 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)];
|
u32 srcPixel = bitmapPtr[x + (y * pitchInU32)];
|
||||||
__m128 src = _mm_set_ps(0, (f32)((srcPixel >> 0) & 0xFF),
|
__m128 src = _mm_set_ps(0,
|
||||||
|
(f32)((srcPixel >> 0) & 0xFF),
|
||||||
(f32)((srcPixel >> 8) & 0xFF),
|
(f32)((srcPixel >> 8) & 0xFF),
|
||||||
(f32)((srcPixel >> 16) & 0xFF));
|
(f32)((srcPixel >> 16) & 0xFF));
|
||||||
src = SIMDSRGB255ToLinearSpace1(src);
|
src = SIMDSRGB255ToLinearSpace1(src);
|
||||||
@ -668,6 +658,8 @@ FILE_SCOPE inline void SIMDSetPixel(DTRRenderContext context, const i32 x, const
|
|||||||
(u32)(destG) << 8 |
|
(u32)(destG) << 8 |
|
||||||
(u32)(destB) << 0;
|
(u32)(destB) << 0;
|
||||||
bitmapPtr[x + (y * pitchInU32)] = pixel;
|
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
|
// 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,
|
// 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
|
// ie. any render function that is used in this call because it'll call into
|
||||||
// itself infinitely.
|
// 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,
|
const i32 pListSize, const DTRRenderTransform transform,
|
||||||
bool drawBoundingBox, bool drawBasis, bool drawVertexMarkers)
|
bool drawBoundingBox, bool drawBasis, bool drawVertexMarkers)
|
||||||
{
|
{
|
||||||
@ -733,10 +725,10 @@ FILE_SCOPE void DebugRenderMarkers(DTRRenderContext context, const DqnV2 *const
|
|||||||
{
|
{
|
||||||
DqnRect bounds = GetBoundingBox(pList, pListSize);
|
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(renderBuffer, 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(renderBuffer, 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(renderBuffer, 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.max.x, bounds.min.y), DqnV2i_2f(bounds.min.x, bounds.min.y), red);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Draw Coordinate Basis
|
// 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;
|
DqnV2 yAxis = DqnV2_2f(-xAxis.y, xAxis.x) * transform.scale.y;
|
||||||
DqnV4 coordSysColor = DqnV4_4f(0, 1, 1, 1);
|
DqnV4 coordSysColor = DqnV4_4f(0, 1, 1, 1);
|
||||||
i32 axisLen = 50;
|
i32 axisLen = 50;
|
||||||
DTRRender_Line(context, DqnV2i_V2(origin),
|
DTRRender_Line(renderBuffer, DqnV2i_V2(origin),
|
||||||
DqnV2i_V2(origin) + DqnV2i_V2(xAxis * axisLen), coordSysColor);
|
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);
|
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++)
|
for (i32 i = 0; i < pListSize; i++)
|
||||||
{
|
{
|
||||||
DqnV2 p = pList[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) \
|
#define DEBUG_SIMD_AUTO_CHOOSE_BEGIN_CYCLE_COUNT(type) \
|
||||||
do \
|
do \
|
||||||
{ \
|
{ \
|
||||||
@ -817,19 +780,21 @@ FILE_SCOPE inline void SetCurrZDepth(DTRRenderContext context, i32 posX, i32 pos
|
|||||||
DTRDebug_EndCycleCount(DTRDebugCycleCount_SIMD##type); \
|
DTRDebug_EndCycleCount(DTRDebugCycleCount_SIMD##type); \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
FILE_SCOPE void
|
FILE_SCOPE void SIMDRasteriseTrianglePixel(DTRRenderBuffer *const renderBuffer,
|
||||||
SIMDRasteriseTrianglePixel(DTRRenderContext context, const DTRBitmap *const texture, const i32 posX,
|
const DTRBitmap *const texture, const i32 posX,
|
||||||
const i32 posY, const i32 maxX, const DqnV2 uv1, const DqnV2 uv2SubUv1,
|
const i32 posY, const i32 maxX, const DqnV2 uv1,
|
||||||
const DqnV2 uv3SubUv1, const __m128 simdColor, const __m128 triangleZ,
|
const DqnV2 uv2SubUv1, const DqnV2 uv3SubUv1,
|
||||||
const __m128 signedArea, const __m128 invSignedAreaParallelogram_4x,
|
const __m128 simdColor, const __m128 triangleZ,
|
||||||
const f32 preserveAlpha, const bool ignoreLight, const __m128 p1Light,
|
const __m128 signedArea,
|
||||||
const __m128 p2Light, const __m128 p3Light)
|
const __m128 invSignedAreaParallelogram_4x)
|
||||||
{
|
{
|
||||||
DTRRenderBuffer *const renderBuffer = context.renderBuffer;
|
|
||||||
const __m128 ZERO_4X = _mm_set_ps1(0.0f);
|
const __m128 ZERO_4X = _mm_set_ps1(0.0f);
|
||||||
const u32 IS_GREATER_MASK = 0xF;
|
const u32 IS_GREATER_MASK = 0xF;
|
||||||
const u32 zBufferPitch = renderBuffer->width;
|
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
|
// Rasterise buffer(X, Y) pixel
|
||||||
{
|
{
|
||||||
__m128 isGreater = _mm_cmpge_ps(signedArea, ZERO_4X);
|
__m128 isGreater = _mm_cmpge_ps(signedArea, ZERO_4X);
|
||||||
@ -838,51 +803,32 @@ SIMDRasteriseTrianglePixel(DTRRenderContext context, const DTRBitmap *const text
|
|||||||
if ((isGreaterResult & IS_GREATER_MASK) == IS_GREATER_MASK && posX < maxX)
|
if ((isGreaterResult & IS_GREATER_MASK) == IS_GREATER_MASK && posX < maxX)
|
||||||
{
|
{
|
||||||
DEBUG_SIMD_AUTO_CHOOSE_BEGIN_CYCLE_COUNT(Triangle_RasterisePixel);
|
DEBUG_SIMD_AUTO_CHOOSE_BEGIN_CYCLE_COUNT(Triangle_RasterisePixel);
|
||||||
{
|
|
||||||
__m128 barycentric = _mm_mul_ps(signedArea, invSignedAreaParallelogram_4x);
|
__m128 barycentric = _mm_mul_ps(signedArea, invSignedAreaParallelogram_4x);
|
||||||
__m128 barycentricZ = _mm_mul_ps(triangleZ, barycentric);
|
__m128 barycentricZ = _mm_mul_ps(triangleZ, barycentric);
|
||||||
|
|
||||||
f32 pixelZDepth = ((f32 *)&barycentricZ)[0] + ((f32 *)&barycentricZ)[1] +
|
|
||||||
((f32 *)&barycentricZ)[2];
|
|
||||||
|
|
||||||
i32 zBufferIndex = posX + (posY * zBufferPitch);
|
i32 zBufferIndex = posX + (posY * zBufferPitch);
|
||||||
if (pixelZDepth > renderBuffer->zBuffer[zBufferIndex])
|
f32 pixelZValue =
|
||||||
|
((f32 *)&barycentricZ)[0] + ((f32 *)&barycentricZ)[1] + ((f32 *)&barycentricZ)[2];
|
||||||
|
f32 currZValue = renderBuffer->zBuffer[zBufferIndex];
|
||||||
|
if (pixelZValue > currZValue)
|
||||||
{
|
{
|
||||||
renderBuffer->zBuffer[zBufferIndex] = pixelZDepth;
|
renderBuffer->zBuffer[zBufferIndex] = pixelZValue;
|
||||||
|
|
||||||
__m128 finalColor = simdColor;
|
__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)
|
if (texture)
|
||||||
{
|
{
|
||||||
__m128 texSampledColor = SIMDSampleTextureForTriangle(
|
__m128 texSampledColor = SIMDSampleTextureForTriangle(texture, uv1, uv2SubUv1,
|
||||||
texture, uv1, uv2SubUv1, uv3SubUv1, barycentric);
|
uv3SubUv1, barycentric);
|
||||||
finalColor = _mm_mul_ps(texSampledColor, finalColor);
|
finalColor = _mm_mul_ps(texSampledColor, simdColor);
|
||||||
}
|
|
||||||
|
|
||||||
SIMDSetPixel(context, posX, posY, finalColor, ColorSpace_Linear);
|
|
||||||
}
|
}
|
||||||
|
SIMDSetPixel(renderBuffer, posX, posY, finalColor, ColorSpace_Linear);
|
||||||
}
|
}
|
||||||
DEBUG_SIMD_AUTO_CHOOSE_END_CYCLE_COUNT(Triangle_RasterisePixel);
|
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 DqnV3 p3, const DqnV2 uv1, const DqnV2 uv2, const DqnV2 uv3,
|
||||||
const f32 lightIntensity1, const f32 lightIntensity2,
|
const f32 lightIntensity1, const f32 lightIntensity2,
|
||||||
const f32 lightIntensity3, const bool ignoreLight,
|
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);
|
||||||
|
|
||||||
DEBUG_SIMD_AUTO_CHOOSE_BEGIN_CYCLE_COUNT(Triangle_Preamble);
|
DEBUG_SIMD_AUTO_CHOOSE_BEGIN_CYCLE_COUNT(Triangle_Preamble);
|
||||||
|
|
||||||
DTRRenderBuffer *const renderBuffer = context.renderBuffer;
|
|
||||||
////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////
|
||||||
// Convert color
|
// Convert color
|
||||||
////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////
|
||||||
@ -920,16 +864,16 @@ FILE_SCOPE void SIMDTriangle(DTRRenderContext context, const DqnV3 p1, const Dqn
|
|||||||
////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////
|
||||||
// Setup SIMD data
|
// 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;
|
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
|
// SignedArea: _mm_set_ps(unused, p3, p2, p1) ie 0=p1, 1=p1, 2=p3, 3=unused
|
||||||
__m128 signedAreaPixel1 = _mm_set_ps1(0);
|
__m128 signedAreaPixel1;
|
||||||
// __m128 signedAreaPixel2 = _mm_set_ps1(0);
|
__m128 signedAreaPixel2;
|
||||||
|
|
||||||
__m128 signedAreaPixelDeltaX = _mm_set_ps1(0);
|
__m128 signedAreaPixelDeltaX;
|
||||||
__m128 signedAreaPixelDeltaY = _mm_set_ps1(0);
|
__m128 signedAreaPixelDeltaY;
|
||||||
__m128 invSignedAreaParallelogram_4x = _mm_set_ps1(0);
|
__m128 invSignedAreaParallelogram_4x;
|
||||||
|
|
||||||
__m128 triangleZ = _mm_set_ps(0, p3.z, p2.z, p1.z);
|
__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);
|
signedAreaPixelDeltaY = _mm_set_ps(0, signedArea3DeltaY, signedArea2DeltaY, signedArea1DeltaY);
|
||||||
|
|
||||||
signedAreaPixel1 = _mm_set_ps(0, signedArea3Start, signedArea2Start, signedArea1Start);
|
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
|
// 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 uv2SubUv1 = uv2 - uv1;
|
||||||
const DqnV2 uv3SubUv1 = uv3 - uv1;
|
const DqnV2 uv3SubUv1 = uv3 - uv1;
|
||||||
|
|
||||||
|
#define UNROLL_LOOP 1
|
||||||
DEBUG_SIMD_AUTO_CHOOSE_END_CYCLE_COUNT(Triangle_Preamble);
|
DEBUG_SIMD_AUTO_CHOOSE_END_CYCLE_COUNT(Triangle_Preamble);
|
||||||
|
|
||||||
|
#if UNROLL_LOOP
|
||||||
const u32 IS_GREATER_MASK = 0xF;
|
const u32 IS_GREATER_MASK = 0xF;
|
||||||
const u32 zBufferPitch = renderBuffer->width;
|
const u32 zBufferPitch = renderBuffer->width;
|
||||||
|
#endif
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////
|
||||||
// Scan and Render
|
// 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)
|
for (i32 bufferY = min.y; bufferY < max.y; bufferY += NUM_Y_PIXELS_TO_SIMD)
|
||||||
{
|
{
|
||||||
__m128 signedArea1 = signedAreaPixel1;
|
__m128 signedArea1 = signedAreaPixel1;
|
||||||
// __m128 signedArea2 = signedAreaPixel2;
|
__m128 signedArea2 = signedAreaPixel2;
|
||||||
|
|
||||||
for (i32 bufferX = min.x; bufferX < max.x; bufferX += NUM_X_PIXELS_TO_SIMD)
|
for (i32 bufferX = min.x; bufferX < max.x; bufferX += NUM_X_PIXELS_TO_SIMD)
|
||||||
{
|
{
|
||||||
|
#if UNROLL_LOOP
|
||||||
// Rasterise buffer(X, Y) pixel
|
// Rasterise buffer(X, Y) pixel
|
||||||
{
|
{
|
||||||
__m128 checkArea = signedArea1;
|
__m128 checkArea = signedArea1;
|
||||||
@ -1007,26 +956,15 @@ FILE_SCOPE void SIMDTriangle(DTRRenderContext context, const DqnV3 p1, const Dqn
|
|||||||
__m128 barycentric = _mm_mul_ps(checkArea, invSignedAreaParallelogram_4x);
|
__m128 barycentric = _mm_mul_ps(checkArea, invSignedAreaParallelogram_4x);
|
||||||
__m128 barycentricZ = _mm_mul_ps(triangleZ, barycentric);
|
__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)[1] +
|
||||||
((f32 *)&barycentricZ)[2];
|
((f32 *)&barycentricZ)[2];
|
||||||
|
f32 currZValue = renderBuffer->zBuffer[zBufferIndex];
|
||||||
i32 zBufferIndex = posX + (posY * zBufferPitch);
|
if (pixelZValue > currZValue)
|
||||||
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])
|
|
||||||
{
|
{
|
||||||
|
renderBuffer->zBuffer[zBufferIndex] = pixelZValue;
|
||||||
__m128 finalColor = simdColor;
|
__m128 finalColor = simdColor;
|
||||||
renderBuffer->zBuffer[zBufferIndex] = pixelZDepth;
|
|
||||||
if (!ignoreLight)
|
if (!ignoreLight)
|
||||||
{
|
{
|
||||||
__m128 barycentricA_4x = _mm_set_ps1(((f32 *)&barycentric)[0]);
|
__m128 barycentricA_4x = _mm_set_ps1(((f32 *)&barycentric)[0]);
|
||||||
@ -1047,28 +985,85 @@ FILE_SCOPE void SIMDTriangle(DTRRenderContext context, const DqnV3 p1, const Dqn
|
|||||||
|
|
||||||
if (texture)
|
if (texture)
|
||||||
{
|
{
|
||||||
__m128 texSampledColor = SIMDSampleTextureForTriangle(
|
__m128 texSampledColor = SIMDSampleTextureForTriangle(texture, uv1, uv2SubUv1, uv3SubUv1, barycentric);
|
||||||
texture, uv1, uv2SubUv1, uv3SubUv1, barycentric);
|
|
||||||
finalColor = _mm_mul_ps(texSampledColor, finalColor);
|
finalColor = _mm_mul_ps(texSampledColor, finalColor);
|
||||||
}
|
}
|
||||||
|
SIMDSetPixel(renderBuffer, posX, posY, finalColor, ColorSpace_Linear);
|
||||||
SIMDSetPixel(context, posX, posY, finalColor, ColorSpace_Linear);
|
|
||||||
}
|
}
|
||||||
renderBuffer->pixelLockTable[zBufferIndex] = false;
|
|
||||||
DEBUG_SIMD_AUTO_CHOOSE_END_CYCLE_COUNT(Triangle_RasterisePixel);
|
DEBUG_SIMD_AUTO_CHOOSE_END_CYCLE_COUNT(Triangle_RasterisePixel);
|
||||||
}
|
}
|
||||||
signedArea1 = _mm_add_ps(signedArea1, signedAreaPixelDeltaX);
|
signedArea1 = _mm_add_ps(signedArea1, signedAreaPixelDeltaX);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
signedAreaPixel1 = _mm_add_ps(signedAreaPixel1, signedAreaPixelDeltaY);
|
// Rasterise buffer(X + 1, Y) pixel
|
||||||
// signedAreaPixel2 = _mm_add_ps(signedAreaPixel2, signedAreaPixelDeltaY);
|
{
|
||||||
|
__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);
|
||||||
|
}
|
||||||
DEBUG_SIMD_AUTO_CHOOSE_END_CYCLE_COUNT(Triangle_Rasterise);
|
DEBUG_SIMD_AUTO_CHOOSE_END_CYCLE_COUNT(Triangle_Rasterise);
|
||||||
DEBUG_SIMD_AUTO_CHOOSE_END_CYCLE_COUNT(Triangle);
|
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 DqnV3 p3, const DqnV2 uv1, const DqnV2 uv2, const DqnV2 uv3,
|
||||||
const f32 lightIntensity1, const f32 lightIntensity2,
|
const f32 lightIntensity1, const f32 lightIntensity2,
|
||||||
const f32 lightIntensity3, const bool ignoreLight,
|
const f32 lightIntensity3, const bool ignoreLight,
|
||||||
@ -1076,6 +1071,7 @@ FILE_SCOPE void SlowTriangle(DTRRenderContext context, const DqnV3 p1, const Dqn
|
|||||||
const DqnV2i max)
|
const DqnV2i max)
|
||||||
{
|
{
|
||||||
DTR_DEBUG_EP_TIMED_FUNCTION();
|
DTR_DEBUG_EP_TIMED_FUNCTION();
|
||||||
|
|
||||||
#define DEBUG_SLOW_AUTO_CHOOSE_BEGIN_CYCLE_COUNT(type) \
|
#define DEBUG_SLOW_AUTO_CHOOSE_BEGIN_CYCLE_COUNT(type) \
|
||||||
do \
|
do \
|
||||||
{ \
|
{ \
|
||||||
@ -1095,9 +1091,8 @@ FILE_SCOPE void SlowTriangle(DTRRenderContext context, const DqnV3 p1, const Dqn
|
|||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
DEBUG_SLOW_AUTO_CHOOSE_BEGIN_CYCLE_COUNT(Triangle);
|
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
|
// 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++)
|
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);
|
DEBUG_SLOW_AUTO_CHOOSE_BEGIN_CYCLE_COUNT(Triangle_RasterisePixel);
|
||||||
f32 barycentricA = signedArea1 * invSignedAreaParallelogram;
|
|
||||||
f32 barycentricB = signedArea2 * invSignedAreaParallelogram;
|
f32 barycentricB = signedArea2 * invSignedAreaParallelogram;
|
||||||
f32 barycentricC = signedArea3 * invSignedAreaParallelogram;
|
f32 barycentricC = signedArea3 * invSignedAreaParallelogram;
|
||||||
|
|
||||||
i32 zBufferIndex = bufferX + (bufferY * zBufferPitch);
|
i32 zBufferIndex = bufferX + (bufferY * zBufferPitch);
|
||||||
if (context.multithread)
|
f32 pixelZValue = p1.z + (barycentricB * (p2SubP1.z)) + (barycentricC * (p3SubP1.z));
|
||||||
{
|
f32 currZValue = renderBuffer->zBuffer[zBufferIndex];
|
||||||
bool currLockValue;
|
DQN_ASSERT(zBufferIndex < (renderBuffer->width * renderBuffer->height));
|
||||||
do
|
|
||||||
{
|
|
||||||
currLockValue = (bool)context.api->AtomicCompareSwap(
|
|
||||||
(u32 *)&renderBuffer->pixelLockTable[zBufferIndex], (u32) true,
|
|
||||||
(u32) false);
|
|
||||||
} while (currLockValue != false);
|
|
||||||
}
|
|
||||||
|
|
||||||
f32 pixelZDepth =
|
if (pixelZValue >= currZValue)
|
||||||
p1.z + (barycentricB * (p2SubP1.z)) + (barycentricC * (p3SubP1.z));
|
|
||||||
if (pixelZDepth > renderBuffer->zBuffer[zBufferIndex])
|
|
||||||
{
|
{
|
||||||
|
renderBuffer->zBuffer[zBufferIndex] = pixelZValue;
|
||||||
DqnV4 finalColor = color;
|
DqnV4 finalColor = color;
|
||||||
renderBuffer->zBuffer[zBufferIndex] = pixelZDepth;
|
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)
|
if (!ignoreLight)
|
||||||
{
|
{
|
||||||
|
f32 barycentricA = signedArea1 * invSignedAreaParallelogram;
|
||||||
DqnV3 light = (p1Light * barycentricA) + (p2Light * barycentricB) +
|
DqnV3 light = (p1Light * barycentricA) + (p2Light * barycentricB) +
|
||||||
(p3Light * barycentricC);
|
(p3Light * barycentricC);
|
||||||
finalColor.rgb *= light;
|
finalColor.rgb *= light;
|
||||||
|
DQN_ASSERT(finalColor.x >= 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DQN_ASSERT(finalColor.x >= 0);
|
||||||
|
|
||||||
if (texture)
|
if (texture)
|
||||||
{
|
{
|
||||||
DqnV2 uv = uv1 + (uv2SubUv1 * barycentricB) + (uv3SubUv1 * barycentricC);
|
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 *= INV_255;
|
||||||
color1 = DTRRender_SRGB1ToLinearSpaceV4(color1);
|
color1 = DTRRender_SRGB1ToLinearSpaceV4(color1);
|
||||||
finalColor *= 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);
|
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;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
FILE_SCOPE void
|
FILE_SCOPE void TexturedTriangleInternal(DTRRenderBuffer *const renderBuffer,
|
||||||
TexturedTriangleInternal(DTRRenderContext context, RenderLightInternal lighting, DqnV3 p1, DqnV3 p2,
|
RenderLightInternal lighting, DqnV3 p1, DqnV3 p2, DqnV3 p3,
|
||||||
DqnV3 p3, DqnV2 uv1, DqnV2 uv2, DqnV2 uv3, DTRBitmap *const texture,
|
DqnV2 uv1, DqnV2 uv2, DqnV2 uv3, DTRBitmap *const texture,
|
||||||
DqnV4 color,
|
DqnV4 color, const DTRRenderTransform transform = DTRRender_DefaultTriangleTransform())
|
||||||
const DTRRenderTransform transform = DTRRender_DefaultTriangleTransform())
|
|
||||||
{
|
{
|
||||||
DTRRenderBuffer *renderBuffer = context.renderBuffer;
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////
|
||||||
// Transform vertexes p1, p2, p3 inplace
|
// Transform vertexes p1, p2, p3 inplace
|
||||||
////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////
|
||||||
@ -1324,14 +1355,14 @@ TexturedTriangleInternal(DTRRenderContext context, RenderLightInternal lighting,
|
|||||||
////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////
|
||||||
// SIMD/Slow Path
|
// 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);
|
lightIntensity3, ignoreLight, texture, color, min, max);
|
||||||
}
|
}
|
||||||
else
|
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);
|
lightIntensity3, ignoreLight, texture, color, min, max);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1344,7 +1375,7 @@ TexturedTriangleInternal(DTRRenderContext context, RenderLightInternal lighting,
|
|||||||
bool drawBasis = false;
|
bool drawBasis = false;
|
||||||
bool drawVertexMarkers = false;
|
bool drawVertexMarkers = false;
|
||||||
|
|
||||||
DebugRenderMarkers(context, pList, DQN_ARRAY_COUNT(pList), transform, drawBoundingBox,
|
DebugRenderMarkers(renderBuffer, pList, DQN_ARRAY_COUNT(pList), transform, drawBoundingBox,
|
||||||
drawBasis, drawVertexMarkers);
|
drawBasis, drawVertexMarkers);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1355,51 +1386,20 @@ FILE_SCOPE RenderLightInternal NullRenderLightInternal()
|
|||||||
return result;
|
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,
|
DqnV3 p1, DqnV3 p2, DqnV3 p3, DqnV2 uv1, DqnV2 uv2, DqnV2 uv3,
|
||||||
DTRBitmap *const texture, DqnV4 color,
|
DTRBitmap *const texture, DqnV4 color,
|
||||||
const DTRRenderTransform transform)
|
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);
|
color, transform);
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef struct RenderMeshJob
|
void DTRRender_Mesh(DTRRenderBuffer *const renderBuffer, DTRMesh *const mesh,
|
||||||
|
DTRRenderLight lighting, const DqnV3 pos,
|
||||||
|
const DTRRenderTransform transform)
|
||||||
{
|
{
|
||||||
DTRRenderContext context;
|
if (!mesh) return;
|
||||||
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;
|
|
||||||
|
|
||||||
DqnMat4 viewPModelViewProjection = {};
|
DqnMat4 viewPModelViewProjection = {};
|
||||||
{
|
{
|
||||||
@ -1502,7 +1502,6 @@ void DTRRender_Mesh(DTRRenderContext context, PlatformJobQueue *const jobQueue,
|
|||||||
DqnV2 uv3 = mesh->texUV[uv3Index].xy;
|
DqnV2 uv3 = mesh->texUV[uv3Index].xy;
|
||||||
|
|
||||||
DqnV4 color = lighting.color;
|
DqnV4 color = lighting.color;
|
||||||
|
|
||||||
RenderLightInternal lightingInternal = {};
|
RenderLightInternal lightingInternal = {};
|
||||||
lightingInternal.mode = lighting.mode;
|
lightingInternal.mode = lighting.mode;
|
||||||
lightingInternal.vector = lighting.vector;
|
lightingInternal.vector = lighting.vector;
|
||||||
@ -1512,92 +1511,43 @@ void DTRRender_Mesh(DTRRenderContext context, PlatformJobQueue *const jobQueue,
|
|||||||
lightingInternal.numNormals = 3;
|
lightingInternal.numNormals = 3;
|
||||||
|
|
||||||
bool DEBUG_NO_TEX = false;
|
bool DEBUG_NO_TEX = false;
|
||||||
if (context.multithread)
|
|
||||||
{
|
|
||||||
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)
|
if (DTR_DEBUG && DEBUG_NO_TEX)
|
||||||
{
|
{
|
||||||
jobData->tex = NULL;
|
TexturedTriangleInternal(renderBuffer, lightingInternal, v1.xyz, v2.xyz, v3.xyz, uv1,
|
||||||
|
uv2, uv3, NULL, color);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
jobData->tex = &mesh->tex;
|
TexturedTriangleInternal(renderBuffer, lightingInternal, v1.xyz, v2.xyz, v3.xyz, uv1,
|
||||||
}
|
uv2, uv3, &mesh->tex, color);
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DEBUG_WIREFRAME = false;
|
bool DEBUG_WIREFRAME = false;
|
||||||
if (DTR_DEBUG && DEBUG_WIREFRAME)
|
if (DTR_DEBUG && DEBUG_WIREFRAME)
|
||||||
{
|
{
|
||||||
DqnV4 wireColor = DqnV4_4f(1.0f, 1.0f, 1.0f, 0.01f);
|
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(renderBuffer, DqnV2i_V2(v1.xy), DqnV2i_V2(v2.xy),
|
||||||
DTRRender_Line(context, DqnV2i_V2(v2.xy), DqnV2i_V2(v3.xy), wireColor);
|
wireColor);
|
||||||
DTRRender_Line(context, DqnV2i_V2(v3.xy), DqnV2i_V2(v1.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)
|
void DTRRender_Triangle(DTRRenderBuffer *const renderBuffer, DqnV3 p1, DqnV3 p2, DqnV3 p3,
|
||||||
{
|
DqnV4 color, const DTRRenderTransform transform)
|
||||||
// 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)
|
|
||||||
{
|
{
|
||||||
const DqnV2 NO_UV = {};
|
const DqnV2 NO_UV = {};
|
||||||
DTRBitmap *const NO_TEX = NULL;
|
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);
|
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)
|
const DTRRenderTransform transform, DqnV4 color)
|
||||||
{
|
{
|
||||||
DTRRenderBuffer *renderBuffer = context.renderBuffer;
|
|
||||||
|
|
||||||
if (!bitmap || !bitmap->memory || !renderBuffer) return;
|
if (!bitmap || !bitmap->memory || !renderBuffer) return;
|
||||||
DTR_DEBUG_EP_TIMED_FUNCTION();
|
DTR_DEBUG_EP_TIMED_FUNCTION();
|
||||||
|
|
||||||
@ -1771,7 +1721,7 @@ void DTRRender_Bitmap(DTRRenderContext context, DTRBitmap *const bitmap, DqnV2 p
|
|||||||
blend.g *= color.g;
|
blend.g *= color.g;
|
||||||
blend.b *= color.b;
|
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 drawBasis = true;
|
||||||
bool drawVertexMarkers = true;
|
bool drawVertexMarkers = true;
|
||||||
|
|
||||||
DebugRenderMarkers(context, pList, RECT_PLIST_SIZE, transform, drawBoundingBox,
|
DebugRenderMarkers(renderBuffer, pList, RECT_PLIST_SIZE, transform, drawBoundingBox,
|
||||||
drawBasis, drawVertexMarkers);
|
drawBasis, drawVertexMarkers);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DTRRender_Clear(DTRRenderContext context, DqnV3 color)
|
void DTRRender_Clear(DTRRenderBuffer *const renderBuffer,
|
||||||
|
DqnV3 color)
|
||||||
{
|
{
|
||||||
DTRRenderBuffer *renderBuffer = context.renderBuffer;
|
|
||||||
if (!renderBuffer) return;
|
if (!renderBuffer) return;
|
||||||
|
|
||||||
DQN_ASSERT(color.r >= 0.0f && color.r <= 1.0f);
|
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
|
#define DTRENDERER_RENDER_H
|
||||||
|
|
||||||
#include "dqn.h"
|
#include "dqn.h"
|
||||||
#include "DTRendererPlatform.h"
|
|
||||||
|
|
||||||
#define DTRRENDER_INV_255 1.0f/255.0f
|
#define DTRRENDER_INV_255 1.0f/255.0f
|
||||||
|
|
||||||
|
typedef struct DTRRenderBuffer DTRRenderBuffer;
|
||||||
typedef struct DTRBitmap DTRBitmap;
|
typedef struct DTRBitmap DTRBitmap;
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
@ -16,11 +16,9 @@ typedef struct DTRRenderBuffer
|
|||||||
i32 width;
|
i32 width;
|
||||||
i32 height;
|
i32 height;
|
||||||
i32 bytesPerPixel;
|
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;
|
} DTRRenderBuffer;
|
||||||
|
|
||||||
@ -76,25 +74,15 @@ typedef struct DTRRenderLight
|
|||||||
DqnV4 color;
|
DqnV4 color;
|
||||||
} DTRRenderLight;
|
} 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
|
// 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.
|
// 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_Text (DTRRenderBuffer *const renderBuffer, 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_Line (DTRRenderBuffer *const renderBuffer, DqnV2i a, DqnV2i b, DqnV4 color);
|
||||||
void DTRRender_Rectangle (DTRRenderContext context, DqnV2 min, DqnV2 max, DqnV4 color, const DTRRenderTransform transform = DTRRender_DefaultTransform());
|
void DTRRender_Rectangle (DTRRenderBuffer *const renderBuffer, 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_Mesh (DTRRenderBuffer *const renderBuffer, 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_Triangle (DTRRenderBuffer *const renderBuffer, 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_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 (DTRRenderContext context, DTRBitmap *const bitmap, DqnV2 pos, const DTRRenderTransform transform = DTRRender_DefaultTransform(), DqnV4 color = DqnV4_4f(1, 1, 1, 1));
|
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 (DTRRenderContext context, DqnV3 color);
|
void DTRRender_Clear (DTRRenderBuffer *const renderBuffer, DqnV3 color);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -1,157 +1,18 @@
|
|||||||
#define UNICODE
|
|
||||||
#define _UNICODE
|
|
||||||
|
|
||||||
#include "DTRenderer.h"
|
#include "DTRenderer.h"
|
||||||
#include "DTRendererPlatform.h"
|
#include "DTRendererPlatform.h"
|
||||||
|
|
||||||
#define DQN_WIN32_IMPLEMENTATION
|
|
||||||
#define DQN_IMPLEMENTATION
|
#define DQN_IMPLEMENTATION
|
||||||
|
#define DQN_WIN32_IMPLEMENTATION
|
||||||
#include "dqn.h"
|
#include "dqn.h"
|
||||||
|
|
||||||
#include <Windows.h>
|
#define UNICODE
|
||||||
#include <Windowsx.h> // For GET_X|Y_LPARAM(), mouse input
|
#define _UNICODE
|
||||||
#include <Psapi.h> // For win32 GetProcessMemoryInfo()
|
|
||||||
|
|
||||||
FILE_SCOPE PlatformMemory globalPlatformMemory;
|
const char *const DLL_NAME = "dtrenderer.dll";
|
||||||
FILE_SCOPE bool globalRunning;
|
const char *const DLL_TMP_NAME = "dtrenderer_temp.dll";
|
||||||
|
|
||||||
void Platform_DieGracefully() { globalRunning = false; }
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// Platform Atomics
|
// Platform API Implementation
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
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
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
FILE_SCOPE inline PlatformFile DqnFileToPlatformFileInternal(const DqnFile file)
|
FILE_SCOPE inline PlatformFile DqnFileToPlatformFileInternal(const DqnFile file)
|
||||||
{
|
{
|
||||||
@ -176,7 +37,7 @@ FILE_SCOPE inline DqnFile PlatformFileToDqnFileInternal(const PlatformFile file)
|
|||||||
void Platform_Print(const char *const string)
|
void Platform_Print(const char *const string)
|
||||||
{
|
{
|
||||||
if (!string) return;
|
if (!string) return;
|
||||||
OutputDebugStringA(string);
|
OutputDebugString(string);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Platform_FileOpen(const char *const path, PlatformFile *const file, const u32 permissionFlags,
|
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;
|
if (!file || !buf) return 0;
|
||||||
|
|
||||||
DqnFile dqnFile = PlatformFileToDqnFileInternal(*file);
|
DqnFile dqnFile = PlatformFileToDqnFileInternal(*file);
|
||||||
size_t numBytesRead = DqnFile_Read(&dqnFile, buf, bytesToRead);
|
size_t numBytesRead = DqnFile_Read(dqnFile, buf, bytesToRead);
|
||||||
|
|
||||||
return numBytesRead;
|
return numBytesRead;
|
||||||
}
|
}
|
||||||
@ -234,9 +95,9 @@ void Platform_FileClose(PlatformFile *const file)
|
|||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// Win32 Layer
|
// Win32 Layer
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
const char *const DLL_NAME = "dtrenderer.dll";
|
#include <Windows.h>
|
||||||
const char *const DLL_TMP_NAME = "dtrenderer_temp.dll";
|
#include <Windowsx.h> // For GET_X|Y_LPARAM(), mouse input
|
||||||
|
#include <Psapi.h> // For win32 GetProcessMemoryInfo()
|
||||||
typedef struct Win32RenderBitmap
|
typedef struct Win32RenderBitmap
|
||||||
{
|
{
|
||||||
BITMAPINFO info;
|
BITMAPINFO info;
|
||||||
@ -248,6 +109,8 @@ typedef struct Win32RenderBitmap
|
|||||||
} Win32RenderBitmap;
|
} Win32RenderBitmap;
|
||||||
|
|
||||||
FILE_SCOPE Win32RenderBitmap globalRenderBitmap;
|
FILE_SCOPE Win32RenderBitmap globalRenderBitmap;
|
||||||
|
FILE_SCOPE PlatformMemory globalPlatformMemory;
|
||||||
|
FILE_SCOPE bool globalRunning;
|
||||||
|
|
||||||
typedef struct Win32ExternalCode
|
typedef struct Win32ExternalCode
|
||||||
{
|
{
|
||||||
@ -287,7 +150,7 @@ FILETIME Win32GetLastWriteTime(const char *const srcName)
|
|||||||
{
|
{
|
||||||
FILETIME lastWriteTime = {};
|
FILETIME lastWriteTime = {};
|
||||||
WIN32_FILE_ATTRIBUTE_DATA attribData = {};
|
WIN32_FILE_ATTRIBUTE_DATA attribData = {};
|
||||||
if (GetFileAttributesExA(srcName, GetFileExInfoStandard, &attribData) != 0)
|
if (GetFileAttributesEx(srcName, GetFileExInfoStandard, &attribData) != 0)
|
||||||
{
|
{
|
||||||
lastWriteTime = attribData.ftLastWriteTime;
|
lastWriteTime = attribData.ftLastWriteTime;
|
||||||
}
|
}
|
||||||
@ -301,7 +164,7 @@ FILE_SCOPE Win32ExternalCode Win32LoadExternalDLL(const char *const srcPath,
|
|||||||
{
|
{
|
||||||
Win32ExternalCode result = {};
|
Win32ExternalCode result = {};
|
||||||
result.lastWriteTime = lastWriteTime;
|
result.lastWriteTime = lastWriteTime;
|
||||||
CopyFileA(srcPath, tmpPath, false);
|
CopyFile(srcPath, tmpPath, false);
|
||||||
|
|
||||||
DTR_UpdateFunction *updateFunction = NULL;
|
DTR_UpdateFunction *updateFunction = NULL;
|
||||||
result.dll = LoadLibraryA(tmpPath);
|
result.dll = LoadLibraryA(tmpPath);
|
||||||
@ -332,10 +195,10 @@ FILE_SCOPE void Win32CreateMenu(HWND window)
|
|||||||
HMENU menuBar = CreateMenu();
|
HMENU menuBar = CreateMenu();
|
||||||
{ // File Menu
|
{ // File Menu
|
||||||
HMENU menu = CreatePopupMenu();
|
HMENU menu = CreatePopupMenu();
|
||||||
AppendMenuA(menuBar, MF_STRING | MF_POPUP, (UINT_PTR)menu, "File");
|
AppendMenu(menuBar, MF_STRING | MF_POPUP, (UINT_PTR)menu, "File");
|
||||||
AppendMenuA(menu, MF_STRING, Win32Menu_FileOpen, "Open");
|
AppendMenu(menu, MF_STRING, Win32Menu_FileOpen, "Open");
|
||||||
AppendMenuA(menu, MF_STRING, Win32Menu_FileFlushMemory, "Flush Memory");
|
AppendMenu(menu, MF_STRING, Win32Menu_FileFlushMemory, "Flush Memory");
|
||||||
AppendMenuA(menu, MF_STRING, Win32Menu_FileExit, "Exit");
|
AppendMenu(menu, MF_STRING, Win32Menu_FileExit, "Exit");
|
||||||
}
|
}
|
||||||
SetMenu(window, menuBar);
|
SetMenu(window, menuBar);
|
||||||
}
|
}
|
||||||
@ -549,13 +412,43 @@ 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
|
// Initialise Win32 Window
|
||||||
////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////
|
||||||
WNDCLASSEXW wc = {
|
WNDCLASSEXW wc =
|
||||||
|
{
|
||||||
sizeof(WNDCLASSEX),
|
sizeof(WNDCLASSEX),
|
||||||
CS_HREDRAW | CS_VREDRAW | CS_OWNDC,
|
CS_HREDRAW | CS_VREDRAW | CS_OWNDC,
|
||||||
Win32MainProcCallback,
|
Win32MainProcCallback,
|
||||||
@ -614,7 +507,7 @@ int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLi
|
|||||||
globalRenderBitmap.width = header.biWidth;
|
globalRenderBitmap.width = header.biWidth;
|
||||||
globalRenderBitmap.height = header.biHeight;
|
globalRenderBitmap.height = header.biHeight;
|
||||||
globalRenderBitmap.bytesPerPixel = header.biBitCount / 8;
|
globalRenderBitmap.bytesPerPixel = header.biBitCount / 8;
|
||||||
if (!DQN_ASSERT(globalRenderBitmap.bytesPerPixel >= 1)) return -1;
|
DQN_ASSERT(globalRenderBitmap.bytesPerPixel >= 1);
|
||||||
|
|
||||||
HDC deviceContext = GetDC(mainWindow);
|
HDC deviceContext = GetDC(mainWindow);
|
||||||
globalRenderBitmap.handle = CreateDIBSection(
|
globalRenderBitmap.handle = CreateDIBSection(
|
||||||
@ -637,130 +530,39 @@ int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLi
|
|||||||
char dllTmpPath[MAX_PATH] = {};
|
char dllTmpPath[MAX_PATH] = {};
|
||||||
{
|
{
|
||||||
char exeDir[MAX_PATH] = {};
|
char exeDir[MAX_PATH] = {};
|
||||||
i32 lastSlashIndex = DqnWin32_GetEXEDirectory(exeDir, DQN_ARRAY_COUNT(exeDir));
|
i32 lastSlashIndex =
|
||||||
if (DQN_ASSERT_MSG(lastSlashIndex != -1, "Not enough space in buffer for exe path"))
|
Win32GetModuleDirectory(exeDir, DQN_ARRAY_COUNT(exeDir));
|
||||||
{
|
DQN_ASSERT(lastSlashIndex + 1 < DQN_ARRAY_COUNT(exeDir));
|
||||||
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);
|
|
||||||
|
|
||||||
if (!DQN_ASSERT_MSG((dllNumCopied < DQN_ARRAY_COUNT(dllPath)) &&
|
exeDir[lastSlashIndex + 1] = 0;
|
||||||
(dllTmpNumCopied < DQN_ARRAY_COUNT(dllPath)),
|
u32 numCopied = Dqn_sprintf(dllPath, "%s%s", exeDir, DLL_NAME);
|
||||||
"Out of space to form DLL path"))
|
DQN_ASSERT(numCopied < DQN_ARRAY_COUNT(dllPath));
|
||||||
{
|
|
||||||
Platform_DieGracefully();
|
numCopied =
|
||||||
}
|
Dqn_sprintf(dllTmpPath, "%s%s", exeDir, DLL_TMP_NAME);
|
||||||
}
|
DQN_ASSERT(numCopied < DQN_ARRAY_COUNT(dllTmpPath));
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////
|
||||||
// Platform Data Pre-amble
|
// Platform Data Pre-amble
|
||||||
////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////
|
||||||
bool memoryInitResult =
|
DQN_ASSERT(DqnMemStack_Init(&globalPlatformMemory.mainStack, DQN_MEGABYTE(4), true, 4) &&
|
||||||
DqnMemStack_Init(&globalPlatformMemory.mainStack, DQN_MEGABYTE(4), true, 4) |
|
DqnMemStack_Init(&globalPlatformMemory.tempStack, DQN_MEGABYTE(4), true, 4) &&
|
||||||
DqnMemStack_Init(&globalPlatformMemory.tempStack, DQN_MEGABYTE(4), true, 4) |
|
DqnMemStack_Init(&globalPlatformMemory.assetStack, 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();
|
|
||||||
}
|
|
||||||
|
|
||||||
PlatformAPI platformAPI = {};
|
PlatformAPI platformAPI = {};
|
||||||
platformAPI.DieGracefully = Platform_DieGracefully;
|
|
||||||
|
|
||||||
platformAPI.FileOpen = Platform_FileOpen;
|
platformAPI.FileOpen = Platform_FileOpen;
|
||||||
platformAPI.FileRead = Platform_FileRead;
|
platformAPI.FileRead = Platform_FileRead;
|
||||||
platformAPI.FileWrite = Platform_FileWrite;
|
platformAPI.FileWrite = Platform_FileWrite;
|
||||||
platformAPI.FileClose = Platform_FileClose;
|
platformAPI.FileClose = Platform_FileClose;
|
||||||
platformAPI.Print = Platform_Print;
|
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 = {};
|
|
||||||
|
|
||||||
PlatformInput platformInput = {};
|
PlatformInput platformInput = {};
|
||||||
platformInput.api = platformAPI;
|
platformInput.api = platformAPI;
|
||||||
platformInput.jobQueue = &jobQueue;
|
|
||||||
platformInput.flags.canUseSSE2 = IsProcessorFeaturePresent(PF_XMMI64_INSTRUCTIONS_AVAILABLE);
|
platformInput.flags.canUseSSE2 = IsProcessorFeaturePresent(PF_XMMI64_INSTRUCTIONS_AVAILABLE);
|
||||||
platformInput.flags.canUseRdtsc = IsProcessorFeaturePresent(PF_RDTSC_INSTRUCTION_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
|
// Update Loop
|
||||||
////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////
|
||||||
@ -774,7 +576,7 @@ int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLi
|
|||||||
////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////
|
||||||
// Update State
|
// Update State
|
||||||
////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////
|
||||||
f64 startFrameTimeInS = DqnTimer_NowInS();
|
f64 startFrameTimeInS = DqnTime_NowInS();
|
||||||
|
|
||||||
FILETIME lastWriteTime = Win32GetLastWriteTime(dllPath);
|
FILETIME lastWriteTime = Win32GetLastWriteTime(dllPath);
|
||||||
if (CompareFileTime(&lastWriteTime, &dllCode.lastWriteTime) != 0)
|
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;
|
platformInput.deltaForFrame = (f32)frameTimeInS;
|
||||||
Win32ProcessMessages(mainWindow, &platformInput);
|
Win32ProcessMessages(mainWindow, &platformInput);
|
||||||
|
|
||||||
@ -797,7 +599,8 @@ int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLi
|
|||||||
|
|
||||||
if (dllCode.DTR_Update)
|
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
|
// Frame Limiting
|
||||||
////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////
|
||||||
{
|
{
|
||||||
f64 workTimeInS = DqnTimer_NowInS() - startFrameTimeInS;
|
f64 workTimeInS = DqnTime_NowInS() - startFrameTimeInS;
|
||||||
if (workTimeInS < targetSecondsPerFrame)
|
if (workTimeInS < targetSecondsPerFrame)
|
||||||
{
|
{
|
||||||
DWORD remainingTimeInMs =
|
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 msPerFrame = 1000.0f * (f32)frameTimeInS;
|
||||||
f32 framesPerSecond = 1.0f / (f32)frameTimeInS;
|
f32 framesPerSecond = 1.0f / (f32)frameTimeInS;
|
||||||
|
|
||||||
|
@ -16,11 +16,6 @@ if %errorlevel%==0 (
|
|||||||
ctags -R
|
ctags -R
|
||||||
)
|
)
|
||||||
|
|
||||||
where /q gtags
|
|
||||||
if %errorlevel%==0 (
|
|
||||||
gtags
|
|
||||||
)
|
|
||||||
|
|
||||||
set ProjectName=dtrenderer
|
set ProjectName=dtrenderer
|
||||||
ctime -begin ..\src\%ProjectName%.ctm
|
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 GR- disable c runtime type information (we don't use)
|
||||||
REM MD use dynamic runtime library
|
REM MD use dynamic runtime library
|
||||||
REM MT use static runtime library, so build and link it into exe
|
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 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 instead of generating a call to external library (i.e. CRT).
|
||||||
REM Zi enables debug data, Z7 combines the debug files into one.
|
REM Zi enables debug data, Z7 combines the debug files into one.
|
||||||
@ -43,10 +39,16 @@ REM wd4100 unused argument parameters
|
|||||||
REM wd4201 nonstandard extension used: nameless struct/union
|
REM wd4201 nonstandard extension used: nameless struct/union
|
||||||
REM wd4189 local variable is initialised but not referenced
|
REM wd4189 local variable is initialised but not referenced
|
||||||
REM wd4505 unreferenced local function not used will be removed
|
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 DLLFlags=/Fm%ProjectName% /Fo%ProjectName% /Fa%ProjectName% /Fe%ProjectName%
|
||||||
set Win32Flags=/FmWin32DTRenderer /FeWin32DTRenderer
|
set Win32Flags=/FmWin32DTRenderer /FeWin32DTRenderer
|
||||||
|
|
||||||
|
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
|
REM Link libraries
|
||||||
set LinkLibraries=user32.lib kernel32.lib gdi32.lib
|
set LinkLibraries=user32.lib kernel32.lib gdi32.lib
|
||||||
|
|
||||||
@ -54,36 +56,11 @@ REM incremental:no, turn incremental builds off
|
|||||||
REM opt:ref, try to remove functions from libs that are not referenced at all
|
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 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 ////////////////////////////////////////////////////////////////////////////
|
||||||
REM Compile
|
REM Compile
|
||||||
REM ////////////////////////////////////////////////////////////////////////////
|
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%
|
|
||||||
|
|
||||||
del *.pdb >NUL 2>NUL
|
del *.pdb >NUL 2>NUL
|
||||||
cl %CompileFlags% %Win32Flags% ..\src\Win32DTRenderer.cpp /link %LinkLibraries% %LinkFlags%
|
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%
|
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%
|
cl %CompileFlags% %DLLFlags% ..\src\UnityBuild\UnityBuild.cpp /LD /link /PDB:%ProjectName%_%TimeStamp%.pdb /export:DTR_Update %LinkFlags%
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user