semi opaque
This commit is contained in:
parent
615d90c36f
commit
0329616148
6 changed files with 80 additions and 91 deletions
|
|
@ -34,7 +34,7 @@ ImageElement::ImageElement() : RenderingElementScaling() {
|
|||
|
||||
}
|
||||
|
||||
ImageElement::ImageElement(const std::string_view imagePath, std::int_fast32_t anchorX, std::int_fast32_t anchorY, std::uint_fast32_t relativeWidth, std::uint_fast32_t relativeHeight, std::int_fast32_t anchorOffsetX, std::int_fast32_t anchorOffsetY, std::int_fast32_t z, bool ignoreScaling) : RenderingElementScaling(false, anchorX, anchorY, relativeWidth, relativeHeight, anchorOffsetX, anchorOffsetY, z, ignoreScaling) {
|
||||
ImageElement::ImageElement(const std::string_view imagePath, std::int_fast32_t anchorX, std::int_fast32_t anchorY, std::uint_fast32_t relativeWidth, std::uint_fast32_t relativeHeight, std::int_fast32_t anchorOffsetX, std::int_fast32_t anchorOffsetY, std::int_fast32_t z, bool ignoreScaling) : RenderingElementScaling(OpaqueType::FullyOpaque, anchorX, anchorY, relativeWidth, relativeHeight, anchorOffsetX, anchorOffsetY, z, ignoreScaling) {
|
||||
RenderImage(imagePath);
|
||||
}
|
||||
|
||||
|
|
@ -42,11 +42,12 @@ void ImageElement::RenderImage(const std::string_view path) {
|
|||
std::filesystem::path abs = std::filesystem::absolute(path);
|
||||
int xSize;
|
||||
int ySize;
|
||||
int channels;
|
||||
unsigned char* bgData = stbi_load(abs.string().c_str(), &xSize, &ySize, &channels, 4);
|
||||
unsigned char* bgData = stbi_load(abs.string().c_str(), &xSize, &ySize, nullptr, 4);
|
||||
|
||||
ResizeBuffer(xSize, ySize);
|
||||
|
||||
opaque = OpaqueType::FullyOpaque;
|
||||
|
||||
for(std::uint_fast32_t x = 0; x < xSize; x++) {
|
||||
for(std::uint_fast32_t y = 0; y < ySize; y++) {
|
||||
std::uint_fast32_t idx = (x*ySize+y)*4;
|
||||
|
|
@ -57,7 +58,16 @@ void ImageElement::RenderImage(const std::string_view path) {
|
|||
}
|
||||
}
|
||||
|
||||
if(channels != 4) {
|
||||
opaque = true;
|
||||
}
|
||||
for(std::uint_fast32_t i = 0; i < xSize*ySize; i++) {
|
||||
if(buffer[i].a != 255) {
|
||||
opaque = OpaqueType::SemiOpaque;
|
||||
for(std::uint_fast32_t i2 = 0; i2 < xSize*ySize; i2++) {
|
||||
if(buffer[i2].a != 0 && buffer[i2].a != 255) {
|
||||
opaque = OpaqueType::Transparent;
|
||||
return;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -27,32 +27,32 @@ import std;
|
|||
|
||||
using namespace Crafter;
|
||||
|
||||
RenderingElement::RenderingElement(bool opaque) : Transform(), opaque(opaque) {
|
||||
RenderingElement::RenderingElement(OpaqueType opaque) : Transform(), opaque(opaque) {
|
||||
|
||||
}
|
||||
|
||||
|
||||
RenderingElement::RenderingElement(bool opaque, std::int_fast32_t anchorX, std::int_fast32_t anchorY, std::uint_fast32_t relativeWidth, std::uint_fast32_t relativeHeight, std::int_fast32_t anchorOffsetX, std::int_fast32_t anchorOffsetY, std::int_fast32_t z, bool ignoreScaling) : Transform(anchorX, anchorY, relativeWidth, relativeHeight, anchorOffsetX, anchorOffsetY, z, ignoreScaling), opaque(opaque) {
|
||||
RenderingElement::RenderingElement(OpaqueType opaque, std::int_fast32_t anchorX, std::int_fast32_t anchorY, std::uint_fast32_t relativeWidth, std::uint_fast32_t relativeHeight, std::int_fast32_t anchorOffsetX, std::int_fast32_t anchorOffsetY, std::int_fast32_t z, bool ignoreScaling) : Transform(anchorX, anchorY, relativeWidth, relativeHeight, anchorOffsetX, anchorOffsetY, z, ignoreScaling), opaque(opaque) {
|
||||
|
||||
}
|
||||
|
||||
RenderingElementPreScaled::RenderingElementPreScaled(bool opaque) : RenderingElement(opaque) {
|
||||
RenderingElementPreScaled::RenderingElementPreScaled(OpaqueType opaque) : RenderingElement(opaque) {
|
||||
|
||||
}
|
||||
|
||||
RenderingElementPreScaled::RenderingElementPreScaled(bool opaque, std::int_fast32_t anchorX, std::int_fast32_t anchorY, std::uint_fast32_t relativeWidth, std::uint_fast32_t relativeHeight, std::int_fast32_t anchorOffsetX, std::int_fast32_t anchorOffsetY, std::int_fast32_t z, bool ignoreScaling) : RenderingElement(opaque, anchorX, anchorY, relativeWidth, relativeHeight, anchorOffsetX, anchorOffsetY, z, ignoreScaling) {
|
||||
RenderingElementPreScaled::RenderingElementPreScaled(OpaqueType opaque, std::int_fast32_t anchorX, std::int_fast32_t anchorY, std::uint_fast32_t relativeWidth, std::uint_fast32_t relativeHeight, std::int_fast32_t anchorOffsetX, std::int_fast32_t anchorOffsetY, std::int_fast32_t z, bool ignoreScaling) : RenderingElement(opaque, anchorX, anchorY, relativeWidth, relativeHeight, anchorOffsetX, anchorOffsetY, z, ignoreScaling) {
|
||||
|
||||
}
|
||||
|
||||
RenderingElementScaling::RenderingElementScaling(bool opaque) : RenderingElement(opaque) {
|
||||
RenderingElementScaling::RenderingElementScaling(OpaqueType opaque) : RenderingElement(opaque) {
|
||||
|
||||
}
|
||||
|
||||
RenderingElementScaling::RenderingElementScaling(bool opaque, std::int_fast32_t anchorX, std::int_fast32_t anchorY, std::uint_fast32_t relativeWidth, std::uint_fast32_t relativeHeight, std::int_fast32_t anchorOffsetX, std::int_fast32_t anchorOffsetY, std::int_fast32_t z, bool ignoreScaling) : RenderingElement(opaque, anchorX, anchorY, relativeWidth, relativeHeight, anchorOffsetX, anchorOffsetY, z, ignoreScaling) {
|
||||
RenderingElementScaling::RenderingElementScaling(OpaqueType opaque, std::int_fast32_t anchorX, std::int_fast32_t anchorY, std::uint_fast32_t relativeWidth, std::uint_fast32_t relativeHeight, std::int_fast32_t anchorOffsetX, std::int_fast32_t anchorOffsetY, std::int_fast32_t z, bool ignoreScaling) : RenderingElement(opaque, anchorX, anchorY, relativeWidth, relativeHeight, anchorOffsetX, anchorOffsetY, z, ignoreScaling) {
|
||||
|
||||
}
|
||||
|
||||
RenderingElementScaling::RenderingElementScaling(bool opaque, std::uint_fast32_t bufferWidth, std::uint_fast32_t bufferHeight, std::int_fast32_t anchorX, std::int_fast32_t anchorY, std::uint_fast32_t relativeWidth, std::uint_fast32_t relativeHeight, std::int_fast32_t anchorOffsetX, std::int_fast32_t anchorOffsetY, std::int_fast32_t z, bool ignoreScaling) : bufferWidth(bufferWidth), bufferHeight(bufferHeight), buffer(bufferWidth*bufferHeight), RenderingElement(opaque, anchorX, anchorY, relativeWidth, relativeHeight, anchorOffsetX, anchorOffsetY, z, ignoreScaling) {
|
||||
RenderingElementScaling::RenderingElementScaling(OpaqueType opaque, std::uint_fast32_t bufferWidth, std::uint_fast32_t bufferHeight, std::int_fast32_t anchorX, std::int_fast32_t anchorY, std::uint_fast32_t relativeWidth, std::uint_fast32_t relativeHeight, std::int_fast32_t anchorOffsetX, std::int_fast32_t anchorOffsetY, std::int_fast32_t z, bool ignoreScaling) : bufferWidth(bufferWidth), bufferHeight(bufferHeight), buffer(bufferWidth*bufferHeight), RenderingElement(opaque, anchorX, anchorY, relativeWidth, relativeHeight, anchorOffsetX, anchorOffsetY, z, ignoreScaling) {
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -157,4 +157,4 @@ void RenderingElementScaling::ResizeBuffer(std::uint_fast32_t width, std::uint_f
|
|||
this->bufferWidth = width;
|
||||
this->bufferHeight = height;
|
||||
buffer.resize(width * height);
|
||||
}
|
||||
}
|
||||
|
|
@ -30,7 +30,7 @@ import std;
|
|||
|
||||
using namespace Crafter;
|
||||
|
||||
TextElement::TextElement(std::int_fast32_t anchorX, std::int_fast32_t anchorY, std::uint_fast32_t relativeWidth, std::uint_fast32_t relativeHeight, std::int_fast32_t anchorOffsetX, std::int_fast32_t anchorOffsetY, std::int_fast32_t z, bool ignoreScaling) : RenderingElementPreScaled(false, anchorX, anchorY, relativeWidth, relativeHeight, anchorOffsetX, anchorOffsetY, z, ignoreScaling) {
|
||||
TextElement::TextElement(std::int_fast32_t anchorX, std::int_fast32_t anchorY, std::uint_fast32_t relativeWidth, std::uint_fast32_t relativeHeight, std::int_fast32_t anchorOffsetX, std::int_fast32_t anchorOffsetY, std::int_fast32_t z, bool ignoreScaling) : RenderingElementPreScaled(OpaqueType::Transparent, anchorX, anchorY, relativeWidth, relativeHeight, anchorOffsetX, anchorOffsetY, z, ignoreScaling) {
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -249,7 +249,7 @@ void TextElement::RenderText(Window& window, const std::string_view text, float
|
|||
} else if (currentLine.empty() || (currentLine.length() + currentWord.length() + 1) * (int)(scale * 1.5f) <= maxLineWidth) {
|
||||
// Add word to current line
|
||||
if (!currentLine.empty()) {
|
||||
currentLine = currentLine.substr(0) + std::string(" ") + currentWord;
|
||||
currentLine = currentLine + std::string(" ") + currentWord;
|
||||
} else {
|
||||
currentLine = currentWord;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -139,6 +139,7 @@ inline void blend_pixel_optimized(Pixel_BU8_GU8_RU8_AU8& dst, const Pixel_BU8_GU
|
|||
if(src.a == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
float srcA = src.a / 255.0f;
|
||||
float dstA = dst.a / 255.0f;
|
||||
|
||||
|
|
@ -173,26 +174,49 @@ void WindowWayland::RenderElement(Transform* transform) {
|
|||
const Pixel_BU8_GU8_RU8_AU8* src_buffer = element->bufferScaled.data();
|
||||
std::int_fast32_t src_width = element->scaled.width;
|
||||
std::int_fast32_t src_height = element->scaled.height;
|
||||
|
||||
if (element->opaque) {
|
||||
for (std::int_fast32_t y = dirty.top; y < dirty.bottom; y++) {
|
||||
std::int_fast32_t src_y = y - element->scaled.y;
|
||||
|
||||
for (std::int_fast32_t x = dirty.left; x < dirty.right; x++) {
|
||||
std::int_fast32_t src_x = x - element->scaled.x;
|
||||
|
||||
switch (element->opaque) {
|
||||
case OpaqueType::FullyOpaque:
|
||||
// For fully opaque, just copy pixels directly
|
||||
for (std::int_fast32_t y = dirty.top; y < dirty.bottom; y++) {
|
||||
std::int_fast32_t src_y = y - element->scaled.y;
|
||||
|
||||
framebuffer[y * width + x] = src_buffer[src_y * src_width + src_x];
|
||||
for (std::int_fast32_t x = dirty.left; x < dirty.right; x++) {
|
||||
std::int_fast32_t src_x = x - element->scaled.x;
|
||||
|
||||
framebuffer[y * width + x] = src_buffer[src_y * src_width + src_x];
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (std::int_fast32_t y = dirty.top; y < dirty.bottom; y++) {
|
||||
std::int_fast32_t src_y = y - element->scaled.y;
|
||||
break;
|
||||
|
||||
for (std::int_fast32_t x = dirty.left; x < dirty.right; x++) {
|
||||
std::int_fast32_t src_x = x - element->scaled.x;
|
||||
blend_pixel_optimized(framebuffer[y * width + x], src_buffer[src_y * src_width + src_x]);
|
||||
case OpaqueType::SemiOpaque:
|
||||
// For semi-opaque, we can avoid blending when alpha is 0 or 255
|
||||
for (std::int_fast32_t y = dirty.top; y < dirty.bottom; y++) {
|
||||
std::int_fast32_t src_y = y - element->scaled.y;
|
||||
|
||||
for (std::int_fast32_t x = dirty.left; x < dirty.right; x++) {
|
||||
std::int_fast32_t src_x = x - element->scaled.x;
|
||||
Pixel_BU8_GU8_RU8_AU8 src_pixel = src_buffer[src_y * src_width + src_x];
|
||||
|
||||
if (src_pixel.a == 0) {
|
||||
continue;
|
||||
}
|
||||
framebuffer[y * width + x] = src_pixel;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case OpaqueType::Transparent:
|
||||
// For transparent, always perform blending
|
||||
for (std::int_fast32_t y = dirty.top; y < dirty.bottom; y++) {
|
||||
std::int_fast32_t src_y = y - element->scaled.y;
|
||||
|
||||
for (std::int_fast32_t x = dirty.left; x < dirty.right; x++) {
|
||||
std::int_fast32_t src_x = x - element->scaled.x;
|
||||
blend_pixel_optimized(framebuffer[y * width + x], src_buffer[src_y * src_width + src_x]);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -23,22 +23,28 @@ import :Transform;
|
|||
import :Types;
|
||||
|
||||
export namespace Crafter {
|
||||
enum class OpaqueType {
|
||||
FullyOpaque, // All pixels have A of 255
|
||||
SemiOpaque, // All pixels have A of 0 or 255 (no blending needed)
|
||||
Transparent // Color blending is used
|
||||
};
|
||||
|
||||
class Window;
|
||||
class RenderingElement : public Transform {
|
||||
public:
|
||||
std::vector<Pixel_BU8_GU8_RU8_AU8> bufferScaled;
|
||||
bool opaque = false;
|
||||
OpaqueType opaque = OpaqueType::Transparent;
|
||||
|
||||
RenderingElement(bool opague = false);
|
||||
RenderingElement(bool opague, std::int_fast32_t anchorX, std::int_fast32_t anchorY, std::uint_fast32_t relativeWidth, std::uint_fast32_t relativeHeight, std::int_fast32_t anchorOffsetX, std::int_fast32_t anchorOffsetY, std::int_fast32_t z, bool ignoreScaling);
|
||||
RenderingElement(OpaqueType opaque = OpaqueType::Transparent);
|
||||
RenderingElement(OpaqueType opaque, std::int_fast32_t anchorX, std::int_fast32_t anchorY, std::uint_fast32_t relativeWidth, std::uint_fast32_t relativeHeight, std::int_fast32_t anchorOffsetX, std::int_fast32_t anchorOffsetY, std::int_fast32_t z, bool ignoreScaling);
|
||||
RenderingElement(RenderingElement&) = delete;
|
||||
RenderingElement& operator=(RenderingElement&) = delete;
|
||||
};
|
||||
|
||||
class RenderingElementPreScaled : public RenderingElement {
|
||||
public:
|
||||
RenderingElementPreScaled(bool opague = false);
|
||||
RenderingElementPreScaled(bool opague, std::int_fast32_t anchorX, std::int_fast32_t anchorY, std::uint_fast32_t relativeWidth, std::uint_fast32_t relativeHeight, std::int_fast32_t anchorOffsetX, std::int_fast32_t anchorOffsetY, std::int_fast32_t z, bool ignoreScaling);
|
||||
RenderingElementPreScaled(OpaqueType opaque = OpaqueType::Transparent);
|
||||
RenderingElementPreScaled(OpaqueType opaque, std::int_fast32_t anchorX, std::int_fast32_t anchorY, std::uint_fast32_t relativeWidth, std::uint_fast32_t relativeHeight, std::int_fast32_t anchorOffsetX, std::int_fast32_t anchorOffsetY, std::int_fast32_t z, bool ignoreScaling);
|
||||
RenderingElementPreScaled(RenderingElementPreScaled&) = delete;
|
||||
RenderingElementPreScaled& operator=(RenderingElementPreScaled&) = delete;
|
||||
|
||||
|
|
@ -52,11 +58,10 @@ export namespace Crafter {
|
|||
std::vector<Pixel_BU8_GU8_RU8_AU8> buffer;
|
||||
std::uint_fast32_t bufferWidth;
|
||||
std::uint_fast32_t bufferHeight;
|
||||
bool opaque = false;
|
||||
|
||||
RenderingElementScaling(bool opague = false);
|
||||
RenderingElementScaling(bool opague, std::int_fast32_t anchorX, std::int_fast32_t anchorY, std::uint_fast32_t relativeWidth, std::uint_fast32_t relativeHeight, std::int_fast32_t anchorOffsetX, std::int_fast32_t anchorOffsetY, std::int_fast32_t z, bool ignoreScaling);
|
||||
RenderingElementScaling(bool opague, std::uint_fast32_t bufferWidth, std::uint_fast32_t bufferHeight, std::int_fast32_t anchorX = FractionalToMapped(0.5), std::int_fast32_t anchorY = FractionalToMapped(0.5), std::uint_fast32_t relativeWidth = FractionalToMapped(1), std::uint_fast32_t relativeHeight = FractionalToMapped(1), std::int_fast32_t anchorOffsetX = FractionalToMapped(0.5), std::int_fast32_t anchorOffsetY = FractionalToMapped(0.5), std::int_fast32_t z = 0, bool ignoreScaling = false);
|
||||
RenderingElementScaling(OpaqueType opaque = OpaqueType::Transparent);
|
||||
RenderingElementScaling(OpaqueType opaque, std::int_fast32_t anchorX, std::int_fast32_t anchorY, std::uint_fast32_t relativeWidth, std::uint_fast32_t relativeHeight, std::int_fast32_t anchorOffsetX, std::int_fast32_t anchorOffsetY, std::int_fast32_t z, bool ignoreScaling);
|
||||
RenderingElementScaling(OpaqueType opaque, std::uint_fast32_t bufferWidth, std::uint_fast32_t bufferHeight, std::int_fast32_t anchorX = FractionalToMapped(0.5), std::int_fast32_t anchorY = FractionalToMapped(0.5), std::uint_fast32_t relativeWidth = FractionalToMapped(1), std::uint_fast32_t relativeHeight = FractionalToMapped(1), std::int_fast32_t anchorOffsetX = FractionalToMapped(0.5), std::int_fast32_t anchorOffsetY = FractionalToMapped(0.5), std::int_fast32_t z = 0, bool ignoreScaling = false);
|
||||
RenderingElementScaling(RenderingElementScaling&) = delete;
|
||||
RenderingElementScaling& operator=(RenderingElementScaling&) = delete;
|
||||
|
||||
|
|
|
|||
|
|
@ -150,54 +150,4 @@ namespace Crafter {
|
|||
export constexpr std::int_fast32_t PixelToMappedBoundless(std::int_fast32_t pixel, std::int_fast32_t width) {
|
||||
return pixel * (SCALEBOUNDLESS / width);
|
||||
}
|
||||
|
||||
// export constexpr double bound = 10;
|
||||
|
||||
// export constexpr std::uint_fast32_t FractionalToMapped(double fractional) {
|
||||
// constexpr double min_x = -bound;
|
||||
// constexpr double max_x = bound + 1.0;
|
||||
// constexpr double range_x = max_x - min_x;
|
||||
|
||||
// constexpr double MAXD = static_cast<double>(
|
||||
// std::numeric_limits<std::uint_fast32_t>::max()
|
||||
// );
|
||||
|
||||
// // Normalize to [0,1]
|
||||
// double t = (fractional - min_x) / range_x;
|
||||
|
||||
// // Clamp (important for constexpr safety and edge behavior)
|
||||
// if (t < 0.0) t = 0.0;
|
||||
// if (t > 1.0) t = 1.0;
|
||||
|
||||
// return static_cast<std::uint_fast32_t>(t * MAXD);
|
||||
// }
|
||||
|
||||
// export constexpr double MappedToFractional(std::uint_fast32_t mapped) {
|
||||
// constexpr double min_x = -bound;
|
||||
// constexpr double max_x = bound + 1.0;
|
||||
// constexpr double range_x = max_x - min_x;
|
||||
|
||||
// constexpr double MAXD = static_cast<double>(
|
||||
// std::numeric_limits<std::uint_fast32_t>::max()
|
||||
// );
|
||||
|
||||
// double t = static_cast<double>(mapped) / MAXD;
|
||||
|
||||
// return min_x + t * range_x;
|
||||
// }
|
||||
|
||||
// export constexpr std::int_fast32_t MappedToPixel(std::uint_fast32_t mapped, std::uint_fast32_t size) {
|
||||
// constexpr double MAXD = static_cast<double>(
|
||||
// std::numeric_limits<std::uint_fast32_t>::max()
|
||||
// );
|
||||
|
||||
// // scale mapped ∈ [0, MAX] to pixel ∈ [0, size]
|
||||
// double t = static_cast<double>(mapped) / MAXD;
|
||||
|
||||
// // Clamp (shouldn't be necessary, but protects constexpr eval)
|
||||
// if (t < 0.0) t = 0.0;
|
||||
// if (t > 1.0) t = 1.0;
|
||||
|
||||
// return static_cast<std::int_fast32_t>(t * static_cast<double>(size));
|
||||
// }
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue