From 1d0e9b8a0761a8bfc95c2a5e2777183f5da3a394 Mon Sep 17 00:00:00 2001 From: Doyle Thai Date: Fri, 19 May 2017 02:21:44 +1000 Subject: [PATCH] All render paths go through srgb->linear pipeline --- src/DTRenderer.cpp | 43 ++++++---- src/DTRendererDebug.cpp | 12 ++- src/DTRendererDebug.h | 4 + src/DTRendererRender.cpp | 175 +++++++++++++++++++++++---------------- src/DTRendererRender.h | 44 ++++++---- 5 files changed, 173 insertions(+), 105 deletions(-) diff --git a/src/DTRenderer.cpp b/src/DTRenderer.cpp index 9d51474..47cc653 100644 --- a/src/DTRenderer.cpp +++ b/src/DTRenderer.cpp @@ -91,13 +91,16 @@ FILE_SCOPE bool BitmapFontCreate(const PlatformAPI api, { // 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); + u32 index = x + (y * bitmapDim.w); + f32 alpha = (f32)(loadedFont.bitmap[index]) / 255.0f; + f32 color = alpha; - 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.g = (f32)((pixel >> 8) & 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) | ((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, 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; 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(); 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); + // 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); - 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(); 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); 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 CompAssignment(renderBuffer, input, memory); #endif diff --git a/src/DTRendererDebug.cpp b/src/DTRendererDebug.cpp index dddc0ec..9632401 100644 --- a/src/DTRendererDebug.cpp +++ b/src/DTRendererDebug.cpp @@ -22,7 +22,8 @@ void DTRDebug_PushText(const char *const formatStr, ...) } 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; } } @@ -57,7 +58,7 @@ FILE_SCOPE void PushMemBufferText(const char *const name, totalUsed, totalSize); DTRRender_Text(globalDebug.renderBuffer, *globalDebug.font, - globalDebug.displayP, str); + globalDebug.displayP, str, globalDebug.displayColor); globalDebug.displayP.y += globalDebug.displayYOffset; } } @@ -72,6 +73,7 @@ void DTRDebug_Update(DTRState *const state, debug->renderBuffer = renderBuffer; debug->font = &state->font; + debug->displayColor = DqnV4_4f(1, 1, 1, 1); if (debug->font->bitmap && debug->renderBuffer) { debug->displayYOffset = -(i32)(state->font.sizeInPt + 0.5f); @@ -85,7 +87,8 @@ void DTRDebug_Update(DTRState *const state, { char str[128] = {}; 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; } @@ -93,7 +96,8 @@ void DTRDebug_Update(DTRState *const state, { char str[128] = {}; 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; } diff --git a/src/DTRendererDebug.h b/src/DTRendererDebug.h index d42176f..f681ae2 100644 --- a/src/DTRendererDebug.h +++ b/src/DTRendererDebug.h @@ -4,6 +4,9 @@ #include "dqn.h" #define DTR_DEBUG 1 +#ifdef DTR_DEBUG + #define DTR_DEBUG_RENDER 0 +#endif typedef struct PlatformRenderBuffer PlatformRenderBuffer; typedef struct DTRFont DTRFont; @@ -16,6 +19,7 @@ typedef struct DTRDebug DTRFont *font; PlatformRenderBuffer *renderBuffer; + DqnV4 displayColor; DqnV2 displayP; i32 displayYOffset; diff --git a/src/DTRendererRender.cpp b/src/DTRendererRender.cpp index 90b8723..c72e115 100644 --- a/src/DTRendererRender.cpp +++ b/src/DTRendererRender.cpp @@ -12,9 +12,9 @@ #include "external/stb_image_write.h" #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; result.r = color.r * color.a; @@ -29,10 +29,11 @@ inline DqnV4 DTRRender_PreMultiplyAlpha1(const DqnV4 color) return result; } -inline DqnV4 DTRRender_PreMultiplyAlpha255(const DqnV4 color) +FILE_SCOPE inline DqnV4 PreMultiplyAlpha255(const DqnV4 color) { DqnV4 result; f32 normA = color.a * DTRRENDER_INV_255; + DQN_ASSERT(normA >= 0.0f && normA <= 1.0f + COLOR_EPSILON); result.r = color.r * normA; result.g = color.g * normA; result.b = color.b * normA; @@ -41,56 +42,68 @@ inline DqnV4 DTRRender_PreMultiplyAlpha255(const DqnV4 color) return result; } -enum ColourSpace +enum ColorSpace { - ColourSpace_SRGB, - ColourSpace_Linear, + ColorSpace_SRGB, + ColorSpace_Linear, }; // NOTE(doyle): We are approximating the actual gamma correct value 2.2 to 2 as // 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); return result; } -FILE_SCOPE inline DqnV4 SRGB1ToLinearSpaceV4(DqnV4 color) +inline DqnV4 DTRRender_SRGB1ToLinearSpaceV4(DqnV4 color) { DqnV4 result = {}; - result.r = SRGB1ToLinearSpacef(color.r); - result.g = SRGB1ToLinearSpacef(color.g); - result.b = SRGB1ToLinearSpacef(color.b); - result.a = SRGB1ToLinearSpacef(color.a); + result.r = DTRRender_SRGB1ToLinearSpacef(color.r); + result.g = DTRRender_SRGB1ToLinearSpacef(color.g); + result.b = DTRRender_SRGB1ToLinearSpacef(color.b); + result.a = color.a; 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; f32 result = DqnMath_Sqrtf(val); return result; } -FILE_SCOPE inline DqnV4 LinearToSRGB1SpaceV4(DqnV4 color) +inline DqnV4 DTRRender_LinearToSRGB1SpaceV4(DqnV4 color) { DqnV4 result = {}; - result.r = LinearToSRGB1Spacef(color.r); - result.g = LinearToSRGB1Spacef(color.g); - result.b = LinearToSRGB1Spacef(color.b); - result.a = LinearToSRGB1Spacef(color.a); + result.r = DTRRender_LinearToSRGB1Spacef(color.r); + result.g = DTRRender_LinearToSRGB1Spacef(color.g); + result.b = DTRRender_LinearToSRGB1Spacef(color.b); + 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; } // IMPORTANT(doyle): Color is expected to be premultiplied already 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 (x <= 0 || x > (renderBuffer->width - 1)) return; - if (y <= 0 || y > (renderBuffer->height - 1)) return; + if (x < 0 || x > (renderBuffer->width - 1)) return; + if (y < 0 || y > (renderBuffer->height - 1)) return; u32 *const bitmapPtr = (u32 *)renderBuffer->memory; 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 // overwriting/keeping the state of the pixel so we can save cycles by skipping. #if 1 - bool needGammaFix = (color.a > 0.0f || color.a < 1.0f) && (colourSpace == ColourSpace_SRGB); - if (needGammaFix) - { - color = SRGB1ToLinearSpaceV4(color); - } + bool needGammaFix = (color.a > 0.0f || color.a < 1.0f + COLOR_EPSILON) && (colorSpace == ColorSpace_SRGB); + if (needGammaFix) color = DTRRender_SRGB1ToLinearSpaceV4(color); #endif 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 srcB = (f32)((src >> 0) & 0xFF) * DTRRENDER_INV_255; - srcR = SRGB1ToLinearSpacef(srcR); - srcG = SRGB1ToLinearSpacef(srcG); - srcB = SRGB1ToLinearSpacef(srcB); + srcR = DTRRender_SRGB1ToLinearSpacef(srcR); + srcG = DTRRender_SRGB1ToLinearSpacef(srcG); + srcB = DTRRender_SRGB1ToLinearSpacef(srcB); // NOTE(doyle): AlphaBlend equations is (alpha * new) + (1 - alpha) * src. // 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 destB = color.b + (invANorm * srcB); -#if 1 - if (needGammaFix || colourSpace == ColourSpace_Linear) - { - destR = LinearToSRGB1Spacef(destR); - destG = LinearToSRGB1Spacef(destG); - destB = LinearToSRGB1Spacef(destB); - } -#endif - - destR *= 255.0f; - destG *= 255.0f; - destB *= 255.0f; + destR = DTRRender_LinearToSRGB1Spacef(destR) * 255.0f; + destG = DTRRender_LinearToSRGB1Spacef(destG) * 255.0f; + destB = DTRRender_LinearToSRGB1Spacef(destB) * 255.0f; DQN_ASSERT(destR >= 0); DQN_ASSERT(destG >= 0); DQN_ASSERT(destB >= 0); - const f32 COLOR_EPSILON = 0.1f; if (destR > 255.0f) { DQN_ASSERT((destR - 255.0f) < COLOR_EPSILON); @@ -176,7 +176,8 @@ void DTRRender_Text(PlatformRenderBuffer *const renderBuffer, if (len == -1) len = Dqn_strlen(text); i32 index = 0; - color = DTRRender_PreMultiplyAlpha1(color); + color = DTRRender_SRGB1ToLinearSpaceV4(color); + color = PreMultiplyAlpha1(color); while (index < len) { if (text[index] < font.codepointRange.min && @@ -228,7 +229,7 @@ void DTRRender_Text(PlatformRenderBuffer *const renderBuffer, u8 srcA = fontPtr[x + (yOffset * fontPitch)]; if (srcA == 0) continue; - f32 srcANorm = srcA / 255.0f; + f32 srcANorm = srcA / 255.0f; DqnV4 resultColor = {}; resultColor.r = color.r * srcANorm; resultColor.g = color.g * srcANorm; @@ -237,7 +238,7 @@ void DTRRender_Text(PlatformRenderBuffer *const renderBuffer, i32 actualX = (i32)(screenRect.min.x + x); 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) { if (!renderBuffer) return; - color = DTRRender_PreMultiplyAlpha1(color); + color = DTRRender_SRGB1ToLinearSpaceV4(color); + color = PreMultiplyAlpha1(color); bool yTallerThanX = false; 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++) { newX = a.x + iterateX; - SetPixel(renderBuffer, *plotX, *plotY, color); + SetPixel(renderBuffer, *plotX, *plotY, color, ColorSpace_Linear); distAccumulator += distFromPixelOrigin; if (distAccumulator > run) @@ -384,7 +386,8 @@ void DTRRender_Rectangle(PlatformRenderBuffer *const renderBuffer, DqnV2 min, Dq //////////////////////////////////////////////////////////////////////////// // Transform vertexes //////////////////////////////////////////////////////////////////////////// - color = DTRRender_PreMultiplyAlpha1(color); + color = DTRRender_SRGB1ToLinearSpaceV4(color); + color = PreMultiplyAlpha1(color); RectPoints rectPoints = TransformRectPoints(min, max, transform); 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++) { 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 //////////////////////////////////////////////////////////////////////////// - if (DTR_DEBUG) + if (DTR_DEBUG_RENDER) { // Draw Bounding box { @@ -491,7 +494,8 @@ void DTRRender_Triangle(PlatformRenderBuffer *const renderBuffer, DqnV2 p1, DqnV p2 = pList[1]; p3 = pList[2]; - color = DTRRender_PreMultiplyAlpha1(color); + color = DTRRender_SRGB1ToLinearSpaceV4(color); + color = PreMultiplyAlpha1(color); //////////////////////////////////////////////////////////////////////////// // Calculate Bounding Box @@ -647,7 +651,7 @@ void DTRRender_Triangle(PlatformRenderBuffer *const renderBuffer, DqnV2 p1, DqnV { 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; @@ -663,7 +667,7 @@ void DTRRender_Triangle(PlatformRenderBuffer *const renderBuffer, DqnV2 p1, DqnV //////////////////////////////////////////////////////////////////////////// // Debug //////////////////////////////////////////////////////////////////////////// - if (DTR_DEBUG) + if (DTR_DEBUG_RENDER) { // Draw Bounding box { @@ -698,9 +702,13 @@ void DTRRender_Triangle(PlatformRenderBuffer *const renderBuffer, DqnV2 p1, DqnV void DTRRender_Bitmap(PlatformRenderBuffer *const renderBuffer, DTRBitmap *const bitmap, DqnV2 pos, - const DTRRenderTransform transform) + const DTRRenderTransform transform, DqnV4 color) { 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 @@ -717,6 +725,8 @@ void DTRRender_Bitmap(PlatformRenderBuffer *const renderBuffer, min = bounds.min; max = bounds.max; + color = DTRRender_SRGB1ToLinearSpaceV4(color); + color = PreMultiplyAlpha1(color); //////////////////////////////////////////////////////////////////////////// // Clip drawing space //////////////////////////////////////////////////////////////////////////// @@ -828,10 +838,10 @@ void DTRRender_Bitmap(PlatformRenderBuffer *const renderBuffer, color3 *= DTRRENDER_INV_255; color4 *= DTRRENDER_INV_255; - color1 = SRGB1ToLinearSpaceV4(color1); - color2 = SRGB1ToLinearSpaceV4(color2); - color3 = SRGB1ToLinearSpaceV4(color3); - color4 = SRGB1ToLinearSpaceV4(color4); + color1 = DTRRender_SRGB1ToLinearSpaceV4(color1); + color2 = DTRRender_SRGB1ToLinearSpaceV4(color2); + color3 = DTRRender_SRGB1ToLinearSpaceV4(color3); + color4 = DTRRender_SRGB1ToLinearSpaceV4(color4); DqnV4 color12; 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.r = DqnMath_Lerp(color3.r, texelFractionalX, color4.r); - DqnV4 color; - color.a = DqnMath_Lerp(color12.a, texelFractionalY, color34.a); - color.b = DqnMath_Lerp(color12.b, texelFractionalY, color34.b); - color.g = DqnMath_Lerp(color12.g, texelFractionalY, color34.g); - color.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); + DqnV4 blend; + blend.a = DqnMath_Lerp(color12.a, texelFractionalY, color34.a); + blend.b = DqnMath_Lerp(color12.b, texelFractionalY, color34.b); + blend.g = DqnMath_Lerp(color12.g, texelFractionalY, color34.g); + blend.r = DqnMath_Lerp(color12.r, texelFractionalY, color34.r); - 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 { @@ -901,20 +929,23 @@ void DTRRender_Bitmap(PlatformRenderBuffer *const renderBuffer, } void DTRRender_Clear(PlatformRenderBuffer *const renderBuffer, - const DqnV3 color) + DqnV3 color) { if (!renderBuffer) return; DQN_ASSERT(color.r >= 0.0f && color.r <= 1.0f); DQN_ASSERT(color.g >= 0.0f && color.g <= 1.0f); DQN_ASSERT(color.b >= 0.0f && color.b <= 1.0f); + color *= 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) | + u32 pixel = ((i32)0 << 24) | + ((i32)color.r << 16) | + ((i32)color.g << 8) | ((i32)color.b << 0); bitmapPtr[x + (y * renderBuffer->width)] = pixel; } diff --git a/src/DTRendererRender.h b/src/DTRendererRender.h index b0d13b2..6b6b01e 100644 --- a/src/DTRendererRender.h +++ b/src/DTRendererRender.h @@ -3,9 +3,14 @@ #include "dqn.h" +#define DTRRENDER_INV_255 0.00392156862f; + typedef struct PlatformRenderBuffer PlatformRenderBuffer; typedef struct DTRBitmap DTRBitmap; +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Utility +//////////////////////////////////////////////////////////////////////////////////////////////////// typedef struct DTRRenderTransform { f32 rotation = 0; // Rotation in degrees @@ -27,23 +32,32 @@ inline DTRRenderTransform DTRRender_DefaultTriangleTransform() return result; } -// NOTE(doyle): 1 & 255 suffix represent the range the color is being sent in. -// 255 means we expect that all the colors are from [0-255] and 1 means all the -// colors should be in the range of [0-1] -inline DqnV4 DTRRender_PreMultiplyAlpha1 (const DqnV4 color); -inline DqnV4 DTRRender_PreMultiplyAlpha255(const DqnV4 color); +// NOTE(doyle): 1 suffix represents the range the color is being sent in which +// means all the colors should be in the range of [0-1] +inline f32 DTRRender_SRGB1ToLinearSpacef (f32 val); +inline DqnV4 DTRRender_SRGB1ToLinearSpaceV4(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. -void DTRRender_Text (PlatformRenderBuffer *const renderBuffer, const DTRFont font, DqnV2 pos, - const char *const text, DqnV4 color = DqnV4_1f(1), i32 len = -1); +void DTRRender_Text (PlatformRenderBuffer *const renderBuffer, const DTRFont font, DqnV2 pos, 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_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_Bitmap (PlatformRenderBuffer *const renderBuffer, DTRBitmap *const bitmap, DqnV2 pos, - const DTRRenderTransform transform = DTRRender_DefaultTransform()); -void DTRRender_Clear (PlatformRenderBuffer *const renderBuffer, const DqnV3 color); + +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_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, DqnV3 color); #endif