Organise functions to files

This commit is contained in:
Doyle Thai 2017-05-16 22:53:28 +10:00
parent 75f23b6d66
commit 13860e4089
12 changed files with 553 additions and 460 deletions

View File

@ -6,9 +6,9 @@ MinimumVisualStudioVersion = 10.0.40219.1
Project("{911E67C6-3D85-4FCE-B560-20A9C3E3FF48}") = "Win32DRenderer", "bin\Win32DRenderer.exe", "{6A9F3AE0-4D5E-4F89-8572-B868AC43C38A}" Project("{911E67C6-3D85-4FCE-B560-20A9C3E3FF48}") = "Win32DRenderer", "bin\Win32DRenderer.exe", "{6A9F3AE0-4D5E-4F89-8572-B868AC43C38A}"
ProjectSection(DebuggerProjectSystem) = preProject ProjectSection(DebuggerProjectSystem) = preProject
PortSupplier = 00000000-0000-0000-0000-000000000000 PortSupplier = 00000000-0000-0000-0000-000000000000
Executable = C:\git\drenderer\bin\Win32DRenderer.exe Executable = C:\git\dtrenderer\bin\Win32DTRenderer.exe
RemoteMachine = THAI-PC RemoteMachine = THAI-PC
StartingDirectory = C:\git\drenderer\data StartingDirectory = C:\git\dtrenderer\data
Environment = Default Environment = Default
LaunchingEngine = 00000000-0000-0000-0000-000000000000 LaunchingEngine = 00000000-0000-0000-0000-000000000000
UseLegacyDebugEngines = No UseLegacyDebugEngines = No
@ -21,7 +21,7 @@ Global
Release|x64 = Release|x64 Release|x64 = Release|x64
EndGlobalSection EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution GlobalSection(ProjectConfigurationPlatforms) = postSolution
{6A9F3AE0-4D5E-4F89-8572-B868AC43C38A}.Release|x64.ActiveCfg = Release|x64 {6A9F3AE0-4D5E-4F89-8572-B868AC43C38A}.Release|x64.ActiveCfg = Release
EndGlobalSection EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE

View File

@ -1,7 +0,0 @@
#ifndef DRENDERER_H
#define DRENDERER_H
typedef void DR_UpdateFunction(struct PlatformRenderBuffer *const renderBuffer,
struct PlatformInput *const input,
struct PlatformMemory *const memory);
#endif

222
src/DTRenderer.cpp Normal file
View File

@ -0,0 +1,222 @@
#include "DTRenderer.h"
#include "DTRendererDebug.h"
#include "DTRendererPlatform.h"
#include "DTRendererRender.h"
#define STB_IMAGE_IMPLEMENTATION
#include "external/stb_image.h"
#define DQN_IMPLEMENTATION
#include "dqn.h"
#include <math.h>
FILE_SCOPE bool BitmapFontCreate(const PlatformAPI api,
PlatformMemory *const memory,
DTRFont *const font, const char *const path,
const DqnV2i bitmapDim,
const DqnV2i codepointRange,
const f32 sizeInPt)
{
if (!memory || !font || !path) return false;
DTRFont loadedFont = {};
loadedFont.bitmapDim = bitmapDim;
loadedFont.codepointRange = codepointRange;
loadedFont.sizeInPt = sizeInPt;
////////////////////////////////////////////////////////////////////////////
// Load font data
////////////////////////////////////////////////////////////////////////////
PlatformFile file = {};
if (!api.FileOpen(path, &file, PlatformFilePermissionFlag_Read))
return false; // TODO(doyle): Logging
DqnTempBuffer tmpMemRegion = DqnMemBuffer_BeginTempRegion(&memory->transientBuffer);
u8 *fontBuf = (u8 *)DqnMemBuffer_Allocate(&memory->transientBuffer, file.size);
size_t bytesRead = api.FileRead(&file, fontBuf, file.size);
api.FileClose(&file);
if (bytesRead != file.size)
{
// TODO(doyle): Logging
DqnMemBuffer_EndTempRegion(tmpMemRegion);
return false;
}
stbtt_fontinfo fontInfo = {};
if (stbtt_InitFont(&fontInfo, fontBuf, 0) == 0)
{
DQN_ASSERT(DQN_INVALID_CODE_PATH);
return false;
}
if (DTR_DEBUG) DQN_ASSERT(stbtt_GetNumberOfFonts(fontBuf) == 1);
////////////////////////////////////////////////////////////////////////////
// Pack font data to bitmap
////////////////////////////////////////////////////////////////////////////
loadedFont.bitmap = (u8 *)DqnMemBuffer_Allocate(
&memory->permanentBuffer,
(size_t)(loadedFont.bitmapDim.w * loadedFont.bitmapDim.h));
stbtt_pack_context fontPackContext = {};
if (stbtt_PackBegin(&fontPackContext, loadedFont.bitmap, bitmapDim.w,
bitmapDim.h, 0, 1, NULL) == 1)
{
// stbtt_PackSetOversampling(&fontPackContext, 2, 2);
i32 numCodepoints =
(i32)((codepointRange.max + 1) - codepointRange.min);
loadedFont.atlas = (stbtt_packedchar *)DqnMemBuffer_Allocate(
&memory->permanentBuffer, numCodepoints * sizeof(stbtt_packedchar));
stbtt_PackFontRange(&fontPackContext, fontBuf, 0,
STBTT_POINT_SIZE(sizeInPt), (i32)codepointRange.min,
numCodepoints, loadedFont.atlas);
stbtt_PackEnd(&fontPackContext);
}
else
{
DQN_ASSERT(DQN_INVALID_CODE_PATH);
return false;
}
////////////////////////////////////////////////////////////////////////////
// Premultiply Alpha of Bitmap
////////////////////////////////////////////////////////////////////////////
for (i32 y = 0; y < bitmapDim.h; y++)
{
for (i32 x = 0; x < bitmapDim.w; x++)
{
// NOTE: Bitmap from stb_truetype is 1BPP. So the actual color
// value represents its' alpha value but also its' color.
u32 index = x + (y * bitmapDim.w);
f32 alpha = (f32)(loadedFont.bitmap[index]) / 255.0f;
f32 color = alpha;
f32 preMulAlphaColor = color * alpha;
DQN_ASSERT(preMulAlphaColor >= 0.0f && preMulAlphaColor <= 255.0f);
loadedFont.bitmap[index] = (u8)(preMulAlphaColor * 255.0f);
}
}
#ifdef DTR_DEBUG_RENDER_FONT_BITMAP
stbi_write_bmp("test.bmp", bitmapDim.w, bitmapDim.h, 1, loadedFont.bitmap);
#endif
*font = loadedFont;
return true;
}
FILE_SCOPE bool BitmapLoad(const PlatformAPI api, DTRBitmap *bitmap,
const char *const path,
DqnMemBuffer *const transientBuffer)
{
if (!bitmap) return false;
PlatformFile file = {};
if (!api.FileOpen(path, &file, PlatformFilePermissionFlag_Read))
return false;
DqnTempBuffer tempBuffer = DqnMemBuffer_BeginTempRegion(transientBuffer);
{
u8 *const rawData =
(u8 *)DqnMemBuffer_Allocate(transientBuffer, file.size);
size_t bytesRead = api.FileRead(&file, rawData, file.size);
api.FileClose(&file);
if (bytesRead != file.size)
{
DqnMemBuffer_EndTempRegion(tempBuffer);
return false;
}
bitmap->memory =
stbi_load_from_memory(rawData, (i32)file.size, &bitmap->dim.w,
&bitmap->dim.h, &bitmap->bytesPerPixel, 4);
}
DqnMemBuffer_EndTempRegion(tempBuffer);
if (!bitmap->memory) return false;
const i32 pitch = bitmap->dim.w * bitmap->bytesPerPixel;
for (i32 y = 0; y < bitmap->dim.h; y++)
{
u8 *const srcRow = bitmap->memory + (y * pitch);
for (i32 x = 0; x < bitmap->dim.w; x++)
{
u32 *pixelPtr = (u32 *)srcRow;
u32 pixel = pixelPtr[x];
DqnV4 color = {};
color.a = (f32)(pixel >> 24);
color.b = (f32)((pixel >> 16) & 0xFF);
color.g = (f32)((pixel >> 8) & 0xFF);
color.r = (f32)((pixel >> 0) & 0xFF);
color = DTRRender_PreMultiplyAlpha(color);
pixel = (((u32)color.a << 24) |
((u32)color.b << 16) |
((u32)color.g << 8) |
((u32)color.r << 0));
pixelPtr[x] = pixel;
}
}
return true;
}
extern "C" void DTR_Update(PlatformRenderBuffer *const renderBuffer,
PlatformInput *const input,
PlatformMemory *const memory)
{
DTRState *state = (DTRState *)memory->context;
if (!memory->isInit)
{
stbi_set_flip_vertically_on_load(true);
memory->isInit = true;
memory->context =
DqnMemBuffer_Allocate(&memory->permanentBuffer, sizeof(DTRState));
DQN_ASSERT(memory->context);
state = (DTRState *)memory->context;
BitmapFontCreate(input->api, memory, &state->font, "Roboto-bold.ttf",
DqnV2i_2i(256, 256), DqnV2i_2i(' ', '~'), 16);
BitmapLoad(input->api, &state->bitmap, "lune_logo.png",
&memory->transientBuffer);
}
DTRRender_Clear(renderBuffer, DqnV3_3f(0, 0, 0));
DqnV4 colorRed = DqnV4_4i(180, 0, 0, 255);
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)};
#if 1
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);
#endif
DqnV4 colorRedHalfA = DqnV4_4i(255, 0, 0, 64);
LOCAL_PERSIST f32 rotation = 0;
rotation += input->deltaForFrame * 0.25f;
DTRRender_Triangle(renderBuffer, t3[0], t3[1], t3[2], colorRedHalfA,
DqnV2_1f(1.0f), rotation, DqnV2_2f(0.33f, 0.33f));
DTRRender_Rectangle(renderBuffer, DqnV2_1f(300.0f), DqnV2_1f(300 + 20.0f),
colorRed, DqnV2_1f(1.0f), 45 + rotation);
DqnV2 fontP = DqnV2_2i(200, 180);
DTRRender_Text(renderBuffer, state->font, fontP, "hello world!");
DTRRender_Bitmap(renderBuffer, &state->bitmap, 300, 250);
DTRDebug_Update(state, renderBuffer, input, memory);
}

