rendering improvements
This commit is contained in:
parent
789bb307d5
commit
7f46ac13fa
14 changed files with 296 additions and 179 deletions
|
|
@ -29,8 +29,8 @@ import :Types;
|
|||
import :Window;
|
||||
|
||||
export namespace Crafter {
|
||||
template<bool Scaling, bool Owning, bool Rotating> requires ((!Rotating || Scaling) && (!Owning || Scaling))
|
||||
struct RenderingElement2D : RenderingElement2DBase, ScalingBase<Scaling, Owning>, RotatingBase<Rotating> {
|
||||
template<bool Scaling, bool Owning, bool Rotating, std::uint8_t Alignment = 0> requires ((!Rotating || Scaling) && (!Owning || Scaling))
|
||||
struct RenderingElement2D : RenderingElement2DBase, ScalingBase<Scaling, Owning, Alignment>, RotatingBase<Rotating> {
|
||||
RenderingElement2D() = default;
|
||||
RenderingElement2D(Anchor2D anchor, OpaqueType opaque) : RenderingElement2DBase(anchor, opaque) {
|
||||
|
||||
|
|
@ -38,22 +38,22 @@ export namespace Crafter {
|
|||
RenderingElement2D(Anchor2D anchor, OpaqueType opaque, std::uint32_t rotation) requires(Rotating) : RenderingElement2DBase(anchor, opaque), RotatingBase<Rotating>(rotation) {
|
||||
|
||||
}
|
||||
RenderingElement2D(Anchor2D anchor, OpaqueType opaque, std::uint32_t bufferWidth, std::uint32_t bufferHeight, Vector<std::uint8_t, 4>* scalingBuffer) requires(Scaling && !Owning) : RenderingElement2DBase(anchor, opaque), ScalingBase<Scaling, Owning>(bufferWidth, bufferHeight, scalingBuffer) {
|
||||
RenderingElement2D(Anchor2D anchor, OpaqueType opaque, std::uint32_t bufferWidth, std::uint32_t bufferHeight, Vector<std::uint8_t, 4, Alignment>* scalingBuffer) requires(Scaling && !Owning) : RenderingElement2DBase(anchor, opaque), ScalingBase<Scaling, Owning, Alignment>(bufferWidth, bufferHeight, scalingBuffer) {
|
||||
|
||||
}
|
||||
RenderingElement2D(Anchor2D anchor, OpaqueType opaque, std::uint32_t bufferWidth, std::uint32_t bufferHeight, Vector<std::uint8_t, 4>* scalingBuffer, std::uint32_t rotation) requires(Scaling && !Owning && Rotating) : RenderingElement2DBase(anchor, opaque), ScalingBase<Scaling, Owning>(bufferWidth, bufferHeight, scalingBuffer), RotatingBase<Rotating>(rotation) {
|
||||
RenderingElement2D(Anchor2D anchor, OpaqueType opaque, std::uint32_t bufferWidth, std::uint32_t bufferHeight, Vector<std::uint8_t, 4, Alignment>* scalingBuffer, std::uint32_t rotation) requires(Scaling && !Owning && Rotating) : RenderingElement2DBase(anchor, opaque), ScalingBase<Scaling, Owning, Alignment>(bufferWidth, bufferHeight, scalingBuffer), RotatingBase<Rotating>(rotation) {
|
||||
|
||||
}
|
||||
RenderingElement2D(Anchor2D anchor, OpaqueType opaque, std::uint32_t bufferWidth, std::uint32_t bufferHeight) requires(Owning) : RenderingElement2DBase(anchor, opaque), ScalingBase<Scaling, Owning>(bufferWidth, bufferHeight) {
|
||||
RenderingElement2D(Anchor2D anchor, OpaqueType opaque, std::uint32_t bufferWidth, std::uint32_t bufferHeight) requires(Owning) : RenderingElement2DBase(anchor, opaque), ScalingBase<Scaling, Owning, Alignment>(bufferWidth, bufferHeight) {
|
||||
|
||||
}
|
||||
RenderingElement2D(Anchor2D anchor, OpaqueType opaque, std::uint32_t bufferWidth, std::uint32_t bufferHeight, std::uint32_t rotation) requires(Owning && Rotating) : RenderingElement2DBase(anchor, opaque), ScalingBase<Scaling, Owning>(bufferWidth, bufferHeight) , RotatingBase<Rotating>(rotation) {
|
||||
RenderingElement2D(Anchor2D anchor, OpaqueType opaque, std::uint32_t bufferWidth, std::uint32_t bufferHeight, std::uint32_t rotation) requires(Owning && Rotating) : RenderingElement2DBase(anchor, opaque), ScalingBase<Scaling, Owning, Alignment>(bufferWidth, bufferHeight) , RotatingBase<Rotating>(rotation) {
|
||||
|
||||
}
|
||||
RenderingElement2D(Anchor2D anchor, TextureAsset<Vector<std::uint8_t, 4>> texture) requires(!Owning && Scaling) : RenderingElement2DBase(anchor, texture.opaque), ScalingBase<Scaling, Owning>(texture.sizeX, texture.sizeY, texture.pixels) {
|
||||
RenderingElement2D(Anchor2D anchor, TextureAsset<Vector<std::uint8_t, 4, Alignment>>& texture) requires(!Owning && Scaling) : RenderingElement2DBase(anchor, texture.opaque), ScalingBase<Scaling, Owning, Alignment>(texture.pixels.data(), texture.sizeX, texture.sizeY) {
|
||||
|
||||
}
|
||||
RenderingElement2D(Anchor2D anchor, TextureAsset<Vector<std::uint8_t, 4>> texture, std::uint32_t rotation) requires(!Owning && Scaling && Rotating) : RenderingElement2DBase(anchor, texture.opaque), ScalingBase<Scaling, Owning>(texture.sizeX, texture.sizeY, texture.pixels), RotatingBase<Rotating>(rotation) {
|
||||
RenderingElement2D(Anchor2D anchor, TextureAsset<Vector<std::uint8_t, 4, Alignment>>& texture, std::uint32_t rotation) requires(!Owning && Scaling && Rotating) : RenderingElement2DBase(anchor, texture.opaque), ScalingBase<Scaling, Owning, Alignment>(texture.pixels.data(), texture.sizeX, texture.sizeY), RotatingBase<Rotating>(rotation) {
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -62,10 +62,10 @@ export namespace Crafter {
|
|||
|
||||
void ScaleNearestNeighbor() requires(Scaling) {
|
||||
for (std::uint32_t y = 0; y < scaled.size.y; y++) {
|
||||
std::uint32_t srcY = y * ScalingBase<true, Owning>::bufferHeight / scaled.size.y;
|
||||
std::uint32_t srcY = y * ScalingBase<true, Owning, Alignment>::bufferHeight / scaled.size.y;
|
||||
for (std::uint32_t x = 0; x < scaled.size.x; x++) {
|
||||
std::uint32_t srcX = x * ScalingBase<true, Owning>::bufferWidth / scaled.size.x;
|
||||
buffer[y * scaled.size.x + x] = ScalingBase<true, Owning>::scalingBuffer[srcY * ScalingBase<true, Owning>::bufferWidth + srcX];
|
||||
std::uint32_t srcX = x * ScalingBase<true, Owning, Alignment>::bufferWidth / scaled.size.x;
|
||||
buffer[y * scaled.size.x + x] = ScalingBase<true, Owning, Alignment>::scalingBuffer[srcY * ScalingBase<true, Owning, Alignment>::bufferWidth + srcX];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -97,15 +97,15 @@ export namespace Crafter {
|
|||
const float dstCy = (static_cast<float>(scaled.size.y) - 1.0) * 0.5;
|
||||
|
||||
// Source center
|
||||
const float srcCx = (static_cast<float>(ScalingBase<true, Owning>::bufferWidth) - 1.0) * 0.5;
|
||||
const float srcCy = (static_cast<float>(ScalingBase<true, Owning>::bufferHeight) - 1.0) * 0.5;
|
||||
const float srcCx = (static_cast<float>(ScalingBase<true, Owning, Alignment>::bufferWidth) - 1.0) * 0.5;
|
||||
const float srcCy = (static_cast<float>(ScalingBase<true, Owning, Alignment>::bufferHeight) - 1.0) * 0.5;
|
||||
|
||||
const float c = std::cos(RotatingBase<true>::rotation);
|
||||
const float s = std::sin(RotatingBase<true>::rotation);
|
||||
|
||||
// Scale factors (destination → source)
|
||||
const float scaleX = static_cast<float>(ScalingBase<true, Owning>::bufferWidth) / dstWidth;
|
||||
const float scaleY = static_cast<float>(ScalingBase<true, Owning>::bufferHeight) / dstHeight;
|
||||
const float scaleX = static_cast<float>(ScalingBase<true, Owning, Alignment>::bufferWidth) / dstWidth;
|
||||
const float scaleY = static_cast<float>(ScalingBase<true, Owning, Alignment>::bufferHeight) / dstHeight;
|
||||
|
||||
for (std::uint32_t yB = 0; yB < scaled.size.y; ++yB) {
|
||||
for (std::uint32_t xB = 0; xB < scaled.size.x; ++xB) {
|
||||
|
|
@ -122,8 +122,8 @@ export namespace Crafter {
|
|||
const std::int32_t srcX = static_cast<std::int32_t>(std::round(sx));
|
||||
const std::int32_t srcY = static_cast<std::int32_t>(std::round(sy));
|
||||
|
||||
if (srcX >= 0 && srcX < ScalingBase<true, Owning>::bufferWidth && srcY >= 0 && srcY < ScalingBase<true, Owning>::bufferHeight) {
|
||||
buffer[yB * scaled.size.x + xB] = ScalingBase<true, Owning>::scalingBuffer[srcY * ScalingBase<true, Owning>::bufferWidth + srcX];
|
||||
if (srcX >= 0 && srcX < ScalingBase<true, Owning, Alignment>::bufferWidth && srcY >= 0 && srcY < ScalingBase<true, Owning, Alignment>::bufferHeight) {
|
||||
buffer[yB * scaled.size.x + xB] = ScalingBase<true, Owning, Alignment>::scalingBuffer[srcY * ScalingBase<true, Owning, Alignment>::bufferWidth + srcX];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -139,13 +139,14 @@ export namespace Crafter {
|
|||
} else if(oldScale.position.x != scaled.position.x || oldScale.position.y != scaled.position.y) {
|
||||
renderer.AddDirtyRect(oldScale);
|
||||
renderer.AddDirtyRect(scaled);
|
||||
if(ScalingBase<true, Owning>::bufferUpdated) {
|
||||
if(ScalingBase<true, Owning, Alignment>::bufferUpdated) {
|
||||
ScaleNearestNeighbor();
|
||||
ScalingBase<true, Owning>::bufferUpdated = false;
|
||||
ScalingBase<true, Owning, Alignment>::bufferUpdated = false;
|
||||
}
|
||||
} else if(ScalingBase<true, Owning>::bufferUpdated) {
|
||||
} else if(ScalingBase<true, Owning, Alignment>::bufferUpdated) {
|
||||
ScaleNearestNeighbor();
|
||||
ScalingBase<true, Owning>::bufferUpdated = false;
|
||||
ScalingBase<true, Owning, Alignment>::bufferUpdated = false;
|
||||
renderer.AddDirtyRect(scaled);
|
||||
}
|
||||
} else if constexpr(Rotating) {
|
||||
if(oldScale.size.x != scaled.size.x || oldScale.size.y != scaled.size.y) {
|
||||
|
|
@ -156,15 +157,16 @@ export namespace Crafter {
|
|||
} else if(oldScale.position.x != scaled.position.x || oldScale.position.y != scaled.position.y) {
|
||||
renderer.AddDirtyRect(oldScale);
|
||||
renderer.AddDirtyRect(scaled);
|
||||
if(ScalingBase<true, Owning>::bufferUpdated || RotatingBase<true>::rotationUpdated) {
|
||||
if(ScalingBase<true, Owning, Alignment>::bufferUpdated || RotatingBase<true>::rotationUpdated) {
|
||||
ScaleRotating();
|
||||
ScalingBase<true, Owning>::bufferUpdated = false;
|
||||
ScalingBase<true, Owning, Alignment>::bufferUpdated = false;
|
||||
RotatingBase<true>::rotationUpdated = false;
|
||||
}
|
||||
} else if(ScalingBase<true, Owning>::bufferUpdated || RotatingBase<true>::rotationUpdated) {
|
||||
} else if(ScalingBase<true, Owning, Alignment>::bufferUpdated || RotatingBase<true>::rotationUpdated) {
|
||||
ScaleRotating();
|
||||
ScalingBase<true, Owning>::bufferUpdated = false;
|
||||
ScalingBase<true, Owning, Alignment>::bufferUpdated = false;
|
||||
RotatingBase<true>::rotationUpdated = false;
|
||||
renderer.AddDirtyRect(scaled);
|
||||
}
|
||||
} else {
|
||||
if(oldScale.size.x != scaled.size.x || oldScale.size.y != scaled.size.y) {
|
||||
|
|
@ -179,15 +181,6 @@ export namespace Crafter {
|
|||
}
|
||||
}
|
||||
|
||||
void UpdatePosition(RendertargetBase& window) override {
|
||||
ScaleData2D oldScale = scaled;
|
||||
ScaleElement(window.transform);
|
||||
UpdatePosition(window, oldScale);
|
||||
for(Transform2D* child : children) {
|
||||
child->UpdatePosition(window, *this);
|
||||
}
|
||||
}
|
||||
|
||||
void UpdatePosition(RendertargetBase& window, Transform2D& parent) override {
|
||||
ScaleData2D oldScale = scaled;
|
||||
ScaleElement(parent);
|
||||
|
|
@ -197,7 +190,7 @@ export namespace Crafter {
|
|||
}
|
||||
}
|
||||
|
||||
std::vector<std::string_view> ResizeText(Window& window, const std::string_view text, float size, Font& font, TextOverflowMode overflowMode = TextOverflowMode::Clip, TextScaleMode scaleMode = TextScaleMode::None, Transform2D* parent = nullptr) {
|
||||
std::vector<std::string_view> ResizeText(RendertargetBase& window, Transform2D& parent, const std::string_view text, float& size, Font& font, TextOverflowMode overflowMode = TextOverflowMode::Clip, TextScaleMode scaleMode = TextScaleMode::None) {
|
||||
float scale = stbtt_ScaleForPixelHeight(&font.font, size);
|
||||
int baseline = (int)(font.ascent * scale);
|
||||
|
||||
|
|
@ -241,14 +234,16 @@ export namespace Crafter {
|
|||
anchor.height = lineHeight * logicalPerPixelY;
|
||||
anchor.width = maxWidth * logicalPerPixelX;
|
||||
if(oldHeight != anchor.height || oldwidth != anchor.width) {
|
||||
if(parent) {
|
||||
UpdatePosition(window, *parent);
|
||||
} else {
|
||||
UpdatePosition(window);
|
||||
}
|
||||
UpdatePosition(window, parent);
|
||||
}
|
||||
} else if(scaleMode == TextScaleMode::Font) {
|
||||
//todo
|
||||
float lineHeightPerFont = lineHeight / size;
|
||||
float lineWidthPerFont = maxWidth / size;
|
||||
|
||||
float maxFontHeight = scaled.size.y / lineHeightPerFont;
|
||||
float maxFontWidth = scaled.size.x / lineWidthPerFont;
|
||||
|
||||
size = std::min(maxFontHeight, maxFontWidth);
|
||||
} else if(scaleMode == TextScaleMode::Buffer) {
|
||||
if constexpr(Scaling && Owning) {
|
||||
std::uint32_t neededHeight = lines.size() * lineHeight;
|
||||
|
|
@ -256,12 +251,12 @@ export namespace Crafter {
|
|||
ScalingBase<true, true>::bufferHeight = neededHeight;
|
||||
ScalingBase<true, true>::bufferWidth = maxWidth;
|
||||
ScalingBase<true, true>::bufferUpdated = true;
|
||||
ScalingBase<true, Owning>::scalingBuffer.resize(neededHeight*maxWidth);
|
||||
ScalingBase<true, Owning, Alignment>::scalingBuffer.resize(neededHeight*maxWidth);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if constexpr(Scaling) {
|
||||
lines.resize(ScalingBase<true, Owning>::bufferHeight / lines.size());
|
||||
lines.resize(ScalingBase<true, Owning, Alignment>::bufferHeight / lines.size());
|
||||
} else {
|
||||
lines.resize(scaled.size.y / lines.size());
|
||||
}
|
||||
|
|
@ -330,26 +325,23 @@ export namespace Crafter {
|
|||
float oldHeight = anchor.height;
|
||||
anchor.height = lineHeight * logicalPerPixelY;
|
||||
if(oldHeight != anchor.height) {
|
||||
if(parent) {
|
||||
UpdatePosition(window, *parent);
|
||||
} else {
|
||||
UpdatePosition(window);
|
||||
}
|
||||
UpdatePosition(window, parent);
|
||||
}
|
||||
} else if(scaleMode == TextScaleMode::Font) {
|
||||
//todo
|
||||
float lineHeightPerFont = lineHeight / size;
|
||||
size = scaled.size.y / lineHeightPerFont;
|
||||
} else if(scaleMode == TextScaleMode::Buffer) {
|
||||
if constexpr(Scaling && Owning) {
|
||||
float neededHeight = lines.size() * lineHeight;
|
||||
if(neededHeight != ScalingBase<true, true>::bufferHeight) {
|
||||
ScalingBase<true, true>::bufferHeight = neededHeight;
|
||||
ScalingBase<true, true>::bufferUpdated = true;
|
||||
ScalingBase<true, Owning>::scalingBuffer.resize(neededHeight*ScalingBase<true, true>::bufferWidth);
|
||||
ScalingBase<true, Owning, Alignment>::scalingBuffer.resize(neededHeight*ScalingBase<true, true>::bufferWidth);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if constexpr(Scaling) {
|
||||
lines.resize(ScalingBase<true, Owning>::bufferHeight / lines.size());
|
||||
lines.resize(ScalingBase<true, Owning, Alignment>::bufferHeight / lines.size());
|
||||
} else {
|
||||
lines.resize(scaled.size.y / lines.size());
|
||||
}
|
||||
|
|
@ -358,7 +350,7 @@ export namespace Crafter {
|
|||
|
||||
return lines;
|
||||
}
|
||||
void RenderText(Window& window, std::span<const std::string_view> lines, float size, Vector<std::uint8_t, 4> color, Font& font, TextAlignment alignment = TextAlignment::Left, std::uint32_t offsetX = 0, std::uint32_t offsetY = 0) {
|
||||
void RenderText(std::span<const std::string_view> lines, float size, Vector<std::uint8_t, 4> color, Font& font, TextAlignment alignment = TextAlignment::Left, std::uint32_t offsetX = 0, std::uint32_t offsetY = 0, OpaqueType opaque = OpaqueType::FullyOpaque) {
|
||||
float scale = stbtt_ScaleForPixelHeight(&font.font, size);
|
||||
int baseline = (int)(font.ascent * scale);
|
||||
std::uint32_t lineHeight = (font.ascent - font.descent) * scale;
|
||||
|
|
@ -372,19 +364,18 @@ export namespace Crafter {
|
|||
lineWidth += (int)(advance * scale);
|
||||
}
|
||||
|
||||
std::uint32_t startX = 0;
|
||||
std::uint32_t x = 0;
|
||||
switch (alignment) {
|
||||
case TextAlignment::Left:
|
||||
startX = 0;
|
||||
x = 0;
|
||||
break;
|
||||
case TextAlignment::Center:
|
||||
startX = (scaled.size.x - lineWidth) / 2;
|
||||
x = (scaled.size.x - lineWidth) / 2;
|
||||
break;
|
||||
case TextAlignment::Right:
|
||||
startX = scaled.size.x - lineWidth;
|
||||
x = scaled.size.x - lineWidth;
|
||||
break;
|
||||
}
|
||||
std::uint32_t x = startX;
|
||||
|
||||
for (std::size_t i = 0; i < line.size(); ++i) {
|
||||
int codepoint = line[i];
|
||||
|
|
@ -403,28 +394,93 @@ export namespace Crafter {
|
|||
stbtt_MakeCodepointBitmap(&font.font, bitmap.data(), w, h, w, scale, scale, codepoint);
|
||||
|
||||
// Only render characters that fit within the scaled bounds
|
||||
for (int j = 0; j < h; j++) {
|
||||
for (int i = 0; i < w; i++) {
|
||||
int bufferX = x + i + c_x1 + offsetX;
|
||||
int bufferY = currentY + j + c_y1 + offsetY;
|
||||
|
||||
// Only draw pixels that are within our scaled buffer bounds
|
||||
if constexpr(Scaling) {
|
||||
if (bufferX >= 0 && bufferX < ScalingBase<true, Owning>::bufferWidth && bufferY >= 0 && bufferY < ScalingBase<true, Owning>::bufferHeight) {
|
||||
ScalingBase<true, Owning>::scalingBuffer[bufferY * ScalingBase<true, Owning>::bufferWidth + bufferX] = {color.r, color.g, color.b, bitmap[j * w + i]};
|
||||
}
|
||||
} else {
|
||||
if (bufferX >= 0 && bufferX < (int)scaled.size.x && bufferY >= 0 && bufferY < (int)scaled.size.y) {
|
||||
buffer[bufferY * scaled.size.x + bufferX] = {color.r, color.g, color.b, bitmap[j * w + i]};
|
||||
switch(opaque) {
|
||||
case OpaqueType::FullyOpaque: {
|
||||
for (int j = 0; j < h; j++) {
|
||||
for (int i = 0; i < w; i++) {
|
||||
int bufferX = x + i + c_x1 + offsetX;
|
||||
int bufferY = currentY + j + c_y1 + offsetY;
|
||||
|
||||
// Only draw pixels that are within our scaled buffer bounds
|
||||
if constexpr(Scaling) {
|
||||
if (bufferX >= 0 && bufferX < ScalingBase<true, Owning, Alignment>::bufferWidth && bufferY >= 0 && bufferY < ScalingBase<true, Owning, Alignment>::bufferHeight) {
|
||||
ScalingBase<true, Owning, Alignment>::scalingBuffer[bufferY * ScalingBase<true, Owning, Alignment>::bufferWidth + bufferX] = {color.r, color.g, color.b, bitmap[j * w + i]};
|
||||
}
|
||||
} else {
|
||||
if (bufferX >= 0 && bufferX < (int)scaled.size.x && bufferY >= 0 && bufferY < (int)scaled.size.y) {
|
||||
buffer[bufferY * scaled.size.x + bufferX] = {color.r, color.g, color.b, bitmap[j * w + i]};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case OpaqueType::SemiOpaque: {
|
||||
for (int j = 0; j < h; j++) {
|
||||
for (int i = 0; i < w; i++) {
|
||||
int bufferX = x + i + c_x1 + offsetX;
|
||||
int bufferY = currentY + j + c_y1 + offsetY;
|
||||
|
||||
// Only draw pixels that are within our scaled buffer bounds
|
||||
if constexpr(Scaling) {
|
||||
if (bufferX >= 0 && bufferX < ScalingBase<true, Owning, Alignment>::bufferWidth && bufferY >= 0 && bufferY < ScalingBase<true, Owning, Alignment>::bufferHeight) {
|
||||
ScalingBase<true, Owning, Alignment>::scalingBuffer[bufferY * ScalingBase<true, Owning, Alignment>::bufferWidth + bufferX] = {color.r, color.g, color.b, bitmap[j * w + i]};
|
||||
}
|
||||
} else {
|
||||
if (bufferX >= 0 && bufferX < (int)scaled.size.x && bufferY >= 0 && bufferY < (int)scaled.size.y) {
|
||||
std::uint8_t alpha = bitmap[j * w + i];
|
||||
if(alpha != 0) {
|
||||
buffer[bufferY * scaled.size.x + bufferX] = {color.r, color.g, color.b, bitmap[j * w + i]};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case OpaqueType::Transparent: {
|
||||
for (int j = 0; j < h; j++) {
|
||||
for (int i = 0; i < w; i++) {
|
||||
int bufferX = x + i + c_x1 + offsetX;
|
||||
int bufferY = currentY + j + c_y1 + offsetY;
|
||||
|
||||
// Only draw pixels that are within our scaled buffer bounds
|
||||
if constexpr(Scaling) {
|
||||
if (bufferX >= 0 && bufferX < ScalingBase<true, Owning, Alignment>::bufferWidth && bufferY >= 0 && bufferY < ScalingBase<true, Owning, Alignment>::bufferHeight) {
|
||||
ScalingBase<true, Owning, Alignment>::scalingBuffer[bufferY * ScalingBase<true, Owning, Alignment>::bufferWidth + bufferX] = {color.r, color.g, color.b, bitmap[j * w + i]};
|
||||
}
|
||||
} else {
|
||||
if (bufferX >= 0 && bufferX < (int)scaled.size.x && bufferY >= 0 && bufferY < (int)scaled.size.y) {
|
||||
std::uint8_t alpha = bitmap[j * w + i];
|
||||
|
||||
if(alpha == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Vector<std::uint8_t, 4, Alignment> dst = buffer[bufferY * scaled.size.x + bufferX];
|
||||
|
||||
float srcA = (alpha / 255.0f) * (color.a / 255.0f);
|
||||
float dstA = dst.a / 255.0f;
|
||||
|
||||
float outA = srcA + dstA * (1.0f - srcA);
|
||||
buffer[bufferY * scaled.size.x + bufferX] = Vector<std::uint8_t, 4, Alignment>(
|
||||
static_cast<std::uint8_t>((color.r * srcA + dst.r * dstA * (1.0f - srcA)) / outA),
|
||||
static_cast<std::uint8_t>((color.g * srcA + dst.g * dstA * (1.0f - srcA)) / outA),
|
||||
static_cast<std::uint8_t>((color.b * srcA + dst.b * dstA * (1.0f - srcA)) / outA),
|
||||
static_cast<std::uint8_t>(outA * 255)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
x += (int)(ax * scale);
|
||||
|
||||
if (i + 1 < line.size()) {
|
||||
x += (int)stbtt_GetCodepointKernAdvance(&font.font, codepoint, line[i+1]);
|
||||
x += (int)stbtt_GetGlyphKernAdvance(&font.font, codepoint, line[i+1]);
|
||||
}
|
||||
}
|
||||
currentY += lineHeight;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue