Add font rendering
This commit is contained in:
parent
85ac211824
commit
0738326384
@ -1,17 +1,23 @@
|
|||||||
#include "DRenderer.h"
|
#include "DRenderer.h"
|
||||||
#include "DRendererPlatform.h"
|
#include "DRendererPlatform.h"
|
||||||
|
|
||||||
|
#define STB_RECT_PACK_IMPLEMENTATION
|
||||||
#define STB_IMAGE_IMPLEMENTATION
|
#define STB_IMAGE_IMPLEMENTATION
|
||||||
#include "external/stb_image.h"
|
|
||||||
|
|
||||||
#define STB_TRUETYPE_IMPLEMENTATION
|
#define STB_TRUETYPE_IMPLEMENTATION
|
||||||
|
#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
|
||||||
|
#ifdef DR_DEBUG_RENDER_FONT_BITMAP
|
||||||
|
#define STB_IMAGE_WRITE_IMPLEMENTATION
|
||||||
|
#include "external/stb_image_write.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#define DQN_IMPLEMENTATION
|
#define DQN_IMPLEMENTATION
|
||||||
#include "dqn.h"
|
#include "dqn.h"
|
||||||
|
|
||||||
#define DR_DEBUG 1
|
#define DR_DEBUG 1
|
||||||
|
|
||||||
typedef struct DRFont
|
typedef struct DRFont
|
||||||
{
|
{
|
||||||
u8 *bitmap;
|
u8 *bitmap;
|
||||||
@ -103,6 +109,7 @@ FILE_SCOPE void DrawTriangle(PlatformRenderBuffer *const renderBuffer,
|
|||||||
const DqnV2 p1, const DqnV2 p2, const DqnV2 p3,
|
const DqnV2 p1, const DqnV2 p2, const DqnV2 p3,
|
||||||
const DqnV3 color)
|
const DqnV3 color)
|
||||||
{
|
{
|
||||||
|
__rdtsc();
|
||||||
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),
|
||||||
@ -232,6 +239,86 @@ FILE_SCOPE void DrawTriangle(PlatformRenderBuffer *const renderBuffer,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FILE_SCOPE void DrawText(PlatformRenderBuffer *const renderBuffer,
|
||||||
|
const DRFont font, DqnV2 pos, const char *const text,
|
||||||
|
i32 len = -1)
|
||||||
|
{
|
||||||
|
if (!text) return;
|
||||||
|
if (len == -1) len = Dqn_strlen(text);
|
||||||
|
|
||||||
|
i32 index = 0;
|
||||||
|
while (index < len)
|
||||||
|
{
|
||||||
|
if (text[index] < font.codepointRange.min &&
|
||||||
|
text[index] > font.codepointRange.max)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
i32 charIndex = text[index++] - (i32)font.codepointRange.min;
|
||||||
|
DQN_ASSERT(charIndex >= 0 &&
|
||||||
|
charIndex < (i32)(font.codepointRange.max -
|
||||||
|
font.codepointRange.min));
|
||||||
|
|
||||||
|
stbtt_aligned_quad alignedQuad = {};
|
||||||
|
stbtt_GetPackedQuad(font.atlas, font.bitmapDim.w, font.bitmapDim.h,
|
||||||
|
charIndex, &pos.x, &pos.y, &alignedQuad, true);
|
||||||
|
stbtt_packedchar *charData = font.atlas + charIndex;
|
||||||
|
|
||||||
|
DqnRect fontRect = {};
|
||||||
|
fontRect.min = DqnV2_2f(alignedQuad.s0 * font.bitmapDim.w, alignedQuad.t1 * font.bitmapDim.h);
|
||||||
|
fontRect.max = DqnV2_2f(alignedQuad.s1 * font.bitmapDim.w, alignedQuad.t0 * font.bitmapDim.h);
|
||||||
|
|
||||||
|
DqnRect screenRect = {};
|
||||||
|
screenRect.min = DqnV2_2f(alignedQuad.x0, alignedQuad.y0);
|
||||||
|
screenRect.max = DqnV2_2f(alignedQuad.x1, alignedQuad.y1);
|
||||||
|
|
||||||
|
// TODO: Assumes 1bpp and pitch of font bitmap
|
||||||
|
const u32 fontPitch = font.bitmapDim.w;
|
||||||
|
u32 fontOffset = (u32)(fontRect.min.x + (fontRect.max.y * fontPitch));
|
||||||
|
u8 *fontPtr = font.bitmap + fontOffset;
|
||||||
|
|
||||||
|
DQN_ASSERT(sizeof(u32) == renderBuffer->bytesPerPixel);
|
||||||
|
f32 fontHeightOffset = charData->yoff2 + charData->yoff;
|
||||||
|
u32 screenOffset = (u32)(screenRect.min.x + (screenRect.min.y - fontHeightOffset) * renderBuffer->width);
|
||||||
|
u32 *screenPtr = ((u32 *)renderBuffer->memory) + screenOffset;
|
||||||
|
|
||||||
|
i32 fontWidth = DQN_ABS((i32)(fontRect.min.x - fontRect.max.x));
|
||||||
|
i32 fontHeight = DQN_ABS((i32)(fontRect.min.y - fontRect.max.y));
|
||||||
|
for (i32 y = 0; y < fontHeight; y++)
|
||||||
|
{
|
||||||
|
for (i32 x = 0; x < fontWidth; x++)
|
||||||
|
{
|
||||||
|
i32 yOffset = fontHeight - y;
|
||||||
|
u8 fontPixel = fontPtr[x + (yOffset * fontPitch)];
|
||||||
|
if (fontPixel == 0) continue;
|
||||||
|
|
||||||
|
f32 srcA = (fontPixel / 255.0f);
|
||||||
|
f32 srcR = (fontPixel / 255.0f);
|
||||||
|
f32 srcG = (fontPixel / 255.0f);
|
||||||
|
f32 srcB = (fontPixel / 255.0f);
|
||||||
|
|
||||||
|
u32 offset = x + (y * renderBuffer->width);
|
||||||
|
u32 old = screenPtr[offset];
|
||||||
|
f32 oldR = (f32)((old >> 16) & 0xFF) / 255.0f;
|
||||||
|
f32 oldG = (f32)((old >> 8) & 0xFF) / 255.0f;
|
||||||
|
f32 oldB = (f32)((old >> 0) & 0xFF) / 255.0f;
|
||||||
|
|
||||||
|
f32 invA = 1 - srcA;
|
||||||
|
f32 destR = srcR + (invA * oldR);
|
||||||
|
f32 destG = srcG + (invA * oldG);
|
||||||
|
f32 destB = srcB + (invA * oldB);
|
||||||
|
u32 dest = ((u32)(destR * 255.0f) << 16) |
|
||||||
|
((u32)(destG * 255.0f) << 8) |
|
||||||
|
((u32)(destB * 255.0f) << 0);
|
||||||
|
|
||||||
|
screenPtr[offset] = dest;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
FILE_SCOPE void ClearRenderBuffer(PlatformRenderBuffer *const renderBuffer, DqnV3 color)
|
FILE_SCOPE void ClearRenderBuffer(PlatformRenderBuffer *const renderBuffer, DqnV3 color)
|
||||||
{
|
{
|
||||||
if (!renderBuffer) return;
|
if (!renderBuffer) return;
|
||||||
@ -288,11 +375,12 @@ FILE_SCOPE void BitmapFontCreate(const PlatformAPI api,
|
|||||||
// Pack font data to bitmap
|
// Pack font data to bitmap
|
||||||
////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////
|
||||||
font->bitmap = (u8 *)DqnMemBuffer_Allocate(
|
font->bitmap = (u8 *)DqnMemBuffer_Allocate(
|
||||||
&memory->permanentBuffer, (size_t)(font->bitmapDim.w * font->bitmapDim.h));
|
&memory->permanentBuffer,
|
||||||
|
(size_t)(font->bitmapDim.w * font->bitmapDim.h));
|
||||||
|
|
||||||
stbtt_pack_context fontPackContext = {};
|
stbtt_pack_context fontPackContext = {};
|
||||||
DQN_ASSERT(stbtt_PackBegin(&fontPackContext, font->bitmap, (i32)bitmapDim.w,
|
DQN_ASSERT(stbtt_PackBegin(&fontPackContext, font->bitmap, bitmapDim.w,
|
||||||
(i32)bitmapDim.h, 0, 1, NULL) == 1);
|
bitmapDim.h, 0, 1, NULL) == 1);
|
||||||
{
|
{
|
||||||
i32 numCodepoints =
|
i32 numCodepoints =
|
||||||
(i32)((codepointRange.max + 1) - codepointRange.min);
|
(i32)((codepointRange.max + 1) - codepointRange.min);
|
||||||
@ -314,7 +402,7 @@ FILE_SCOPE void BitmapFontCreate(const PlatformAPI api,
|
|||||||
{
|
{
|
||||||
// NOTE: Bitmap from stb_truetype is 1BPP. So the actual color
|
// NOTE: Bitmap from stb_truetype is 1BPP. So the actual color
|
||||||
// value represents its' alpha value but also its' color.
|
// value represents its' alpha value but also its' color.
|
||||||
u32 index = x + (y * (i32)bitmapDim.w);
|
u32 index = x + (y * bitmapDim.w);
|
||||||
f32 alpha = (f32)(font->bitmap[index]) / 255.0f;
|
f32 alpha = (f32)(font->bitmap[index]) / 255.0f;
|
||||||
f32 color = alpha;
|
f32 color = alpha;
|
||||||
f32 preMulAlphaColor = color * alpha;
|
f32 preMulAlphaColor = color * alpha;
|
||||||
@ -322,6 +410,11 @@ FILE_SCOPE void BitmapFontCreate(const PlatformAPI api,
|
|||||||
font->bitmap[index] = (u8)(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);
|
DqnMemBuffer_EndTempRegion(transientTempBufferRegion);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -338,9 +431,8 @@ extern "C" void DR_Update(PlatformRenderBuffer *const renderBuffer,
|
|||||||
DQN_ASSERT(memory->context);
|
DQN_ASSERT(memory->context);
|
||||||
|
|
||||||
state = (DRState *)memory->context;
|
state = (DRState *)memory->context;
|
||||||
BitmapFontCreate(input->api, memory, &state->font, "Roboto-Bold.ttf",
|
BitmapFontCreate(input->api, memory, &state->font, "Roboto-bold.ttf",
|
||||||
DqnV2i_2i(512, 512), DqnV2i_2i(' ', '~'), 20);
|
DqnV2i_2i(256, 256), DqnV2i_2i(' ', '~'), 35);
|
||||||
input->api.Print("Hello world!\n");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ClearRenderBuffer(renderBuffer, DqnV3_3f(0, 0, 0));
|
ClearRenderBuffer(renderBuffer, DqnV3_3f(0, 0, 0));
|
||||||
@ -377,6 +469,8 @@ extern "C" void DR_Update(PlatformRenderBuffer *const renderBuffer,
|
|||||||
DrawTriangle(renderBuffer, t0[0], t0[1], t0[2], colorRed);
|
DrawTriangle(renderBuffer, t0[0], t0[1], t0[2], colorRed);
|
||||||
DrawTriangle(renderBuffer, t1[0], t1[1], t1[2], colorRed);
|
DrawTriangle(renderBuffer, t1[0], t1[1], t1[2], colorRed);
|
||||||
DrawTriangle(renderBuffer, t2[0], t2[1], t2[2], colorRed);
|
DrawTriangle(renderBuffer, t2[0], t2[1], t2[2], colorRed);
|
||||||
DrawTriangle(renderBuffer, t3[0], t3[1], t3[2], colorRed);
|
// DrawTriangle(renderBuffer, t3[0], t3[1], t3[2], colorRed);
|
||||||
|
|
||||||
|
DqnV2 fontP = DqnV2_2i(200, 180);
|
||||||
|
DrawText(renderBuffer, state->font, fontP, "hello world!");
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user