33
src/DTRenderer.h Normal file
View File

@ -0,0 +1,33 @@
#ifndef DTRENDERER_H
#define DTRENDERER_H
#include "dqn.h"
#include "external/stb_truetype.h"
typedef void DTR_UpdateFunction(struct PlatformRenderBuffer *const renderBuffer,
struct PlatformInput *const input,
struct PlatformMemory *const memory);
typedef struct DTRFont
{
u8 *bitmap;
DqnV2i bitmapDim;
DqnV2i codepointRange;
f32 sizeInPt;
stbtt_packedchar *atlas;
} DTRFont;
typedef struct DTRBitmap
{
u8 *memory;
DqnV2i dim;
i32 bytesPerPixel;
} DTRBitmap;
typedef struct DTRState
{
DTRFont font;
DTRBitmap bitmap;
} DTRState;
#endif

114
src/DTRendererDebug.cpp Normal file
View File

@ -0,0 +1,114 @@
#include "DTRendererDebug.h"
#include "DTRenderer.h"
#include "DTRendererPlatform.h"
#include "DTRendererRender.h"
DTRDebug globalDebug;
void DTRDebug_PushText(const char *const formatStr, ...)
{
if (DTR_DEBUG)
{
DTRDebug *const debug = &globalDebug;
if (!debug->renderBuffer) return;
char str[1024] = {};
va_list argList;
va_start(argList, formatStr);
{
i32 numCopied = Dqn_vsprintf(str, formatStr, argList);
DQN_ASSERT(numCopied < DQN_ARRAY_COUNT(str));
}
va_end(argList);
DTRRender_Text(debug->renderBuffer, *debug->font, debug->displayP, str);
debug->displayP.y += globalDebug.displayYOffset;
}
}
FILE_SCOPE void PushMemBufferText(const char *const name,
const DqnMemBuffer *const buffer)
{
if (DTR_DEBUG)
{
if (!buffer) return;
size_t totalUsed = 0;
size_t totalSize = 0;
size_t totalWasted = 0;
i32 numBlocks = 0;
DqnMemBufferBlock *blockPtr = buffer->block;
while (blockPtr)
{
totalUsed += blockPtr->used;
totalSize += blockPtr->size;
blockPtr = blockPtr->prevBlock;
numBlocks++;
}
size_t totalUsedKb = totalUsed / 1024;
size_t totalSizeKb = totalSize / 1024;
size_t totalWastedKb = totalWasted / 1024;
char str[128] = {};
Dqn_sprintf(str, "%s: %d block(s): %_$lld/%_$lld", name, numBlocks,
totalUsed, totalSize);
DTRRender_Text(globalDebug.renderBuffer, *globalDebug.font,
globalDebug.displayP, str);
globalDebug.displayP.y += globalDebug.displayYOffset;
}
}
void DTRDebug_Update(DTRState *const state,
PlatformRenderBuffer *const renderBuffer,
PlatformInput *const input, PlatformMemory *const memory)
{
if (DTR_DEBUG)
{
DTRDebug *const debug = &globalDebug;
debug->renderBuffer = renderBuffer;
debug->font = &state->font;
if (debug->font->bitmap && debug->renderBuffer)
{
debug->displayYOffset = -(i32)(state->font.sizeInPt + 0.5f);
debug->displayP =
DqnV2_2i(0, renderBuffer->height + globalDebug.displayYOffset);
DQN_ASSERT(globalDebug.displayYOffset < 0);
}
debug->totalSetPixels += debug->setPixelsPerFrame;
debug->totalSetPixels = DQN_MAX(0, debug->totalSetPixels);
// totalSetPixels
{
char str[128] = {};
Dqn_sprintf(str, "%s: %'lld", "TotalSetPixels", debug->totalSetPixels);
DTRRender_Text(debug->renderBuffer, *debug->font, debug->displayP, str);
debug->displayP.y += globalDebug.displayYOffset;
}
// setPixelsPerFrame
{
char str[128] = {};
Dqn_sprintf(str, "%s: %'lld", "SetPixelsPerFrame", debug->setPixelsPerFrame);
DTRRender_Text(debug->renderBuffer, *debug->font, debug->displayP, str);
debug->displayP.y += globalDebug.displayYOffset;
}
// memory
{
PushMemBufferText("PermBuffer", &memory->permanentBuffer);
PushMemBufferText("TransBuffer", &memory->transientBuffer);
}
debug->setPixelsPerFrame = 0;
debug->displayP =
DqnV2_2i(0, debug->renderBuffer->height + globalDebug.displayYOffset);
}
}

32
src/DTRendererDebug.h Normal file
View File

@ -0,0 +1,32 @@
#ifndef DTRENDERER_DEBUG_H
#define DTRENDERER_DEBUG_H
#include "dqn.h"
#define DTR_DEBUG 1
typedef struct PlatformRenderBuffer PlatformRenderBuffer;
typedef struct DTRFont DTRFont;
typedef struct DTRState DTRState;
typedef struct PlatformInput PlatformInput;
typedef struct PlatformMemory PlatformMemory;
typedef struct DTRDebug
{
DTRFont *font;
PlatformRenderBuffer *renderBuffer;
DqnV2 displayP;
i32 displayYOffset;
u64 setPixelsPerFrame;
u64 totalSetPixels;
} DTRDebug;
extern DTRDebug globalDebug;
void DTRDebug_PushText(const char *const formatStr, ...);
void DTRDebug_Update(DTRState *const state,
PlatformRenderBuffer *const renderBuffer,
PlatformInput *const input, PlatformMemory *const memory);
#endif

View File

@ -1,61 +1,18 @@
#include "DRenderer.h" #include "DTRendererRender.h"
#include "DRendererPlatform.h" #include "DTRendererPlatform.h"
#define STB_RECT_PACK_IMPLEMENTATION #define STB_RECT_PACK_IMPLEMENTATION
#define STB_IMAGE_IMPLEMENTATION
#define STB_TRUETYPE_IMPLEMENTATION #define STB_TRUETYPE_IMPLEMENTATION
#include "external/stb_rect_pack.h" #include "external/stb_rect_pack.h"
#include "external/stb_image.h"
#include "external/stb_truetype.h" #include "external/stb_truetype.h"
// #define DR_DEBUG_RENDER_FONT_BITMAP // #define DTR_DEBUG_RENDER_FONT_BITMAP
#ifdef DR_DEBUG_RENDER_FONT_BITMAP #ifdef DTR_DEBUG_RENDER_FONT_BITMAP
#define STB_IMAGE_WRITE_IMPLEMENTATION #define STB_IMAGE_WRITE_IMPLEMENTATION
#include "external/stb_image_write.h" #include "external/stb_image_write.h"
#endif #endif
#define DQN_IMPLEMENTATION inline DqnV4 DTRRender_PreMultiplyAlpha(const DqnV4 color)
#include "dqn.h"
#include <math.h>
#define DR_DEBUG 1
typedef struct DRFont
{
u8 *bitmap;
DqnV2i bitmapDim;
DqnV2i codepointRange;
f32 sizeInPt;
stbtt_packedchar *atlas;
} DRFont;
typedef struct DRBitmap
{
u8 *memory;
DqnV2i dim;
i32 bytesPerPixel;
} DRBitmap;
typedef struct DRState
{
DRFont font;
DRBitmap bitmap;
} DRState;
typedef struct DRDebug
{
DRFont *font;
PlatformRenderBuffer *renderBuffer;
DqnV2 displayP;
i32 displayYOffset;
u64 setPixelsPerFrame;
u64 totalSetPixels;
} DRDebug;
FILE_SCOPE inline DqnV4 PreMultiplyAlpha(DqnV4 color)
{ {
DqnV4 result; DqnV4 result;
f32 normA = color.a / 255.0f; f32 normA = color.a / 255.0f;
@ -67,8 +24,6 @@ FILE_SCOPE inline DqnV4 PreMultiplyAlpha(DqnV4 color)
return result; return result;
} }
FILE_SCOPE DRDebug globalDebug;
// IMPORTANT(doyle): Color is expected to be premultiplied already // IMPORTANT(doyle): Color is expected to be premultiplied already
FILE_SCOPE inline void SetPixel(PlatformRenderBuffer *const renderBuffer, FILE_SCOPE inline void SetPixel(PlatformRenderBuffer *const renderBuffer,
const i32 x, const i32 y, const DqnV4 color) const i32 x, const i32 y, const DqnV4 color)
@ -94,12 +49,10 @@ FILE_SCOPE inline void SetPixel(PlatformRenderBuffer *const renderBuffer,
// NOTE(doyle): AlphaBlend equations is (alpha * new) + (1 - alpha) * src. // NOTE(doyle): AlphaBlend equations is (alpha * new) + (1 - alpha) * src.
// IMPORTANT(doyle): We pre-multiply so we can take out the (alpha * new) // IMPORTANT(doyle): We pre-multiply so we can take out the (alpha * new)
f32 invANorm = 1 - newANorm; f32 invANorm = 1 - newANorm;
// f32 destA = (((1 - srcA) * newA) + srcA) * 255.0f;
f32 destR = newR + (invANorm * srcR); f32 destR = newR + (invANorm * srcR);
f32 destG = newG + (invANorm * srcG); f32 destG = newG + (invANorm * srcG);
f32 destB = newB + (invANorm * srcB); f32 destB = newB + (invANorm * srcB);
// DQN_ASSERT(destA >= 0 && destA <= 255.0f);
DQN_ASSERT(destR >= 0 && destR <= 255.0f); DQN_ASSERT(destR >= 0 && destR <= 255.0f);
DQN_ASSERT(destG >= 0 && destG <= 255.0f); DQN_ASSERT(destG >= 0 && destG <= 255.0f);
DQN_ASSERT(destB >= 0 && destB <= 255.0f); DQN_ASSERT(destB >= 0 && destB <= 255.0f);
@ -112,15 +65,17 @@ FILE_SCOPE inline void SetPixel(PlatformRenderBuffer *const renderBuffer,
globalDebug.setPixelsPerFrame++; globalDebug.setPixelsPerFrame++;
} }
FILE_SCOPE void DrawText(PlatformRenderBuffer *const renderBuffer, void DTRRender_Text(PlatformRenderBuffer *const renderBuffer,
const DRFont font, DqnV2 pos, const char *const text, const DTRFont font, DqnV2 pos, const char *const text,
DqnV4 color = DqnV4_4f(255, 255, 255, 255), i32 len = -1) DqnV4 color, i32 len)
{ {
if (!text) return; if (!text) return;
if (!font.bitmap || !font.atlas || !renderBuffer) return;
if (len == -1) len = Dqn_strlen(text); if (len == -1) len = Dqn_strlen(text);
i32 index = 0; i32 index = 0;
color = PreMultiplyAlpha(color); color = DTRRender_PreMultiplyAlpha(color);
while (index < len) while (index < len)
{ {
if (text[index] < font.codepointRange.min && if (text[index] < font.codepointRange.min &&
@ -187,33 +142,29 @@ FILE_SCOPE void DrawText(PlatformRenderBuffer *const renderBuffer,
} }
} }
FILE_SCOPE void DebugPushText(const char *const formatStr, ...) FILE_SCOPE void TransformPoints(const DqnV2 origin, DqnV2 *const pList,
const i32 numP, const DqnV2 scale,
const f32 rotation)
{ {
if (DR_DEBUG) if (!pList || numP == 0) return;
DqnV2 xAxis = (DqnV2_2f(cosf(rotation), sinf(rotation)));
DqnV2 yAxis = DqnV2_2f(-xAxis.y, xAxis.x);
xAxis *= scale.x;
yAxis *= scale.y;
for (i32 i = 0; i < numP; i++)
{ {
DRDebug *const debug = &globalDebug; DqnV2 p = pList[i];
if (!debug->renderBuffer) return; pList[i] = origin + (xAxis * p.x) + (yAxis * p.y);
char str[1024] = {};
va_list argList;
va_start(argList, formatStr);
{
i32 numCopied = Dqn_vsprintf(str, formatStr, argList);
DQN_ASSERT(numCopied < DQN_ARRAY_COUNT(str));
}
va_end(argList);
DrawText(debug->renderBuffer, *debug->font, debug->displayP, str);
debug->displayP.y += globalDebug.displayYOffset;
} }
} }
FILE_SCOPE void DrawLine(PlatformRenderBuffer *const renderBuffer, DqnV2i a, void DTRRender_Line(PlatformRenderBuffer *const renderBuffer, DqnV2i a,
DqnV2i b, DqnV4 color) DqnV2i b, DqnV4 color)
{ {
if (!renderBuffer) return; if (!renderBuffer) return;
color = PreMultiplyAlpha(color); color = DTRRender_PreMultiplyAlpha(color);
bool yTallerThanX = false; bool yTallerThanX = false;
if (DQN_ABS(a.x - b.x) < DQN_ABS(a.y - b.y)) if (DQN_ABS(a.x - b.x) < DQN_ABS(a.y - b.y))
@ -269,44 +220,10 @@ FILE_SCOPE void DrawLine(PlatformRenderBuffer *const renderBuffer, DqnV2i a,
} }
} }
FILE_SCOPE void TransformPoints(const DqnV2 origin, DqnV2 *const pList, void DTRRender_Rectangle(PlatformRenderBuffer *const renderBuffer, DqnV2 min,
const i32 numP, const DqnV2 scale, DqnV2 max, DqnV4 color, const DqnV2 scale,
const f32 rotation) const f32 rotation, const DqnV2 anchor)
{ {
if (!pList || numP == 0) return;
DqnV2 xAxis = (DqnV2_2f(cosf(rotation), sinf(rotation)));
DqnV2 yAxis = DqnV2_2f(-xAxis.y, xAxis.x);
xAxis *= scale.x;
yAxis *= scale.y;
for (i32 i = 0; i < numP; i++)
{
DqnV2 p = pList[i];
pList[i] = origin + (xAxis * p.x) + (yAxis * p.y);
}
}
FILE_SCOPE void DrawRectangle(PlatformRenderBuffer *const renderBuffer,
DqnV2 min, DqnV2 max, DqnV4 color,
const DqnV2 scale = DqnV2_1f(1.0f),
f32 rotation = 0,
const DqnV2 anchor = DqnV2_1f(0.5f))
{
// TODO(doyle): Do edge test for quads
#if 0
if (rotation > 0)
{
DqnV2 p1 = min;
DqnV2 p2 = DqnV2_2f(max.x, min.y);
DqnV2 p3 = max;
DqnV2 p4 = DqnV2_2f(min.x, max.y);
DrawTriangle(renderBuffer, p1, p2, p3, color, scale, rotation, anchor);
DrawTriangle(renderBuffer, p1, p3, p4, color, scale, rotation, anchor);
return;
}
#endif
//////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////
// Transform vertexes // Transform vertexes
//////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////
@ -332,7 +249,7 @@ FILE_SCOPE void DrawRectangle(PlatformRenderBuffer *const renderBuffer,
max.y = DQN_MAX(max.y, checkP.y); max.y = DQN_MAX(max.y, checkP.y);
} }
color = PreMultiplyAlpha(color); color = DTRRender_PreMultiplyAlpha(color);
//////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////
// Clip Drawing Space // Clip Drawing Space
//////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////
@ -376,10 +293,10 @@ FILE_SCOPE void DrawRectangle(PlatformRenderBuffer *const renderBuffer,
} }
else else
{ {
for (i32 y = 0; y < clippedSize.w; y++) for (i32 y = 0; y < clippedSize.h; y++)
{ {
i32 bufferY = (i32)clippedRect.min.y + y; i32 bufferY = (i32)clippedRect.min.y + y;
for (i32 x = 0; x < clippedSize.h; x++) for (i32 x = 0; x < clippedSize.w; x++)
{ {
i32 bufferX = (i32)clippedRect.min.x + x; i32 bufferX = (i32)clippedRect.min.x + x;
SetPixel(renderBuffer, bufferX, bufferY, color); SetPixel(renderBuffer, bufferX, bufferY, color);
@ -387,35 +304,39 @@ FILE_SCOPE void DrawRectangle(PlatformRenderBuffer *const renderBuffer,
} }
} }
if (DR_DEBUG) ////////////////////////////////////////////////////////////////////////////
// Debug
////////////////////////////////////////////////////////////////////////////
if (DTR_DEBUG)
{ {
// Draw Bounding box // Draw Bounding box
{ {
DrawLine(renderBuffer, 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);
DrawLine(renderBuffer, 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);
DrawLine(renderBuffer, 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);
DrawLine(renderBuffer, 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 (rotation > 0) if (rotation > 0)
{ {
DqnV4 green = DqnV4_4f(0, 255, 0, 255); DqnV4 green = DqnV4_4f(0, 255, 0, 255);
DrawLine(renderBuffer, DqnV2i_V2(pList[0]), DqnV2i_V2(pList[1]), green); DTRRender_Line(renderBuffer, DqnV2i_V2(pList[0]), DqnV2i_V2(pList[1]), green);
DrawLine(renderBuffer, DqnV2i_V2(pList[1]), DqnV2i_V2(pList[2]), green); DTRRender_Line(renderBuffer, DqnV2i_V2(pList[1]), DqnV2i_V2(pList[2]), green);
DrawLine(renderBuffer, DqnV2i_V2(pList[2]), DqnV2i_V2(pList[3]), green); DTRRender_Line(renderBuffer, DqnV2i_V2(pList[2]), DqnV2i_V2(pList[3]), green);
DrawLine(renderBuffer, DqnV2i_V2(pList[3]), DqnV2i_V2(pList[0]), green); DTRRender_Line(renderBuffer, DqnV2i_V2(pList[3]), DqnV2i_V2(pList[0]), green);
} }
} }
} }
FILE_SCOPE void DrawTriangle(PlatformRenderBuffer *const renderBuffer, DqnV2 p1, void DTRRender_Triangle(PlatformRenderBuffer *const renderBuffer, DqnV2 p1,
DqnV2 p2, DqnV2 p3, DqnV4 color, DqnV2 p2, DqnV2 p3, DqnV4 color, const DqnV2 scale,
DqnV2 scale = DqnV2_1f(1.0f), f32 rotation = 0, const f32 rotation, const DqnV2 anchor)
DqnV2 anchor = DqnV2_1f(0.33f))
{ {
////////////////////////////////////////////////////////////////////////////
// Transform vertexes // Transform vertexes
////////////////////////////////////////////////////////////////////////////
DqnV2 p1p2 = p2 - p1; DqnV2 p1p2 = p2 - p1;
DqnV2 p1p3 = p3 - p1; DqnV2 p1p3 = p3 - p1;
DqnV2 p1p2Anchored = p1p2 * anchor; DqnV2 p1p2Anchored = p1p2 * anchor;
@ -428,7 +349,11 @@ FILE_SCOPE void DrawTriangle(PlatformRenderBuffer *const renderBuffer, DqnV2 p1,
p2 = pList[1]; p2 = pList[1];
p3 = pList[2]; p3 = pList[2];
color = PreMultiplyAlpha(color); color = DTRRender_PreMultiplyAlpha(color);
////////////////////////////////////////////////////////////////////////////
// Calculate Bounding Box
////////////////////////////////////////////////////////////////////////////
DqnV2i max = DqnV2i_2f(DQN_MAX(DQN_MAX(p1.x, p2.x), p3.x), DqnV2i max = DqnV2i_2f(DQN_MAX(DQN_MAX(p1.x, p2.x), p3.x),
DQN_MAX(DQN_MAX(p1.y, p2.y), p3.y)); DQN_MAX(DQN_MAX(p1.y, p2.y), p3.y));
DqnV2i min = DqnV2i_2f(DQN_MIN(DQN_MIN(p1.x, p2.x), p3.x), DqnV2i min = DqnV2i_2f(DQN_MIN(DQN_MIN(p1.x, p2.x), p3.x),
@ -566,6 +491,9 @@ FILE_SCOPE void DrawTriangle(PlatformRenderBuffer *const renderBuffer, DqnV2 p1,
f32 invSignedAreaParallelogram = 1 / ((b.x - a.x) * (c.y - a.y) - (b.y - a.y) * (c.x - a.x)); f32 invSignedAreaParallelogram = 1 / ((b.x - a.x) * (c.y - a.y) - (b.y - a.y) * (c.x - a.x));
////////////////////////////////////////////////////////////////////////////
// Scan and Render
////////////////////////////////////////////////////////////////////////////
for (scanP.y = min.y; scanP.y < max.y; scanP.y++) for (scanP.y = min.y; scanP.y < max.y; scanP.y++)
{ {
@ -590,14 +518,17 @@ FILE_SCOPE void DrawTriangle(PlatformRenderBuffer *const renderBuffer, DqnV2 p1,
signedArea3 += signedArea3DeltaY; signedArea3 += signedArea3DeltaY;
} }
if (DR_DEBUG) ////////////////////////////////////////////////////////////////////////////
// Debug
////////////////////////////////////////////////////////////////////////////
if (DTR_DEBUG)
{ {
// Draw Bounding box // Draw Bounding box
{ {
DrawLine(renderBuffer, DqnV2i_2i(min.x, min.y), DqnV2i_2i(min.x, max.y), color); DTRRender_Line(renderBuffer, DqnV2i_2i(min.x, min.y), DqnV2i_2i(min.x, max.y), color);
DrawLine(renderBuffer, DqnV2i_2i(min.x, max.y), DqnV2i_2i(max.x, max.y), color); DTRRender_Line(renderBuffer, DqnV2i_2i(min.x, max.y), DqnV2i_2i(max.x, max.y), color);
DrawLine(renderBuffer, DqnV2i_2i(max.x, max.y), DqnV2i_2i(max.x, min.y), color); DTRRender_Line(renderBuffer, DqnV2i_2i(max.x, max.y), DqnV2i_2i(max.x, min.y), color);
DrawLine(renderBuffer, DqnV2i_2i(max.x, min.y), DqnV2i_2i(min.x, min.y), color); DTRRender_Line(renderBuffer, DqnV2i_2i(max.x, min.y), DqnV2i_2i(min.x, min.y), color);
} }
// Draw Triangle Coordinate Basis // Draw Triangle Coordinate Basis
@ -606,8 +537,8 @@ FILE_SCOPE void DrawTriangle(PlatformRenderBuffer *const renderBuffer, DqnV2 p1,
DqnV2 yAxis = DqnV2_2f(-xAxis.y, xAxis.x) * scale.y; DqnV2 yAxis = DqnV2_2f(-xAxis.y, xAxis.x) * scale.y;
DqnV4 coordSysColor = DqnV4_4f(0, 255, 255, 255); DqnV4 coordSysColor = DqnV4_4f(0, 255, 255, 255);
i32 axisLen = 50; i32 axisLen = 50;
DrawLine(renderBuffer, DqnV2i_V2(origin), DqnV2i_V2(origin) + DqnV2i_V2(xAxis * axisLen), coordSysColor); DTRRender_Line(renderBuffer, DqnV2i_V2(origin), DqnV2i_V2(origin) + DqnV2i_V2(xAxis * axisLen), coordSysColor);
DrawLine(renderBuffer, DqnV2i_V2(origin), DqnV2i_V2(origin) + DqnV2i_V2(yAxis * axisLen), coordSysColor); DTRRender_Line(renderBuffer, DqnV2i_V2(origin), DqnV2i_V2(origin) + DqnV2i_V2(yAxis * axisLen), coordSysColor);
} }
// Draw axis point // Draw axis point
@ -616,116 +547,15 @@ FILE_SCOPE void DrawTriangle(PlatformRenderBuffer *const renderBuffer, DqnV2 p1,
DqnV4 blue = DqnV4_4f(0, 0, 255, 255); DqnV4 blue = DqnV4_4f(0, 0, 255, 255);
DqnV4 purple = DqnV4_4f(255, 0, 255, 255); DqnV4 purple = DqnV4_4f(255, 0, 255, 255);
DrawRectangle(renderBuffer, p1 - DqnV2_1f(5), p1 + DqnV2_1f(5), green); DTRRender_Rectangle(renderBuffer, p1 - DqnV2_1f(5), p1 + DqnV2_1f(5), green);
DrawRectangle(renderBuffer, p2 - DqnV2_1f(5), p2 + DqnV2_1f(5), blue); DTRRender_Rectangle(renderBuffer, p2 - DqnV2_1f(5), p2 + DqnV2_1f(5), blue);
DrawRectangle(renderBuffer, p3 - DqnV2_1f(5), p3 + DqnV2_1f(5), purple); DTRRender_Rectangle(renderBuffer, p3 - DqnV2_1f(5), p3 + DqnV2_1f(5), purple);
} }
} }
} }
FILE_SCOPE void ClearRenderBuffer(PlatformRenderBuffer *const renderBuffer, void DTRRender_Bitmap(PlatformRenderBuffer *const renderBuffer,
DqnV3 color) DTRBitmap *const bitmap, i32 x, i32 y)
{
if (!renderBuffer) return;
DQN_ASSERT(color.r >= 0.0f && color.r <= 255.0f);
DQN_ASSERT(color.g >= 0.0f && color.g <= 255.0f);
DQN_ASSERT(color.b >= 0.0f && color.b <= 255.0f);
u32 *const bitmapPtr = (u32 *)renderBuffer->memory;
for (i32 y = 0; y < renderBuffer->height; y++)
{
for (i32 x = 0; x < renderBuffer->width; x++)
{
u32 pixel = ((i32)color.r << 16) | ((i32)color.g << 8) |
((i32)color.b << 0);
bitmapPtr[x + (y * renderBuffer->width)] = pixel;
}
}
}
FILE_SCOPE void BitmapFontCreate(const PlatformAPI api,
PlatformMemory *const memory,
DRFont *const font, const char *const path,
const DqnV2i bitmapDim,
const DqnV2i codepointRange,
const f32 sizeInPt)
{
font->bitmapDim = bitmapDim;
font->codepointRange = codepointRange;
font->sizeInPt = sizeInPt;
DqnTempBuffer transientTempBufferRegion =
DqnMemBuffer_BeginTempRegion(&memory->transientBuffer);
////////////////////////////////////////////////////////////////////////////
// Load font data
////////////////////////////////////////////////////////////////////////////
PlatformFile file = {};
bool result = api.FileOpen(path, &file, PlatformFilePermissionFlag_Read);
DQN_ASSERT(result);
u8 *fontBuf = (u8 *)DqnMemBuffer_Allocate(&memory->transientBuffer, file.size);
size_t bytesRead = api.FileRead(&file, fontBuf, file.size);
DQN_ASSERT(bytesRead == file.size);
api.FileClose(&file);
stbtt_fontinfo fontInfo = {};
DQN_ASSERT(stbtt_InitFont(&fontInfo, fontBuf, 0) != 0);
if (DR_DEBUG) DQN_ASSERT(stbtt_GetNumberOfFonts(fontBuf) == 1);
////////////////////////////////////////////////////////////////////////////
// Pack font data to bitmap
////////////////////////////////////////////////////////////////////////////
font->bitmap = (u8 *)DqnMemBuffer_Allocate(
&memory->permanentBuffer,
(size_t)(font->bitmapDim.w * font->bitmapDim.h));
stbtt_pack_context fontPackContext = {};
DQN_ASSERT(stbtt_PackBegin(&fontPackContext, font->bitmap, bitmapDim.w,
bitmapDim.h, 0, 1, NULL) == 1);
{
// stbtt_PackSetOversampling(&fontPackContext, 2, 2);
i32 numCodepoints =
(i32)((codepointRange.max + 1) - codepointRange.min);
font->atlas = (stbtt_packedchar *)DqnMemBuffer_Allocate(
&memory->permanentBuffer, numCodepoints * sizeof(stbtt_packedchar));
stbtt_PackFontRange(&fontPackContext, fontBuf, 0,
STBTT_POINT_SIZE(sizeInPt), (i32)codepointRange.min,
numCodepoints, font->atlas);
}
stbtt_PackEnd(&fontPackContext);
////////////////////////////////////////////////////////////////////////////
// Premultiply Alpha of Bitmap
////////////////////////////////////////////////////////////////////////////
for (i32 y = 0; y < bitmapDim.h; y++)
{
for (i32 x = 0; x < bitmapDim.w; x++)
{
// NOTE: Bitmap from stb_truetype is 1BPP. So the actual color
// value represents its' alpha value but also its' color.
u32 index = x + (y * bitmapDim.w);
f32 alpha = (f32)(font->bitmap[index]) / 255.0f;
f32 color = alpha;
f32 preMulAlphaColor = color * alpha;
DQN_ASSERT(preMulAlphaColor >= 0.0f && preMulAlphaColor <= 255.0f);
font->bitmap[index] = (u8)(preMulAlphaColor * 255.0f);
}
}
#ifdef DR_DEBUG_RENDER_FONT_BITMAP
stbi_write_bmp("test.bmp", bitmapDim.w, bitmapDim.h, 1, font->bitmap);
#endif
DqnMemBuffer_EndTempRegion(transientTempBufferRegion);
}
FILE_SCOPE void DrawBitmap(PlatformRenderBuffer *const renderBuffer,
DRBitmap *const bitmap, i32 x, i32 y)
{ {
if (!bitmap || !bitmap->memory || !renderBuffer) return; if (!bitmap || !bitmap->memory || !renderBuffer) return;
@ -763,201 +593,25 @@ FILE_SCOPE void DrawBitmap(PlatformRenderBuffer *const renderBuffer,
} }
} }
FILE_SCOPE bool BitmapLoad(const PlatformAPI api, DRBitmap *bitmap, void DTRRender_Clear(PlatformRenderBuffer *const renderBuffer,
const char *const path, const DqnV3 color)
DqnMemBuffer *const transientBuffer)
{ {
if (!bitmap) return false; if (!renderBuffer) return;
PlatformFile file = {}; DQN_ASSERT(color.r >= 0.0f && color.r <= 255.0f);
if (!api.FileOpen(path, &file, PlatformFilePermissionFlag_Read)) DQN_ASSERT(color.g >= 0.0f && color.g <= 255.0f);
return false; DQN_ASSERT(color.b >= 0.0f && color.b <= 255.0f);
DqnTempBuffer tempBuffer = DqnMemBuffer_BeginTempRegion(transientBuffer); u32 *const bitmapPtr = (u32 *)renderBuffer->memory;
for (i32 y = 0; y < renderBuffer->height; y++)
{ {
u8 *const rawData = for (i32 x = 0; x < renderBuffer->width; x++)
(u8 *)DqnMemBuffer_Allocate(transientBuffer, file.size);
size_t bytesRead = api.FileRead(&file, rawData, file.size);
api.FileClose(&file);
if (bytesRead != file.size)
{ {
DqnMemBuffer_EndTempRegion(tempBuffer); u32 pixel = ((i32)color.r << 16) | ((i32)color.g << 8) |
return false; ((i32)color.b << 0);
bitmapPtr[x + (y * renderBuffer->width)] = pixel;
} }
bitmap->memory =
stbi_load_from_memory(rawData, (i32)file.size, &bitmap->dim.w,
&bitmap->dim.h, &bitmap->bytesPerPixel, 4);
}
DqnMemBuffer_EndTempRegion(tempBuffer);
if (!bitmap->memory) return false;
const i32 pitch = bitmap->dim.w * bitmap->bytesPerPixel;
for (i32 y = 0; y < bitmap->dim.h; y++)
{
u8 *const srcRow = bitmap->memory + (y * pitch);
for (i32 x = 0; x < bitmap->dim.w; x++)
{
u32 *pixelPtr = (u32 *)srcRow;
u32 pixel = pixelPtr[x];
DqnV4 color = {};
color.a = (f32)(pixel >> 24);
color.b = (f32)((pixel >> 16) & 0xFF);
color.g = (f32)((pixel >> 8) & 0xFF);
color.r = (f32)((pixel >> 0) & 0xFF);
color = PreMultiplyAlpha(color);
pixel = (((u32)color.a << 24) |
((u32)color.b << 16) |
((u32)color.g << 8) |
((u32)color.r << 0));
pixelPtr[x] = pixel;
}
}
return true;
}
void DebugDisplayMemBuffer(PlatformRenderBuffer *const renderBuffer,
const char *const name,
const DqnMemBuffer *const buffer,
DqnV2 *const debugP, const DRFont font)
{
if (!name && !buffer && !debugP) return;
size_t totalUsed = 0;
size_t totalSize = 0;
size_t totalWasted = 0;
i32 numBlocks = 0;
DqnMemBufferBlock *blockPtr = buffer->block;
while (blockPtr)
{
totalUsed += blockPtr->used;
totalSize += blockPtr->size;
blockPtr = blockPtr->prevBlock;
numBlocks++;
}
size_t totalUsedKb = totalUsed / 1024;
size_t totalSizeKb = totalSize / 1024;
size_t totalWastedKb = totalWasted / 1024;
char str[128] = {};
Dqn_sprintf(str, "%s: %d block(s): %_$lld/%_$lld", name, numBlocks, totalUsed,
totalSize);
DrawText(renderBuffer, font, *debugP, str);
debugP->y += globalDebug.displayYOffset;
}
void DebugUpdate(DRState *const state, PlatformRenderBuffer *const renderBuffer,
PlatformInput *const input, PlatformMemory *const memory)
{
if (DR_DEBUG)
{
DRDebug *const debug = &globalDebug;
if (input->executableReloaded || !memory->isInit)
{
debug->font = &state->font;
debug->displayYOffset = -(i32)(state->font.sizeInPt + 0.5f);
debug->displayP =
DqnV2_2i(0, renderBuffer->height + globalDebug.displayYOffset);
DQN_ASSERT(globalDebug.displayYOffset < 0);
debug->renderBuffer = renderBuffer;
}
debug->totalSetPixels += debug->setPixelsPerFrame;
debug->totalSetPixels = DQN_MAX(0, debug->totalSetPixels);
// totalSetPixels
{
char str[128] = {};
Dqn_sprintf(str, "%s: %'lld", "TotalSetPixels", debug->totalSetPixels);
DrawText(debug->renderBuffer, *debug->font, debug->displayP, str);
debug->displayP.y += globalDebug.displayYOffset;
}
// setPixelsPerFrame
{
char str[128] = {};
Dqn_sprintf(str, "%s: %'lld", "SetPixelsPerFrame", debug->setPixelsPerFrame);
DrawText(debug->renderBuffer, *debug->font, debug->displayP, str);
debug->displayP.y += globalDebug.displayYOffset;
}
// memory
{
DebugDisplayMemBuffer(debug->renderBuffer, "PermBuffer",
&memory->permanentBuffer, &debug->displayP,
*debug->font);
DebugDisplayMemBuffer(debug->renderBuffer, "TransBuffer",
&memory->transientBuffer, &debug->displayP,
*debug->font);
}
debug->setPixelsPerFrame = 0;
debug->displayP =
DqnV2_2i(0, debug->renderBuffer->height + globalDebug.displayYOffset);
} }
} }
extern "C" void DR_Update(PlatformRenderBuffer *const renderBuffer,
PlatformInput *const input,
PlatformMemory *const memory)
{
DRState *state = (DRState *)memory->context;
if (!memory->isInit)
{
stbi_set_flip_vertically_on_load(true);
memory->isInit = true;
memory->context =
DqnMemBuffer_Allocate(&memory->permanentBuffer, sizeof(DRState));
DQN_ASSERT(memory->context);
state = (DRState *)memory->context;
BitmapFontCreate(input->api, memory, &state->font, "Roboto-bold.ttf",
DqnV2i_2i(256, 256), DqnV2i_2i(' ', '~'), 16);
DQN_ASSERT(BitmapLoad(input->api, &state->bitmap, "lune_logo.png",
&memory->transientBuffer));
}
ClearRenderBuffer(renderBuffer, DqnV3_3f(0, 0, 0));
DqnV4 colorRed = DqnV4_4i(180, 0, 0, 255);
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)};
#if 1
DrawTriangle(renderBuffer, t0[0], t0[1], t0[2], colorRed);
DrawTriangle(renderBuffer, t1[0], t1[1], t1[2], colorRed);
DrawTriangle(renderBuffer, t2[0], t2[1], t2[2], colorRed);
#endif
DqnV4 colorRedHalfA = DqnV4_4i(255, 0, 0, 64);
LOCAL_PERSIST f32 rotation = 0;
rotation += input->deltaForFrame * 0.25f;
DrawTriangle(renderBuffer, t3[0], t3[1], t3[2], colorRedHalfA,
DqnV2_1f(1.0f), rotation, DqnV2_2f(0.33f, 0.33f));
DrawRectangle(renderBuffer, DqnV2_1f(300.0f), DqnV2_1f(300 + 20.0f),
colorRed, DqnV2_1f(1.0f), 45 + rotation);
DqnV2 fontP = DqnV2_2i(200, 180);
// DrawText(renderBuffer, state->font, fontP, "hello world!");
// DrawBitmap(renderBuffer, &state->bitmap, 300, 250);
DebugUpdate(state, renderBuffer, input, memory);
}

36
src/DTRendererRender.h Normal file
View File

@ -0,0 +1,36 @@
#ifndef DTRENDERER_RENDER_H
#define DTRENDERER_RENDER_H
#include "dqn.h"
typedef struct PlatformRenderBuffer PlatformRenderBuffer;
typedef struct DTRBitmap DTRBitmap;
inline DqnV4 DTRRender_PreMultiplyAlpha(const DqnV4 color);
void DTRRender_Text(PlatformRenderBuffer *const renderBuffer,
const DTRFont font, DqnV2 pos, const char *const text,
DqnV4 color = DqnV4_4f(255, 255, 255, 255), 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 DqnV2 scale = DqnV2_1f(1.0f),
const f32 rotation = 0,
const DqnV2 anchor = DqnV2_1f(0.5f));
void DTRRender_Triangle(PlatformRenderBuffer *const renderBuffer, DqnV2 p1,
DqnV2 p2, DqnV2 p3, DqnV4 color,
const DqnV2 scale = DqnV2_1f(1.0f),
const f32 rotation = 0,
const DqnV2 anchor = DqnV2_1f(0.33f));
void DTRRender_Bitmap(PlatformRenderBuffer *const renderBuffer,
DTRBitmap *const bitmap, i32 x, i32 y);
void DTRRender_Clear(PlatformRenderBuffer *const renderBuffer,
const DqnV3 color);
#endif

View File

@ -1 +1,3 @@
#include "..\DRenderer.cpp" #include "..\DTRendererDebug.cpp"
#include "..\DTRendererRender.cpp"
#include "..\DTRenderer.cpp"

View File

@ -1,5 +1,5 @@
#include "DRenderer.h" #include "DTRenderer.h"
#include "DRendererPlatform.h" #include "DTRendererPlatform.h"
#define DQN_IMPLEMENTATION #define DQN_IMPLEMENTATION
#define DQN_WIN32_IMPLEMENTATION #define DQN_WIN32_IMPLEMENTATION
@ -8,6 +8,9 @@
#define UNICODE #define UNICODE
#define _UNICODE #define _UNICODE
const char *const DLL_NAME = "dtrenderer.dll";
const char *const DLL_TMP_NAME = "dtrenderer_temp.dll";
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// Platform API Implementation // Platform API Implementation
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -98,7 +101,7 @@ typedef struct Win32ExternalCode
HMODULE dll; HMODULE dll;
FILETIME lastWriteTime; FILETIME lastWriteTime;
DR_UpdateFunction *DR_Update; DTR_UpdateFunction *DTR_Update;
} Win32ExternalCode; } Win32ExternalCode;
enum Win32Menu enum Win32Menu
@ -147,13 +150,13 @@ FILE_SCOPE Win32ExternalCode Win32LoadExternalDLL(const char *const srcPath,
result.lastWriteTime = lastWriteTime; result.lastWriteTime = lastWriteTime;
CopyFile(srcPath, tmpPath, false); CopyFile(srcPath, tmpPath, false);
DR_UpdateFunction *updateFunction = NULL; DTR_UpdateFunction *updateFunction = NULL;
result.dll = LoadLibraryA(tmpPath); result.dll = LoadLibraryA(tmpPath);
if (result.dll) if (result.dll)
{ {
updateFunction = updateFunction =
(DR_UpdateFunction *)GetProcAddress(result.dll, "DR_Update"); (DTR_UpdateFunction *)GetProcAddress(result.dll, "DTR_Update");
if (updateFunction) result.DR_Update = updateFunction; if (updateFunction) result.DTR_Update = updateFunction;
} }
return result; return result;
@ -164,7 +167,7 @@ FILE_SCOPE void Win32UnloadExternalDLL(Win32ExternalCode *externalCode)
if (externalCode->dll) FreeLibrary(externalCode->dll); if (externalCode->dll) FreeLibrary(externalCode->dll);
externalCode->dll = NULL; externalCode->dll = NULL;
externalCode->DR_Update = NULL; externalCode->DTR_Update = NULL;
} }
FILE_SCOPE void Win32CreateMenu(HWND window) FILE_SCOPE void Win32CreateMenu(HWND window)
@ -484,11 +487,11 @@ int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
DQN_ASSERT(lastSlashIndex + 1 < DQN_ARRAY_COUNT(exeDir)); DQN_ASSERT(lastSlashIndex + 1 < DQN_ARRAY_COUNT(exeDir));
exeDir[lastSlashIndex + 1] = 0; exeDir[lastSlashIndex + 1] = 0;
u32 numCopied = Dqn_sprintf(dllPath, "%s%s", exeDir, "drenderer.dll"); u32 numCopied = Dqn_sprintf(dllPath, "%s%s", exeDir, DLL_NAME);
DQN_ASSERT(numCopied < DQN_ARRAY_COUNT(dllPath)); DQN_ASSERT(numCopied < DQN_ARRAY_COUNT(dllPath));
numCopied = numCopied =
Dqn_sprintf(dllTmpPath, "%s%s", exeDir, "drenderer_temp.dll"); Dqn_sprintf(dllTmpPath, "%s%s", exeDir, DLL_TMP_NAME);
DQN_ASSERT(numCopied < DQN_ARRAY_COUNT(dllTmpPath)); DQN_ASSERT(numCopied < DQN_ARRAY_COUNT(dllTmpPath));
} }
@ -537,10 +540,10 @@ int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
platformBuffer.width = globalRenderBitmap.width; platformBuffer.width = globalRenderBitmap.width;
platformBuffer.bytesPerPixel = globalRenderBitmap.bytesPerPixel; platformBuffer.bytesPerPixel = globalRenderBitmap.bytesPerPixel;
if (dllCode.DR_Update) if (dllCode.DTR_Update)
{ {
dllCode.DR_Update(&platformBuffer, &platformInput, dllCode.DTR_Update(&platformBuffer, &platformInput,
&globalPlatformMemory); &globalPlatformMemory);
} }
} }

