diff --git a/implementations/Crafter.Graphics-Device.cpp b/implementations/Crafter.Graphics-Device.cpp index 5845570..4eb86b3 100644 --- a/implementations/Crafter.Graphics-Device.cpp +++ b/implementations/Crafter.Graphics-Device.cpp @@ -593,8 +593,14 @@ void Device::Initialize() { queueCreateInfo.queueCount = 1; queueCreateInfo.pQueuePriorities = &priority; + VkPhysicalDevice16BitStorageFeatures bit16 { + .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_16BIT_STORAGE_FEATURES, + .storageBuffer16BitAccess = VK_TRUE, + }; + VkPhysicalDeviceVulkan12Features features12 { .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES, + .pNext = &bit16, .runtimeDescriptorArray = VK_TRUE, .bufferDeviceAddress = VK_TRUE }; diff --git a/implementations/Crafter.Graphics-Window.cpp b/implementations/Crafter.Graphics-Window.cpp index fad11c8..02079e9 100644 --- a/implementations/Crafter.Graphics-Window.cpp +++ b/implementations/Crafter.Graphics-Window.cpp @@ -737,16 +737,7 @@ void Window::Render() { #endif vkCmdBindPipeline(drawCmdBuffers[currentBuffer], VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, rtPipeline); - VkBindDescriptorSetsInfo bindDescriptorSetsInfo{ - .sType = VK_STRUCTURE_TYPE_BIND_DESCRIPTOR_SETS_INFO, - .stageFlags = VK_SHADER_STAGE_ALL, - .layout = rtPipelineLayout, - .firstSet = 0, - .descriptorSetCount = static_cast(descriptorsRt.size()), - .pDescriptorSets = descriptorsRt.data() - }; - - vkCmdBindDescriptorSets2(drawCmdBuffers[currentBuffer], &bindDescriptorSetsInfo); + vkCmdBindDescriptorSets(drawCmdBuffers[currentBuffer], VK_PIPELINE_BIND_POINT_RAY_TRACING_KHR, rtPipelineLayout, 0, static_cast(descriptorsRt.size()), descriptorsRt.data(), 0, nullptr); Device::vkCmdTraceRaysKHR(drawCmdBuffers[currentBuffer], &raygenRegion, &missRegion, &hitRegion, &callableRegion, width, height, 1); diff --git a/interfaces/Crafter.Graphics-RenderingElement2D.cppm b/interfaces/Crafter.Graphics-RenderingElement2D.cppm index eb3ce7c..c54d906 100644 --- a/interfaces/Crafter.Graphics-RenderingElement2D.cppm +++ b/interfaces/Crafter.Graphics-RenderingElement2D.cppm @@ -30,7 +30,7 @@ import :Window; export namespace Crafter { template requires ((!Rotating || Scaling) && (!Owning || Scaling)) - struct RenderingElement2D : RenderingElement2DBase, ScalingBase, RotatingBase { + struct RenderingElement2D : RenderingElement2DBase, ScalingBase, RotatingBase { 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(rotation) { } - RenderingElement2D(Anchor2D anchor, OpaqueType opaque, std::uint32_t bufferWidth, std::uint32_t bufferHeight, Vector* scalingBuffer) requires(Scaling && !Owning) : RenderingElement2DBase(anchor, opaque), ScalingBase(bufferWidth, bufferHeight, scalingBuffer) { + RenderingElement2D(Anchor2D anchor, OpaqueType opaque, std::uint32_t bufferWidth, std::uint32_t bufferHeight, Vector* scalingBuffer) requires(Scaling && !Owning) : RenderingElement2DBase(anchor, opaque), ScalingBase(bufferWidth, bufferHeight, scalingBuffer) { } - RenderingElement2D(Anchor2D anchor, OpaqueType opaque, std::uint32_t bufferWidth, std::uint32_t bufferHeight, Vector* scalingBuffer, std::uint32_t rotation) requires(Scaling && !Owning && Rotating) : RenderingElement2DBase(anchor, opaque), ScalingBase(bufferWidth, bufferHeight, scalingBuffer), RotatingBase(rotation) { + RenderingElement2D(Anchor2D anchor, OpaqueType opaque, std::uint32_t bufferWidth, std::uint32_t bufferHeight, Vector* scalingBuffer, std::uint32_t rotation) requires(Scaling && !Owning && Rotating) : RenderingElement2DBase(anchor, opaque), ScalingBase(bufferWidth, bufferHeight, scalingBuffer), RotatingBase(rotation) { } - RenderingElement2D(Anchor2D anchor, OpaqueType opaque, std::uint32_t bufferWidth, std::uint32_t bufferHeight) requires(Owning) : RenderingElement2DBase(anchor, opaque), ScalingBase(bufferWidth, bufferHeight) { + RenderingElement2D(Anchor2D anchor, OpaqueType opaque, std::uint32_t bufferWidth, std::uint32_t bufferHeight) requires(Owning) : RenderingElement2DBase(anchor, opaque), ScalingBase(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(bufferWidth, bufferHeight) , RotatingBase(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(bufferWidth, bufferHeight) , RotatingBase(rotation) { } - RenderingElement2D(Anchor2D anchor, TextureAsset>& texture) requires(!Owning && Scaling) : RenderingElement2DBase(anchor, texture.opaque), ScalingBase(texture.pixels.data(), texture.sizeX, texture.sizeY) { + RenderingElement2D(Anchor2D anchor, TextureAsset>& texture) requires(!Owning && Scaling) : RenderingElement2DBase(anchor, texture.opaque), ScalingBase(texture.pixels.data(), texture.sizeX, texture.sizeY) { } - RenderingElement2D(Anchor2D anchor, TextureAsset>& texture, std::uint32_t rotation) requires(!Owning && Scaling && Rotating) : RenderingElement2DBase(anchor, texture.opaque), ScalingBase(texture.pixels.data(), texture.sizeX, texture.sizeY), RotatingBase(rotation) { + RenderingElement2D(Anchor2D anchor, TextureAsset>& texture, std::uint32_t rotation) requires(!Owning && Scaling && Rotating) : RenderingElement2DBase(anchor, texture.opaque), ScalingBase(texture.pixels.data(), texture.sizeX, texture.sizeY), RotatingBase(rotation) { } @@ -62,10 +62,10 @@ export namespace Crafter { void ScaleNearestNeighbor() requires(Scaling) { for (std::uint32_t y = 0; y < this->scaled.size.y; y++) { - std::uint32_t srcY = y * ScalingBase::bufferHeight / this->scaled.size.y; + std::uint32_t srcY = y * ScalingBase::bufferHeight / this->scaled.size.y; for (std::uint32_t x = 0; x < this->scaled.size.x; x++) { - std::uint32_t srcX = x * ScalingBase::bufferWidth / this->scaled.size.x; - this->buffer[y * this->scaled.size.x + x] = ScalingBase::scalingBuffer[srcY * ScalingBase::bufferWidth + srcX]; + std::uint32_t srcX = x * ScalingBase::bufferWidth / this->scaled.size.x; + this->buffer[y * this->scaled.size.x + x] = ScalingBase::scalingBuffer[srcY * ScalingBase::bufferWidth + srcX]; } } } @@ -97,15 +97,15 @@ export namespace Crafter { const float dstCy = (this->scaled.size.y - 1.0) * 0.5; // Source center - const float srcCx = (ScalingBase::bufferWidth - 1.0) * 0.5; - const float srcCy = (ScalingBase::bufferHeight - 1.0) * 0.5; + const float srcCx = (ScalingBase::bufferWidth - 1.0) * 0.5; + const float srcCy = (ScalingBase::bufferHeight - 1.0) * 0.5; const float c = std::cos(RotatingBase::rotation); const float s = std::sin(RotatingBase::rotation); // Scale factors (destination → source) - const float scaleX = static_cast(ScalingBase::bufferWidth) / dstWidth; - const float scaleY = static_cast(ScalingBase::bufferHeight) / dstHeight; + const float scaleX = static_cast(ScalingBase::bufferWidth) / dstWidth; + const float scaleY = static_cast(ScalingBase::bufferHeight) / dstHeight; for (std::uint32_t yB = 0; yB < this->scaled.size.y; ++yB) { for (std::uint32_t xB = 0; xB < this->scaled.size.x; ++xB) { @@ -122,8 +122,8 @@ export namespace Crafter { const std::int32_t srcX = static_cast(std::round(sx)); const std::int32_t srcY = static_cast(std::round(sy)); - if (srcX >= 0 && srcX < ScalingBase::bufferWidth && srcY >= 0 && srcY < ScalingBase::bufferHeight) { - this->buffer[yB * this->scaled.size.x + xB] = ScalingBase::scalingBuffer[srcY * ScalingBase::bufferWidth + srcX]; + if (srcX >= 0 && srcX < ScalingBase::bufferWidth && srcY >= 0 && srcY < ScalingBase::bufferHeight) { + this->buffer[yB * this->scaled.size.x + xB] = ScalingBase::scalingBuffer[srcY * ScalingBase::bufferWidth + srcX]; } } } @@ -208,7 +208,7 @@ export namespace Crafter { size = std::min(maxFontHeight, maxFontWidth); } else { if constexpr(Scaling) { - lines.resize(ScalingBase::bufferHeight / lines.size()); + lines.resize(ScalingBase::bufferHeight / lines.size()); } else { lines.resize(this->scaled.size.y / lines.size()); } @@ -284,7 +284,7 @@ export namespace Crafter { size = this->scaled.size.y / lineHeightPerFont; } else { if constexpr(Scaling) { - lines.resize(ScalingBase::bufferHeight / lines.size()); + lines.resize(ScalingBase::bufferHeight / lines.size()); } else { lines.resize(this->scaled.size.y / lines.size()); } @@ -293,7 +293,27 @@ export namespace Crafter { return lines; } - void RenderText(std::span lines, float size, Vector color, Font& font, TextAlignment alignment = TextAlignment::Left, std::uint32_t offsetX = 0, std::uint32_t offsetY = 0, OpaqueType opaque = OpaqueType::FullyOpaque) { + + int utf8_decode(const char* s, int* bytes_consumed) { + unsigned char c = s[0]; + if (c < 0x80) { + *bytes_consumed = 1; + return c; + } else if ((c & 0xE0) == 0xC0) { + *bytes_consumed = 2; + return ((c & 0x1F) << 6) | (s[1] & 0x3F); + } else if ((c & 0xF0) == 0xE0) { + *bytes_consumed = 3; + return ((c & 0x0F) << 12) | ((s[1] & 0x3F) << 6) | (s[2] & 0x3F); + } else if ((c & 0xF8) == 0xF0) { + *bytes_consumed = 4; + return ((c & 0x07) << 18) | ((s[1] & 0x3F) << 12) | ((s[2] & 0x3F) << 6) | (s[3] & 0x3F); + } + *bytes_consumed = 1; + return 0xFFFD; // replacement char + } + + void RenderText(std::span lines, float size, Vector 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; @@ -320,8 +340,13 @@ export namespace Crafter { break; } - for (std::size_t i = 0; i < line.size(); ++i) { - int codepoint = line[i]; + const char* p = line.data(); + const char* end = p + line.size(); + + while (p < end) { + int bytes; + int codepoint = utf8_decode(p, &bytes); + p += bytes; int ax; int lsb; @@ -346,12 +371,12 @@ export namespace Crafter { // Only draw pixels that are within our scaled buffer bounds if constexpr(Scaling) { - if (bufferX >= 0 && bufferX < ScalingBase::bufferWidth && bufferY >= 0 && bufferY < ScalingBase::bufferHeight) { - ScalingBase::scalingBuffer[bufferY * ScalingBase::bufferWidth + bufferX] = {color.r, color.g, color.b, bitmap[j * w + i]}; + if (bufferX >= 0 && bufferX < ScalingBase::bufferWidth && bufferY >= 0 && bufferY < ScalingBase::bufferHeight) { + ScalingBase::scalingBuffer[bufferY * ScalingBase::bufferWidth + bufferX] = {color.r, color.g, color.b, static_cast(bitmap[j * w + i])}; } } else { if (bufferX >= 0 && bufferX < (int)this->scaled.size.x && bufferY >= 0 && bufferY < (int)this->scaled.size.y) { - this->buffer[bufferY * this->scaled.size.x + bufferX] = {color.r, color.g, color.b, bitmap[j * w + i]}; + this->buffer[bufferY * this->scaled.size.x + bufferX] = {color.r, color.g, color.b, static_cast(bitmap[j * w + i])}; } } } @@ -366,14 +391,14 @@ export namespace Crafter { // Only draw pixels that are within our scaled buffer bounds if constexpr(Scaling) { - if (bufferX >= 0 && bufferX < ScalingBase::bufferWidth && bufferY >= 0 && bufferY < ScalingBase::bufferHeight) { - ScalingBase::scalingBuffer[bufferY * ScalingBase::bufferWidth + bufferX] = {color.r, color.g, color.b, bitmap[j * w + i]}; + if (bufferX >= 0 && bufferX < ScalingBase::bufferWidth && bufferY >= 0 && bufferY < ScalingBase::bufferHeight) { + ScalingBase::scalingBuffer[bufferY * ScalingBase::bufferWidth + bufferX] = {color.r, color.g, color.b, static_cast(bitmap[j * w + i])}; } } else { if (bufferX >= 0 && bufferX < (int)this->scaled.size.x && bufferY >= 0 && bufferY < (int)this->scaled.size.y) { std::uint8_t alpha = bitmap[j * w + i]; if(alpha != 0) { - this->buffer[bufferY * this->scaled.size.x + bufferX] = {color.r, color.g, color.b, bitmap[j * w + i]}; + this->buffer[bufferY * this->scaled.size.x + bufferX] = {color.r, color.g, color.b, static_cast(bitmap[j * w + i])}; } } } @@ -389,29 +414,41 @@ export namespace Crafter { // Only draw pixels that are within our scaled buffer bounds if constexpr(Scaling) { - if (bufferX >= 0 && bufferX < ScalingBase::bufferWidth && bufferY >= 0 && bufferY < ScalingBase::bufferHeight) { - ScalingBase::scalingBuffer[bufferY * ScalingBase::bufferWidth + bufferX] = {color.r, color.g, color.b, bitmap[j * w + i]}; + if (bufferX >= 0 && bufferX < ScalingBase::bufferWidth && bufferY >= 0 && bufferY < ScalingBase::bufferHeight) { + ScalingBase::scalingBuffer[bufferY * ScalingBase::bufferWidth + bufferX] = {color.r, color.g, color.b, static_cast(bitmap[j * w + i])}; } } else { if (bufferX >= 0 && bufferX < (int)this->scaled.size.x && bufferY >= 0 && bufferY < (int)this->scaled.size.y) { - std::uint8_t alpha = bitmap[j * w + i]; + if constexpr(std::same_as) { + std::uint8_t alpha = bitmap[j * w + i]; - if(alpha == 0) { - continue; - } - - Vector dst = this->buffer[bufferY * this->scaled.size.x + bufferX]; + Vector dst = this->buffer[bufferY * this->scaled.size.x + bufferX]; - float srcA = (alpha / 255.0f) * (color.a / 255.0f); - float dstA = dst.a / 255.0f; + float srcA = (alpha / 255.0f) * (color.a / 255.0f); + float dstA = dst.a / 255.0f; - float outA = srcA + dstA * (1.0f - srcA); - this->buffer[bufferY * this->scaled.size.x + bufferX] = Vector( - static_cast((color.r * srcA + dst.r * dstA * (1.0f - srcA)) / outA), - static_cast((color.g * srcA + dst.g * dstA * (1.0f - srcA)) / outA), - static_cast((color.b * srcA + dst.b * dstA * (1.0f - srcA)) / outA), - static_cast(outA * 255) - ); + float oneMinusSrcA = 1.0f - color.a; + + float outA = srcA + dstA * (1.0f - srcA); + this->buffer[bufferY * this->scaled.size.x + bufferX] = Vector( + static_cast((color.r * srcA + dst.r * dstA * (1.0f - srcA)) / outA), + static_cast((color.g * srcA + dst.g * dstA * (1.0f - srcA)) / outA), + static_cast((color.b * srcA + dst.b * dstA * (1.0f - srcA)) / outA), + static_cast(outA * 255) + ); + } else if constexpr(std::same_as) { + std::uint8_t alpha = bitmap[j * w + i]; + _Float16 srcA = (_Float16(alpha)/_Float16(255.0f))*color.a; + Vector<_Float16, 4, Alignment> dst = this->buffer[bufferY * this->scaled.size.x + bufferX]; + + _Float16 outA = srcA + dst.a * (1.0f - srcA); + this->buffer[bufferY * this->scaled.size.x + bufferX] = Vector<_Float16, 4, Alignment>( + (color.r * srcA + dst.r * dst.a * (1.0f - srcA)), + (color.g * srcA + dst.g * dst.a * (1.0f - srcA)), + (color.b * srcA + dst.b * dst.a * (1.0f - srcA)), + outA + ); + } } } } @@ -422,8 +459,9 @@ export namespace Crafter { x += (int)(ax * scale); - if (i + 1 < line.size()) { - x += (int)stbtt_GetGlyphKernAdvance(&font.font, codepoint, line[i+1]); + if (p + 1 < end) { + int next; + x += (int)stbtt_GetGlyphKernAdvance(&font.font, codepoint, utf8_decode(p+1, &next)); } } currentY += lineHeight; diff --git a/interfaces/Crafter.Graphics-RenderingElement2DBase.cppm b/interfaces/Crafter.Graphics-RenderingElement2DBase.cppm index d86fab1..b4cf182 100644 --- a/interfaces/Crafter.Graphics-RenderingElement2DBase.cppm +++ b/interfaces/Crafter.Graphics-RenderingElement2DBase.cppm @@ -42,9 +42,9 @@ export namespace Crafter { Buffer }; - template + template struct RenderElement2DScalingOwning { - std::vector> scalingBuffer; + std::vector> scalingBuffer; std::uint32_t bufferWidth; std::uint32_t bufferHeight; RenderElement2DScalingOwning() = default; @@ -53,13 +53,13 @@ export namespace Crafter { } }; - template + template struct RenderElement2DScalingNonOwning { - Vector* scalingBuffer; + Vector* scalingBuffer; std::uint32_t bufferWidth; std::uint32_t bufferHeight; RenderElement2DScalingNonOwning() = default; - RenderElement2DScalingNonOwning(Vector* scalingBuffer, std::uint32_t bufferWidth, std::uint32_t bufferHeight) : scalingBuffer(scalingBuffer), bufferWidth(bufferWidth), bufferHeight(bufferHeight) { + RenderElement2DScalingNonOwning(Vector* scalingBuffer, std::uint32_t bufferWidth, std::uint32_t bufferHeight) : scalingBuffer(scalingBuffer), bufferWidth(bufferWidth), bufferHeight(bufferHeight) { } }; @@ -76,13 +76,13 @@ export namespace Crafter { struct EmptyScalingBase {}; struct EmptyRotatingBase {}; - template + template using ScalingBase = std::conditional_t< Scaling, std::conditional_t, - RenderElement2DScalingNonOwning>, + RenderElement2DScalingOwning, + RenderElement2DScalingNonOwning>, EmptyScalingBase >; @@ -115,7 +115,7 @@ export namespace Crafter { redraw[i] = true; } } - void CopyNearestNeighbor(Vector* dst, std::uint16_t dstSizeX, std::uint16_t dstScaledSizeX, std::uint16_t dstScaledSizeY, std::uint16_t offsetX, std::uint16_t offsetY) { + void CopyNearestNeighbor(Vector* dst, std::uint16_t dstSizeX, std::uint16_t dstScaledSizeX, std::uint16_t dstScaledSizeY, std::uint16_t offsetX, std::uint16_t offsetY) { for (std::uint16_t y = 0; y < dstScaledSizeY; y++) { std::uint16_t srcY = y * scaled.size.y / dstScaledSizeY; std::uint16_t dstY = y + offsetY; diff --git a/interfaces/Crafter.Graphics-Rendertarget.cppm b/interfaces/Crafter.Graphics-Rendertarget.cppm index 77dd2e9..53d3c8f 100644 --- a/interfaces/Crafter.Graphics-Rendertarget.cppm +++ b/interfaces/Crafter.Graphics-Rendertarget.cppm @@ -66,15 +66,20 @@ export namespace Crafter { dirty.right = std::min(std::uint16_t(element->scaled.position.x+element->scaled.size.x), dirty.right); dirty.bottom = std::min(std::uint16_t(element->scaled.position.y+element->scaled.size.y), dirty.bottom); + if(dirty.right <= dirty.left || dirty.bottom <= dirty.top) { + continue; + } + const Vector* src_buffer = element->buffer.data(); - std::int32_t src_width = element->scaled.size.x; - std::int32_t src_height = element->scaled.size.y; + std::uint16_t src_width = element->scaled.size.x; + std::uint16_t src_height = element->scaled.size.y; switch (element->opaque) { case OpaqueType::FullyOpaque: { - for (std::int32_t y = dirty.top; y < dirty.bottom; y++) { - std::int32_t src_y = y - element->scaled.position.y; - std::memcpy(&this->buffer[frame][y * this->sizeX], &src_buffer[src_y * src_width], dirty.right-dirty.left*sizeof(Vector)); + for (std::uint16_t y = dirty.top; y < dirty.bottom; y++) { + std::uint16_t src_y = y - element->scaled.position.y; + std::uint16_t src_x = dirty.left - element->scaled.position.x; + std::memcpy(&this->buffer[frame][y * this->sizeX + dirty.left], &src_buffer[src_y * src_width + src_x], (dirty.right - dirty.left) * sizeof(Vector)); } break; } @@ -83,20 +88,20 @@ export namespace Crafter { if constexpr(std::same_as) { for (std::uint16_t y = dirty.top; y < dirty.bottom; y++) { std::uint16_t src_y = y - element->scaled.position.y; - std::uint32_t pixel_width = dirty.right - dirty.left; + std::uint16_t pixel_width = dirty.right - dirty.left; + constexpr std::uint32_t simd_width = VectorF16<1, 1>::MaxElement / 4; std::uint32_t rows = pixel_width / simd_width; for (std::uint32_t x = 0; x < rows; x++) { std::uint16_t px = dirty.left + x * simd_width; std::uint16_t src_x = px - element->scaled.position.x; - std::uint16_t dst_x = px; VectorF16<4, simd_width> src(&src_buffer[src_y * src_width + src_x].v[0]); - VectorF16<4, simd_width> dst(&buffer[frame][y * this->sizeX + dst_x].v[0]); + VectorF16<4, simd_width> dst(&buffer[frame][y * this->sizeX + px].v[0]); VectorF16<4, simd_width> oneMinusSrcA = VectorF16<4, simd_width>(1) - src.Shuffle<{{3, 3, 3, 3}}>(); VectorF16<4, simd_width> result = VectorF16<4, simd_width>::MulitplyAdd(dst, oneMinusSrcA, src); - result.Store(buffer[frame][y * this->sizeX + dst_x]); + result.Store(&buffer[frame][y * this->sizeX + px].v[0]); } std::uint32_t remainder = pixel_width - (rows * simd_width); @@ -108,7 +113,7 @@ export namespace Crafter { Vector src = src_buffer[src_y * src_width + src_x]; Vector dst = buffer[frame][y * this->sizeX + px]; - _Float16 oneMinusSrcA = (_Float16)1.0f - src[3]; + _Float16 oneMinusSrcA = (_Float16)1.0f - src.a; buffer[frame][y * this->sizeX + px] = Vector( src.r + dst.r * oneMinusSrcA, @@ -119,9 +124,10 @@ export namespace Crafter { } } } else { - for (std::int32_t y = dirty.top; y < dirty.bottom; y++) { - std::int32_t src_y = y - element->scaled.position.y; - std::memcpy(&this->buffer[frame][y * this->sizeX], &src_buffer[src_y * src_width], dirty.right-dirty.left*sizeof(Vector)); + for (std::uint16_t y = dirty.top; y < dirty.bottom; y++) { + std::uint16_t src_y = y - element->scaled.position.y; + std::uint16_t src_x = dirty.left - element->scaled.position.x; + std::memcpy(&this->buffer[frame][y * this->sizeX + dirty.left], &src_buffer[src_y * src_width + src_x], (dirty.right - dirty.left) * sizeof(Vector)); } } break;