Prepare triangle rendering for zbuffer support

This commit is contained in:
Doyle Thai 2017-05-23 22:42:54 +10:00
parent e922efb897
commit d42d6ef5bf
7 changed files with 221 additions and 170 deletions

View File

@ -52,8 +52,9 @@ FILE_SCOPE bool ObjWavefrontLoad(const PlatformAPI api, PlatformMemory *const me
if (!api.FileOpen(path, &file, PlatformFilePermissionFlag_Read))
return false; // TODO(doyle): Logging
// TODO(doyle): Make arrays use given memory not malloc
DqnTempMemStack tmpMemRegion = DqnMemStack_BeginTempRegion(&memory->transMemStack);
u8 *rawBytes = (u8 *)DqnMemStack_Allocate(&memory->transMemStack, file.size);
u8 *rawBytes = (u8 *)DqnMemStack_Push(&memory->transMemStack, file.size);
size_t bytesRead = api.FileRead(&file, rawBytes, file.size);
size_t fileSize = file.size;
api.FileClose(&file);
@ -284,7 +285,7 @@ FILE_SCOPE bool ObjWavefrontLoad(const PlatformAPI api, PlatformMemory *const me
DQN_ASSERT(obj->model.groupNameIndex + 1 < DQN_ARRAY_COUNT(obj->model.groupName));
DQN_ASSERT(!obj->model.groupName[obj->model.groupNameIndex]);
obj->model.groupName[obj->model.groupNameIndex++] = (char *)DqnMemStack_Allocate(
obj->model.groupName[obj->model.groupNameIndex++] = (char *)DqnMemStack_Push(
&memory->permMemStack, (nameLen + 1) * sizeof(char));
for (i32 i = 0; i < nameLen; i++)
@ -371,7 +372,7 @@ FILE_SCOPE bool BitmapFontCreate(const PlatformAPI api,
return false; // TODO(doyle): Logging
DqnTempMemStack tmpMemRegion = DqnMemStack_BeginTempRegion(&memory->transMemStack);
u8 *fontBuf = (u8 *)DqnMemStack_Allocate(&memory->transMemStack, file.size);
u8 *fontBuf = (u8 *)DqnMemStack_Push(&memory->transMemStack, file.size);
size_t bytesRead = api.FileRead(&file, fontBuf, file.size);
api.FileClose(&file);
if (bytesRead != file.size)
@ -392,7 +393,7 @@ FILE_SCOPE bool BitmapFontCreate(const PlatformAPI api,
////////////////////////////////////////////////////////////////////////////
// Pack font data to bitmap
////////////////////////////////////////////////////////////////////////////
loadedFont.bitmap = (u8 *)DqnMemStack_Allocate(
loadedFont.bitmap = (u8 *)DqnMemStack_Push(
&memory->permMemStack,
(size_t)(loadedFont.bitmapDim.w * loadedFont.bitmapDim.h));
@ -405,7 +406,7 @@ FILE_SCOPE bool BitmapFontCreate(const PlatformAPI api,
i32 numCodepoints =
(i32)((codepointRange.max + 1) - codepointRange.min);
loadedFont.atlas = (stbtt_packedchar *)DqnMemStack_Allocate(
loadedFont.atlas = (stbtt_packedchar *)DqnMemStack_Push(
&memory->permMemStack, numCodepoints * sizeof(stbtt_packedchar));
stbtt_PackFontRange(&fontPackContext, fontBuf, 0,
STBTT_POINT_SIZE(sizeInPt), (i32)codepointRange.min,
@ -463,7 +464,7 @@ FILE_SCOPE bool BitmapLoad(const PlatformAPI api, DTRBitmap *bitmap,
DqnTempMemStack tempBuffer = DqnMemStack_BeginTempRegion(transMemStack);
{
u8 *const rawData =
(u8 *)DqnMemStack_Allocate(transMemStack, file.size);
(u8 *)DqnMemStack_Push(transMemStack, file.size);
size_t bytesRead = api.FileRead(&file, rawData, file.size);
api.FileClose(&file);
@ -511,7 +512,7 @@ FILE_SCOPE bool BitmapLoad(const PlatformAPI api, DTRBitmap *bitmap,
}
// #include <algorithm>
void CompAssignment(PlatformRenderBuffer *const renderBuffer, PlatformInput *const input,
void CompAssignment(DTRRenderBuffer *const renderBuffer, PlatformInput *const input,
PlatformMemory *const memory)
{
#if 1
@ -1441,10 +1442,13 @@ FILE_SCOPE void TestStrToF32Converter()
DQN_ASSERT(DQN_ABS(vQ) - DQN_ABS(9.64635e-05) < EPSILON);
}
extern "C" void DTR_Update(PlatformRenderBuffer *const renderBuffer,
extern "C" void DTR_Update(PlatformRenderBuffer *const platformRenderBuffer,
PlatformInput *const input,
PlatformMemory *const memory)
{
////////////////////////////////////////////////////////////////////////////
// Initialisation
////////////////////////////////////////////////////////////////////////////
DTRState *state = (DTRState *)memory->context;
if (input->executableReloaded)
{
@ -1463,7 +1467,7 @@ extern "C" void DTR_Update(PlatformRenderBuffer *const renderBuffer,
memory->isInit = true;
memory->context =
DqnMemStack_Allocate(&memory->permMemStack, sizeof(DTRState));
DqnMemStack_Push(&memory->permMemStack, sizeof(DTRState));
DQN_ASSERT(memory->context);
state = (DTRState *)memory->context;
@ -1473,126 +1477,149 @@ extern "C" void DTR_Update(PlatformRenderBuffer *const renderBuffer,
&memory->transMemStack);
DTRBitmap test = {};
DqnTempMemStack tmp = DqnMemStack_BeginTempRegion(&memory->permMemStack);
DqnTempMemStack tmp = DqnMemStack_BeginTempRegion(&memory->transMemStack);
BitmapLoad(input->api, &test, "byte_read_check.bmp",
&memory->transMemStack);
DqnMemStack_EndTempRegion(tmp);
DQN_ASSERT(ObjWavefrontLoad(input->api, memory, "african_head.obj", &state->obj));
}
DTRRender_Clear(renderBuffer, DqnV3_3f(0.0f, 0.0f, 0.0f));
const DqnV3 LIGHT = DqnV3_3i(0, 0, -1);
const f32 MODEL_SCALE = DQN_MIN(renderBuffer->width, renderBuffer->height) * 0.5f;
WavefrontObj *const waveObj = &state->obj;
DqnV2 modelP = DqnV2_2f(renderBuffer->width * 0.5f, renderBuffer->height * 0.5f);
DqnTempMemStack transMemTmpRegion = DqnMemStack_BeginTempRegion(&memory->transMemStack);
for (i32 i = 0; i < waveObj->model.faces.count; i++)
DTRRenderBuffer renderBuffer = {};
renderBuffer.width = platformRenderBuffer->width;
renderBuffer.height = platformRenderBuffer->height;
renderBuffer.bytesPerPixel = platformRenderBuffer->bytesPerPixel;
renderBuffer.memory = (u8 *)platformRenderBuffer->memory;
renderBuffer.zBuffer = (f32 *)DqnMemStack_Push(
&memory->transMemStack,
platformRenderBuffer->width * platformRenderBuffer->height * sizeof(*renderBuffer.zBuffer));
////////////////////////////////////////////////////////////////////////////
// Update and Render
////////////////////////////////////////////////////////////////////////////
DTRRender_Clear(&renderBuffer, DqnV3_3f(0.0f, 0.0f, 0.0f));
#if 1
DqnV4 colorRed = DqnV4_4f(0.8f, 0, 0, 1);
DqnV2i bufferMidP = DqnV2i_2f(renderBuffer.width * 0.5f, renderBuffer.height * 0.5f);
f32 rotation = (f32)input->timeNowInS * 0.25f;
// Triangle Drawing
{
WavefrontModelFace face = waveObj->model.faces.data[i];
DQN_ASSERT(face.vertexArray.count == 3);
i32 vertAIndex = face.vertexArray.data[0];
i32 vertBIndex = face.vertexArray.data[1];
i32 vertCIndex = face.vertexArray.data[2];
DqnV4 redTransparent = DqnV4_4f(1, 0, 0, 0.5f);
DqnV4 vertA = waveObj->geometryArray.data[vertAIndex];
DqnV4 vertB = waveObj->geometryArray.data[vertBIndex];
DqnV4 vertC = waveObj->geometryArray.data[vertCIndex];
i32 boundsOffset = 100;
DqnV3 t0[3] = {DqnV3_3i(10, 70, 0), DqnV3_3i(50, 160, 0), DqnV3_3i(70, 80, 0)};
DqnV3 t1[3] = {DqnV3_3i(180, 50, 0), DqnV3_3i(150, 1, 0), DqnV3_3i(70, 180, 0)};
DqnV3 t2[3] = {DqnV3_3i(180, 150, 0), DqnV3_3i(120, 160, 0), DqnV3_3i(130, 180, 0)};
DqnV3 t3[3] = {DqnV3_3i(boundsOffset, boundsOffset, 0),
DqnV3_3i(bufferMidP.w, renderBuffer.height - boundsOffset, 0),
DqnV3_3i(renderBuffer.width - boundsOffset, boundsOffset, 0)};
DqnV3 t4[3] = {DqnV3_3i(100, 150, 0), DqnV3_3i(200, 150, 0), DqnV3_3i(200, 250, 0)};
DqnV3 t5[3] = {DqnV3_3i(300, 150, 0), DqnV3_3i(201, 150, 0), DqnV3_3i(200, 250, 0)};
DqnV4 vertAB = vertB - vertA;
DqnV4 vertAC = vertC - vertA;
DqnV3 normal = DqnV3_Cross(vertAC.xyz, vertAB.xyz);
DTRRenderTransform rotatingXform = DTRRender_DefaultTriangleTransform();
rotatingXform.rotation = rotation;
f32 intensity = DqnV3_Dot(DqnV3_Normalise(normal), LIGHT);
if (intensity > 0)
DTRRender_Triangle(&renderBuffer, t0[0], t0[1], t0[2], colorRed);
DTRRender_Triangle(&renderBuffer, t1[0], t1[1], t1[2], colorRed);
DTRRender_Triangle(&renderBuffer, t3[0], t3[1], t3[2], colorRed, rotatingXform);
DTRRender_Triangle(&renderBuffer, t2[0], t2[1], t2[2], colorRed);
DTRRender_Triangle(&renderBuffer, t4[0], t4[1], t4[2], colorRed);
DTRRender_Triangle(&renderBuffer, t5[0], t5[1], t5[2], colorRed);
////////////////////////////////////////////////////////////////////////
// Draw Loaded Model
////////////////////////////////////////////////////////////////////////
const DqnV3 LIGHT = DqnV3_3i(0, 0, -1);
const f32 MODEL_SCALE = DQN_MIN(renderBuffer.width, renderBuffer.height) * 0.5f;
WavefrontObj *const waveObj = &state->obj;
DqnV3 modelP = DqnV3_3f(renderBuffer.width * 0.5f, renderBuffer.height * 0.5f, 0);
for (i32 i = 0; i < waveObj->model.faces.count; i++)
{
DqnV4 modelCol = DqnV4_4f(1, 1, 1, 1);
modelCol.rgb *= intensity;
WavefrontModelFace face = waveObj->model.faces.data[i];
DQN_ASSERT(face.vertexArray.count == 3);
i32 vertAIndex = face.vertexArray.data[0];
i32 vertBIndex = face.vertexArray.data[1];
i32 vertCIndex = face.vertexArray.data[2];
DqnV2 screenVertA = (vertA.xy * MODEL_SCALE) + modelP;
DqnV2 screenVertB = (vertB.xy * MODEL_SCALE) + modelP;
DqnV2 screenVertC = (vertC.xy * MODEL_SCALE) + modelP;
DqnV4 vertA = waveObj->geometryArray.data[vertAIndex];
DqnV4 vertB = waveObj->geometryArray.data[vertBIndex];
DqnV4 vertC = waveObj->geometryArray.data[vertCIndex];
// TODO(doyle): Why do we need rounding here? Maybe it's because
// I don't do any interpolation in the triangle routine for jagged
// edges.
screenVertA.x = (f32)(i32)(screenVertA.x + 0.5f);
screenVertA.y = (f32)(i32)(screenVertA.y + 0.5f);
screenVertB.x = (f32)(i32)(screenVertB.x + 0.5f);
screenVertB.y = (f32)(i32)(screenVertB.y + 0.5f);
screenVertC.x = (f32)(i32)(screenVertC.x + 0.5f);
screenVertC.y = (f32)(i32)(screenVertC.y + 0.5f);
DqnV4 vertAB = vertB - vertA;
DqnV4 vertAC = vertC - vertA;
DqnV3 normal = DqnV3_Cross(vertAC.xyz, vertAB.xyz);
DTRRender_Triangle(renderBuffer, screenVertA, screenVertB, screenVertC, modelCol);
f32 intensity = DqnV3_Dot(DqnV3_Normalise(normal), LIGHT);
if (intensity > 0)
{
DqnV4 modelCol = DqnV4_4f(1, 1, 1, 1);
modelCol.rgb *= intensity;
DqnV3 screenVA = (vertA.xyz * MODEL_SCALE) + modelP;
DqnV3 screenVB = (vertB.xyz * MODEL_SCALE) + modelP;
DqnV3 screenVC = (vertC.xyz * MODEL_SCALE) + modelP;
// TODO(doyle): Why do we need rounding here? Maybe it's because
// I don't do any interpolation in the triangle routine for jagged
// edges.
screenVA.x = (f32)(i32)(screenVA.x + 0.5f);
screenVA.y = (f32)(i32)(screenVA.y + 0.5f);
screenVB.x = (f32)(i32)(screenVB.x + 0.5f);
screenVB.y = (f32)(i32)(screenVB.y + 0.5f);
screenVC.x = (f32)(i32)(screenVC.x + 0.5f);
screenVC.y = (f32)(i32)(screenVC.y + 0.5f);
DTRRender_Triangle(&renderBuffer, screenVA, screenVB, screenVC, modelCol);
#if 0
DqnV4 wireColor = DqnV4_1f(1.0f);
for (i32 j = 0; j < 3; j++)
{
DTRRender_Line(renderBuffer, DqnV2i_V2(screenVertA), DqnV2i_V2(screenVertB), wireColor);
}
DqnV4 wireColor = DqnV4_1f(1.0f);
for (i32 j = 0; j < 3; j++)
{
DTRRender_Line(renderBuffer, DqnV2i_V2(screenVertA), DqnV2i_V2(screenVertB), wireColor);
}
#endif
}
}
}
#if 1
DqnV4 colorRed = DqnV4_4f(0.8f, 0, 0, 1);
DqnV2i bufferMidP =
DqnV2i_2f(renderBuffer->width * 0.5f, renderBuffer->height * 0.5f);
i32 boundsOffset = 100;
DqnV2 t0[3] = {DqnV2_2i(10, 70), DqnV2_2i(50, 160), DqnV2_2i(70, 80)};
DqnV2 t1[3] = {DqnV2_2i(180, 50), DqnV2_2i(150, 1), DqnV2_2i(70, 180)};
DqnV2 t2[3] = {DqnV2_2i(180, 150), DqnV2_2i(120, 160), DqnV2_2i(130, 180)};
LOCAL_PERSIST DqnV2 t3[3] = {
DqnV2_2i(boundsOffset, boundsOffset),
DqnV2_2i(bufferMidP.w, renderBuffer->height - boundsOffset),
DqnV2_2i(renderBuffer->width - boundsOffset, boundsOffset)};
DTRRender_Triangle(renderBuffer, t0[0], t0[1], t0[2], colorRed);
DTRRender_Triangle(renderBuffer, t1[0], t1[1], t1[2], colorRed);
DTRRender_Triangle(renderBuffer, t2[0], t2[1], t2[2], colorRed);
DqnV2 t4[3] = {DqnV2_2i(100, 150), DqnV2_2i(200, 150), DqnV2_2i(200, 250)};
DqnV2 t5[3] = {DqnV2_2i(300, 150), DqnV2_2i(201, 150), DqnV2_2i(200, 250)};
DTRRender_Triangle(renderBuffer, t4[0], t4[1], t4[2], colorRed);
DTRRender_Triangle(renderBuffer, t5[0], t5[1], t5[2], colorRed);
DqnV4 colorRedHalfA = DqnV4_4f(1, 0, 0, 0.1f);
LOCAL_PERSIST f32 rotation = 0;
rotation += input->deltaForFrame * 0.25f;
DTRRenderTransform defaultTransform = DTRRender_DefaultTransform();
defaultTransform.rotation = rotation + 45;
DTRRender_Rectangle(renderBuffer, DqnV2_1f(300.0f), DqnV2_1f(300 + 100.0f), DqnV4_4f(0, 1.0f, 1.0f, 1.0f),
defaultTransform);
// Rotating triangle
// Rect drawing
{
DTRRenderTransform triTransform = DTRRender_DefaultTriangleTransform();
triTransform.rotation = rotation;
DTRRender_Triangle(renderBuffer, t3[0], t3[1], t3[2], colorRedHalfA, triTransform);
DTRRenderTransform transform = DTRRender_DefaultTransform();
transform.rotation = rotation + 45;
DTRRender_Rectangle(&renderBuffer, DqnV2_1f(300.0f), DqnV2_1f(300 + 100.0f),
DqnV4_4f(0, 1.0f, 1.0f, 1.0f), transform);
}
// Bitmap drawing
{
DTRRenderTransform transform = DTRRender_DefaultTransform();
transform.scale = DqnV2_1f(2.0f);
DqnV2 fontP = DqnV2_2i(200, 180);
DTRRender_Text(renderBuffer, state->font, fontP, "hello world!", DqnV4_4f(0, 0, 0, 1));
LOCAL_PERSIST DqnV2 bitmapP = DqnV2_2f(300, 250);
bitmapP.x += 3.0f * sinf((f32)input->timeNowInS * 0.5f);
DTRRenderTransform transform = DTRRender_DefaultTransform();
transform.rotation = 0;
transform.scale = DqnV2_1f(2.0f);
LOCAL_PERSIST DqnV2 bitmapP = DqnV2_2f(300, 250);
bitmapP.x += 3.0f * sinf((f32)input->timeNowInS * 0.5f);
f32 cAngle = (f32)input->timeNowInS;
DqnV4 color = DqnV4_4f(0.5f + 0.5f * sinf(cAngle), 0.5f + 0.5f * sinf(2.9f * cAngle),
0.5f + 0.5f * cosf(10.0f * cAngle), 1.0f);
DTRRender_Bitmap(renderBuffer, &state->bitmap, bitmapP, transform, color);
f32 cAngle = (f32)input->timeNowInS;
DqnV4 color = DqnV4_4f(0.5f + 0.5f * sinf(cAngle), 0.5f + 0.5f * sinf(2.9f * cAngle),
0.5f + 0.5f * cosf(10.0f * cAngle), 1.0f);
DTRRender_Bitmap(&renderBuffer, &state->bitmap, bitmapP, transform, color);
}
#else
// CompAssignment(renderBuffer, input, memory);
#endif
DTRDebug_Update(state, renderBuffer, input, memory);
DTRDebug_Update(state, &renderBuffer, input, memory);
////////////////////////////////////////////////////////////////////////////
// End Update
////////////////////////////////////////////////////////////////////////////
DqnMemStack_EndTempRegion(transMemTmpRegion);
DQN_ASSERT(memory->transMemStack.tempStackCount == 0);
DQN_ASSERT(memory->permMemStack.tempStackCount == 0);
}

View File

@ -54,8 +54,8 @@ FILE_SCOPE void PushMemStackText(const char *const name,
size_t totalWastedKb = totalWasted / 1024;
char str[128] = {};
Dqn_sprintf(str, "%s: %d block(s): %_$lld/%_$lld", name, numBlocks,
totalUsed, totalSize);
Dqn_sprintf(str, "%s: %d block(s): %_$lld/%_$lld: wasted: %_$lld", name, numBlocks,
totalUsed, totalSize, totalWastedKb);
DTRRender_Text(globalDebug.renderBuffer, *globalDebug.font,
globalDebug.displayP, str, globalDebug.displayColor);
@ -64,7 +64,7 @@ FILE_SCOPE void PushMemStackText(const char *const name,
}
void DTRDebug_Update(DTRState *const state,
PlatformRenderBuffer *const renderBuffer,
DTRRenderBuffer *const renderBuffer,
PlatformInput *const input, PlatformMemory *const memory)
{
if (DTR_DEBUG)
@ -80,11 +80,13 @@ void DTRDebug_Update(DTRState *const state,
DQN_ASSERT(globalDebug.displayYOffset < 0);
}
debug->totalSetPixels += debug->setPixelsPerFrame;
debug->totalSetPixels += debug->counter[DTRDebugCounter_SetPixels];
debug->totalSetPixels = DQN_MAX(0, debug->totalSetPixels);
DTRDebug_PushText("TotalSetPixels: %'lld", debug->totalSetPixels);
DTRDebug_PushText("SetPixelsPerFrame: %'lld", debug->setPixelsPerFrame);
DTRDebug_PushText("SetPixelsPerFrame: %'lld", debug->counter[DTRDebugCounter_SetPixels]);
DTRDebug_PushText("TrianglesRendered: %'lld", debug->counter[DTRDebugCounter_RenderTriangle]);
DTRDebug_PushText("");
// memory
{
@ -94,9 +96,11 @@ void DTRDebug_Update(DTRState *const state,
DTRDebug_PushText("SSE2Support: %s", (input->canUseSSE2) ? "true" : "false");
debug->setPixelsPerFrame = 0;
debug->displayP =
DqnV2_2i(0, debug->renderBuffer->height + globalDebug.displayYOffset);
for (i32 i = 0; i < DQN_ARRAY_COUNT(debug->counter); i++)
debug->counter[i] = 0;
}
}

View File

@ -30,22 +30,29 @@
#endif
typedef struct PlatformRenderBuffer PlatformRenderBuffer;
typedef struct DTRFont DTRFont;
typedef struct DTRState DTRState;
typedef struct PlatformInput PlatformInput;
typedef struct PlatformMemory PlatformMemory;
typedef struct DTRRenderBuffer DTRRenderBuffer;
typedef struct DTRFont DTRFont;
typedef struct DTRState DTRState;
typedef struct PlatformInput PlatformInput;
typedef struct PlatformMemory PlatformMemory;
enum DTRDebugCounter
{
DTRDebugCounter_SetPixels,
DTRDebugCounter_RenderTriangle,
DTRDebugCounter_Count,
};
typedef struct DTRDebug
{
DTRFont *font;
PlatformRenderBuffer *renderBuffer;
DTRFont *font;
DTRRenderBuffer *renderBuffer;
DqnV4 displayColor;
DqnV2 displayP;
i32 displayYOffset;
u64 setPixelsPerFrame;
u64 counter[DTRDebugCounter_Count];
u64 totalSetPixels;
} DTRDebug;
@ -53,6 +60,16 @@ extern DTRDebug globalDebug;
void DTRDebug_PushText(const char *const formatStr, ...);
void DTRDebug_Update(DTRState *const state,
PlatformRenderBuffer *const renderBuffer,
DTRRenderBuffer *const renderBuffer,
PlatformInput *const input, PlatformMemory *const memory);
void inline DTRDebug_CounterIncrement(enum DTRDebugCounter tag)
{
if (DTR_DEBUG)
{
DQN_ASSERT(tag >= 0 && tag < DTRDebugCounter_Count);
globalDebug.counter[tag]++;
}
}
#endif

View File

@ -99,7 +99,7 @@ inline DqnV4 DTRRender_PreMultiplyAlphaSRGB1WithLinearConversion(DqnV4 color)
}
// IMPORTANT(doyle): Color is expected to be premultiplied already
FILE_SCOPE inline void SetPixel(PlatformRenderBuffer *const renderBuffer, const i32 x, const i32 y,
FILE_SCOPE inline void SetPixel(DTRRenderBuffer *const renderBuffer, const i32 x, const i32 y,
DqnV4 color, const enum ColorSpace colorSpace = ColorSpace_SRGB)
{
if (!renderBuffer) return;
@ -166,10 +166,10 @@ FILE_SCOPE inline void SetPixel(PlatformRenderBuffer *const renderBuffer, const
(u32)(destB) << 0;
bitmapPtr[x + (y * pitchInU32)] = pixel;
globalDebug.setPixelsPerFrame++;
DTRDebug_CounterIncrement(DTRDebugCounter_SetPixels);
}
void DTRRender_Text(PlatformRenderBuffer *const renderBuffer,
void DTRRender_Text(DTRRenderBuffer *const renderBuffer,
const DTRFont font, DqnV2 pos, const char *const text,
DqnV4 color, i32 len)
{
@ -267,7 +267,7 @@ FILE_SCOPE void TransformPoints(const DqnV2 origin, DqnV2 *const pList,
}
}
void DTRRender_Line(PlatformRenderBuffer *const renderBuffer, DqnV2i a,
void DTRRender_Line(DTRRenderBuffer *const renderBuffer, DqnV2i a,
DqnV2i b, DqnV4 color)
{
if (!renderBuffer) return;
@ -387,7 +387,7 @@ FILE_SCOPE DqnRect GetBoundingBox(const DqnV2 *const pList, const i32 numP)
return result;
}
void DTRRender_Rectangle(PlatformRenderBuffer *const renderBuffer, DqnV2 min, DqnV2 max,
void DTRRender_Rectangle(DTRRenderBuffer *const renderBuffer, DqnV2 min, DqnV2 max,
DqnV4 color, const DTRRenderTransform transform)
{
DTR_DEBUG_TIMED_FUNCTION();
@ -484,7 +484,7 @@ void DTRRender_Rectangle(PlatformRenderBuffer *const renderBuffer, DqnV2 min, Dq
}
}
void DTRRender_Triangle(PlatformRenderBuffer *const renderBuffer, DqnV2 p1, DqnV2 p2, DqnV2 p3,
void DTRRender_Triangle(DTRRenderBuffer *const renderBuffer, DqnV3 p1, DqnV3 p2, DqnV3 p3,
DqnV4 color, const DTRRenderTransform transform)
{
DTR_DEBUG_TIMED_FUNCTION();
@ -492,17 +492,18 @@ void DTRRender_Triangle(PlatformRenderBuffer *const renderBuffer, DqnV2 p1, DqnV
////////////////////////////////////////////////////////////////////////////
// Transform vertexes
////////////////////////////////////////////////////////////////////////////
DqnV2 p1p2 = p2 - p1;
DqnV2 p1p3 = p3 - p1;
DqnV2 p1p2Anchored = p1p2 * transform.anchor;
DqnV2 p1p3Anchored = p1p3 * transform.anchor;
DqnV3 p1p2 = p2 - p1;
DqnV3 p1p3 = p3 - p1;
DqnV2 origin = p1 + p1p2Anchored + p1p3Anchored;
DqnV2 pList[3] = {p1 - origin, p2 - origin, p3 - origin};
// TODO(doyle): Transform is only in 2d right now
DqnV2 p1p2Anchored = p1p2.xy * transform.anchor;
DqnV2 p1p3Anchored = p1p3.xy * transform.anchor;
DqnV2 origin = p1.xy + p1p2Anchored + p1p3Anchored;
DqnV2 pList[3] = {p1.xy - origin, p2.xy - origin, p3.xy - origin};
TransformPoints(origin, pList, DQN_ARRAY_COUNT(pList), transform.scale, transform.rotation);
p1 = pList[0];
p2 = pList[1];
p3 = pList[2];
p1.xy = pList[0];
p2.xy = pList[1];
p3.xy = pList[2];
color = DTRRender_SRGB1ToLinearSpaceV4(color);
color = PreMultiplyAlpha1(color);
@ -625,12 +626,12 @@ void DTRRender_Triangle(PlatformRenderBuffer *const renderBuffer, DqnV2 p1, DqnV
if (area2Times > 0)
{
// Clockwise swap any point to make it clockwise
DQN_SWAP(DqnV2, p2, p3);
DQN_SWAP(DqnV3, p2, p3);
}
const DqnV2 a = p1;
const DqnV2 b = p2;
const DqnV2 c = p3;
const DqnV3 a = p1;
const DqnV3 b = p2;
const DqnV3 c = p3;
DqnV2i startP = min;
f32 signedArea1 = ((b.x - a.x) * (startP.y - a.y)) - ((b.y - a.y) * (startP.x - a.x));
@ -678,6 +679,7 @@ void DTRRender_Triangle(PlatformRenderBuffer *const renderBuffer, DqnV2 p1, DqnV
////////////////////////////////////////////////////////////////////////////
// Debug
////////////////////////////////////////////////////////////////////////////
DTRDebug_CounterIncrement(DTRDebugCounter_RenderTriangle);
if (DTR_DEBUG_RENDER)
{
// Draw Bounding box
@ -704,14 +706,14 @@ void DTRRender_Triangle(PlatformRenderBuffer *const renderBuffer, DqnV2 p1, DqnV
DqnV4 blue = DqnV4_4f(0, 0, 1, 1);
DqnV4 purple = DqnV4_4f(1, 0, 1, 1);
DTRRender_Rectangle(renderBuffer, p1 - DqnV2_1f(5), p1 + DqnV2_1f(5), green);
DTRRender_Rectangle(renderBuffer, p2 - DqnV2_1f(5), p2 + DqnV2_1f(5), blue);
DTRRender_Rectangle(renderBuffer, p3 - DqnV2_1f(5), p3 + DqnV2_1f(5), purple);
DTRRender_Rectangle(renderBuffer, p1.xy - DqnV2_1f(5), p1.xy + DqnV2_1f(5), green);
DTRRender_Rectangle(renderBuffer, p2.xy - DqnV2_1f(5), p2.xy + DqnV2_1f(5), blue);
DTRRender_Rectangle(renderBuffer, p3.xy - DqnV2_1f(5), p3.xy + DqnV2_1f(5), purple);
}
}
}
void DTRRender_Bitmap(PlatformRenderBuffer *const renderBuffer,
void DTRRender_Bitmap(DTRRenderBuffer *const renderBuffer,
DTRBitmap *const bitmap, DqnV2 pos,
const DTRRenderTransform transform, DqnV4 color)
{
@ -723,7 +725,6 @@ void DTRRender_Bitmap(PlatformRenderBuffer *const renderBuffer,
////////////////////////////////////////////////////////////////////////////
DqnV2 min = pos;
DqnV2 max = min + DqnV2_V2i(bitmap->dim);
DTRDebug_PushText("OldRect: (%5.2f, %5.2f), (%5.2f, %5.2f)", min.x, min.y, max.x, max.y);
RectPoints rectPoints = TransformRectPoints(min, max, transform);
const DqnV2 *const pList = &rectPoints.pList[0];
@ -748,16 +749,12 @@ void DTRRender_Bitmap(PlatformRenderBuffer *const renderBuffer,
DqnRect clippedDrawRect = DqnRect_ClipRect(drawRect, clip);
DqnV2 clippedSize = DqnRect_GetSizeV2(clippedDrawRect);
DTRDebug_PushText("ClippedRect: (%5.2f, %5.2f), (%5.2f, %5.2f)", clippedDrawRect.min.x, clippedDrawRect.min.y, clippedDrawRect.max.x, clippedDrawRect.max.y);
DTRDebug_PushText("ClippedSize: (%5.2f, %5.2f)", clippedSize.w, clippedSize.h);
DTRDebug_PushText("DrawRect: (%5.2f, %5.2f), (%5.2f, %5.2f)", drawRect.min.x, drawRect.min.y, drawRect.max.x, drawRect.max.y);
const i32 pitch = bitmap->dim.w * bitmap->bytesPerPixel;
u8 *const bitmapPtr = (u8 *)bitmap->memory;
////////////////////////////////////////////////////////////////////////////
// Setup Texture Mapping
////////////////////////////////////////////////////////////////////////////
const i32 pitch = bitmap->dim.w * bitmap->bytesPerPixel;
u8 *const bitmapPtr = (u8 *)bitmap->memory;
const DqnV2 rectBasis = pList[RectPointsIndex_Basis];
const DqnV2 xAxisRelToBasis = pList[RectPointsIndex_XAxis] - rectBasis;
const DqnV2 yAxisRelToBasis = pList[RectPointsIndex_YAxis] - rectBasis;
@ -945,7 +942,7 @@ void DTRRender_Bitmap(PlatformRenderBuffer *const renderBuffer,
}
}
void DTRRender_Clear(PlatformRenderBuffer *const renderBuffer,
void DTRRender_Clear(DTRRenderBuffer *const renderBuffer,
DqnV3 color)
{
if (!renderBuffer) return;

View File

@ -5,12 +5,23 @@
#define DTRRENDER_INV_255 1.0f/255.0f
typedef struct PlatformRenderBuffer PlatformRenderBuffer;
typedef struct DTRRenderBuffer DTRRenderBuffer;
typedef struct DTRBitmap DTRBitmap;
////////////////////////////////////////////////////////////////////////////////////////////////////
// Utility
////////////////////////////////////////////////////////////////////////////////////////////////////
typedef struct DTRRenderBuffer
{
i32 width;
i32 height;
i32 bytesPerPixel;
u8 *memory; // Format: XX RR GG BB, and has (width * height * bytesPerPixels) elements
f32 *zBuffer; // zBuffer has (width * height) elements
} DTRRenderBuffer;
typedef struct DTRRenderTransform
{
f32 rotation = 0; // Rotation in degrees
@ -48,16 +59,11 @@ inline DqnV4 DTRRender_PreMultiplyAlphaSRGB1WithLinearConversion(DqnV4 color);
////////////////////////////////////////////////////////////////////////////////////////////////////
// NOTE: All colors should be in the range of [0->1] where DqnV4 is a struct with 4 floats, rgba
// Leaving len = -1 for text will make the system use strlen to determine len.
void DTRRender_Text (PlatformRenderBuffer *const renderBuffer, const DTRFont font, DqnV2 pos, const char *const text, DqnV4 color = DqnV4_1f(1), i32 len = -1);
void DTRRender_Line (PlatformRenderBuffer *const renderBuffer, DqnV2i a, DqnV2i b, DqnV4 color);
void DTRRender_Rectangle(PlatformRenderBuffer *const renderBuffer, DqnV2 min, DqnV2 max, DqnV4 color, const DTRRenderTransform transform = DTRRender_DefaultTransform());
void DTRRender_Triangle (PlatformRenderBuffer *const renderBuffer, DqnV2 p1, DqnV2 p2, DqnV2 p3, DqnV4 color, const DTRRenderTransform transform = DTRRender_DefaultTriangleTransform());
void DTRRender_Bitmap (PlatformRenderBuffer *const renderBuffer, DTRBitmap *const bitmap, DqnV2 pos, const DTRRenderTransform transform = DTRRender_DefaultTransform(), DqnV4 color = DqnV4_4f(1, 1, 1, 1));
void DTRRender_Clear (PlatformRenderBuffer *const renderBuffer, DqnV3 color);
void DTRRender_Text (DTRRenderBuffer *const renderBuffer, const DTRFont font, DqnV2 pos, const char *const text, DqnV4 color = DqnV4_1f(1), i32 len = -1);
void DTRRender_Line (DTRRenderBuffer *const renderBuffer, DqnV2i a, DqnV2i b, DqnV4 color);
void DTRRender_Rectangle(DTRRenderBuffer *const renderBuffer, DqnV2 min, DqnV2 max, DqnV4 color, const DTRRenderTransform transform = DTRRender_DefaultTransform());
void DTRRender_Triangle (DTRRenderBuffer *const renderBuffer, DqnV3 p1, DqnV3 p2, DqnV3 p3, DqnV4 color, const DTRRenderTransform transform = DTRRender_DefaultTriangleTransform());
void DTRRender_Bitmap (DTRRenderBuffer *const renderBuffer, DTRBitmap *const bitmap, DqnV2 pos, const DTRRenderTransform transform = DTRRender_DefaultTransform(), DqnV4 color = DqnV4_4f(1, 1, 1, 1));
void DTRRender_Clear (DTRRenderBuffer *const renderBuffer, DqnV3 color);
#endif

View File

@ -502,8 +502,8 @@ int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
////////////////////////////////////////////////////////////////////////////
// Platform Data Pre-amble
////////////////////////////////////////////////////////////////////////////
DQN_ASSERT(DqnMemStack_Init(&globalPlatformMemory.permMemStack, DQN_MEGABYTE(1), true, 4) &&
DqnMemStack_Init(&globalPlatformMemory.transMemStack, DQN_MEGABYTE(1), true, 4));
DQN_ASSERT(DqnMemStack_Init(&globalPlatformMemory.permMemStack, DQN_MEGABYTE(4), true, 4) &&
DqnMemStack_Init(&globalPlatformMemory.transMemStack, DQN_MEGABYTE(4), true, 4));
PlatformAPI platformAPI = {};
platformAPI.FileOpen = Platform_FileOpen;

View File

@ -75,7 +75,7 @@ DQN_FILE_SCOPE void DqnMem_Free (void *memory);
// When an allocation requires a larger amount of memory than available in the
// block then the MemStack will allocate a new block of sufficient size for
// you in DqnMemStack_Allocate(..). This _DOES_ mean that there will be wasted
// you in DqnMemStack_Push(..). This _DOES_ mean that there will be wasted
// space at the end of each block and is a tradeoff for memory locality against
// optimal space usage.
@ -88,7 +88,7 @@ DQN_FILE_SCOPE void DqnMem_Free (void *memory);
// - InitWithFixedSize() allows you to to disable dynamic allocations and
// sub-allocate from the initial MemStack allocation size only.
// 2. Use DqnMemStack_Allocate(..) to allocate memory for use.
// 2. Use DqnMemStack_Push(..) to allocate memory for use.
// - "Freeing" memory is dealt by creating temporary MemStacks or using the
// BeginTempRegion and EndTempRegion functions. Specifically freeing
// individual items is typically not generalisable in this scheme.
@ -129,12 +129,12 @@ DQN_FILE_SCOPE bool DqnMemStack_InitWithFixedMem (DqnMemStack *const stack, u8 *
DQN_FILE_SCOPE bool DqnMemStack_InitWithFixedSize(DqnMemStack *const stack, size_t size, const bool zeroClear, const u32 byteAlign = 4); // Single allocation from platform, no further allocations, returns NULL of allocate if out of space
DQN_FILE_SCOPE bool DqnMemStack_Init (DqnMemStack *const stack, size_t size, const bool zeroClear, const u32 byteAlign = 4); // Allocates from platform dynamically as space runs out
DQN_FILE_SCOPE void *DqnMemStack_Allocate (DqnMemStack *const stack, size_t size); // Returns NULL if out of space and stack is using fixed memory/size, or platform allocation fails
DQN_FILE_SCOPE bool DqnMemStack_Pop (DqnMemStack *const stack, void *ptr, size_t size); // Frees the given ptr. It MUST be the last allocated item in the stack
DQN_FILE_SCOPE void DqnMemStack_Free (DqnMemStack *const stack); // Frees all blocks belonging to this stack
DQN_FILE_SCOPE bool DqnMemStack_FreeStackBlock (DqnMemStack *const stack, DqnMemStackBlock *block); // Frees the specified block, returns false if block doesn't belong
DQN_FILE_SCOPE bool DqnMemStack_FreeLastBlock (DqnMemStack *const stack); // Frees the last-most memory block. If last block, free that block, next allocate will attach a block.
DQN_FILE_SCOPE void DqnMemStack_ClearCurrBlock (DqnMemStack *const stack, const bool zeroClear); // Reset the current memory block usage to 0
DQN_FILE_SCOPE void *DqnMemStack_Push (DqnMemStack *const stack, size_t size); // Returns NULL if out of space and stack is using fixed memory/size, or platform allocation fails
DQN_FILE_SCOPE bool DqnMemStack_Pop (DqnMemStack *const stack, void *ptr, size_t size); // Frees the given ptr. It MUST be the last allocated item in the stack
DQN_FILE_SCOPE void DqnMemStack_Free (DqnMemStack *const stack); // Frees all blocks belonging to this stack
DQN_FILE_SCOPE bool DqnMemStack_FreeStackBlock(DqnMemStack *const stack, DqnMemStackBlock *block); // Frees the specified block, returns false if block doesn't belong
DQN_FILE_SCOPE bool DqnMemStack_FreeLastBlock (DqnMemStack *const stack); // Frees the last-most memory block. If last block, free that block, next allocate will attach a block.
DQN_FILE_SCOPE void DqnMemStack_ClearCurrBlock(DqnMemStack *const stack, const bool zeroClear); // Reset the current memory block usage to 0
// TempMemStack is only required for the function. Once BeginTempRegion() is called, subsequent allocation calls can be made using the original stack.
// Upon EndTempRegion() the original stack will free any additional blocks it allocated during the temp region and revert to the original
@ -1453,7 +1453,7 @@ DQN_FILE_SCOPE bool DqnMemStack_InitWithFixedSize(DqnMemStack *const stack,
return false;
}
DQN_FILE_SCOPE void *DqnMemStack_Allocate(DqnMemStack *const stack, size_t size)
DQN_FILE_SCOPE void *DqnMemStack_Push(DqnMemStack *const stack, size_t size)
{
if (!stack || size == 0) return NULL;