mirror of
https://github.com/RGBCube/serenity
synced 2025-05-31 10:58:12 +00:00
LibGL: Implement color blending
This implements different blend modes in the SoftwareRasterizer by first setting up the blend factors then rendering the pixels into a temporary buffer and finally mixing the contents of the temporary buffer with the contents of the backbuffer based on the blend factors.
This commit is contained in:
parent
d6e9b433cf
commit
f70a6ff712
1 changed files with 134 additions and 2 deletions
|
@ -38,6 +38,66 @@ static Gfx::RGBA32 to_rgba32(const FloatVector4& v)
|
|||
return a << 24 | b << 16 | g << 8 | r;
|
||||
}
|
||||
|
||||
static FloatVector4 to_vec4(Gfx::RGBA32 rgba)
|
||||
{
|
||||
return {
|
||||
(rgba & 0xff) / 255.0f,
|
||||
((rgba >> 8) & 0xff) / 255.0f,
|
||||
((rgba >> 16) & 0xff) / 255.0f,
|
||||
((rgba >> 24) & 0xff) / 255.0f
|
||||
};
|
||||
}
|
||||
|
||||
static constexpr void setup_blend_factors(GLenum mode, FloatVector4& constant, float& src_alpha, float& dst_alpha, float& src_color, float& dst_color)
|
||||
{
|
||||
constant = { 0.0f, 0.0f, 0.0f, 0.0f };
|
||||
src_alpha = 0;
|
||||
dst_alpha = 0;
|
||||
src_color = 0;
|
||||
dst_color = 0;
|
||||
|
||||
switch (mode) {
|
||||
case GL_ZERO:
|
||||
break;
|
||||
case GL_ONE:
|
||||
constant = { 1.0f, 1.0f, 1.0f, 1.0f };
|
||||
break;
|
||||
case GL_SRC_COLOR:
|
||||
src_color = 1;
|
||||
break;
|
||||
case GL_ONE_MINUS_SRC_COLOR:
|
||||
constant = { 1.0f, 1.0f, 1.0f, 1.0f };
|
||||
src_color = -1;
|
||||
break;
|
||||
case GL_SRC_ALPHA:
|
||||
src_alpha = 1;
|
||||
break;
|
||||
case GL_ONE_MINUS_SRC_ALPHA:
|
||||
constant = { 1.0f, 1.0f, 1.0f, 1.0f };
|
||||
src_alpha = -1;
|
||||
break;
|
||||
case GL_DST_ALPHA:
|
||||
dst_alpha = -1;
|
||||
break;
|
||||
case GL_ONE_MINUS_DST_ALPHA:
|
||||
constant = { 1.0f, 1.0f, 1.0f, 1.0f };
|
||||
dst_alpha = -1;
|
||||
break;
|
||||
case GL_DST_COLOR:
|
||||
dst_color = 1;
|
||||
break;
|
||||
case GL_ONE_MINUS_DST_COLOR:
|
||||
constant = { 1.0f, 1.0f, 1.0f, 1.0f };
|
||||
dst_color = -1;
|
||||
break;
|
||||
case GL_SRC_ALPHA_SATURATE:
|
||||
// FIXME: How do we implement this?
|
||||
break;
|
||||
default:
|
||||
VERIFY_NOT_REACHED();
|
||||
}
|
||||
}
|
||||
|
||||
template<typename PS>
|
||||
static void rasterize_triangle(const RasterizerOptions& options, Gfx::Bitmap& render_target, DepthBuffer& depth_buffer, const GLTriangle& triangle, PS pixel_shader)
|
||||
{
|
||||
|
@ -57,6 +117,36 @@ static void rasterize_triangle(const RasterizerOptions& options, Gfx::Bitmap& re
|
|||
|
||||
float one_over_area = 1.0f / area;
|
||||
|
||||
FloatVector4 src_constant {};
|
||||
float src_factor_src_alpha = 0;
|
||||
float src_factor_dst_alpha = 0;
|
||||
float src_factor_src_color = 0;
|
||||
float src_factor_dst_color = 0;
|
||||
|
||||
FloatVector4 dst_constant {};
|
||||
float dst_factor_src_alpha = 0;
|
||||
float dst_factor_dst_alpha = 0;
|
||||
float dst_factor_src_color = 0;
|
||||
float dst_factor_dst_color = 0;
|
||||
|
||||
if (options.enable_blending) {
|
||||
setup_blend_factors(
|
||||
options.blend_source_factor,
|
||||
src_constant,
|
||||
src_factor_src_alpha,
|
||||
src_factor_dst_alpha,
|
||||
src_factor_src_color,
|
||||
src_factor_dst_color);
|
||||
|
||||
setup_blend_factors(
|
||||
options.blend_source_factor,
|
||||
dst_constant,
|
||||
dst_factor_src_alpha,
|
||||
dst_factor_dst_alpha,
|
||||
dst_factor_src_color,
|
||||
dst_factor_dst_color);
|
||||
}
|
||||
|
||||
// Obey top-left rule:
|
||||
// This sets up "zero" for later pixel coverage tests.
|
||||
// Depending on where on the triangle the edge is located
|
||||
|
@ -97,6 +187,8 @@ static void rasterize_triangle(const RasterizerOptions& options, Gfx::Bitmap& re
|
|||
static_assert(RASTERIZER_BLOCK_SIZE < sizeof(int) * 8, "RASTERIZER_BLOCK_SIZE must be smaller than the pixel_mask's width in bits");
|
||||
int pixel_mask[RASTERIZER_BLOCK_SIZE];
|
||||
|
||||
FloatVector4 pixel_buffer[RASTERIZER_BLOCK_SIZE][RASTERIZER_BLOCK_SIZE];
|
||||
|
||||
// Iterate over all blocks within the bounds of the triangle
|
||||
for (int by = by0; by < by1; by++) {
|
||||
for (int bx = bx0; bx < bx1; bx++) {
|
||||
|
@ -191,7 +283,7 @@ static void rasterize_triangle(const RasterizerOptions& options, Gfx::Bitmap& re
|
|||
continue;
|
||||
}
|
||||
|
||||
auto* pixel = &render_target.scanline(y0 + y)[x0];
|
||||
auto* pixel = pixel_buffer[y];
|
||||
for (int x = 0; x < RASTERIZER_BLOCK_SIZE; x++, coords += dbdx, pixel++) {
|
||||
if (~pixel_mask[y] & (1 << x))
|
||||
continue;
|
||||
|
@ -215,7 +307,47 @@ static void rasterize_triangle(const RasterizerOptions& options, Gfx::Bitmap& re
|
|||
FloatVector2(triangle.vertices[2].u, triangle.vertices[2].v),
|
||||
barycentric);
|
||||
|
||||
*pixel = to_rgba32(pixel_shader(uv, rgba));
|
||||
*pixel = pixel_shader(uv, rgba);
|
||||
}
|
||||
}
|
||||
|
||||
if (options.enable_blending) {
|
||||
// Blend color values from pixel_buffer into render_target
|
||||
for (int y = 0; y < RASTERIZER_BLOCK_SIZE; y++) {
|
||||
auto src = pixel_buffer[y];
|
||||
auto dst = &render_target.scanline(y + y0)[x0];
|
||||
for (int x = 0; x < RASTERIZER_BLOCK_SIZE; x++, src++, dst++) {
|
||||
if (~pixel_mask[y] & (1 << x))
|
||||
continue;
|
||||
|
||||
auto float_dst = to_vec4(*dst);
|
||||
|
||||
auto src_factor = src_constant
|
||||
+ *src * src_factor_src_color
|
||||
+ FloatVector4(src->w(), src->w(), src->w(), src->w()) * src_factor_src_alpha
|
||||
+ float_dst * src_factor_dst_color
|
||||
+ FloatVector4(float_dst.w(), float_dst.w(), float_dst.w(), float_dst.w()) * src_factor_dst_alpha;
|
||||
|
||||
auto dst_factor = dst_constant
|
||||
+ *src * dst_factor_src_color
|
||||
+ FloatVector4(src->w(), src->w(), src->w(), src->w()) * dst_factor_src_alpha
|
||||
+ float_dst * dst_factor_dst_color
|
||||
+ FloatVector4(float_dst.w(), float_dst.w(), float_dst.w(), float_dst.w()) * dst_factor_dst_alpha;
|
||||
|
||||
*dst = to_rgba32(*src * src_factor + float_dst * dst_factor);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Copy color values from pixel_buffer into render_target
|
||||
for (int y = 0; y < RASTERIZER_BLOCK_SIZE; y++) {
|
||||
auto src = pixel_buffer[y];
|
||||
auto dst = &render_target.scanline(y + y0)[x0];
|
||||
for (int x = 0; x < RASTERIZER_BLOCK_SIZE; x++, src++, dst++) {
|
||||
if (~pixel_mask[y] & (1 << x))
|
||||
continue;
|
||||
|
||||
*dst = to_rgba32(*src);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue