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 Release|x64 = Release|x64
EndGlobalSection EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution GlobalSection(ProjectConfigurationPlatforms) = postSolution
{6A9F3AE0-4D5E-4F89-8572-B868AC43C38A}.Release|x64.ActiveCfg = Release {6A9F3AE0-4D5E-4F89-8572-B868AC43C38A}.Release|x64.ActiveCfg = Release|x64
EndGlobalSection EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE

View File

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

View File

@ -217,6 +217,8 @@ extern "C" void DTR_Update(PlatformRenderBuffer *const renderBuffer,
DqnV2 fontP = DqnV2_2i(200, 180); DqnV2 fontP = DqnV2_2i(200, 180);
DTRRender_Text(renderBuffer, state->font, fontP, "hello world!"); 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); DTRDebug_Update(state, renderBuffer, input, memory);
} }

View File

@ -75,8 +75,6 @@ void DTRDebug_Update(DTRState *const state,
if (debug->font->bitmap && debug->renderBuffer) if (debug->font->bitmap && debug->renderBuffer)
{ {
debug->displayYOffset = -(i32)(state->font.sizeInPt + 0.5f); debug->displayYOffset = -(i32)(state->font.sizeInPt + 0.5f);
debug->displayP =
DqnV2_2i(0, renderBuffer->height + globalDebug.displayYOffset);
DQN_ASSERT(globalDebug.displayYOffset < 0); 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, void DTRRender_Rectangle(PlatformRenderBuffer *const renderBuffer, DqnV2 min,
DqnV2 max, DqnV4 color, const DqnV2 scale, DqnV2 max, DqnV4 color, const DqnV2 scale,
const f32 rotation, const DqnV2 anchor) const f32 rotation, const DqnV2 anchor)
@ -227,29 +273,16 @@ void DTRRender_Rectangle(PlatformRenderBuffer *const renderBuffer, DqnV2 min,
//////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////
// Transform vertexes // 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); 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 // Clip Drawing Space
//////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////
@ -272,11 +305,10 @@ void DTRRender_Rectangle(PlatformRenderBuffer *const renderBuffer, DqnV2 min,
i32 bufferX = (i32)clippedRect.min.x + x; i32 bufferX = (i32)clippedRect.min.x + x;
bool pIsInside = true; bool pIsInside = true;
for (i32 pIndex = 0; pIndex < DQN_ARRAY_COUNT(pList); for (i32 pIndex = 0; pIndex < RECT_PLIST_SIZE; pIndex++)
pIndex++)
{ {
DqnV2 origin = pList[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; DqnV2 axis = DqnV2_2i(bufferX, bufferY) - origin;
f32 dotResult = DqnV2_Dot(line, axis); f32 dotResult = DqnV2_Dot(line, axis);
@ -555,32 +587,53 @@ void DTRRender_Triangle(PlatformRenderBuffer *const renderBuffer, DqnV2 p1,
} }
void DTRRender_Bitmap(PlatformRenderBuffer *const renderBuffer, 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; 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); // Transform vertexes
bitmapRect = DqnRect_ClipRect(bitmapRect, viewport); ////////////////////////////////////////////////////////////////////////////
if (bitmapRect.max.x < 0 || bitmapRect.max.y < 0) return; 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); RectPoints rectPoints = TransformRectPoints(min, max, transform.anchor, transform.scale, transform.rotation);
i32 startY = (y > 0) ? 0 : DQN_ABS(y); DqnV2 *const pList = &rectPoints.pList[0];
const i32 RECT_PLIST_SIZE = DQN_ARRAY_COUNT(rectPoints.pList);
i32 endX, endY; DqnRect bounds = GetBoundingBox(pList, RECT_PLIST_SIZE);
DqnRect_GetSize2i(bitmapRect, &endX, &endY); 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; 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); u8 *const srcRow = bitmap->memory + ((texelY + y) * pitch);
i32 bufferY = (i32)bitmapRect.min.y + bitmapY; 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 *pixelPtr = (u32 *)srcRow;
u32 pixel = pixelPtr[bitmapX]; u32 pixel = 0; // pixelPtr[texelX + x];
i32 bufferX = (i32)bitmapRect.min.x + bitmapX; i32 bufferX = (i32)clippedDrawRect.min.x + x;
DqnV4 color = {}; DqnV4 color = {};
color.a = (f32)(pixel >> 24); color.a = (f32)(pixel >> 24);
@ -591,6 +644,45 @@ void DTRRender_Bitmap(PlatformRenderBuffer *const renderBuffer,
SetPixel(renderBuffer, bufferX, bufferY, color); 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, void DTRRender_Clear(PlatformRenderBuffer *const renderBuffer,

View File

@ -4,33 +4,40 @@
#include "dqn.h" #include "dqn.h"
typedef struct PlatformRenderBuffer PlatformRenderBuffer; 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); inline DqnV4 DTRRender_PreMultiplyAlpha(const DqnV4 color);
void DTRRender_Text(PlatformRenderBuffer *const renderBuffer, void DTRRender_Text (PlatformRenderBuffer *const renderBuffer, const DTRFont font, DqnV2 pos,
const DTRFont font, DqnV2 pos, const char *const text, const char *const text, DqnV4 color = DqnV4_4f(255, 255, 255, 255), i32 len = -1);
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,
void DTRRender_Line(PlatformRenderBuffer *const renderBuffer, DqnV2i a, DqnV4 color, const DqnV2 scale = DqnV2_1f(1.0f), const f32 rotation = 0, const DqnV2 anchor = DqnV2_1f(0.5f));
DqnV2i b, DqnV4 color); 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_Rectangle(PlatformRenderBuffer *const renderBuffer, DqnV2 min, void DTRRender_Bitmap (PlatformRenderBuffer *const renderBuffer, DTRBitmap *const bitmap, DqnV2i pos,
DqnV2 max, DqnV4 color, DTRRenderTransform transform = DTRRender_DefaultTransform());
const DqnV2 scale = DqnV2_1f(1.0f), void DTRRender_Clear (PlatformRenderBuffer *const renderBuffer, const DqnV3 color);
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 #endif

View File

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

View File

@ -432,9 +432,18 @@ typedef union DqnV2 {
f32 e[2]; f32 e[2];
} DqnV2; } DqnV2;
DQN_FILE_SCOPE DqnV2 DqnV2_2i(i32 x, i32 y); // Typecasts 2 integers to 2 floats typedef union DqnV2i {
DQN_FILE_SCOPE DqnV2 DqnV2_1f(f32 xy); struct { i32 x, y; };
DQN_FILE_SCOPE DqnV2 DqnV2_2f(f32 x, f32 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_Add (DqnV2 a, DqnV2 b);
DQN_FILE_SCOPE DqnV2 DqnV2_Sub (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 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); } DQN_FILE_SCOPE inline bool operator==(DqnV2 a, DqnV2 b) { return DqnV2_Equals (a, b); }
typedef union DqnV2i { // DqnV2i
struct { i32 x, y; };
struct { i32 w, h; };
struct { i32 min, max; };
i32 e[2];
} DqnV2i;
DQN_FILE_SCOPE DqnV2i DqnV2i_2i(i32 x, i32 y); 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_2f(f32 x, f32 y); // Typecasts 2 floats to 2 integers
DQN_FILE_SCOPE DqnV2i DqnV2i_V2(DqnV2 a); DQN_FILE_SCOPE DqnV2i DqnV2i_V2(DqnV2 a);
@ -1735,6 +1738,14 @@ DQN_FILE_SCOPE DqnV2 DqnV2_2i(i32 x, i32 y)
return result; 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) DQN_FILE_SCOPE DqnV2 DqnV2_Add(DqnV2 a, DqnV2 b)
{ {
DqnV2 result = {}; DqnV2 result = {};