Add proper bitmap rotation and 1:1 texture mapping

This commit is contained in:
Doyle Thai 2017-05-17 16:18:03 +10:00
parent ce69de7aeb
commit ceb37ec4b0
3 changed files with 101 additions and 24 deletions

View File

@ -73,10 +73,12 @@ FILE_SCOPE bool BitmapFontCreate(const PlatformAPI api,
STBTT_POINT_SIZE(sizeInPt), (i32)codepointRange.min,
numCodepoints, loadedFont.atlas);
stbtt_PackEnd(&fontPackContext);
DqnMemBuffer_EndTempRegion(tmpMemRegion);
}
else
{
DQN_ASSERT(DQN_INVALID_CODE_PATH);
DqnMemBuffer_EndTempRegion(tmpMemRegion);
return false;
}

View File

@ -220,9 +220,21 @@ void DTRRender_Line(PlatformRenderBuffer *const renderBuffer, DqnV2i a,
}
}
// NOTE: This information is only particularly relevant for bitmaps so that
// after transformation, we can still programatically find the original
// coordinate system of the bitmap for texture mapping.
enum RectPointsIndex
{
RectPointsIndex_Basis = 0,
RectPointsIndex_XAxis,
RectPointsIndex_Point,
RectPointsIndex_YAxis,
RectPointsIndex_Count
};
typedef struct RectPoints
{
DqnV2 pList[4];
DqnV2 pList[RectPointsIndex_Count];
} RectPoints;
// Apply rotation and scale around the anchored point. This is a helper function that expands the
@ -236,10 +248,10 @@ FILE_SCOPE RectPoints TransformRectPoints(DqnV2 min, DqnV2 max, DqnV2 anchor, Dq
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;
result.pList[RectPointsIndex_Basis] = min - origin;
result.pList[RectPointsIndex_XAxis] = DqnV2_2f(max.x, min.y) - origin;
result.pList[RectPointsIndex_Point] = max - origin;
result.pList[RectPointsIndex_YAxis] = DqnV2_2f(min.x, max.y) - origin;
TransformPoints(origin, result.pList, DQN_ARRAY_COUNT(result.pList), scale, rotation);
@ -600,7 +612,7 @@ void DTRRender_Bitmap(PlatformRenderBuffer *const renderBuffer,
DTRDebug_PushText("OldRect: (%5.2f, %5.2f), (%5.2f, %5.2f)", min.x, min.y, max.x, max.y);
RectPoints rectPoints = TransformRectPoints(min, max, transform.anchor, transform.scale, transform.rotation);
DqnV2 *const pList = &rectPoints.pList[0];
const DqnV2 *const pList = &rectPoints.pList[0];
const i32 RECT_PLIST_SIZE = DQN_ARRAY_COUNT(rectPoints.pList);
DqnRect bounds = GetBoundingBox(pList, RECT_PLIST_SIZE);
@ -616,32 +628,83 @@ void DTRRender_Bitmap(PlatformRenderBuffer *const renderBuffer,
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;
u32 *const pixelPtr = (u32 *)bitmap->memory;
////////////////////////////////////////////////////////////////////////////
// Setup Texture Mapping
////////////////////////////////////////////////////////////////////////////
const DqnV2 rectBasis = pList[RectPointsIndex_Basis];
const DqnV2 xAxisRelToBasis = pList[RectPointsIndex_XAxis] - rectBasis;
const DqnV2 yAxisRelToBasis = pList[RectPointsIndex_YAxis] - rectBasis;
const f32 invXAxisLenSq = 1 / DqnV2_LengthSquared(DqnV2_1f(0), xAxisRelToBasis);
const f32 invYAxisLenSq = 1 / DqnV2_LengthSquared(DqnV2_1f(0), yAxisRelToBasis);
for (i32 y = 0; y < (i32)clippedSize.h; y++)
{
u8 *const srcRow = bitmap->memory + ((texelY + y) * pitch);
i32 bufferY = (i32)clippedDrawRect.min.y + y;
const i32 bufferY = (i32)clippedDrawRect.min.y + y;
for (i32 x = 0; x < (i32)clippedSize.w; x++)
{
u32 *pixelPtr = (u32 *)srcRow;
u32 pixel = 0; // pixelPtr[texelX + x];
i32 bufferX = (i32)clippedDrawRect.min.x + x;
const i32 bufferX = (i32)clippedDrawRect.min.x + x;
DqnV4 color = {};
color.a = (f32)(pixel >> 24);
color.b = (f32)((pixel >> 16) & 0xFF);
color.g = (f32)((pixel >> 8) & 0xFF);
color.r = (f32)((pixel >> 0) & 0xFF);
bool bufXYIsInside = true;
for (i32 pIndex = 0; pIndex < RECT_PLIST_SIZE; pIndex++)
{
DqnV2 origin = pList[pIndex];
DqnV2 axis = pList[(pIndex + 1) % RECT_PLIST_SIZE] - origin;
DqnV2 testP = DqnV2_2i(bufferX, bufferY) - origin;
SetPixel(renderBuffer, bufferX, bufferY, color);
f32 dot = DqnV2_Dot(testP, axis);
if (dot < 0)
{
bufXYIsInside = false;
break;
}
}
if (bufXYIsInside)
{
#if 0
u32 *pixelPtr = (u32 *)srcRow;
u32 pixel = 0xFFFFFFFF; // pixelPtr[texelX + x];
DqnV4 color = {};
color.a = (f32)(pixel >> 24);
color.b = (f32)((pixel >> 16) & 0xFF);
color.g = (f32)((pixel >> 8) & 0xFF);
color.r = (f32)((pixel >> 0) & 0xFF);
SetPixel(renderBuffer, bufferX, bufferY, color);
#else
DqnV2 bufPRelToBasis = DqnV2_2i(bufferX, bufferY) - rectBasis;
f32 u = DqnV2_Dot(bufPRelToBasis, xAxisRelToBasis) * invXAxisLenSq;
f32 v = DqnV2_Dot(bufPRelToBasis, yAxisRelToBasis) * invYAxisLenSq;
u = DqnMath_Clampf(u, 0.0f, 1.0f);
v = DqnMath_Clampf(v, 0.0f, 1.0f);
i32 texelX = (i32)(u * (f32)(bitmap->dim.w - 1));
i32 texelY = (i32)(v * (f32)(bitmap->dim.h - 1));
DQN_ASSERT(texelX >= 0 && texelX < bitmap->dim.w);
DQN_ASSERT(texelX >= 0 && texelY < bitmap->dim.h);
#if 1
u32 pixel = pixelPtr[texelX + (texelY * bitmap->dim.w)];
DqnV4 color = {};
color.a = (f32)(pixel >> 24);
color.b = (f32)((pixel >> 16) & 0xFF);
color.g = (f32)((pixel >> 8) & 0xFF);
color.r = (f32)((pixel >> 0) & 0xFF);
SetPixel(renderBuffer, bufferX, bufferY, color);
#endif
int yo = 5;
#endif
}
}
}

View File

@ -421,6 +421,7 @@ bool DqnArray_RemoveStable(DqnArray<T> *array, u64 index)
////////////////////////////////////////////////////////////////////////////////
DQN_FILE_SCOPE f32 DqnMath_Lerp(f32 a, f32 t, f32 b);
DQN_FILE_SCOPE f32 DqnMath_Sqrtf(f32 a);
DQN_FILE_SCOPE f32 DqnMath_Clampf(f32 val, f32 min, f32 max);
////////////////////////////////////////////////////////////////////////////////
// Vec2
@ -1711,6 +1712,13 @@ DQN_FILE_SCOPE f32 DqnMath_Sqrtf(f32 a)
return result;
}
DQN_FILE_SCOPE f32 DqnMath_Clampf(f32 val, f32 min, f32 max)
{
if (val < min) return min;
if (val > max) return max;
return val;
}
////////////////////////////////////////////////////////////////////////////////
// Vec2
////////////////////////////////////////////////////////////////////////////////
@ -1826,13 +1834,17 @@ DQN_FILE_SCOPE f32 DqnV2_LengthSquared(DqnV2 a, DqnV2 b)
DQN_FILE_SCOPE f32 DqnV2_Length(DqnV2 a, DqnV2 b)
{
f32 lengthSq = DqnV2_LengthSquared(a, b);
f32 result = DqnMath_Sqrtf(lengthSq);
if (lengthSq == 0) return 0;
f32 result = DqnMath_Sqrtf(lengthSq);
return result;
}
DQN_FILE_SCOPE DqnV2 DqnV2_Normalise(DqnV2 a)
{
f32 magnitude = DqnV2_Length(DqnV2_2f(0, 0), a);
if (magnitude == 0) return DqnV2_1f(0.0f);
DqnV2 result = DqnV2_2f(a.x, a.y);
result = DqnV2_Scalef(a, 1 / magnitude);
return result;