Add mem diagnostics, prepare for bitmap rotation

This commit is contained in:
Doyle Thai 2017-05-17 02:49:33 +10:00
parent 13860e4089
commit ce69de7aeb
8 changed files with 201 additions and 83 deletions

View File

@ -21,7 +21,7 @@ Global
Release|x64 = Release|x64
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{6A9F3AE0-4D5E-4F89-8572-B868AC43C38A}.Release|x64.ActiveCfg = Release
{6A9F3AE0-4D5E-4F89-8572-B868AC43C38A}.Release|x64.ActiveCfg = Release|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

View File

@ -1,5 +1,5 @@
{
ColumnLimit: 80,
ColumnLimit: 100,
TabWidth: 4,
IndentWidth: 4, # 1 tab
UseTab: ForIndentation,

View File

@ -217,6 +217,8 @@ extern "C" void DTR_Update(PlatformRenderBuffer *const renderBuffer,
DqnV2 fontP = DqnV2_2i(200, 180);
DTRRender_Text(renderBuffer, state->font, fontP, "hello world!");
DTRRender_Bitmap(renderBuffer, &state->bitmap, 300, 250);
DTRRenderTransform transform = DTRRender_DefaultTransform();
transform.rotation = rotation;
DTRRender_Bitmap(renderBuffer, &state->bitmap, DqnV2i_2i(200, 300), transform);
DTRDebug_Update(state, renderBuffer, input, memory);
}

View File

@ -75,8 +75,6 @@ void DTRDebug_Update(DTRState *const state,
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);
}

View File

