All render paths go through srgb->linear pipeline
This commit is contained in:
parent
f040c377e9
commit
1d0e9b8a07
@ -94,10 +94,13 @@ FILE_SCOPE bool BitmapFontCreate(const PlatformAPI api,
|
|||||||
u32 index = x + (y * bitmapDim.w);
|
u32 index = x + (y * bitmapDim.w);
|
||||||
f32 alpha = (f32)(loadedFont.bitmap[index]) / 255.0f;
|
f32 alpha = (f32)(loadedFont.bitmap[index]) / 255.0f;
|
||||||
f32 color = alpha;
|
f32 color = alpha;
|
||||||
f32 preMulAlphaColor = color * alpha;
|
|
||||||
DQN_ASSERT(preMulAlphaColor >= 0.0f && preMulAlphaColor <= 255.0f);
|
|
||||||
|
|
||||||
loadedFont.bitmap[index] = (u8)(preMulAlphaColor * 255.0f);
|
color = DTRRender_SRGB1ToLinearSpacef(color);
|
||||||
|
color = color * alpha;
|
||||||
|
color = DTRRender_LinearToSRGB1Spacef(color) * 255.0f;
|
||||||
|
DQN_ASSERT(color >= 0.0f && color <= 255.0f);
|
||||||
|
|
||||||
|
loadedFont.bitmap[index] = (u8)color;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -152,7 +155,10 @@ FILE_SCOPE bool BitmapLoad(const PlatformAPI api, DTRBitmap *bitmap,
|
|||||||
color.b = (f32)((pixel >> 16) & 0xFF);
|
color.b = (f32)((pixel >> 16) & 0xFF);
|
||||||
color.g = (f32)((pixel >> 8) & 0xFF);
|
color.g = (f32)((pixel >> 8) & 0xFF);
|
||||||
color.r = (f32)((pixel >> 0) & 0xFF);
|
color.r = (f32)((pixel >> 0) & 0xFF);
|
||||||
color = DTRRender_PreMultiplyAlpha255(color);
|
|
||||||
|
color *= DTRRENDER_INV_255;
|
||||||
|
color = DTRRender_PreMultiplyAlphaSRGB1WithLinearConversion(color);
|
||||||
|
color *= 255.0f;
|
||||||
|
|
||||||
pixel = (((u32)color.a << 24) |
|
pixel = (((u32)color.a << 24) |
|
||||||
((u32)color.b << 16) |
|
((u32)color.b << 16) |
|
||||||
@ -1074,20 +1080,25 @@ extern "C" void DTR_Update(PlatformRenderBuffer *const renderBuffer,
|
|||||||
DTRRender_Triangle(renderBuffer, t1[0], t1[1], t1[2], colorRed);
|
DTRRender_Triangle(renderBuffer, t1[0], t1[1], t1[2], colorRed);
|
||||||
DTRRender_Triangle(renderBuffer, t2[0], t2[1], t2[2], colorRed);
|
DTRRender_Triangle(renderBuffer, t2[0], t2[1], t2[2], colorRed);
|
||||||
|
|
||||||
DqnV4 colorRedHalfA = DqnV4_4f(1, 0, 0, 0.25f);
|
DqnV4 colorRedHalfA = DqnV4_4f(1, 0, 0, 0.1f);
|
||||||
LOCAL_PERSIST f32 rotation = 0;
|
LOCAL_PERSIST f32 rotation = 0;
|
||||||
rotation += input->deltaForFrame * 0.25f;
|
rotation += input->deltaForFrame * 0.25f;
|
||||||
DTRRenderTransform triTransform = DTRRender_DefaultTriangleTransform();
|
|
||||||
triTransform.rotation = rotation;
|
|
||||||
DTRRender_Triangle(renderBuffer, t3[0], t3[1], t3[2], colorRedHalfA, triTransform);
|
|
||||||
|
|
||||||
DTRRenderTransform defaultTransform = DTRRender_DefaultTransform();
|
DTRRenderTransform defaultTransform = DTRRender_DefaultTransform();
|
||||||
defaultTransform.rotation = rotation + 45;
|
defaultTransform.rotation = rotation + 45;
|
||||||
DTRRender_Rectangle(renderBuffer, DqnV2_1f(300.0f), DqnV2_1f(300 + 20.0f), colorRed,
|
DTRRender_Rectangle(renderBuffer, DqnV2_1f(300.0f), DqnV2_1f(300 + 20.0f), DqnV4_4f(0, 1.0f, 1.0f, 1.0f),
|
||||||
defaultTransform);
|
defaultTransform);
|
||||||
|
|
||||||
|
// Rotating triangle
|
||||||
|
{
|
||||||
|
DTRRenderTransform triTransform = DTRRender_DefaultTriangleTransform();
|
||||||
|
triTransform.rotation = rotation;
|
||||||
|
DTRRender_Triangle(renderBuffer, t3[0], t3[1], t3[2], colorRedHalfA, triTransform);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
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!", DqnV4_4f(0, 0, 0, 1));
|
||||||
|
|
||||||
DTRRenderTransform transform = DTRRender_DefaultTransform();
|
DTRRenderTransform transform = DTRRender_DefaultTransform();
|
||||||
transform.rotation = rotation * 2.0f;
|
transform.rotation = rotation * 2.0f;
|
||||||
@ -1096,7 +1107,11 @@ extern "C" void DTR_Update(PlatformRenderBuffer *const renderBuffer,
|
|||||||
LOCAL_PERSIST DqnV2 bitmapP = DqnV2_2f(300, 250);
|
LOCAL_PERSIST DqnV2 bitmapP = DqnV2_2f(300, 250);
|
||||||
bitmapP.x += 3.0f * sinf((f32)input->timeNowInS * 0.5f);
|
bitmapP.x += 3.0f * sinf((f32)input->timeNowInS * 0.5f);
|
||||||
|
|
||||||
DTRRender_Bitmap(renderBuffer, &state->bitmap, bitmapP, transform);
|
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(9.9f * cAngle), 1.0f);
|
||||||
|
DTRRender_Bitmap(renderBuffer, &state->bitmap, bitmapP, transform, color);
|
||||||
|
|
||||||
#else
|
#else
|
||||||
CompAssignment(renderBuffer, input, memory);
|
CompAssignment(renderBuffer, input, memory);
|
||||||
#endif
|
#endif
|
||||||
|
@ -22,7 +22,8 @@ void DTRDebug_PushText(const char *const formatStr, ...)
|
|||||||
}
|
}
|
||||||
va_end(argList);
|
va_end(argList);
|
||||||
|
|
||||||
DTRRender_Text(debug->renderBuffer, *debug->font, debug->displayP, str);
|
DTRRender_Text(debug->renderBuffer, *debug->font, debug->displayP, str,
|
||||||
|
debug->displayColor);
|
||||||
debug->displayP.y += globalDebug.displayYOffset;
|
debug->displayP.y += globalDebug.displayYOffset;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -57,7 +58,7 @@ FILE_SCOPE void PushMemBufferText(const char *const name,
|
|||||||
totalUsed, totalSize);
|
totalUsed, totalSize);
|
||||||
|
|
||||||
DTRRender_Text(globalDebug.renderBuffer, *globalDebug.font,
|
DTRRender_Text(globalDebug.renderBuffer, *globalDebug.font,
|
||||||
globalDebug.displayP, str);
|
globalDebug.displayP, str, globalDebug.displayColor);
|
||||||
globalDebug.displayP.y += globalDebug.displayYOffset;
|
globalDebug.displayP.y += globalDebug.displayYOffset;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -72,6 +73,7 @@ void DTRDebug_Update(DTRState *const state,
|
|||||||
|
|
||||||
debug->renderBuffer = renderBuffer;
|
debug->renderBuffer = renderBuffer;
|
||||||
debug->font = &state->font;
|
debug->font = &state->font;
|
||||||
|
debug->displayColor = DqnV4_4f(1, 1, 1, 1);
|
||||||
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);
|
||||||
@ -85,7 +87,8 @@ void DTRDebug_Update(DTRState *const state,
|
|||||||
{
|
{
|
||||||
char str[128] = {};
|
char str[128] = {};
|
||||||
Dqn_sprintf(str, "%s: %'lld", "TotalSetPixels", debug->totalSetPixels);
|
Dqn_sprintf(str, "%s: %'lld", "TotalSetPixels", debug->totalSetPixels);
|
||||||
DTRRender_Text(debug->renderBuffer, *debug->font, debug->displayP, str);
|
DTRRender_Text(debug->renderBuffer, *debug->font, debug->displayP, str,
|
||||||
|
debug->displayColor);
|
||||||
debug->displayP.y += globalDebug.displayYOffset;
|
debug->displayP.y += globalDebug.displayYOffset;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -93,7 +96,8 @@ void DTRDebug_Update(DTRState *const state,
|
|||||||
{
|
{
|
||||||
char str[128] = {};
|
char str[128] = {};
|
||||||
Dqn_sprintf(str, "%s: %'lld", "SetPixelsPerFrame", debug->setPixelsPerFrame);
|
Dqn_sprintf(str, "%s: %'lld", "SetPixelsPerFrame", debug->setPixelsPerFrame);
|
||||||
DTRRender_Text(debug->renderBuffer, *debug->font, debug->displayP, str);
|
DTRRender_Text(debug->renderBuffer, *debug->font, debug->displayP, str,
|
||||||
|
debug->displayColor);
|
||||||
debug->displayP.y += globalDebug.displayYOffset;
|
debug->displayP.y += globalDebug.displayYOffset;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,6 +4,9 @@
|
|||||||
#include "dqn.h"
|
#include "dqn.h"
|
||||||
|
|
||||||
#define DTR_DEBUG 1
|
#define DTR_DEBUG 1
|
||||||
|
#ifdef DTR_DEBUG
|
||||||
|
#define DTR_DEBUG_RENDER 0
|
||||||
|
#endif
|
||||||
|
|
||||||
typedef struct PlatformRenderBuffer PlatformRenderBuffer;
|
typedef struct PlatformRenderBuffer PlatformRenderBuffer;
|
||||||
typedef struct DTRFont DTRFont;
|
typedef struct DTRFont DTRFont;
|
||||||
@ -16,6 +19,7 @@ typedef struct DTRDebug
|
|||||||
DTRFont *font;
|
DTRFont *font;
|
||||||
PlatformRenderBuffer *renderBuffer;
|
PlatformRenderBuffer *renderBuffer;
|
||||||
|
|
||||||
|
DqnV4 displayColor;
|
||||||
DqnV2 displayP;
|
DqnV2 displayP;
|
||||||
i32 displayYOffset;
|
i32 displayYOffset;
|
||||||
|
|
||||||
|
@ -12,9 +12,9 @@
|
|||||||
#include "external/stb_image_write.h"
|
#include "external/stb_image_write.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define DTRRENDER_INV_255 0.00392156862f;
|
FILE_SCOPE const f32 COLOR_EPSILON = 0.9f;
|
||||||
|
|
||||||
inline DqnV4 DTRRender_PreMultiplyAlpha1(const DqnV4 color)
|
FILE_SCOPE inline DqnV4 PreMultiplyAlpha1(const DqnV4 color)
|
||||||
{
|
{
|
||||||
DqnV4 result;
|
DqnV4 result;
|
||||||
result.r = color.r * color.a;
|
result.r = color.r * color.a;
|
||||||
@ -29,10 +29,11 @@ inline DqnV4 DTRRender_PreMultiplyAlpha1(const DqnV4 color)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline DqnV4 DTRRender_PreMultiplyAlpha255(const DqnV4 color)
|
FILE_SCOPE inline DqnV4 PreMultiplyAlpha255(const DqnV4 color)
|
||||||
{
|
{
|
||||||
DqnV4 result;
|
DqnV4 result;
|
||||||
f32 normA = color.a * DTRRENDER_INV_255;
|
f32 normA = color.a * DTRRENDER_INV_255;
|
||||||
|
DQN_ASSERT(normA >= 0.0f && normA <= 1.0f + COLOR_EPSILON);
|
||||||
result.r = color.r * normA;
|
result.r = color.r * normA;
|
||||||
result.g = color.g * normA;
|
result.g = color.g * normA;
|
||||||
result.b = color.b * normA;
|
result.b = color.b * normA;
|
||||||
@ -41,56 +42,68 @@ inline DqnV4 DTRRender_PreMultiplyAlpha255(const DqnV4 color)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
enum ColourSpace
|
enum ColorSpace
|
||||||
{
|
{
|
||||||
ColourSpace_SRGB,
|
ColorSpace_SRGB,
|
||||||
ColourSpace_Linear,
|
ColorSpace_Linear,
|
||||||
};
|
};
|
||||||
|
|
||||||
// NOTE(doyle): We are approximating the actual gamma correct value 2.2 to 2 as
|
// NOTE(doyle): We are approximating the actual gamma correct value 2.2 to 2 as
|
||||||
// a compromise.
|
// a compromise.
|
||||||
FILE_SCOPE inline f32 SRGB1ToLinearSpacef(f32 val)
|
inline f32 DTRRender_SRGB1ToLinearSpacef(f32 val)
|
||||||
{
|
{
|
||||||
|
DQN_ASSERT(val >= 0.0f && val <= 1.0f + COLOR_EPSILON);
|
||||||
f32 result = DQN_SQUARED(val);
|
f32 result = DQN_SQUARED(val);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
FILE_SCOPE inline DqnV4 SRGB1ToLinearSpaceV4(DqnV4 color)
|
inline DqnV4 DTRRender_SRGB1ToLinearSpaceV4(DqnV4 color)
|
||||||
{
|
{
|
||||||
DqnV4 result = {};
|
DqnV4 result = {};
|
||||||
result.r = SRGB1ToLinearSpacef(color.r);
|
result.r = DTRRender_SRGB1ToLinearSpacef(color.r);
|
||||||
result.g = SRGB1ToLinearSpacef(color.g);
|
result.g = DTRRender_SRGB1ToLinearSpacef(color.g);
|
||||||
result.b = SRGB1ToLinearSpacef(color.b);
|
result.b = DTRRender_SRGB1ToLinearSpacef(color.b);
|
||||||
result.a = SRGB1ToLinearSpacef(color.a);
|
result.a = color.a;
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
FILE_SCOPE inline f32 LinearToSRGB1Spacef(f32 val)
|
inline f32 DTRRender_LinearToSRGB1Spacef(f32 val)
|
||||||
{
|
{
|
||||||
|
DQN_ASSERT(val >= 0.0f && val <= 1.0f + COLOR_EPSILON);
|
||||||
if (val == 0) return 0;
|
if (val == 0) return 0;
|
||||||
f32 result = DqnMath_Sqrtf(val);
|
f32 result = DqnMath_Sqrtf(val);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
FILE_SCOPE inline DqnV4 LinearToSRGB1SpaceV4(DqnV4 color)
|
inline DqnV4 DTRRender_LinearToSRGB1SpaceV4(DqnV4 color)
|
||||||
{
|
{
|
||||||
DqnV4 result = {};
|
DqnV4 result = {};
|
||||||
result.r = LinearToSRGB1Spacef(color.r);
|
result.r = DTRRender_LinearToSRGB1Spacef(color.r);
|
||||||
result.g = LinearToSRGB1Spacef(color.g);
|
result.g = DTRRender_LinearToSRGB1Spacef(color.g);
|
||||||
result.b = LinearToSRGB1Spacef(color.b);
|
result.b = DTRRender_LinearToSRGB1Spacef(color.b);
|
||||||
result.a = LinearToSRGB1Spacef(color.a);
|
result.a = color.a;
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline DqnV4 DTRRender_PreMultiplyAlphaSRGB1WithLinearConversion(DqnV4 color)
|
||||||
|
{
|
||||||
|
DqnV4 result = color;
|
||||||
|
result = DTRRender_SRGB1ToLinearSpaceV4(result);
|
||||||
|
result = PreMultiplyAlpha1(result);
|
||||||
|
result = DTRRender_LinearToSRGB1SpaceV4(result);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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, const i32 x, const i32 y,
|
FILE_SCOPE inline void SetPixel(PlatformRenderBuffer *const renderBuffer, const i32 x, const i32 y,
|
||||||
DqnV4 color, const enum ColourSpace colourSpace = ColourSpace_SRGB)
|
DqnV4 color, const enum ColorSpace colorSpace = ColorSpace_SRGB)
|
||||||
{
|
{
|
||||||
if (!renderBuffer) return;
|
if (!renderBuffer) return;
|
||||||
if (x <= 0 || x > (renderBuffer->width - 1)) return;
|
if (x < 0 || x > (renderBuffer->width - 1)) return;
|
||||||
if (y <= 0 || y > (renderBuffer->height - 1)) return;
|
if (y < 0 || y > (renderBuffer->height - 1)) return;
|
||||||
|
|
||||||
u32 *const bitmapPtr = (u32 *)renderBuffer->memory;
|
u32 *const bitmapPtr = (u32 *)renderBuffer->memory;
|
||||||
const u32 pitchInU32 = (renderBuffer->width * renderBuffer->bytesPerPixel) / 4;
|
const u32 pitchInU32 = (renderBuffer->width * renderBuffer->bytesPerPixel) / 4;
|
||||||
@ -99,11 +112,8 @@ FILE_SCOPE inline void SetPixel(PlatformRenderBuffer *const renderBuffer, const
|
|||||||
// new pixel is totally opaque or invisible then we're just flat out
|
// new pixel is totally opaque or invisible then we're just flat out
|
||||||
// overwriting/keeping the state of the pixel so we can save cycles by skipping.
|
// overwriting/keeping the state of the pixel so we can save cycles by skipping.
|
||||||
#if 1
|
#if 1
|
||||||
bool needGammaFix = (color.a > 0.0f || color.a < 1.0f) && (colourSpace == ColourSpace_SRGB);
|
bool needGammaFix = (color.a > 0.0f || color.a < 1.0f + COLOR_EPSILON) && (colorSpace == ColorSpace_SRGB);
|
||||||
if (needGammaFix)
|
if (needGammaFix) color = DTRRender_SRGB1ToLinearSpaceV4(color);
|
||||||
{
|
|
||||||
color = SRGB1ToLinearSpaceV4(color);
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
u32 src = bitmapPtr[x + (y * pitchInU32)];
|
u32 src = bitmapPtr[x + (y * pitchInU32)];
|
||||||
@ -111,9 +121,9 @@ FILE_SCOPE inline void SetPixel(PlatformRenderBuffer *const renderBuffer, const
|
|||||||
f32 srcG = (f32)((src >> 8) & 0xFF) * DTRRENDER_INV_255;
|
f32 srcG = (f32)((src >> 8) & 0xFF) * DTRRENDER_INV_255;
|
||||||
f32 srcB = (f32)((src >> 0) & 0xFF) * DTRRENDER_INV_255;
|
f32 srcB = (f32)((src >> 0) & 0xFF) * DTRRENDER_INV_255;
|
||||||
|
|
||||||
srcR = SRGB1ToLinearSpacef(srcR);
|
srcR = DTRRender_SRGB1ToLinearSpacef(srcR);
|
||||||
srcG = SRGB1ToLinearSpacef(srcG);
|
srcG = DTRRender_SRGB1ToLinearSpacef(srcG);
|
||||||
srcB = SRGB1ToLinearSpacef(srcB);
|
srcB = DTRRender_SRGB1ToLinearSpacef(srcB);
|
||||||
|
|
||||||
// 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)
|
||||||
@ -122,24 +132,14 @@ FILE_SCOPE inline void SetPixel(PlatformRenderBuffer *const renderBuffer, const
|
|||||||
f32 destG = color.g + (invANorm * srcG);
|
f32 destG = color.g + (invANorm * srcG);
|
||||||
f32 destB = color.b + (invANorm * srcB);
|
f32 destB = color.b + (invANorm * srcB);
|
||||||
|
|
||||||
#if 1
|
destR = DTRRender_LinearToSRGB1Spacef(destR) * 255.0f;
|
||||||
if (needGammaFix || colourSpace == ColourSpace_Linear)
|
destG = DTRRender_LinearToSRGB1Spacef(destG) * 255.0f;
|
||||||
{
|
destB = DTRRender_LinearToSRGB1Spacef(destB) * 255.0f;
|
||||||
destR = LinearToSRGB1Spacef(destR);
|
|
||||||
destG = LinearToSRGB1Spacef(destG);
|
|
||||||
destB = LinearToSRGB1Spacef(destB);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
destR *= 255.0f;
|
|
||||||
destG *= 255.0f;
|
|
||||||
destB *= 255.0f;
|
|
||||||
|
|
||||||
DQN_ASSERT(destR >= 0);
|
DQN_ASSERT(destR >= 0);
|
||||||
DQN_ASSERT(destG >= 0);
|
DQN_ASSERT(destG >= 0);
|
||||||
DQN_ASSERT(destB >= 0);
|
DQN_ASSERT(destB >= 0);
|
||||||
|
|
||||||
const f32 COLOR_EPSILON = 0.1f;
|
|
||||||
if (destR > 255.0f)
|
if (destR > 255.0f)
|
||||||
{
|
{
|
||||||
DQN_ASSERT((destR - 255.0f) < COLOR_EPSILON);
|
DQN_ASSERT((destR - 255.0f) < COLOR_EPSILON);
|
||||||
@ -176,7 +176,8 @@ void DTRRender_Text(PlatformRenderBuffer *const renderBuffer,
|
|||||||
if (len == -1) len = Dqn_strlen(text);
|
if (len == -1) len = Dqn_strlen(text);
|
||||||
|
|
||||||
i32 index = 0;
|
i32 index = 0;
|
||||||
color = DTRRender_PreMultiplyAlpha1(color);
|
color = DTRRender_SRGB1ToLinearSpaceV4(color);
|
||||||
|
color = PreMultiplyAlpha1(color);
|
||||||
while (index < len)
|
while (index < len)
|
||||||
{
|
{
|
||||||
if (text[index] < font.codepointRange.min &&
|
if (text[index] < font.codepointRange.min &&
|
||||||
@ -237,7 +238,7 @@ void DTRRender_Text(PlatformRenderBuffer *const renderBuffer,
|
|||||||
|
|
||||||
i32 actualX = (i32)(screenRect.min.x + x);
|
i32 actualX = (i32)(screenRect.min.x + x);
|
||||||
i32 actualY = (i32)(screenRect.min.y + y - fontHeightOffset);
|
i32 actualY = (i32)(screenRect.min.y + y - fontHeightOffset);
|
||||||
SetPixel(renderBuffer, actualX, actualY, resultColor);
|
SetPixel(renderBuffer, actualX, actualY, resultColor, ColorSpace_Linear);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -265,7 +266,8 @@ void DTRRender_Line(PlatformRenderBuffer *const renderBuffer, DqnV2i a,
|
|||||||
DqnV2i b, DqnV4 color)
|
DqnV2i b, DqnV4 color)
|
||||||
{
|
{
|
||||||
if (!renderBuffer) return;
|
if (!renderBuffer) return;
|
||||||
color = DTRRender_PreMultiplyAlpha1(color);
|
color = DTRRender_SRGB1ToLinearSpaceV4(color);
|
||||||
|
color = PreMultiplyAlpha1(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))
|
||||||
@ -310,7 +312,7 @@ void DTRRender_Line(PlatformRenderBuffer *const renderBuffer, DqnV2i a,
|
|||||||
for (i32 iterateX = 0; iterateX < numIterations; iterateX++)
|
for (i32 iterateX = 0; iterateX < numIterations; iterateX++)
|
||||||
{
|
{
|
||||||
newX = a.x + iterateX;
|
newX = a.x + iterateX;
|
||||||
SetPixel(renderBuffer, *plotX, *plotY, color);
|
SetPixel(renderBuffer, *plotX, *plotY, color, ColorSpace_Linear);
|
||||||
|
|
||||||
distAccumulator += distFromPixelOrigin;
|
distAccumulator += distFromPixelOrigin;
|
||||||
if (distAccumulator > run)
|
if (distAccumulator > run)
|
||||||
@ -384,7 +386,8 @@ void DTRRender_Rectangle(PlatformRenderBuffer *const renderBuffer, DqnV2 min, Dq
|
|||||||
////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////
|
||||||
// Transform vertexes
|
// Transform vertexes
|
||||||
////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////
|
||||||
color = DTRRender_PreMultiplyAlpha1(color);
|
color = DTRRender_SRGB1ToLinearSpaceV4(color);
|
||||||
|
color = PreMultiplyAlpha1(color);
|
||||||
|
|
||||||
RectPoints rectPoints = TransformRectPoints(min, max, transform);
|
RectPoints rectPoints = TransformRectPoints(min, max, transform);
|
||||||
DqnV2 *const pList = &rectPoints.pList[0];
|
DqnV2 *const pList = &rectPoints.pList[0];
|
||||||
@ -430,7 +433,7 @@ void DTRRender_Rectangle(PlatformRenderBuffer *const renderBuffer, DqnV2 min, Dq
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pIsInside) SetPixel(renderBuffer, bufferX, bufferY, color);
|
if (pIsInside) SetPixel(renderBuffer, bufferX, bufferY, color, ColorSpace_Linear);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -442,7 +445,7 @@ void DTRRender_Rectangle(PlatformRenderBuffer *const renderBuffer, DqnV2 min, Dq
|
|||||||
for (i32 x = 0; x < clippedSize.w; 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, ColorSpace_Linear);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -450,7 +453,7 @@ void DTRRender_Rectangle(PlatformRenderBuffer *const renderBuffer, DqnV2 min, Dq
|
|||||||
////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////
|
||||||
// Debug
|
// Debug
|
||||||
////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////
|
||||||
if (DTR_DEBUG)
|
if (DTR_DEBUG_RENDER)
|
||||||
{
|
{
|
||||||
// Draw Bounding box
|
// Draw Bounding box
|
||||||
{
|
{
|
||||||
@ -491,7 +494,8 @@ void DTRRender_Triangle(PlatformRenderBuffer *const renderBuffer, DqnV2 p1, DqnV
|
|||||||
p2 = pList[1];
|
p2 = pList[1];
|
||||||
p3 = pList[2];
|
p3 = pList[2];
|
||||||
|
|
||||||
color = DTRRender_PreMultiplyAlpha1(color);
|
color = DTRRender_SRGB1ToLinearSpaceV4(color);
|
||||||
|
color = PreMultiplyAlpha1(color);
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////
|
||||||
// Calculate Bounding Box
|
// Calculate Bounding Box
|
||||||
@ -647,7 +651,7 @@ void DTRRender_Triangle(PlatformRenderBuffer *const renderBuffer, DqnV2 p1, DqnV
|
|||||||
{
|
{
|
||||||
if (signedArea1Row >= 0 && signedArea2Row >= 0 && signedArea3Row >= 0)
|
if (signedArea1Row >= 0 && signedArea2Row >= 0 && signedArea3Row >= 0)
|
||||||
{
|
{
|
||||||
SetPixel(renderBuffer, scanP.x, scanP.y, color);
|
SetPixel(renderBuffer, scanP.x, scanP.y, color, ColorSpace_Linear);
|
||||||
}
|
}
|
||||||
|
|
||||||
signedArea1Row += signedArea1DeltaX;
|
signedArea1Row += signedArea1DeltaX;
|
||||||
@ -663,7 +667,7 @@ void DTRRender_Triangle(PlatformRenderBuffer *const renderBuffer, DqnV2 p1, DqnV
|
|||||||
////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////
|
||||||
// Debug
|
// Debug
|
||||||
////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////
|
||||||
if (DTR_DEBUG)
|
if (DTR_DEBUG_RENDER)
|
||||||
{
|
{
|
||||||
// Draw Bounding box
|
// Draw Bounding box
|
||||||
{
|
{
|
||||||
@ -698,9 +702,13 @@ void DTRRender_Triangle(PlatformRenderBuffer *const renderBuffer, DqnV2 p1, DqnV
|
|||||||
|
|
||||||
void DTRRender_Bitmap(PlatformRenderBuffer *const renderBuffer,
|
void DTRRender_Bitmap(PlatformRenderBuffer *const renderBuffer,
|
||||||
DTRBitmap *const bitmap, DqnV2 pos,
|
DTRBitmap *const bitmap, DqnV2 pos,
|
||||||
const DTRRenderTransform transform)
|
const DTRRenderTransform transform, DqnV4 color)
|
||||||
{
|
{
|
||||||
if (!bitmap || !bitmap->memory || !renderBuffer) return;
|
if (!bitmap || !bitmap->memory || !renderBuffer) return;
|
||||||
|
DQN_ASSERT(color.a >= 0 && color.a <= 1.0f);
|
||||||
|
DQN_ASSERT(color.r >= 0 && color.r <= 1.0f);
|
||||||
|
DQN_ASSERT(color.g >= 0 && color.g <= 1.0f);
|
||||||
|
DQN_ASSERT(color.b >= 0 && color.b <= 1.0f);
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////
|
||||||
// Transform vertexes
|
// Transform vertexes
|
||||||
@ -717,6 +725,8 @@ void DTRRender_Bitmap(PlatformRenderBuffer *const renderBuffer,
|
|||||||
min = bounds.min;
|
min = bounds.min;
|
||||||
max = bounds.max;
|
max = bounds.max;
|
||||||
|
|
||||||
|
color = DTRRender_SRGB1ToLinearSpaceV4(color);
|
||||||
|
color = PreMultiplyAlpha1(color);
|
||||||
////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////
|
||||||
// Clip drawing space
|
// Clip drawing space
|
||||||
////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////
|
||||||
@ -828,10 +838,10 @@ void DTRRender_Bitmap(PlatformRenderBuffer *const renderBuffer,
|
|||||||
color3 *= DTRRENDER_INV_255;
|
color3 *= DTRRENDER_INV_255;
|
||||||
color4 *= DTRRENDER_INV_255;
|
color4 *= DTRRENDER_INV_255;
|
||||||
|
|
||||||
color1 = SRGB1ToLinearSpaceV4(color1);
|
color1 = DTRRender_SRGB1ToLinearSpaceV4(color1);
|
||||||
color2 = SRGB1ToLinearSpaceV4(color2);
|
color2 = DTRRender_SRGB1ToLinearSpaceV4(color2);
|
||||||
color3 = SRGB1ToLinearSpaceV4(color3);
|
color3 = DTRRender_SRGB1ToLinearSpaceV4(color3);
|
||||||
color4 = SRGB1ToLinearSpaceV4(color4);
|
color4 = DTRRender_SRGB1ToLinearSpaceV4(color4);
|
||||||
|
|
||||||
DqnV4 color12;
|
DqnV4 color12;
|
||||||
color12.a = DqnMath_Lerp(color1.a, texelFractionalX, color2.a);
|
color12.a = DqnMath_Lerp(color1.a, texelFractionalX, color2.a);
|
||||||
@ -845,22 +855,40 @@ void DTRRender_Bitmap(PlatformRenderBuffer *const renderBuffer,
|
|||||||
color34.g = DqnMath_Lerp(color3.g, texelFractionalX, color4.g);
|
color34.g = DqnMath_Lerp(color3.g, texelFractionalX, color4.g);
|
||||||
color34.r = DqnMath_Lerp(color3.r, texelFractionalX, color4.r);
|
color34.r = DqnMath_Lerp(color3.r, texelFractionalX, color4.r);
|
||||||
|
|
||||||
DqnV4 color;
|
DqnV4 blend;
|
||||||
color.a = DqnMath_Lerp(color12.a, texelFractionalY, color34.a);
|
blend.a = DqnMath_Lerp(color12.a, texelFractionalY, color34.a);
|
||||||
color.b = DqnMath_Lerp(color12.b, texelFractionalY, color34.b);
|
blend.b = DqnMath_Lerp(color12.b, texelFractionalY, color34.b);
|
||||||
color.g = DqnMath_Lerp(color12.g, texelFractionalY, color34.g);
|
blend.g = DqnMath_Lerp(color12.g, texelFractionalY, color34.g);
|
||||||
color.r = DqnMath_Lerp(color12.r, texelFractionalY, color34.r);
|
blend.r = DqnMath_Lerp(color12.r, texelFractionalY, color34.r);
|
||||||
DQN_ASSERT(color.a >= 0 && color.a <= 1.0f);
|
|
||||||
DQN_ASSERT(color.r >= 0 && color.r <= 1.0f);
|
|
||||||
DQN_ASSERT(color.g >= 0 && color.g <= 1.0f);
|
|
||||||
DQN_ASSERT(color.b >= 0 && color.b <= 1.0f);
|
|
||||||
|
|
||||||
SetPixel(renderBuffer, bufferX, bufferY, color, ColourSpace_Linear);
|
DQN_ASSERT(blend.a >= 0 && blend.a <= 1.0f);
|
||||||
|
DQN_ASSERT(blend.r >= 0 && blend.r <= 1.0f);
|
||||||
|
DQN_ASSERT(blend.g >= 0 && blend.g <= 1.0f);
|
||||||
|
DQN_ASSERT(blend.b >= 0 && blend.b <= 1.0f);
|
||||||
|
|
||||||
|
// TODO(doyle): Color modulation does not work!!! By supplying
|
||||||
|
// colors [0->1] it'll reduce some of the coverage of a channel
|
||||||
|
// and once alpha blending is applied that reduced coverage will
|
||||||
|
// blend with the background and cause the bitmap to go
|
||||||
|
// transparent when it shouldn't.
|
||||||
|
blend.a *= color.a;
|
||||||
|
blend.r *= color.r;
|
||||||
|
blend.g *= color.g;
|
||||||
|
blend.b *= color.b;
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
blend.a = DqnMath_Clampf(blend.a, 0.0f, 1.0f);
|
||||||
|
blend.r = DqnMath_Clampf(blend.r, 0.0f, 1.0f);
|
||||||
|
blend.g = DqnMath_Clampf(blend.g, 0.0f, 1.0f);
|
||||||
|
blend.b = DqnMath_Clampf(blend.b, 0.0f, 1.0f);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
SetPixel(renderBuffer, bufferX, bufferY, blend, ColorSpace_Linear);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (DTR_DEBUG)
|
if (DTR_DEBUG_RENDER)
|
||||||
{
|
{
|
||||||
// Draw Bounding box
|
// Draw Bounding box
|
||||||
{
|
{
|
||||||
@ -901,20 +929,23 @@ void DTRRender_Bitmap(PlatformRenderBuffer *const renderBuffer,
|
|||||||
}
|
}
|
||||||
|
|
||||||
void DTRRender_Clear(PlatformRenderBuffer *const renderBuffer,
|
void DTRRender_Clear(PlatformRenderBuffer *const renderBuffer,
|
||||||
const DqnV3 color)
|
DqnV3 color)
|
||||||
{
|
{
|
||||||
if (!renderBuffer) return;
|
if (!renderBuffer) return;
|
||||||
|
|
||||||
DQN_ASSERT(color.r >= 0.0f && color.r <= 1.0f);
|
DQN_ASSERT(color.r >= 0.0f && color.r <= 1.0f);
|
||||||
DQN_ASSERT(color.g >= 0.0f && color.g <= 1.0f);
|
DQN_ASSERT(color.g >= 0.0f && color.g <= 1.0f);
|
||||||
DQN_ASSERT(color.b >= 0.0f && color.b <= 1.0f);
|
DQN_ASSERT(color.b >= 0.0f && color.b <= 1.0f);
|
||||||
|
color *= 255.0f;
|
||||||
|
|
||||||
u32 *const bitmapPtr = (u32 *)renderBuffer->memory;
|
u32 *const bitmapPtr = (u32 *)renderBuffer->memory;
|
||||||
for (i32 y = 0; y < renderBuffer->height; y++)
|
for (i32 y = 0; y < renderBuffer->height; y++)
|
||||||
{
|
{
|
||||||
for (i32 x = 0; x < renderBuffer->width; x++)
|
for (i32 x = 0; x < renderBuffer->width; x++)
|
||||||
{
|
{
|
||||||
u32 pixel = ((i32)color.r << 16) | ((i32)color.g << 8) |
|
u32 pixel = ((i32)0 << 24) |
|
||||||
|
((i32)color.r << 16) |
|
||||||
|
((i32)color.g << 8) |
|
||||||
((i32)color.b << 0);
|
((i32)color.b << 0);
|
||||||
bitmapPtr[x + (y * renderBuffer->width)] = pixel;
|
bitmapPtr[x + (y * renderBuffer->width)] = pixel;
|
||||||
}
|
}
|
||||||
|
@ -3,9 +3,14 @@
|
|||||||
|
|
||||||
#include "dqn.h"
|
#include "dqn.h"
|
||||||
|
|
||||||
|
#define DTRRENDER_INV_255 0.00392156862f;
|
||||||
|
|
||||||
typedef struct PlatformRenderBuffer PlatformRenderBuffer;
|
typedef struct PlatformRenderBuffer PlatformRenderBuffer;
|
||||||
typedef struct DTRBitmap DTRBitmap;
|
typedef struct DTRBitmap DTRBitmap;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Utility
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
typedef struct DTRRenderTransform
|
typedef struct DTRRenderTransform
|
||||||
{
|
{
|
||||||
f32 rotation = 0; // Rotation in degrees
|
f32 rotation = 0; // Rotation in degrees
|
||||||
@ -27,23 +32,32 @@ inline DTRRenderTransform DTRRender_DefaultTriangleTransform()
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE(doyle): 1 & 255 suffix represent the range the color is being sent in.
|
// NOTE(doyle): 1 suffix represents the range the color is being sent in which
|
||||||
// 255 means we expect that all the colors are from [0-255] and 1 means all the
|
// means all the colors should be in the range of [0-1]
|
||||||
// colors should be in the range of [0-1]
|
inline f32 DTRRender_SRGB1ToLinearSpacef (f32 val);
|
||||||
inline DqnV4 DTRRender_PreMultiplyAlpha1 (const DqnV4 color);
|
inline DqnV4 DTRRender_SRGB1ToLinearSpaceV4(DqnV4 color);
|
||||||
inline DqnV4 DTRRender_PreMultiplyAlpha255(const DqnV4 color);
|
inline f32 DTRRender_LinearToSRGB1Spacef (f32 val);
|
||||||
|
inline DqnV4 DTRRender_LinearToSRGB1SpaceV4(DqnV4 color);
|
||||||
|
|
||||||
// NOTE: All specified colors should be in the range of [0->1], rgba, respectively.
|
// Takes SRGB in [0->1], converts to linear space, premultiplies alpha and returns
|
||||||
|
// color back in SRGB space.
|
||||||
|
inline DqnV4 DTRRender_PreMultiplyAlphaSRGB1WithLinearConversion(DqnV4 color);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Rendering
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// 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.
|
// 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,
|
void DTRRender_Text (PlatformRenderBuffer *const renderBuffer, const DTRFont font, DqnV2 pos, const char *const text, DqnV4 color = DqnV4_1f(1), i32 len = -1);
|
||||||
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_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_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_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());
|
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, const DqnV3 color);
|
|
||||||
|
void DTRRender_Clear (PlatformRenderBuffer *const renderBuffer, DqnV3 color);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
Loading…
Reference in New Issue
Block a user