This commit is contained in:
tildearrow 2024-04-08 03:40:16 -05:00
parent 484f6570aa
commit d4c48a06a1

View file

@ -32,14 +32,11 @@ static ImGui_ImplSW_Data* ImGui_ImplSW_GetBackendData()
return ImGui::GetCurrentContext() ? (ImGui_ImplSW_Data*)ImGui::GetIO().BackendRendererUserData : nullptr;
}
// TODO: de-namespace and static-ize
namespace {
struct PaintTarget
{
uint32_t *pixels;
int width;
int height;
ImVec2 scale;// Multiply ImGui (point) coordinates with this to get pixel coordinates.
ImVec2 DisplayPos;
};
@ -55,13 +52,16 @@ namespace {
ColorInt():
u32(0) {}
ColorInt(uint32_t c):
u32(c) {}
ColorInt &operator*=(const ColorInt &other)
{
r = r * other.r / 255;
g = g * other.g / 255;
b = b * other.b / 255;
a = a * other.a / 255;
r = (r * other.r + 255) >> 8;
g = (g * other.g + 255) >> 8;
b = (b * other.b + 255) >> 8;
a = (a * other.a + 255) >> 8;
return *this;
}
};
@ -69,7 +69,7 @@ namespace {
uint32_t blend(const ColorInt &target, const ColorInt &source)
{
if (source.a >= 255) return *reinterpret_cast<const uint32_t *>(&source);
if (source.a >= 255) return source.u32;
return (target.a << 24u) | (((source.b * source.a + target.b * (255 - source.a)) / 255) << 16u)
| (((source.g * source.a + target.g * (255 - source.a)) / 255) << 8u)
| ((source.r * source.a + target.r * (255 - source.a)) / 255);
@ -109,7 +109,7 @@ namespace {
// ----------------------------------------------------------------------------
// Copies of functions in ImGui, inlined for speed:
ImVec4 color_convert_u32_to_float4(ImU32 in)
inline ImVec4 color_convert_u32_to_float4(ImU32 in)
{
const float s = 1.0f / 255.0f;
return ImVec4(((in >> IM_COL32_R_SHIFT) & 0xFF) * s,
@ -118,7 +118,7 @@ namespace {
((in >> IM_COL32_A_SHIFT) & 0xFF) * s);
}
ImU32 color_convert_float4_to_u32(const ImVec4 &in)
inline ImU32 color_convert_float4_to_u32(const ImVec4 &in)
{
ImU32 out;
out = uint32_t(in.x * 255.0f + 0.5f) << IM_COL32_R_SHIFT;
@ -152,19 +152,19 @@ namespace {
// ----------------------------------------------------------------------------
float min3(float a, float b, float c)
inline float min3(float a, float b, float c)
{
if (a < b && a < c) { return a; }
return b < c ? b : c;
}
float max3(float a, float b, float c)
inline float max3(float a, float b, float c)
{
if (a > b && a > c) { return a; }
return b > c ? b : c;
}
float barycentric(const ImVec2 &a, const ImVec2 &b, const ImVec2 &point)
inline float barycentric(const ImVec2 &a, const ImVec2 &b, const ImVec2 &point)
{
return (b.x - a.x) * (point.y - a.y) - (b.y - a.y) * (point.x - a.x);
}
@ -176,16 +176,16 @@ namespace {
inline uint32_t sample_texture(const SWTexture &texture, int x, int y) { return texture.pixels[x + y * texture.width]; }
void paint_uniform_rectangle(const PaintTarget &target,
static void paint_uniform_rectangle(const PaintTarget &target,
const ImVec2 &min_f,
const ImVec2 &max_f,
const ColorInt &color)
{
// Integer bounding box [min, max):
int min_x_i = static_cast<int>(target.scale.x * min_f.x + 0.5f);
int min_y_i = static_cast<int>(target.scale.y * min_f.y + 0.5f);
int max_x_i = static_cast<int>(target.scale.x * max_f.x + 0.5f);
int max_y_i = static_cast<int>(target.scale.y * max_f.y + 0.5f);
int min_x_i = static_cast<int>(min_f.x + 0.5f);
int min_y_i = static_cast<int>(min_f.y + 0.5f);
int max_x_i = static_cast<int>(max_f.x + 0.5f);
int max_y_i = static_cast<int>(max_f.y + 0.5f);
// Clamp to render target:
min_x_i = std::max(min_x_i, 0);
@ -213,14 +213,14 @@ namespace {
}
}
void paint_uniform_textured_rectangle(const PaintTarget &target,
static void paint_uniform_textured_rectangle(const PaintTarget &target,
const SWTexture &texture,
const ImVec4 &clip_rect,
const ImDrawVert &min_v,
const ImDrawVert &max_v)
{
const ImVec2 min_p = ImVec2(target.scale.x * min_v.pos.x, target.scale.y * min_v.pos.y);
const ImVec2 max_p = ImVec2(target.scale.x * max_v.pos.x, target.scale.y * max_v.pos.y);
const ImVec2 min_p = ImVec2(min_v.pos.x, min_v.pos.y);
const ImVec2 max_p = ImVec2(max_v.pos.x, max_v.pos.y);
float distanceX = max_p.x - min_p.x;
float distanceY = max_p.y - min_p.y;
@ -233,10 +233,10 @@ namespace {
float max_y_f = max_p.y;
// Clip against clip_rect:
min_x_f = std::max(min_x_f, target.scale.x * clip_rect.x - target.DisplayPos.x);
min_y_f = std::max(min_y_f, target.scale.y * clip_rect.y - target.DisplayPos.y);
max_x_f = std::min(max_x_f, target.scale.x * clip_rect.z - 0.5f - target.DisplayPos.x);
max_y_f = std::min(max_y_f, target.scale.y * clip_rect.w - 0.5f - target.DisplayPos.y);
min_x_f = std::max(min_x_f, clip_rect.x - target.DisplayPos.x);
min_y_f = std::max(min_y_f, clip_rect.y - target.DisplayPos.y);
max_x_f = std::min(max_x_f, clip_rect.z - 0.5f - target.DisplayPos.x);
max_y_f = std::min(max_y_f, clip_rect.w - 0.5f - target.DisplayPos.y);
// Integer bounding box [min, max):
int min_x_i = static_cast<int>(min_x_f);
@ -250,7 +250,7 @@ namespace {
max_x_i = std::min(max_x_i, target.width);
max_y_i = std::min(max_y_i, target.height);
const auto topleft = ImVec2(min_x_i + 0.5f * target.scale.x, min_y_i + 0.5f * target.scale.y);
const auto topleft = ImVec2(min_x_i + 0.5f, min_y_i + 0.5f);
const ImVec2 delta_uv_per_pixel = {
(max_v.uv.x - min_v.uv.x) / distanceX,
(max_v.uv.y - min_v.uv.y) / distanceY,
@ -273,8 +273,8 @@ namespace {
currentX = startX;
for (int x = min_x_i; x < max_x_i; ++x) {
uint32_t& target_pixel = target.pixels[y * target.width + x];
const auto *targetColorRef = reinterpret_cast<const ColorInt *>(&target_pixel);
const auto *colorRef = reinterpret_cast<const ColorInt *>(&min_v.col);
const ColorInt targetColorRef = ColorInt(target_pixel);
const ColorInt colorRef = ColorInt(min_v.col);
if (texture.isAlpha) {
uint8_t texel = sample_font_texture(texture, currentX, currentY);
@ -283,18 +283,18 @@ namespace {
// The font texture is all black or all white, so optimize for this:
if (texel == 0) { continue; }
if (texel == 255) {
target_pixel = blend(*targetColorRef, *colorRef);
target_pixel = blend(targetColorRef, colorRef);
continue;
}
} else {
auto texColor = sample_texture(texture, currentX, currentY);
auto src_color = reinterpret_cast<ColorInt *>(&texColor);
uint32_t texColor = sample_texture(texture, currentX, currentY);
auto src_color = ColorInt(texColor);
if (deltaX != 0 && currentX < texture.width - 1) { currentX += 1; }
*src_color *= *colorRef;
target_pixel = blend(*targetColorRef, *src_color);
src_color *= colorRef;
target_pixel = blend(targetColorRef, src_color);
}
}
if (deltaY != 0 && currentY < texture.height - 1) { currentY += 1; }
@ -305,23 +305,23 @@ namespace {
// The edge will be the same, but the direction will be the opposite
// (assuming the two triangles have the same winding order).
// Which edge wins? This functions decides.
bool is_dominant_edge(ImVec2 edge)
static bool is_dominant_edge(ImVec2 edge)
{
// return edge.x < 0 || (edge.x == 0 && edge.y > 0);
return edge.y > 0 || (edge.y == 0 && edge.x < 0);
}
// Handles triangles in any winding order (CW/CCW)
void paint_triangle(const PaintTarget &target,
static void paint_triangle(const PaintTarget &target,
const SWTexture *texture,
const ImVec4 &clip_rect,
const ImDrawVert &v0,
const ImDrawVert &v1,
const ImDrawVert &v2)
{
const ImVec2 p0 = ImVec2(target.scale.x * v0.pos.x, target.scale.y * v0.pos.y);
const ImVec2 p1 = ImVec2(target.scale.x * v1.pos.x, target.scale.y * v1.pos.y);
const ImVec2 p2 = ImVec2(target.scale.x * v2.pos.x, target.scale.y * v2.pos.y);
const ImVec2 p0 = ImVec2(v0.pos.x, v0.pos.y);
const ImVec2 p1 = ImVec2(v1.pos.x, v1.pos.y);
const ImVec2 p2 = ImVec2(v2.pos.x, v2.pos.y);
const auto rect_area = barycentric(p0, p1, p2);// Can be positive or negative depending on winding order
if (rect_area == 0.0f) { return; }
@ -334,10 +334,10 @@ namespace {
float max_y_f = max3(p0.y, p1.y, p2.y);
// Clip against clip_rect:
min_x_f = std::max(min_x_f, target.scale.x * clip_rect.x - target.DisplayPos.x);
min_y_f = std::max(min_y_f, target.scale.y * clip_rect.y - target.DisplayPos.y);
max_x_f = std::min(max_x_f, target.scale.x * clip_rect.z - 0.5f - target.DisplayPos.x);
max_y_f = std::min(max_y_f, target.scale.y * clip_rect.w - 0.5f - target.DisplayPos.y);
min_x_f = std::max(min_x_f, clip_rect.x - target.DisplayPos.x);
min_y_f = std::max(min_y_f, clip_rect.y - target.DisplayPos.y);
max_x_f = std::min(max_x_f, clip_rect.z - 0.5f - target.DisplayPos.x);
max_y_f = std::min(max_y_f, clip_rect.w - 0.5f - target.DisplayPos.y);
// Integer bounding box [min, max):
int min_x_i = static_cast<int>(min_x_f);
@ -354,7 +354,7 @@ namespace {
// ------------------------------------------------------------------------
// Set up interpolation of barycentric coordinates:
const auto topleft = ImVec2(min_x_i + 0.5f * target.scale.x, min_y_i + 0.5f * target.scale.y);
const auto topleft = ImVec2(min_x_i + 0.5f, min_y_i + 0.5f);
const auto dx = ImVec2(1, 0);
const auto dy = ImVec2(0, 1);
@ -481,7 +481,7 @@ namespace {
}
}
void paint_draw_cmd(const PaintTarget &target,
static void paint_draw_cmd(const PaintTarget &target,
const ImDrawVert *vertices,
const ImDrawIdx *idx_buffer,
const ImDrawCmd &pcmd,
@ -582,7 +582,7 @@ namespace {
}
}
void paint_draw_list(const PaintTarget &target, const ImDrawList *cmd_list, const SwOptions &options)
static void paint_draw_list(const PaintTarget &target, const ImDrawList *cmd_list, const SwOptions &options)
{
const ImDrawIdx *idx_buffer = &cmd_list->IdxBuffer[0];
const ImDrawVert *vertices = cmd_list->VtxBuffer.Data;
@ -598,15 +598,11 @@ namespace {
}
}
}// namespace
void paint_imgui(uint32_t *pixels, ImDrawData *drawData, const SwOptions &options = {})
static void paint_imgui(uint32_t *pixels, ImDrawData *drawData, int fb_width, int fb_height, const SwOptions &options = {})
{
int fb_width = (int)(drawData->DisplaySize.x * drawData->FramebufferScale.x);
int fb_height = (int)(drawData->DisplaySize.y * drawData->FramebufferScale.y);
if (fb_width <= 0 || fb_height <= 0) return;
PaintTarget target{ pixels, fb_width, fb_height, drawData->FramebufferScale, drawData->DisplayPos };
PaintTarget target{ pixels, fb_width, fb_height, drawData->DisplayPos };
for (int i = 0; i < drawData->CmdListsCount; ++i) {
paint_draw_list(target, drawData->CmdLists[i], options);
@ -662,7 +658,7 @@ void ImGui_ImplSW_RenderDrawData(ImDrawData* draw_data) {
if (mustLock) {
if (SDL_LockSurface(surf)!=0) return;
}
paint_imgui((uint32_t*)surf->pixels,draw_data);
paint_imgui((uint32_t*)surf->pixels,draw_data,surf->w,surf->h);
if (mustLock) {
SDL_UnlockSurface(surf);
}