@ -220,6 +220,52 @@ void DTRRender_Line(PlatformRenderBuffer *const renderBuffer, DqnV2i a,
}
}
typedef struct RectPoints
{
DqnV2 pList[4];
} RectPoints;
// Apply rotation and scale around the anchored point. This is a helper function that expands the
// min and max into the 4 vertexes of a rectangle then calls the normal transform routine.
// anchor: A normalised [0->1] value the points should be positioned from
FILE_SCOPE RectPoints TransformRectPoints(DqnV2 min, DqnV2 max, DqnV2 anchor, DqnV2 scale,
f32 rotation)
{
DqnV2 dim = DqnV2_2f(max.x - min.x, max.y - min.y);
DqnV2 origin = DqnV2_2f(min.x + (anchor.x * dim.w), min.y + (anchor.y * dim.h));
DQN_ASSERT(dim.w > 0 && dim.h > 0);
RectPoints result = {};
result.pList[0] = min - origin;
result.pList[1] = DqnV2_2f(max.x, min.y) - origin;
result.pList[2] = max - origin;
result.pList[3] = DqnV2_2f(min.x, max.y) - origin;
TransformPoints(origin, result.pList, DQN_ARRAY_COUNT(result.pList), scale, rotation);
return result;
}
FILE_SCOPE DqnRect GetBoundingBox(const DqnV2 *const pList, const i32 numP)
{
DqnRect result = {};
if (numP == 0 || !pList) return result;
result.min = pList[0];
result.max = pList[0];
for (i32 i = 1; i < numP; i++)
{
DqnV2 checkP = pList[i];
result.min.x = DQN_MIN(result.min.x, checkP.x);
result.min.y = DQN_MIN(result.min.y, checkP.y);
result.max.x = DQN_MAX(result.max.x, checkP.x);
result.max.y = DQN_MAX(result.max.y, checkP.y);
}
return result;
}
void DTRRender_Rectangle(PlatformRenderBuffer *const renderBuffer, DqnV2 min,
DqnV2 max, DqnV4 color, const DqnV2 scale,
const f32 rotation, const DqnV2 anchor)
@ -227,29 +273,16 @@ void DTRRender_Rectangle(PlatformRenderBuffer *const renderBuffer, DqnV2 min,
////////////////////////////////////////////////////////////////////////////
// Transform vertexes
////////////////////////////////////////////////////////////////////////////
DqnV2 dim = DqnV2_2f(max.x - min.x, max.y - min.y);
DQN_ASSERT(dim.w > 0 && dim.h > 0);
DqnV2 initOrigin = DqnV2_2f(min.x + (anchor.x * dim.w), min.y + (anchor.y * dim.h));
DqnV2 p1 = min - initOrigin;
DqnV2 p2 = DqnV2_2f(max.x, min.y) - initOrigin;
DqnV2 p3 = max - initOrigin;
DqnV2 p4 = DqnV2_2f(min.x, max.y) - initOrigin;
DqnV2 pList[] = {p1, p2, p3, p4};
TransformPoints(initOrigin, pList, DQN_ARRAY_COUNT(pList), scale, rotation);
min = pList[0];
max = pList[0];
for (i32 i = 1; i < DQN_ARRAY_COUNT(pList); i++)
{
DqnV2 checkP = pList[i];
min.x = DQN_MIN(min.x, checkP.x);
min.y = DQN_MIN(min.y, checkP.y);
max.x = DQN_MAX(max.x, checkP.x);
max.y = DQN_MAX(max.y, checkP.y);
}
color = DTRRender_PreMultiplyAlpha(color);
RectPoints rectPoints = TransformRectPoints(min, max, anchor, scale, rotation);
DqnV2 *const pList = &rectPoints.pList[0];
const i32 RECT_PLIST_SIZE = DQN_ARRAY_COUNT(rectPoints.pList);
DqnRect bounds = GetBoundingBox(pList, RECT_PLIST_SIZE);
min = bounds.min;
max = bounds.max;
////////////////////////////////////////////////////////////////////////////
// Clip Drawing Space
////////////////////////////////////////////////////////////////////////////
@ -272,11 +305,10 @@ void DTRRender_Rectangle(PlatformRenderBuffer *const renderBuffer, DqnV2 min,
i32 bufferX = (i32)clippedRect.min.x + x;
bool pIsInside = true;
for (i32 pIndex = 0; pIndex < DQN_ARRAY_COUNT(pList);
pIndex++)
for (i32 pIndex = 0; pIndex < RECT_PLIST_SIZE; pIndex++)
{
DqnV2 origin = pList[pIndex];
DqnV2 line = pList[(pIndex + 1) % DQN_ARRAY_COUNT(pList)] - origin;
DqnV2 line = pList[(pIndex + 1) % RECT_PLIST_SIZE] - origin;
DqnV2 axis = DqnV2_2i(bufferX, bufferY) - origin;
f32 dotResult = DqnV2_Dot(line, axis);
@ -555,32 +587,53 @@ void DTRRender_Triangle(PlatformRenderBuffer *const renderBuffer, DqnV2 p1,
}
void DTRRender_Bitmap(PlatformRenderBuffer *const renderBuffer,
DTRBitmap *const bitmap, i32 x, i32 y)
DTRBitmap *const bitmap, DqnV2i pos,
DTRRenderTransform transform)
{
if (!bitmap || !bitmap->memory || !renderBuffer) return;
DqnRect viewport = DqnRect_4i(0, 0, renderBuffer->width, renderBuffer->height);
DqnRect bitmapRect = DqnRect_4i(x, y, x + bitmap->dim.w, y + bitmap->dim.h);
bitmapRect = DqnRect_ClipRect(bitmapRect, viewport);
if (bitmapRect.max.x < 0 || bitmapRect.max.y < 0) return;
////////////////////////////////////////////////////////////////////////////
// Transform vertexes
////////////////////////////////////////////////////////////////////////////
DqnV2 min = DqnV2_V2i(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);
i32 startX = (x > 0) ? 0 : DQN_ABS(x);
i32 startY = (y > 0) ? 0 : DQN_ABS(y);
RectPoints rectPoints = TransformRectPoints(min, max, transform.anchor, transform.scale, transform.rotation);
DqnV2 *const pList = &rectPoints.pList[0];
const i32 RECT_PLIST_SIZE = DQN_ARRAY_COUNT(rectPoints.pList);
i32 endX, endY;
DqnRect_GetSize2i(bitmapRect, &endX, &endY);
DqnRect bounds = GetBoundingBox(pList, RECT_PLIST_SIZE);
min = bounds.min;
max = bounds.max;
////////////////////////////////////////////////////////////////////////////
// Clip drawing space
////////////////////////////////////////////////////////////////////////////
DqnRect drawRect = DqnRect_4f(bounds.min.x, bounds.min.y, bounds.max.x, bounds.max.y);
DqnRect clip = DqnRect_4i(0, 0, renderBuffer->width, renderBuffer->height);
DqnRect clippedDrawRect = DqnRect_ClipRect(drawRect, clip);
DqnV2 clippedSize = DqnRect_GetSizeV2(clippedDrawRect);
i32 texelX = (pos.x > 0) ? 0 : DQN_ABS(pos.x);
i32 texelY = (pos.y > 0) ? 0 : DQN_ABS(pos.y);
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);
DTRDebug_PushText("TexelXY: (%d, %d)", texelX, texelY);
const i32 pitch = bitmap->dim.w * bitmap->bytesPerPixel;
for (i32 bitmapY = startY; bitmapY < endY; bitmapY++)
for (i32 y = 0; y < (i32)clippedSize.h; y++)
{
u8 *const srcRow = bitmap->memory + (bitmapY * pitch);
i32 bufferY = (i32)bitmapRect.min.y + bitmapY;
u8 *const srcRow = bitmap->memory + ((texelY + y) * pitch);
i32 bufferY = (i32)clippedDrawRect.min.y + y;
for (i32 bitmapX = startX; bitmapX < endX; bitmapX++)
for (i32 x = 0; x < (i32)clippedSize.w; x++)
{
u32 *pixelPtr = (u32 *)srcRow;
u32 pixel = pixelPtr[bitmapX];
i32 bufferX = (i32)bitmapRect.min.x + bitmapX;
u32 pixel = 0; // pixelPtr[texelX + x];
i32 bufferX = (i32)clippedDrawRect.min.x + x;
DqnV4 color = {};
color.a = (f32)(pixel >> 24);
@ -591,6 +644,45 @@ void DTRRender_Bitmap(PlatformRenderBuffer *const renderBuffer,
SetPixel(renderBuffer, bufferX, bufferY, color);
}
}
if (DTR_DEBUG)
{
// Draw Bounding box
{
DqnV4 yellow = DqnV4_4f(255, 255, 0, 255);
DTRRender_Line(renderBuffer, DqnV2i_2f(min.x, min.y), DqnV2i_2f(min.x, max.y), yellow);
DTRRender_Line(renderBuffer, DqnV2i_2f(min.x, max.y), DqnV2i_2f(max.x, max.y), yellow);
DTRRender_Line(renderBuffer, DqnV2i_2f(max.x, max.y), DqnV2i_2f(max.x, min.y), yellow);
DTRRender_Line(renderBuffer, DqnV2i_2f(max.x, min.y), DqnV2i_2f(min.x, min.y), yellow);
}
// Draw rotating outline
if (transform.rotation > 0)
{
DqnV4 green = DqnV4_4f(0, 255, 0, 255);
DTRRender_Line(renderBuffer, DqnV2i_V2(pList[0]), DqnV2i_V2(pList[1]), green);
DTRRender_Line(renderBuffer, DqnV2i_V2(pList[1]), DqnV2i_V2(pList[2]), green);
DTRRender_Line(renderBuffer, DqnV2i_V2(pList[2]), DqnV2i_V2(pList[3]), green);
DTRRender_Line(renderBuffer, DqnV2i_V2(pList[3]), DqnV2i_V2(pList[0]), green);
}
// Draw axis point
{
DqnV4 red = DqnV4_4f(255, 0, 0, 255);
DqnV4 green = DqnV4_4f(0, 255, 0, 255);
DqnV4 blue = DqnV4_4f(0, 0, 255, 255);
DqnV4 purple = DqnV4_4f(255, 0, 255, 255);
DqnV2 p1 = pList[0];
DqnV2 p2 = pList[1];
DqnV2 p3 = pList[2];
DqnV2 p4 = pList[3];
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, p4 - DqnV2_1f(5), p4 + DqnV2_1f(5), red);
}
}
}
void DTRRender_Clear(PlatformRenderBuffer *const renderBuffer,

View File

@ -4,33 +4,40 @@
#include "dqn.h"
typedef struct PlatformRenderBuffer PlatformRenderBuffer;
typedef struct DTRBitmap DTRBitmap;
typedef struct DTRBitmap DTRBitmap;
typedef struct DTRRenderTransform
{
f32 rotation = 0;
DqnV2 anchor = DqnV2_1f(0.5f);
DqnV2 scale = DqnV2_1f(1.0f);
} DTRRenderTransform;
inline DTRRenderTransform DTRRender_DefaultTransform()
{
DTRRenderTransform result = {};
return result;
}
// NOTE: 0.33f is the midpoint of a triangle
inline DTRRenderTransform DTRRender_DefaultTriangleTransform()
{
DTRRenderTransform result = {};
result.anchor = DqnV2_1f(0.33f);
return result;
}
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);
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, DqnV2i pos,
DTRRenderTransform transform = DTRRender_DefaultTransform());
void DTRRender_Clear (PlatformRenderBuffer *const renderBuffer, const DqnV3 color);
#endif

View File

@ -80,8 +80,8 @@ void Platform_FileClose(PlatformFile *const file)
////////////////////////////////////////////////////////////////////////////////
// Win32 Layer
////////////////////////////////////////////////////////////////////////////////
#include <Pathcch.h>
#include <Windows.h>
#include <Psapi.h> // For win32 GetProcessMemoryInfo()
typedef struct Win32RenderBitmap
{
BITMAPINFO info;
@ -581,9 +581,17 @@ int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
frameTimeInS = DqnTime_NowInS() - startFrameTimeInS;
f32 msPerFrame = 1000.0f * (f32)frameTimeInS;
////////////////////////////////////////////////////////////////////////
// Misc
////////////////////////////////////////////////////////////////////////
// Get Win32 reported mem usage
PROCESS_MEMORY_COUNTERS memCounter = {};
GetProcessMemoryInfo(GetCurrentProcess(), &memCounter, sizeof(memCounter));
// Update title bar
char windowTitleBuffer[128] = {};
Dqn_sprintf(windowTitleBuffer, "drenderer - dev - %5.2f ms/f",
msPerFrame);
Dqn_sprintf(windowTitleBuffer, "drenderer - dev - %5.2f ms/f - mem %'dkb", msPerFrame,
(u32)(memCounter.PagefileUsage / 1024.0f));
SetWindowTextA(mainWindow, windowTitleBuffer);
}

View File

@ -432,9 +432,18 @@ typedef union DqnV2 {
f32 e[2];
} DqnV2;
DQN_FILE_SCOPE DqnV2 DqnV2_2i(i32 x, i32 y); // Typecasts 2 integers to 2 floats
DQN_FILE_SCOPE DqnV2 DqnV2_1f(f32 xy);
DQN_FILE_SCOPE DqnV2 DqnV2_2f(f32 x, f32 y);
typedef union DqnV2i {
struct { i32 x, y; };
struct { i32 w, h; };
struct { i32 min, max; };
i32 e[2];
} DqnV2i;
// DqnV2
DQN_FILE_SCOPE DqnV2 DqnV2_2i (i32 x, i32 y); // Typecasts 2 integers to 2 floats
DQN_FILE_SCOPE DqnV2 DqnV2_1f (f32 xy);
DQN_FILE_SCOPE DqnV2 DqnV2_2f (f32 x, f32 y);
DQN_FILE_SCOPE DqnV2 DqnV2_V2i(DqnV2i a);
DQN_FILE_SCOPE DqnV2 DqnV2_Add (DqnV2 a, DqnV2 b);
DQN_FILE_SCOPE DqnV2 DqnV2_Sub (DqnV2 a, DqnV2 b);
@ -464,13 +473,7 @@ DQN_FILE_SCOPE inline DqnV2 &operator-=(DqnV2 &a, DqnV2 b) { return (a = DqnV2_S
DQN_FILE_SCOPE inline DqnV2 &operator+=(DqnV2 &a, DqnV2 b) { return (a = DqnV2_Add (a, b)); }
DQN_FILE_SCOPE inline bool operator==(DqnV2 a, DqnV2 b) { return DqnV2_Equals (a, b); }
typedef union DqnV2i {
struct { i32 x, y; };
struct { i32 w, h; };
struct { i32 min, max; };
i32 e[2];
} DqnV2i;
// DqnV2i
DQN_FILE_SCOPE DqnV2i DqnV2i_2i(i32 x, i32 y);
DQN_FILE_SCOPE DqnV2i DqnV2i_2f(f32 x, f32 y); // Typecasts 2 floats to 2 integers
DQN_FILE_SCOPE DqnV2i DqnV2i_V2(DqnV2 a);
@ -1735,6 +1738,14 @@ DQN_FILE_SCOPE DqnV2 DqnV2_2i(i32 x, i32 y)
return result;
}
DQN_FILE_SCOPE DqnV2 DqnV2_V2i(DqnV2i a)
{
DqnV2 result = {};
result.x = (f32)a.x;
result.y = (f32)a.y;
return result;
}
DQN_FILE_SCOPE DqnV2 DqnV2_Add(DqnV2 a, DqnV2 b)
{
DqnV2 result = {};