View File

@ -10,10 +10,13 @@ if %errorlevel%==1 (
goto end goto end
) )
REM Build tags file REM Build tags file if you have ctags in path
ctags -R where /q ctags
if %errorlevel%==0 (
ctags -R
)
set ProjectName=drenderer set ProjectName=dtrenderer
ctime -begin ..\src\%ProjectName%.ctm ctime -begin ..\src\%ProjectName%.ctm
IF NOT EXIST ..\bin mkdir ..\bin IF NOT EXIST ..\bin mkdir ..\bin
@ -38,7 +41,7 @@ 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=-EHa- -GR- -Oi -MT -Z7 -W4 -wd4100 -wd4201 -wd4189 -wd4505 -Od -FAsc set CompileFlags=-EHa- -GR- -Oi -MT -Z7 -W4 -wd4100 -wd4201 -wd4189 -wd4505 -Od -FAsc
set DLLFlags=/Fm%ProjectName% /Fo%ProjectName% /Fa%ProjectName% /Fe%ProjectName% set DLLFlags=/Fm%ProjectName% /Fo%ProjectName% /Fa%ProjectName% /Fe%ProjectName%
set Win32Flags=/FmWin32DRenderer /FeWin32DRenderer set Win32Flags=/FmWin32DTRenderer /FeWin32DTRenderer
REM Clean time necessary for hours <10, which produces H:MM:SS.SS where the 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 first character of time is an empty space. CleanTime will pad a 0 if
@ -57,8 +60,9 @@ REM ////////////////////////////////////////////////////////////////////////////
REM Compile REM Compile
REM //////////////////////////////////////////////////////////////////////////// REM ////////////////////////////////////////////////////////////////////////////
del *.pdb >NUL 2>NUL del *.pdb >NUL 2>NUL
cl %CompileFlags% %Win32Flags% ..\src\Win32DRenderer.cpp /link %LinkLibraries% %LinkFlags% cl %CompileFlags% %Win32Flags% ..\src\Win32DTRenderer.cpp /link %LinkLibraries% %LinkFlags%
cl %CompileFlags% %DLLFlags% ..\src\UnityBuild\UnityBuild.cpp /LD /link /PDB:%ProjectName%_%TimeStamp%.pdb /export:DR_Update %LinkFlags% cl %CompileFlags% %DLLFlags% ..\src\UnityBuild\UnityBuild.cpp /LD /link /PDB:%ProjectName%_%TimeStamp%.pdb /export:DTR_Update %LinkFlags%
popd popd
set LastError=%ERRORLEVEL% set LastError=%ERRORLEVEL%
ctime -end %ProjectName%.ctm %LastError% ctime -end %ProjectName%.ctm %LastError%