rendering improvements
This commit is contained in:
parent
789bb307d5
commit
7f46ac13fa
14 changed files with 296 additions and 179 deletions
|
|
@ -32,7 +32,7 @@ export namespace Crafter {
|
|||
Transform2D transform;
|
||||
std::int32_t sizeX;
|
||||
std::int32_t sizeY;
|
||||
std::vector<RenderingElement2DBase*> elements;
|
||||
std::vector<Transform2D*> elements;
|
||||
std::vector<ClipRect> dirtyRects;
|
||||
RendertargetBase() = default;
|
||||
RendertargetBase(std::int16_t sizeX, std::int16_t sizeY) : sizeX(sizeX), sizeY(sizeY), transform({0, 0, 1, 1, 0, 0, 0}){
|
||||
|
|
@ -42,13 +42,7 @@ export namespace Crafter {
|
|||
transform.scaled.position.y = 0;
|
||||
}
|
||||
void AddDirtyRect(ScaleData2D scale) {
|
||||
ClipRect rect {
|
||||
.left = std::max(scale.position.x, std::int32_t(0)),
|
||||
.right = std::min(scale.position.x + scale.size.x, sizeX),
|
||||
.top = std::max(scale.position.y, std::int32_t(0)),
|
||||
.bottom = std::min(scale.position.y + scale.size.y, sizeY),
|
||||
};
|
||||
dirtyRects.push_back(rect);
|
||||
dirtyRects.emplace_back(std::max(scale.position.x, std::int32_t(0)), std::min(scale.position.x + scale.size.x, sizeX), std::max(scale.position.y, std::int32_t(0)), std::min(scale.position.y + scale.size.y, sizeY));
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -59,89 +53,99 @@ export namespace Crafter {
|
|||
Rendertarget(std::int16_t sizeX, std::int16_t sizeY) : RendertargetBase(sizeX, sizeY) {
|
||||
|
||||
}
|
||||
void RenderElement(RenderingElement2DBase* element) {
|
||||
#ifdef CRAFTER_TIMING
|
||||
auto start = std::chrono::high_resolution_clock::now();
|
||||
#endif
|
||||
void RenderElement(Transform2D* elementTransform) {
|
||||
RenderingElement2DBase* element = dynamic_cast<RenderingElement2DBase*>(elementTransform);
|
||||
if(element) {
|
||||
#ifdef CRAFTER_TIMING
|
||||
auto start = std::chrono::high_resolution_clock::now();
|
||||
#endif
|
||||
|
||||
if(element->scaled.size.x < 1 || element->scaled.size.y < 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
for(ClipRect dirty : dirtyRects) {
|
||||
dirty.left = std::max(element->scaled.position.x, dirty.left);
|
||||
dirty.top = std::max(element->scaled.position.y, dirty.top);
|
||||
dirty.right = std::min(element->scaled.position.x+element->scaled.size.x, dirty.right);
|
||||
dirty.bottom = std::min(element->scaled.position.y+element->scaled.size.y, dirty.bottom);
|
||||
|
||||
const Vector<std::uint8_t, 4>* src_buffer = element->buffer.data();
|
||||
std::int32_t src_width = element->scaled.size.x;
|
||||
std::int32_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;
|
||||
|
||||
for (std::int32_t x = dirty.left; x < dirty.right; x++) {
|
||||
std::int32_t src_x = x - element->scaled.position.x;
|
||||
|
||||
buffer[y * sizeX + x] = src_buffer[src_y * src_width + src_x];
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case OpaqueType::SemiOpaque:
|
||||
// For semi-opaque, we can avoid blending when alpha is 0 or 255
|
||||
for (std::int32_t y = dirty.top; y < dirty.bottom; y++) {
|
||||
std::int32_t src_y = y - element->scaled.position.y;
|
||||
|
||||
for (std::int32_t x = dirty.left; x < dirty.right; x++) {
|
||||
std::int32_t src_x = x - element->scaled.position.x;
|
||||
Vector<std::uint8_t, 4> src_pixel = src_buffer[src_y * src_width + src_x];
|
||||
|
||||
if (src_pixel.a == 0) {
|
||||
continue;
|
||||
}
|
||||
buffer[y * sizeX + x] = src_pixel;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case OpaqueType::Transparent:
|
||||
// For transparent, always perform blending
|
||||
for (std::int32_t y = dirty.top; y < dirty.bottom; y++) {
|
||||
std::int32_t src_y = y - element->scaled.position.y;
|
||||
for (std::int32_t x = dirty.left; x < dirty.right; x++) {
|
||||
std::int32_t src_x = x - element->scaled.position.x;
|
||||
Vector<T, Channels, Alignment> src = src_buffer[src_y * src_width + src_x];
|
||||
Vector<T, Channels, Alignment> dst = buffer[y * sizeX + x];
|
||||
|
||||
if(src.a == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
float srcA = src.a / 255.0f;
|
||||
float dstA = dst.a / 255.0f;
|
||||
|
||||
float outA = srcA + dstA * (1.0f - srcA);
|
||||
buffer[y * sizeX + x] = Vector<T, Channels, Alignment>(
|
||||
static_cast<T>((src.r * srcA + dst.r * dstA * (1.0f - srcA)) / outA),
|
||||
static_cast<T>((src.g * srcA + dst.g * dstA * (1.0f - srcA)) / outA),
|
||||
static_cast<T>((src.b * srcA + dst.b * dstA * (1.0f - srcA)) / outA),
|
||||
static_cast<T>(outA * 255)
|
||||
);
|
||||
}
|
||||
}
|
||||
break;
|
||||
if(element->scaled.size.x < 1 || element->scaled.size.y < 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
for(ClipRect dirty : dirtyRects) {
|
||||
dirty.left = std::max(element->scaled.position.x, dirty.left);
|
||||
dirty.top = std::max(element->scaled.position.y, dirty.top);
|
||||
dirty.right = std::min(element->scaled.position.x+element->scaled.size.x, dirty.right);
|
||||
dirty.bottom = std::min(element->scaled.position.y+element->scaled.size.y, dirty.bottom);
|
||||
|
||||
const Vector<std::uint8_t, 4>* src_buffer = element->buffer.data();
|
||||
std::int32_t src_width = element->scaled.size.x;
|
||||
std::int32_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;
|
||||
|
||||
for (std::int32_t x = dirty.left; x < dirty.right; x++) {
|
||||
std::int32_t src_x = x - element->scaled.position.x;
|
||||
|
||||
buffer[y * sizeX + x] = src_buffer[src_y * src_width + src_x];
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case OpaqueType::SemiOpaque:
|
||||
// For semi-opaque, we can avoid blending when alpha is 0 or 255
|
||||
for (std::int32_t y = dirty.top; y < dirty.bottom; y++) {
|
||||
std::int32_t src_y = y - element->scaled.position.y;
|
||||
|
||||
for (std::int32_t x = dirty.left; x < dirty.right; x++) {
|
||||
std::int32_t src_x = x - element->scaled.position.x;
|
||||
Vector<std::uint8_t, 4> src_pixel = src_buffer[src_y * src_width + src_x];
|
||||
|
||||
if (src_pixel.a == 0) {
|
||||
continue;
|
||||
}
|
||||
buffer[y * sizeX + x] = src_pixel;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case OpaqueType::Transparent:
|
||||
// For transparent, always perform blending
|
||||
for (std::int32_t y = dirty.top; y < dirty.bottom; y++) {
|
||||
std::int32_t src_y = y - element->scaled.position.y;
|
||||
for (std::int32_t x = dirty.left; x < dirty.right; x++) {
|
||||
std::int32_t src_x = x - element->scaled.position.x;
|
||||
Vector<T, Channels, Alignment> src = src_buffer[src_y * src_width + src_x];
|
||||
Vector<T, Channels, Alignment> dst = buffer[y * sizeX + x];
|
||||
|
||||
if(src.a == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
float srcA = src.a / 255.0f;
|
||||
float dstA = dst.a / 255.0f;
|
||||
|
||||
float outA = srcA + dstA * (1.0f - srcA);
|
||||
buffer[y * sizeX + x] = Vector<T, Channels, Alignment>(
|
||||
static_cast<T>((src.r * srcA + dst.r * dstA * (1.0f - srcA)) / outA),
|
||||
static_cast<T>((src.g * srcA + dst.g * dstA * (1.0f - srcA)) / outA),
|
||||
static_cast<T>((src.b * srcA + dst.b * dstA * (1.0f - srcA)) / outA),
|
||||
static_cast<T>(outA * 255)
|
||||
);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
#ifdef CRAFTER_TIMING
|
||||
auto end = std::chrono::high_resolution_clock::now();
|
||||
renderTimings.push_back({element, element->scaled.size.x, element->scaled.size.y, end-start});
|
||||
#endif
|
||||
}
|
||||
std::sort(elementTransform->children.begin(), elementTransform->children.end(), [](Transform2D* a, Transform2D* b){ return a->anchor.z < b->anchor.z; });
|
||||
for(Transform2D* child : elementTransform->children) {
|
||||
this->RenderElement(child);
|
||||
}
|
||||
#ifdef CRAFTER_TIMING
|
||||
auto end = std::chrono::high_resolution_clock::now();
|
||||
renderTimings.push_back({element, element->scaled.size.x, element->scaled.size.y, end-start});
|
||||
#endif
|
||||
}
|
||||
void Render() {
|
||||
elements.erase(std::remove(elements.begin(), elements.end(), static_cast<Transform2D*>(nullptr)), elements.end());
|
||||
std::sort(elements.begin(), elements.end(), [](Transform2D* a, Transform2D* b){ return a->anchor.z < b->anchor.z; });
|
||||
|
||||
//std::vector<ClipRect> newClip;
|
||||
// for (std::uint32_t i = 0; i < dirtyRects.size(); i++) {
|
||||
// ClipRect rect = dirtyRects[i];
|
||||
|
|
@ -250,7 +254,7 @@ export namespace Crafter {
|
|||
}
|
||||
}
|
||||
|
||||
for(RenderingElement2DBase* child : elements) {
|
||||
for(Transform2D* child : elements) {
|
||||
RenderElement(child);
|
||||
}
|
||||
dirtyRects.clear();
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue