software renderer, part E
This commit is contained in:
parent
8b4581e5e6
commit
823876a5c6
106
extern/imgui_software_renderer/imgui_sw.cpp
vendored
106
extern/imgui_software_renderer/imgui_sw.cpp
vendored
|
@ -5,6 +5,7 @@
|
||||||
// publish, and distribute this file as you see fit.
|
// publish, and distribute this file as you see fit.
|
||||||
|
|
||||||
#include "imgui.h"
|
#include "imgui.h"
|
||||||
|
#include "imgui_internal.h"
|
||||||
#ifndef IMGUI_DISABLE
|
#ifndef IMGUI_DISABLE
|
||||||
#include "imgui_sw.hpp"
|
#include "imgui_sw.hpp"
|
||||||
|
|
||||||
|
@ -45,7 +46,11 @@ struct PaintTarget
|
||||||
union ColorInt
|
union ColorInt
|
||||||
{
|
{
|
||||||
struct {
|
struct {
|
||||||
uint8_t r, g, b, a;
|
#ifdef TA_BIG_ENDIAN
|
||||||
|
uint8_t a, r, g, b;
|
||||||
|
#else
|
||||||
|
uint8_t b, g, r, a;
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
uint32_t u32;
|
uint32_t u32;
|
||||||
ColorInt():
|
ColorInt():
|
||||||
|
@ -54,6 +59,10 @@ union ColorInt
|
||||||
ColorInt(uint32_t c):
|
ColorInt(uint32_t c):
|
||||||
u32(c) {}
|
u32(c) {}
|
||||||
|
|
||||||
|
static ColorInt bgra(uint32_t c) {
|
||||||
|
return ColorInt((c&0xff00ff00)|((c&0xff)<<16)|((c&0xff0000)>>16));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
ColorInt &operator*=(const ColorInt &other)
|
ColorInt &operator*=(const ColorInt &other)
|
||||||
{
|
{
|
||||||
|
@ -73,9 +82,9 @@ static inline uint32_t blend(const ColorInt &target, const ColorInt &source)
|
||||||
const unsigned char ia=255-source.a;
|
const unsigned char ia=255-source.a;
|
||||||
return (
|
return (
|
||||||
(target.a << 24u) |
|
(target.a << 24u) |
|
||||||
(((source.b * source.a + target.b * ia + 255) >> 8) << 16u) |
|
(((source.r * source.a + target.r * ia + 255) >> 8) << 16u) |
|
||||||
(((source.g * source.a + target.g * ia + 255) >> 8) << 8u) |
|
(((source.g * source.a + target.g * ia + 255) >> 8) << 8u) |
|
||||||
(((source.r * source.a + target.r * ia + 255) >> 8))
|
(((source.b * source.a + target.b * ia + 255) >> 8) << 0u)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -125,9 +134,9 @@ inline ImVec4 color_convert_u32_to_float4(ImU32 in)
|
||||||
inline ImU32 color_convert_float4_to_u32(const ImVec4 &in)
|
inline ImU32 color_convert_float4_to_u32(const ImVec4 &in)
|
||||||
{
|
{
|
||||||
ImU32 out;
|
ImU32 out;
|
||||||
out = uint32_t(in.x * 255.0f + 0.5f) << IM_COL32_R_SHIFT;
|
out = uint32_t(in.x * 255.0f + 0.5f) << IM_COL32_B_SHIFT;
|
||||||
out |= uint32_t(in.y * 255.0f + 0.5f) << IM_COL32_G_SHIFT;
|
out |= uint32_t(in.y * 255.0f + 0.5f) << IM_COL32_G_SHIFT;
|
||||||
out |= uint32_t(in.z * 255.0f + 0.5f) << IM_COL32_B_SHIFT;
|
out |= uint32_t(in.z * 255.0f + 0.5f) << IM_COL32_R_SHIFT;
|
||||||
out |= uint32_t(in.w * 255.0f + 0.5f) << IM_COL32_A_SHIFT;
|
out |= uint32_t(in.w * 255.0f + 0.5f) << IM_COL32_A_SHIFT;
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
@ -175,16 +184,19 @@ inline float barycentric(const ImVec2 &a, const ImVec2 &b, const ImVec2 &point)
|
||||||
|
|
||||||
inline uint8_t sample_font_texture(const SWTexture &texture, int x, int y)
|
inline uint8_t sample_font_texture(const SWTexture &texture, int x, int y)
|
||||||
{
|
{
|
||||||
return ((const uint8_t*)texture.pixels)[x + y * texture.width];
|
return ((const uint8_t*)texture.pixels)[x + y];
|
||||||
}
|
}
|
||||||
|
|
||||||
inline uint32_t sample_texture(const SWTexture &texture, int x, int y) { return texture.pixels[x + y * texture.width]; }
|
inline uint32_t sample_texture(const SWTexture &texture, int x, int y) { return texture.pixels[x + y]; }
|
||||||
|
|
||||||
static void paint_uniform_rectangle(const PaintTarget &target,
|
static void paint_uniform_rectangle(const PaintTarget &target,
|
||||||
const ImVec2 &min_f,
|
const ImVec2 &min_f,
|
||||||
const ImVec2 &max_f,
|
const ImVec2 &max_f,
|
||||||
const ColorInt &color)
|
const ColorInt &color)
|
||||||
{
|
{
|
||||||
|
// don't if our rectangle is transparent
|
||||||
|
if (color.a==0) return;
|
||||||
|
|
||||||
// Integer bounding box [min, max):
|
// Integer bounding box [min, max):
|
||||||
int min_x_i = (int)(min_f.x + 0.5f);
|
int min_x_i = (int)(min_f.x + 0.5f);
|
||||||
int min_y_i = (int)(min_f.y + 0.5f);
|
int min_y_i = (int)(min_f.y + 0.5f);
|
||||||
|
@ -197,23 +209,34 @@ static void paint_uniform_rectangle(const PaintTarget &target,
|
||||||
max_x_i = std::min(max_x_i, target.width);
|
max_x_i = std::min(max_x_i, target.width);
|
||||||
max_y_i = std::min(max_y_i, target.height);
|
max_y_i = std::min(max_y_i, target.height);
|
||||||
|
|
||||||
// We often blend the same colors over and over again, so optimize for this (saves 25% total cpu):
|
if (color.a==255) {
|
||||||
uint32_t last_target_pixel = target.pixels[min_y_i * target.width + min_x_i];
|
// fast path if alpha blending is not necessary
|
||||||
const ColorInt* lastColorRef = (const ColorInt*)(&last_target_pixel);
|
for (int y = min_y_i; y < max_y_i; ++y) {
|
||||||
uint32_t last_output = blend(*lastColorRef, color);
|
uint32_t* target_pixel = &target.pixels[y * target.width + min_x_i - 1];
|
||||||
|
for (int x = min_x_i; x < max_x_i; ++x) {
|
||||||
for (int y = min_y_i; y < max_y_i; ++y) {
|
++target_pixel;
|
||||||
uint32_t* target_pixel = &target.pixels[y * target.width + min_x_i - 1];
|
*target_pixel = color.u32;
|
||||||
for (int x = min_x_i; x < max_x_i; ++x) {
|
}
|
||||||
++target_pixel;
|
}
|
||||||
if (*target_pixel == last_target_pixel) {
|
} else {
|
||||||
*target_pixel = last_output;
|
// We often blend the same colors over and over again, so optimize for this (saves 25% total cpu):
|
||||||
continue;
|
uint32_t last_target_pixel = target.pixels[min_y_i * target.width + min_x_i];
|
||||||
|
const ColorInt* lastColorRef = (const ColorInt*)(&last_target_pixel);
|
||||||
|
uint32_t last_output = blend(*lastColorRef, color);
|
||||||
|
|
||||||
|
for (int y = min_y_i; y < max_y_i; ++y) {
|
||||||
|
uint32_t* target_pixel = &target.pixels[y * target.width + min_x_i - 1];
|
||||||
|
for (int x = min_x_i; x < max_x_i; ++x) {
|
||||||
|
++target_pixel;
|
||||||
|
if (*target_pixel == last_target_pixel) {
|
||||||
|
*target_pixel = last_output;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
last_target_pixel = *target_pixel;
|
||||||
|
const ColorInt* colorRef = (const ColorInt*)(target_pixel);
|
||||||
|
*target_pixel = blend(*colorRef, color);
|
||||||
|
last_output = *target_pixel;
|
||||||
}
|
}
|
||||||
last_target_pixel = *target_pixel;
|
|
||||||
const ColorInt* colorRef = (const ColorInt*)(target_pixel);
|
|
||||||
*target_pixel = blend(*colorRef, color);
|
|
||||||
last_output = *target_pixel;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -269,29 +292,30 @@ static void paint_uniform_textured_rectangle(const PaintTarget &target,
|
||||||
int startY = uv_topleft.y * (texture.height - 1.0f) + 0.5f;
|
int startY = uv_topleft.y * (texture.height - 1.0f) + 0.5f;
|
||||||
|
|
||||||
int currentX = startX;
|
int currentX = startX;
|
||||||
int currentY = startY;
|
int currentY = startY * texture.width;
|
||||||
|
|
||||||
float deltaX = delta_uv_per_pixel.x * texture.width;
|
float deltaX = delta_uv_per_pixel.x * texture.width;
|
||||||
float deltaY = delta_uv_per_pixel.y * texture.height;
|
float deltaY = delta_uv_per_pixel.y * texture.height;
|
||||||
|
|
||||||
|
const ColorInt colorRef = ColorInt::bgra(min_v.col);
|
||||||
|
|
||||||
for (int y = min_y_i; y < max_y_i; ++y) {
|
for (int y = min_y_i; y < max_y_i; ++y) {
|
||||||
currentX = startX;
|
currentX = startX;
|
||||||
uint32_t* target_pixel = &target.pixels[y * target.width - 1 + min_x_i];
|
uint32_t* target_pixel = &target.pixels[y * target.width - 1 + min_x_i];
|
||||||
for (int x = min_x_i; x < max_x_i; ++x) {
|
for (int x = min_x_i; x < max_x_i; ++x) {
|
||||||
++target_pixel;
|
++target_pixel;
|
||||||
const ColorInt* targetColorRef = (const ColorInt*)(target_pixel);
|
const ColorInt* targetColorRef = (const ColorInt*)(target_pixel);
|
||||||
const ColorInt* colorRef = (const ColorInt*)(&min_v.col);
|
|
||||||
|
|
||||||
if (texture.isAlpha) {
|
if (texture.isAlpha) {
|
||||||
uint8_t texel = sample_font_texture(texture, currentX, currentY);
|
uint8_t texel = sample_font_texture(texture, currentX, currentY);
|
||||||
if (deltaX != 0 && currentX < texture.width - 1) { currentX += 1; }
|
if (deltaX != 0 && currentX < texture.width - 1) { currentX += 1; }
|
||||||
|
|
||||||
// The font texture is all black or all white, so optimize for this:
|
// The font texture is all black or all white, so optimize for this:
|
||||||
if (texel == 0) { continue; }
|
// anti-aliasing will be lost, but it doesn't matter
|
||||||
if (texel == 255) {
|
if (texel & 0x80) {
|
||||||
*target_pixel = blend(*targetColorRef, *colorRef);
|
*target_pixel = blend(*targetColorRef, colorRef);
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
continue;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
uint32_t texColor = sample_texture(texture, currentX, currentY);
|
uint32_t texColor = sample_texture(texture, currentX, currentY);
|
||||||
|
@ -299,11 +323,11 @@ static void paint_uniform_textured_rectangle(const PaintTarget &target,
|
||||||
|
|
||||||
if (deltaX != 0 && currentX < texture.width - 1) { currentX += 1; }
|
if (deltaX != 0 && currentX < texture.width - 1) { currentX += 1; }
|
||||||
|
|
||||||
src_color *= *colorRef;
|
src_color *= colorRef;
|
||||||
*target_pixel = blend(*targetColorRef, src_color);
|
*target_pixel = blend(*targetColorRef, src_color);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (deltaY != 0 && currentY < texture.height - 1) { currentY += 1; }
|
if (deltaY != 0 && currentY < (texture.height - 1)*texture.width) { currentY += texture.width; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -411,8 +435,8 @@ static void paint_triangle(const PaintTarget &target,
|
||||||
// We often blend the same colors over and over again, so optimize for this (saves 10% total cpu):
|
// We often blend the same colors over and over again, so optimize for this (saves 10% total cpu):
|
||||||
uint32_t last_target_pixel = 0;
|
uint32_t last_target_pixel = 0;
|
||||||
const ColorInt* lastColorRef = (const ColorInt*)(&last_target_pixel);
|
const ColorInt* lastColorRef = (const ColorInt*)(&last_target_pixel);
|
||||||
const ColorInt* colorRef = (const ColorInt*)(&v0.col);
|
const ColorInt colorRef = ColorInt::bgra(v0.col);
|
||||||
uint32_t last_output = blend(*lastColorRef, *colorRef);
|
uint32_t last_output = blend(*lastColorRef, colorRef);
|
||||||
|
|
||||||
for (int y = min_y_i; y < max_y_i; ++y) {
|
for (int y = min_y_i; y < max_y_i; ++y) {
|
||||||
auto bary = bary_current_row;
|
auto bary = bary_current_row;
|
||||||
|
@ -449,7 +473,7 @@ static void paint_triangle(const PaintTarget &target,
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
last_target_pixel = target_pixel;
|
last_target_pixel = target_pixel;
|
||||||
target_pixel = blend(*lastColorRef, *colorRef);
|
target_pixel = blend(*lastColorRef, colorRef);
|
||||||
last_output = target_pixel;
|
last_output = target_pixel;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -491,14 +515,12 @@ static void paint_draw_cmd(const PaintTarget &target,
|
||||||
const ImDrawVert *vertices,
|
const ImDrawVert *vertices,
|
||||||
const ImDrawIdx *idx_buffer,
|
const ImDrawIdx *idx_buffer,
|
||||||
const ImDrawCmd &pcmd,
|
const ImDrawCmd &pcmd,
|
||||||
const SwOptions &options)
|
const SwOptions &options,
|
||||||
|
const ImVec2& white_uv)
|
||||||
{
|
{
|
||||||
const SWTexture* texture = (const SWTexture*)(pcmd.TextureId);
|
const SWTexture* texture = (const SWTexture*)(pcmd.TextureId);
|
||||||
IM_ASSERT(texture);
|
IM_ASSERT(texture);
|
||||||
|
|
||||||
// ImGui uses the first pixel for "white".
|
|
||||||
const ImVec2 white_uv = ImVec2(0.5f / texture->width, 0.5f / texture->height);
|
|
||||||
|
|
||||||
for (unsigned int i = 0; i + 3 <= pcmd.ElemCount;) {
|
for (unsigned int i = 0; i + 3 <= pcmd.ElemCount;) {
|
||||||
ImDrawVert v0 = vertices[idx_buffer[i + 0]];
|
ImDrawVert v0 = vertices[idx_buffer[i + 0]];
|
||||||
ImDrawVert v1 = vertices[idx_buffer[i + 1]];
|
ImDrawVert v1 = vertices[idx_buffer[i + 1]];
|
||||||
|
@ -560,8 +582,8 @@ static void paint_draw_cmd(const PaintTarget &target,
|
||||||
}// Completely clipped
|
}// Completely clipped
|
||||||
|
|
||||||
if (has_uniform_color) {
|
if (has_uniform_color) {
|
||||||
const ColorInt* colorRef = (const ColorInt*)(&v0.col);
|
const ColorInt colorRef = ColorInt::bgra(v0.col);
|
||||||
paint_uniform_rectangle(target, min, max, *colorRef);
|
paint_uniform_rectangle(target, min, max, colorRef);
|
||||||
i += 6;
|
i += 6;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -578,13 +600,14 @@ static void paint_draw_list(const PaintTarget &target, const ImDrawList *cmd_lis
|
||||||
{
|
{
|
||||||
const ImDrawIdx *idx_buffer = &cmd_list->IdxBuffer[0];
|
const ImDrawIdx *idx_buffer = &cmd_list->IdxBuffer[0];
|
||||||
const ImDrawVert *vertices = cmd_list->VtxBuffer.Data;
|
const ImDrawVert *vertices = cmd_list->VtxBuffer.Data;
|
||||||
|
const ImVec2 white_uv = cmd_list->_Data->TexUvWhitePixel;
|
||||||
|
|
||||||
for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.size(); cmd_i++) {
|
for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.size(); cmd_i++) {
|
||||||
const ImDrawCmd &pcmd = cmd_list->CmdBuffer[cmd_i];
|
const ImDrawCmd &pcmd = cmd_list->CmdBuffer[cmd_i];
|
||||||
if (pcmd.UserCallback) {
|
if (pcmd.UserCallback) {
|
||||||
pcmd.UserCallback(cmd_list, &pcmd);
|
pcmd.UserCallback(cmd_list, &pcmd);
|
||||||
} else {
|
} else {
|
||||||
paint_draw_cmd(target, vertices, idx_buffer, pcmd, options);
|
paint_draw_cmd(target, vertices, idx_buffer, pcmd, options, white_uv);
|
||||||
}
|
}
|
||||||
idx_buffer += pcmd.ElemCount;
|
idx_buffer += pcmd.ElemCount;
|
||||||
}
|
}
|
||||||
|
@ -651,6 +674,7 @@ void ImGui_ImplSW_RenderDrawData(ImDrawData* draw_data) {
|
||||||
if (SDL_LockSurface(surf)!=0) return;
|
if (SDL_LockSurface(surf)!=0) return;
|
||||||
}
|
}
|
||||||
paint_imgui((uint32_t*)surf->pixels,draw_data,surf->w,surf->h);
|
paint_imgui((uint32_t*)surf->pixels,draw_data,surf->w,surf->h);
|
||||||
|
// 0xAARRGGBB
|
||||||
if (mustLock) {
|
if (mustLock) {
|
||||||
SDL_UnlockSurface(surf);
|
SDL_UnlockSurface(surf);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue