1820 lines
73 KiB
C++
1820 lines
73 KiB
C++
// dear imgui: CPU framebuffer renderer backend
|
|
// (supports caller-owned framebuffers/textures in generic packed pixel formats)
|
|
//
|
|
// Implemented features:
|
|
// [X] Renderer: User texture binding. Use 'ImGui_ImplCPU_Texture*' as texture identifier.
|
|
// [X] Renderer: Large meshes support (64k+ vertices) even with 16-bit indices (ImGuiBackendFlags_RendererHasVtxOffset).
|
|
// [X] Renderer: Texture updates support for dynamic font atlas (ImGuiBackendFlags_RendererHasTextures).
|
|
//
|
|
// CHANGELOG
|
|
// 2026-03-16: Added generic packed-pixel format support, builtin formats, Alpha8 textures, and parity-oriented generic paths.
|
|
// 2026-03-15: Initial version, extracted from the SDL surface software renderer.
|
|
|
|
#include "imgui.h"
|
|
#ifndef IMGUI_DISABLE
|
|
#include "imgui_impl_cpu.h"
|
|
|
|
#include <algorithm>
|
|
#include <cmath>
|
|
#include <cstring>
|
|
#include <stdint.h>
|
|
|
|
#if defined(__clang__)
|
|
#pragma clang diagnostic push
|
|
#pragma clang diagnostic ignored "-Wfloat-equal"
|
|
#pragma clang diagnostic ignored "-Wold-style-cast"
|
|
#elif defined(__GNUC__)
|
|
#pragma GCC diagnostic ignored "-Wfloat-equal"
|
|
#endif
|
|
|
|
#if defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)
|
|
#define IMGUI_IMPL_CPU_BIG_ENDIAN 1
|
|
#else
|
|
#define IMGUI_IMPL_CPU_BIG_ENDIAN 0
|
|
#endif
|
|
|
|
#if IMGUI_IMPL_CPU_BIG_ENDIAN
|
|
#define IMGUI_IMPL_CPU_RGBA8888_RMASK 0xFF000000u
|
|
#define IMGUI_IMPL_CPU_RGBA8888_GMASK 0x00FF0000u
|
|
#define IMGUI_IMPL_CPU_RGBA8888_BMASK 0x0000FF00u
|
|
#define IMGUI_IMPL_CPU_RGBA8888_AMASK 0x000000FFu
|
|
#define IMGUI_IMPL_CPU_BGRA8888_RMASK 0x0000FF00u
|
|
#define IMGUI_IMPL_CPU_BGRA8888_GMASK 0x00FF0000u
|
|
#define IMGUI_IMPL_CPU_BGRA8888_BMASK 0xFF000000u
|
|
#define IMGUI_IMPL_CPU_BGRA8888_AMASK 0x000000FFu
|
|
#define IMGUI_IMPL_CPU_ARGB8888_RMASK 0x00FF0000u
|
|
#define IMGUI_IMPL_CPU_ARGB8888_GMASK 0x0000FF00u
|
|
#define IMGUI_IMPL_CPU_ARGB8888_BMASK 0x000000FFu
|
|
#define IMGUI_IMPL_CPU_ARGB8888_AMASK 0xFF000000u
|
|
#define IMGUI_IMPL_CPU_ABGR8888_RMASK 0x000000FFu
|
|
#define IMGUI_IMPL_CPU_ABGR8888_GMASK 0x0000FF00u
|
|
#define IMGUI_IMPL_CPU_ABGR8888_BMASK 0x00FF0000u
|
|
#define IMGUI_IMPL_CPU_ABGR8888_AMASK 0xFF000000u
|
|
#define IMGUI_IMPL_CPU_RGB888_RMASK 0x00FF0000u
|
|
#define IMGUI_IMPL_CPU_RGB888_GMASK 0x0000FF00u
|
|
#define IMGUI_IMPL_CPU_RGB888_BMASK 0x000000FFu
|
|
#define IMGUI_IMPL_CPU_BGR888_RMASK 0x000000FFu
|
|
#define IMGUI_IMPL_CPU_BGR888_GMASK 0x0000FF00u
|
|
#define IMGUI_IMPL_CPU_BGR888_BMASK 0x00FF0000u
|
|
#else
|
|
#define IMGUI_IMPL_CPU_RGBA8888_RMASK 0x000000FFu
|
|
#define IMGUI_IMPL_CPU_RGBA8888_GMASK 0x0000FF00u
|
|
#define IMGUI_IMPL_CPU_RGBA8888_BMASK 0x00FF0000u
|
|
#define IMGUI_IMPL_CPU_RGBA8888_AMASK 0xFF000000u
|
|
#define IMGUI_IMPL_CPU_BGRA8888_RMASK 0x00FF0000u
|
|
#define IMGUI_IMPL_CPU_BGRA8888_GMASK 0x0000FF00u
|
|
#define IMGUI_IMPL_CPU_BGRA8888_BMASK 0x000000FFu
|
|
#define IMGUI_IMPL_CPU_BGRA8888_AMASK 0xFF000000u
|
|
#define IMGUI_IMPL_CPU_ARGB8888_RMASK 0x0000FF00u
|
|
#define IMGUI_IMPL_CPU_ARGB8888_GMASK 0x00FF0000u
|
|
#define IMGUI_IMPL_CPU_ARGB8888_BMASK 0xFF000000u
|
|
#define IMGUI_IMPL_CPU_ARGB8888_AMASK 0x000000FFu
|
|
#define IMGUI_IMPL_CPU_ABGR8888_RMASK 0xFF000000u
|
|
#define IMGUI_IMPL_CPU_ABGR8888_GMASK 0x00FF0000u
|
|
#define IMGUI_IMPL_CPU_ABGR8888_BMASK 0x0000FF00u
|
|
#define IMGUI_IMPL_CPU_ABGR8888_AMASK 0x000000FFu
|
|
#define IMGUI_IMPL_CPU_RGB888_RMASK 0x000000FFu
|
|
#define IMGUI_IMPL_CPU_RGB888_GMASK 0x0000FF00u
|
|
#define IMGUI_IMPL_CPU_RGB888_BMASK 0x00FF0000u
|
|
#define IMGUI_IMPL_CPU_BGR888_RMASK 0x00FF0000u
|
|
#define IMGUI_IMPL_CPU_BGR888_GMASK 0x0000FF00u
|
|
#define IMGUI_IMPL_CPU_BGR888_BMASK 0x000000FFu
|
|
#endif
|
|
|
|
static const ImGui_ImplCPU_PixelFormat GImGui_ImplCPU_BuiltinFormats[ImGui_ImplCPU_BuiltinFormat_COUNT] =
|
|
{
|
|
{ 32, 4, IMGUI_IMPL_CPU_RGBA8888_RMASK, IMGUI_IMPL_CPU_RGBA8888_GMASK, IMGUI_IMPL_CPU_RGBA8888_BMASK, IMGUI_IMPL_CPU_RGBA8888_AMASK, 0, 8, 16, 24, 0, 0, 0, 0, nullptr, 0, nullptr },
|
|
{ 32, 4, IMGUI_IMPL_CPU_BGRA8888_RMASK, IMGUI_IMPL_CPU_BGRA8888_GMASK, IMGUI_IMPL_CPU_BGRA8888_BMASK, IMGUI_IMPL_CPU_BGRA8888_AMASK, 16, 8, 0, 24, 0, 0, 0, 0, nullptr, 0, nullptr },
|
|
{ 32, 4, IMGUI_IMPL_CPU_ARGB8888_RMASK, IMGUI_IMPL_CPU_ARGB8888_GMASK, IMGUI_IMPL_CPU_ARGB8888_BMASK, IMGUI_IMPL_CPU_ARGB8888_AMASK, 8, 16, 24, 0, 0, 0, 0, 0, nullptr, 0, nullptr },
|
|
{ 32, 4, IMGUI_IMPL_CPU_ABGR8888_RMASK, IMGUI_IMPL_CPU_ABGR8888_GMASK, IMGUI_IMPL_CPU_ABGR8888_BMASK, IMGUI_IMPL_CPU_ABGR8888_AMASK, 24, 16, 8, 0, 0, 0, 0, 0, nullptr, 0, nullptr },
|
|
{ 16, 2, 0xF800u, 0x07E0u, 0x001Fu, 0x0000u, 11, 5, 0, 0, 3, 2, 3, 8, nullptr, 0, nullptr },
|
|
{ 16, 2, 0x7C00u, 0x03E0u, 0x001Fu, 0x8000u, 10, 5, 0, 15, 3, 3, 3, 7, nullptr, 0, nullptr },
|
|
{ 16, 2, 0xF000u, 0x0F00u, 0x00F0u, 0x000Fu, 12, 8, 4, 0, 4, 4, 4, 4, nullptr, 0, nullptr },
|
|
{ 24, 3, IMGUI_IMPL_CPU_RGB888_RMASK, IMGUI_IMPL_CPU_RGB888_GMASK, IMGUI_IMPL_CPU_RGB888_BMASK, 0x00000000u, 0, 8, 16, 0, 0, 0, 0, 8, nullptr, 0, nullptr },
|
|
{ 24, 3, IMGUI_IMPL_CPU_BGR888_RMASK, IMGUI_IMPL_CPU_BGR888_GMASK, IMGUI_IMPL_CPU_BGR888_BMASK, 0x00000000u, 16, 8, 0, 0, 0, 0, 0, 8, nullptr, 0, nullptr },
|
|
{ 8, 1, 0x00000000u, 0x00000000u, 0x00000000u, 0x000000FFu, 0, 0, 0, 0, 8, 8, 8, 0, nullptr, 0, nullptr }
|
|
};
|
|
|
|
const ImGui_ImplCPU_PixelFormat* ImGui_ImplCPU_GetBuiltinPixelFormat(ImGui_ImplCPU_BuiltinFormat format)
|
|
{
|
|
if (format < 0 || format >= ImGui_ImplCPU_BuiltinFormat_COUNT)
|
|
return nullptr;
|
|
return &GImGui_ImplCPU_BuiltinFormats[format];
|
|
}
|
|
|
|
enum ImGui_ImplCPU_FormatClass
|
|
{
|
|
ImGui_ImplCPU_FormatClass_FastRGBA32,
|
|
ImGui_ImplCPU_FormatClass_FastBGRA32,
|
|
ImGui_ImplCPU_FormatClass_FastARGB32,
|
|
ImGui_ImplCPU_FormatClass_FastABGR32,
|
|
ImGui_ImplCPU_FormatClass_RGB565,
|
|
ImGui_ImplCPU_FormatClass_ARGB1555,
|
|
ImGui_ImplCPU_FormatClass_RGBA4444,
|
|
ImGui_ImplCPU_FormatClass_RGB888,
|
|
ImGui_ImplCPU_FormatClass_BGR888,
|
|
ImGui_ImplCPU_FormatClass_Alpha8,
|
|
ImGui_ImplCPU_FormatClass_Indexed,
|
|
ImGui_ImplCPU_FormatClass_Generic
|
|
};
|
|
|
|
struct ImGui_ImplCPU_FastFormat32
|
|
{
|
|
ImU32 Rmask;
|
|
ImU32 Gmask;
|
|
ImU32 Bmask;
|
|
ImU32 Amask;
|
|
ImU8 Rshift;
|
|
ImU8 Gshift;
|
|
ImU8 Bshift;
|
|
ImU8 Ashift;
|
|
bool HasAlpha;
|
|
bool Valid;
|
|
|
|
ImGui_ImplCPU_FastFormat32() { memset((void*)this, 0, sizeof(*this)); }
|
|
};
|
|
|
|
struct ImGui_ImplCPU_SurfaceInfo;
|
|
typedef void (*ImGui_ImplCPU_ReadRGBAFn)(const ImGui_ImplCPU_SurfaceInfo& surface, int x, int y, unsigned char* r, unsigned char* g, unsigned char* b, unsigned char* a);
|
|
typedef unsigned char (*ImGui_ImplCPU_ReadAlphaFn)(const ImGui_ImplCPU_SurfaceInfo& surface, int x, int y);
|
|
typedef ImU32 (*ImGui_ImplCPU_PackRGBAFn)(const ImGui_ImplCPU_SurfaceInfo& surface, unsigned char r, unsigned char g, unsigned char b, unsigned char a);
|
|
|
|
struct ImGui_ImplCPU_SurfaceInfo
|
|
{
|
|
unsigned char* Pixels;
|
|
int Pitch;
|
|
int Width;
|
|
int Height;
|
|
const ImGui_ImplCPU_PixelFormat* Format;
|
|
ImGui_ImplCPU_FormatClass Class;
|
|
ImGui_ImplCPU_FastFormat32 FastFormat;
|
|
ImGui_ImplCPU_ReadRGBAFn ReadRGBAFn;
|
|
ImGui_ImplCPU_ReadAlphaFn ReadAlphaFn;
|
|
ImGui_ImplCPU_PackRGBAFn PackRGBAFn;
|
|
bool IsFast;
|
|
bool HasAlpha;
|
|
bool IsAlphaOnly;
|
|
bool IsIndexed;
|
|
|
|
ImGui_ImplCPU_SurfaceInfo() { memset((void*)this, 0, sizeof(*this)); }
|
|
};
|
|
|
|
struct ImGui_ImplCPU_RasterVertex
|
|
{
|
|
float X;
|
|
float Y;
|
|
float U;
|
|
float V;
|
|
float R;
|
|
float G;
|
|
float B;
|
|
float A;
|
|
};
|
|
|
|
struct ImGui_ImplCPU_Quad
|
|
{
|
|
const ImGui_ImplCPU_RasterVertex* TL;
|
|
const ImGui_ImplCPU_RasterVertex* TR;
|
|
const ImGui_ImplCPU_RasterVertex* BR;
|
|
const ImGui_ImplCPU_RasterVertex* BL;
|
|
};
|
|
|
|
struct ImGui_ImplCPU_Data
|
|
{
|
|
ImVector<ImGui_ImplCPU_RasterVertex> VertexCache;
|
|
};
|
|
|
|
static ImGui_ImplCPU_Data* ImGui_ImplCPU_GetBackendData()
|
|
{
|
|
return ImGui::GetCurrentContext() ? (ImGui_ImplCPU_Data*)ImGui::GetIO().BackendRendererUserData : nullptr;
|
|
}
|
|
|
|
static inline const ImGui_ImplCPU_PixelFormat* ImGui_ImplCPU_GetDefaultPixelFormat()
|
|
{
|
|
return ImGui_ImplCPU_GetBuiltinPixelFormat(ImGui_ImplCPU_BuiltinFormat_RGBA8888);
|
|
}
|
|
|
|
static inline float ImGui_ImplCPU_Edge(float ax, float ay, float bx, float by, float px, float py)
|
|
{
|
|
return (bx - ax) * (py - ay) - (by - ay) * (px - ax);
|
|
}
|
|
|
|
static inline bool ImGui_ImplCPU_NearEqual(float a, float b)
|
|
{
|
|
return fabsf(a - b) <= 0.0001f;
|
|
}
|
|
|
|
static inline int ImGui_ImplCPU_ClampInt(int v, int lo, int hi)
|
|
{
|
|
return (v < lo) ? lo : (v > hi ? hi : v);
|
|
}
|
|
|
|
static inline unsigned char ImGui_ImplCPU_ClampByte(float v)
|
|
{
|
|
if (v <= 0.0f)
|
|
return 0;
|
|
if (v >= 255.0f)
|
|
return 255;
|
|
return (unsigned char)(v + 0.5f);
|
|
}
|
|
|
|
static inline unsigned char ImGui_ImplCPU_Mul255(unsigned int a, unsigned int b)
|
|
{
|
|
unsigned int t = a * b + 128;
|
|
return (unsigned char)((t + (t >> 8)) >> 8);
|
|
}
|
|
|
|
static inline unsigned char ImGui_ImplCPU_ExpandBits(ImU32 value, int bits)
|
|
{
|
|
if (bits <= 0)
|
|
return 0;
|
|
if (bits >= 8)
|
|
return (unsigned char)value;
|
|
ImU32 max_value = (1u << bits) - 1u;
|
|
return (unsigned char)((value * 255u + (max_value >> 1)) / max_value);
|
|
}
|
|
|
|
static inline ImU32 ImGui_ImplCPU_CompressBits(unsigned char value, int bits)
|
|
{
|
|
if (bits <= 0)
|
|
return 0;
|
|
if (bits >= 8)
|
|
return value;
|
|
ImU32 max_value = (1u << bits) - 1u;
|
|
return (ImU32)((value * max_value + 127u) / 255u);
|
|
}
|
|
|
|
static inline void ImGui_ImplCPU_UnpackCanonicalRGBA(ImU32 pixel, unsigned char* r, unsigned char* g, unsigned char* b, unsigned char* a)
|
|
{
|
|
*r = (unsigned char)((pixel >> IM_COL32_R_SHIFT) & 0xFF);
|
|
*g = (unsigned char)((pixel >> IM_COL32_G_SHIFT) & 0xFF);
|
|
*b = (unsigned char)((pixel >> IM_COL32_B_SHIFT) & 0xFF);
|
|
*a = (unsigned char)((pixel >> IM_COL32_A_SHIFT) & 0xFF);
|
|
}
|
|
|
|
static inline bool ImGui_ImplCPU_CanUseFastPath(const void* pixels, int pitch)
|
|
{
|
|
#ifdef IMGUI_IMPL_CPU_DISABLE_FAST_PATH
|
|
IM_UNUSED(pixels);
|
|
IM_UNUSED(pitch);
|
|
return false;
|
|
#else
|
|
if (pixels == nullptr || pitch <= 0)
|
|
return false;
|
|
if ((pitch & 3) != 0)
|
|
return false;
|
|
if ((((uintptr_t)pixels) & 3) != 0)
|
|
return false;
|
|
return true;
|
|
#endif
|
|
}
|
|
|
|
static inline bool ImGui_ImplCPU_MatchesFormat(const ImGui_ImplCPU_PixelFormat* format, const ImGui_ImplCPU_PixelFormat* builtin)
|
|
{
|
|
return format->BitsPerPixel == builtin->BitsPerPixel
|
|
&& format->BytesPerPixel == builtin->BytesPerPixel
|
|
&& format->Rmask == builtin->Rmask
|
|
&& format->Gmask == builtin->Gmask
|
|
&& format->Bmask == builtin->Bmask
|
|
&& format->Amask == builtin->Amask
|
|
&& format->Rshift == builtin->Rshift
|
|
&& format->Gshift == builtin->Gshift
|
|
&& format->Bshift == builtin->Bshift
|
|
&& format->Ashift == builtin->Ashift
|
|
&& format->Rloss == builtin->Rloss
|
|
&& format->Gloss == builtin->Gloss
|
|
&& format->Bloss == builtin->Bloss
|
|
&& format->Aloss == builtin->Aloss;
|
|
}
|
|
|
|
static inline ImGui_ImplCPU_FormatClass ImGui_ImplCPU_ClassifyFormat(const ImGui_ImplCPU_PixelFormat* format)
|
|
{
|
|
if (format == nullptr)
|
|
format = ImGui_ImplCPU_GetDefaultPixelFormat();
|
|
|
|
if (format->Palette != nullptr && format->PaletteSize > 0)
|
|
return ImGui_ImplCPU_FormatClass_Indexed;
|
|
if (ImGui_ImplCPU_MatchesFormat(format, ImGui_ImplCPU_GetBuiltinPixelFormat(ImGui_ImplCPU_BuiltinFormat_RGBA8888)))
|
|
return ImGui_ImplCPU_FormatClass_FastRGBA32;
|
|
if (ImGui_ImplCPU_MatchesFormat(format, ImGui_ImplCPU_GetBuiltinPixelFormat(ImGui_ImplCPU_BuiltinFormat_BGRA8888)))
|
|
return ImGui_ImplCPU_FormatClass_FastBGRA32;
|
|
if (ImGui_ImplCPU_MatchesFormat(format, ImGui_ImplCPU_GetBuiltinPixelFormat(ImGui_ImplCPU_BuiltinFormat_ARGB8888)))
|
|
return ImGui_ImplCPU_FormatClass_FastARGB32;
|
|
if (ImGui_ImplCPU_MatchesFormat(format, ImGui_ImplCPU_GetBuiltinPixelFormat(ImGui_ImplCPU_BuiltinFormat_ABGR8888)))
|
|
return ImGui_ImplCPU_FormatClass_FastABGR32;
|
|
if (ImGui_ImplCPU_MatchesFormat(format, ImGui_ImplCPU_GetBuiltinPixelFormat(ImGui_ImplCPU_BuiltinFormat_RGB565)))
|
|
return ImGui_ImplCPU_FormatClass_RGB565;
|
|
if (ImGui_ImplCPU_MatchesFormat(format, ImGui_ImplCPU_GetBuiltinPixelFormat(ImGui_ImplCPU_BuiltinFormat_ARGB1555)))
|
|
return ImGui_ImplCPU_FormatClass_ARGB1555;
|
|
if (ImGui_ImplCPU_MatchesFormat(format, ImGui_ImplCPU_GetBuiltinPixelFormat(ImGui_ImplCPU_BuiltinFormat_RGBA4444)))
|
|
return ImGui_ImplCPU_FormatClass_RGBA4444;
|
|
if (ImGui_ImplCPU_MatchesFormat(format, ImGui_ImplCPU_GetBuiltinPixelFormat(ImGui_ImplCPU_BuiltinFormat_RGB888)))
|
|
return ImGui_ImplCPU_FormatClass_RGB888;
|
|
if (ImGui_ImplCPU_MatchesFormat(format, ImGui_ImplCPU_GetBuiltinPixelFormat(ImGui_ImplCPU_BuiltinFormat_BGR888)))
|
|
return ImGui_ImplCPU_FormatClass_BGR888;
|
|
if (ImGui_ImplCPU_MatchesFormat(format, ImGui_ImplCPU_GetBuiltinPixelFormat(ImGui_ImplCPU_BuiltinFormat_Alpha8)))
|
|
return ImGui_ImplCPU_FormatClass_Alpha8;
|
|
return ImGui_ImplCPU_FormatClass_Generic;
|
|
}
|
|
|
|
static inline ImGui_ImplCPU_FastFormat32 ImGui_ImplCPU_BuildFastFormat(const ImGui_ImplCPU_PixelFormat* format)
|
|
{
|
|
ImGui_ImplCPU_FastFormat32 out;
|
|
if (format == nullptr)
|
|
return out;
|
|
if (format->BitsPerPixel != 32 || format->BytesPerPixel != 4)
|
|
return out;
|
|
if (format->Rloss != 0 || format->Gloss != 0 || format->Bloss != 0)
|
|
return out;
|
|
if (format->Amask != 0 && format->Aloss != 0)
|
|
return out;
|
|
out.Rmask = format->Rmask;
|
|
out.Gmask = format->Gmask;
|
|
out.Bmask = format->Bmask;
|
|
out.Amask = format->Amask;
|
|
out.Rshift = format->Rshift;
|
|
out.Gshift = format->Gshift;
|
|
out.Bshift = format->Bshift;
|
|
out.Ashift = format->Ashift;
|
|
out.HasAlpha = format->Amask != 0;
|
|
out.Valid = true;
|
|
return out;
|
|
}
|
|
|
|
static inline ImU32 ImGui_ImplCPU_ReadPixelRaw(const ImGui_ImplCPU_SurfaceInfo& surface, int x, int y)
|
|
{
|
|
const unsigned char* p = surface.Pixels + (size_t)y * (size_t)surface.Pitch + (size_t)x * (size_t)surface.Format->BytesPerPixel;
|
|
switch (surface.Format->BytesPerPixel)
|
|
{
|
|
case 1:
|
|
return *p;
|
|
case 2:
|
|
{
|
|
ImU16 pixel = 0;
|
|
memcpy(&pixel, p, sizeof(pixel));
|
|
return pixel;
|
|
}
|
|
case 3:
|
|
#if IMGUI_IMPL_CPU_BIG_ENDIAN
|
|
return (ImU32)((p[0] << 16) | (p[1] << 8) | p[2]);
|
|
#else
|
|
return (ImU32)(p[0] | (p[1] << 8) | (p[2] << 16));
|
|
#endif
|
|
case 4:
|
|
{
|
|
ImU32 pixel = 0;
|
|
memcpy(&pixel, p, sizeof(pixel));
|
|
return pixel;
|
|
}
|
|
default:
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
static inline void ImGui_ImplCPU_WritePixelRaw(const ImGui_ImplCPU_SurfaceInfo& surface, int x, int y, ImU32 pixel)
|
|
{
|
|
unsigned char* p = surface.Pixels + (size_t)y * (size_t)surface.Pitch + (size_t)x * (size_t)surface.Format->BytesPerPixel;
|
|
switch (surface.Format->BytesPerPixel)
|
|
{
|
|
case 1:
|
|
*p = (unsigned char)pixel;
|
|
return;
|
|
case 2:
|
|
{
|
|
ImU16 v = (ImU16)pixel;
|
|
memcpy(p, &v, sizeof(v));
|
|
return;
|
|
}
|
|
case 3:
|
|
#if IMGUI_IMPL_CPU_BIG_ENDIAN
|
|
p[0] = (unsigned char)((pixel >> 16) & 0xFF);
|
|
p[1] = (unsigned char)((pixel >> 8) & 0xFF);
|
|
p[2] = (unsigned char)(pixel & 0xFF);
|
|
#else
|
|
p[0] = (unsigned char)(pixel & 0xFF);
|
|
p[1] = (unsigned char)((pixel >> 8) & 0xFF);
|
|
p[2] = (unsigned char)((pixel >> 16) & 0xFF);
|
|
#endif
|
|
return;
|
|
case 4:
|
|
memcpy(p, &pixel, sizeof(pixel));
|
|
return;
|
|
default:
|
|
return;
|
|
}
|
|
}
|
|
|
|
static inline void ImGui_ImplCPU_UnpackFastRGBA(const ImGui_ImplCPU_FastFormat32& format, ImU32 pixel, unsigned char* r, unsigned char* g, unsigned char* b, unsigned char* a)
|
|
{
|
|
*r = (unsigned char)((pixel & format.Rmask) >> format.Rshift);
|
|
*g = (unsigned char)((pixel & format.Gmask) >> format.Gshift);
|
|
*b = (unsigned char)((pixel & format.Bmask) >> format.Bshift);
|
|
*a = format.HasAlpha ? (unsigned char)((pixel & format.Amask) >> format.Ashift) : 255;
|
|
}
|
|
|
|
static inline ImU32 ImGui_ImplCPU_PackFastRGBA(const ImGui_ImplCPU_FastFormat32& format, unsigned char r, unsigned char g, unsigned char b, unsigned char a)
|
|
{
|
|
ImU32 pixel = (((ImU32)r << format.Rshift) & format.Rmask)
|
|
| (((ImU32)g << format.Gshift) & format.Gmask)
|
|
| (((ImU32)b << format.Bshift) & format.Bmask);
|
|
if (format.HasAlpha)
|
|
pixel |= (((ImU32)a << format.Ashift) & format.Amask);
|
|
return pixel;
|
|
}
|
|
|
|
static inline void ImGui_ImplCPU_UnpackGenericRGBA(const ImGui_ImplCPU_PixelFormat* format, ImU32 pixel, unsigned char* r, unsigned char* g, unsigned char* b, unsigned char* a)
|
|
{
|
|
*r = (format->Rmask != 0) ? ImGui_ImplCPU_ExpandBits((pixel & format->Rmask) >> format->Rshift, 8 - format->Rloss) : 0;
|
|
*g = (format->Gmask != 0) ? ImGui_ImplCPU_ExpandBits((pixel & format->Gmask) >> format->Gshift, 8 - format->Gloss) : 0;
|
|
*b = (format->Bmask != 0) ? ImGui_ImplCPU_ExpandBits((pixel & format->Bmask) >> format->Bshift, 8 - format->Bloss) : 0;
|
|
*a = (format->Amask != 0) ? ImGui_ImplCPU_ExpandBits((pixel & format->Amask) >> format->Ashift, 8 - format->Aloss) : 255;
|
|
}
|
|
|
|
static inline ImU32 ImGui_ImplCPU_PackGenericRGBA(const ImGui_ImplCPU_PixelFormat* format, unsigned char r, unsigned char g, unsigned char b, unsigned char a)
|
|
{
|
|
ImU32 pixel = 0;
|
|
if (format->Rmask != 0)
|
|
pixel |= (ImGui_ImplCPU_CompressBits(r, 8 - format->Rloss) << format->Rshift) & format->Rmask;
|
|
if (format->Gmask != 0)
|
|
pixel |= (ImGui_ImplCPU_CompressBits(g, 8 - format->Gloss) << format->Gshift) & format->Gmask;
|
|
if (format->Bmask != 0)
|
|
pixel |= (ImGui_ImplCPU_CompressBits(b, 8 - format->Bloss) << format->Bshift) & format->Bmask;
|
|
if (format->Amask != 0)
|
|
pixel |= (ImGui_ImplCPU_CompressBits(a, 8 - format->Aloss) << format->Ashift) & format->Amask;
|
|
return pixel;
|
|
}
|
|
|
|
static inline ImU32 ImGui_ImplCPU_MapNearestPaletteColor(const ImGui_ImplCPU_PixelFormat* format, unsigned char r, unsigned char g, unsigned char b, unsigned char a)
|
|
{
|
|
if (format->Palette == nullptr || format->PaletteSize <= 0)
|
|
return 0;
|
|
|
|
unsigned int best_distance = 0xFFFFFFFFu;
|
|
int best_index = 0;
|
|
for (int i = 0; i < format->PaletteSize; i++)
|
|
{
|
|
unsigned char pr, pg, pb, pa;
|
|
ImGui_ImplCPU_UnpackCanonicalRGBA(format->Palette[i], &pr, &pg, &pb, &pa);
|
|
int dr = (int)pr - (int)r;
|
|
int dg = (int)pg - (int)g;
|
|
int db = (int)pb - (int)b;
|
|
int da = (int)pa - (int)a;
|
|
unsigned int distance = (unsigned int)(dr * dr + dg * dg + db * db + da * da);
|
|
if (distance < best_distance)
|
|
{
|
|
best_distance = distance;
|
|
best_index = i;
|
|
if (distance == 0)
|
|
break;
|
|
}
|
|
}
|
|
return (ImU32)best_index;
|
|
}
|
|
|
|
static inline void ImGui_ImplCPU_ReadRGBAFast32(const ImGui_ImplCPU_SurfaceInfo& surface, int x, int y, unsigned char* r, unsigned char* g, unsigned char* b, unsigned char* a)
|
|
{
|
|
ImGui_ImplCPU_UnpackFastRGBA(surface.FastFormat, ImGui_ImplCPU_ReadPixelRaw(surface, x, y), r, g, b, a);
|
|
}
|
|
|
|
static inline unsigned char ImGui_ImplCPU_ReadAlphaFast32(const ImGui_ImplCPU_SurfaceInfo& surface, int x, int y)
|
|
{
|
|
if (!surface.FastFormat.HasAlpha)
|
|
return 255;
|
|
ImU32 pixel = ImGui_ImplCPU_ReadPixelRaw(surface, x, y);
|
|
return (unsigned char)((pixel & surface.FastFormat.Amask) >> surface.FastFormat.Ashift);
|
|
}
|
|
|
|
static inline ImU32 ImGui_ImplCPU_PackFast32(const ImGui_ImplCPU_SurfaceInfo& surface, unsigned char r, unsigned char g, unsigned char b, unsigned char a)
|
|
{
|
|
return ImGui_ImplCPU_PackFastRGBA(surface.FastFormat, r, g, b, a);
|
|
}
|
|
|
|
static inline void ImGui_ImplCPU_ReadRGBAGenericSurface(const ImGui_ImplCPU_SurfaceInfo& surface, int x, int y, unsigned char* r, unsigned char* g, unsigned char* b, unsigned char* a)
|
|
{
|
|
ImGui_ImplCPU_UnpackGenericRGBA(surface.Format, ImGui_ImplCPU_ReadPixelRaw(surface, x, y), r, g, b, a);
|
|
}
|
|
|
|
static inline unsigned char ImGui_ImplCPU_ReadAlphaGenericSurface(const ImGui_ImplCPU_SurfaceInfo& surface, int x, int y)
|
|
{
|
|
if (surface.Format->Amask == 0)
|
|
return 255;
|
|
ImU32 pixel = ImGui_ImplCPU_ReadPixelRaw(surface, x, y);
|
|
return ImGui_ImplCPU_ExpandBits((pixel & surface.Format->Amask) >> surface.Format->Ashift, 8 - surface.Format->Aloss);
|
|
}
|
|
|
|
static inline ImU32 ImGui_ImplCPU_PackGenericSurface(const ImGui_ImplCPU_SurfaceInfo& surface, unsigned char r, unsigned char g, unsigned char b, unsigned char a)
|
|
{
|
|
return ImGui_ImplCPU_PackGenericRGBA(surface.Format, r, g, b, a);
|
|
}
|
|
|
|
static inline void ImGui_ImplCPU_ReadRGBAAlpha8Surface(const ImGui_ImplCPU_SurfaceInfo& surface, int x, int y, unsigned char* r, unsigned char* g, unsigned char* b, unsigned char* a)
|
|
{
|
|
IM_UNUSED(surface);
|
|
IM_UNUSED(x);
|
|
IM_UNUSED(y);
|
|
*r = 255;
|
|
*g = 255;
|
|
*b = 255;
|
|
*a = surface.Pixels[(size_t)y * (size_t)surface.Pitch + (size_t)x];
|
|
}
|
|
|
|
static inline unsigned char ImGui_ImplCPU_ReadAlphaAlpha8Surface(const ImGui_ImplCPU_SurfaceInfo& surface, int x, int y)
|
|
{
|
|
return surface.Pixels[(size_t)y * (size_t)surface.Pitch + (size_t)x];
|
|
}
|
|
|
|
static inline ImU32 ImGui_ImplCPU_PackAlpha8Surface(const ImGui_ImplCPU_SurfaceInfo& surface, unsigned char r, unsigned char g, unsigned char b, unsigned char a)
|
|
{
|
|
IM_UNUSED(surface);
|
|
IM_UNUSED(r);
|
|
IM_UNUSED(g);
|
|
IM_UNUSED(b);
|
|
return a;
|
|
}
|
|
|
|
static inline void ImGui_ImplCPU_ReadRGBAIndexedSurface(const ImGui_ImplCPU_SurfaceInfo& surface, int x, int y, unsigned char* r, unsigned char* g, unsigned char* b, unsigned char* a)
|
|
{
|
|
ImU32 index = ImGui_ImplCPU_ReadPixelRaw(surface, x, y);
|
|
if (surface.Format->Palette == nullptr || index >= (ImU32)surface.Format->PaletteSize)
|
|
{
|
|
*r = *g = *b = *a = 0;
|
|
return;
|
|
}
|
|
ImGui_ImplCPU_UnpackCanonicalRGBA(surface.Format->Palette[index], r, g, b, a);
|
|
}
|
|
|
|
static inline unsigned char ImGui_ImplCPU_ReadAlphaIndexedSurface(const ImGui_ImplCPU_SurfaceInfo& surface, int x, int y)
|
|
{
|
|
ImU32 index = ImGui_ImplCPU_ReadPixelRaw(surface, x, y);
|
|
if (surface.Format->Palette == nullptr || index >= (ImU32)surface.Format->PaletteSize)
|
|
return 0;
|
|
return (unsigned char)((surface.Format->Palette[index] >> IM_COL32_A_SHIFT) & 0xFF);
|
|
}
|
|
|
|
static inline ImU32 ImGui_ImplCPU_PackIndexedSurface(const ImGui_ImplCPU_SurfaceInfo& surface, unsigned char r, unsigned char g, unsigned char b, unsigned char a)
|
|
{
|
|
if (surface.Format->MapColorFn != nullptr)
|
|
return surface.Format->MapColorFn(surface.Format, r, g, b, a);
|
|
return ImGui_ImplCPU_MapNearestPaletteColor(surface.Format, r, g, b, a);
|
|
}
|
|
|
|
static inline void ImGui_ImplCPU_ReadRGBARGB565(const ImGui_ImplCPU_SurfaceInfo& surface, int x, int y, unsigned char* r, unsigned char* g, unsigned char* b, unsigned char* a)
|
|
{
|
|
ImU32 pixel = ImGui_ImplCPU_ReadPixelRaw(surface, x, y);
|
|
*r = ImGui_ImplCPU_ExpandBits((pixel >> 11) & 0x1Fu, 5);
|
|
*g = ImGui_ImplCPU_ExpandBits((pixel >> 5) & 0x3Fu, 6);
|
|
*b = ImGui_ImplCPU_ExpandBits(pixel & 0x1Fu, 5);
|
|
*a = 255;
|
|
}
|
|
|
|
static inline unsigned char ImGui_ImplCPU_ReadAlphaOpaqueSurface(const ImGui_ImplCPU_SurfaceInfo& surface, int x, int y)
|
|
{
|
|
IM_UNUSED(surface);
|
|
IM_UNUSED(x);
|
|
IM_UNUSED(y);
|
|
return 255;
|
|
}
|
|
|
|
static inline ImU32 ImGui_ImplCPU_PackRGB565(const ImGui_ImplCPU_SurfaceInfo& surface, unsigned char r, unsigned char g, unsigned char b, unsigned char a)
|
|
{
|
|
IM_UNUSED(surface);
|
|
IM_UNUSED(a);
|
|
return (ImU32)((ImGui_ImplCPU_CompressBits(r, 5) << 11) | (ImGui_ImplCPU_CompressBits(g, 6) << 5) | ImGui_ImplCPU_CompressBits(b, 5));
|
|
}
|
|
|
|
static inline void ImGui_ImplCPU_ReadRGBAARGB1555(const ImGui_ImplCPU_SurfaceInfo& surface, int x, int y, unsigned char* r, unsigned char* g, unsigned char* b, unsigned char* a)
|
|
{
|
|
ImU32 pixel = ImGui_ImplCPU_ReadPixelRaw(surface, x, y);
|
|
*r = ImGui_ImplCPU_ExpandBits((pixel >> 10) & 0x1Fu, 5);
|
|
*g = ImGui_ImplCPU_ExpandBits((pixel >> 5) & 0x1Fu, 5);
|
|
*b = ImGui_ImplCPU_ExpandBits(pixel & 0x1Fu, 5);
|
|
*a = (pixel & 0x8000u) ? 255 : 0;
|
|
}
|
|
|
|
static inline unsigned char ImGui_ImplCPU_ReadAlphaARGB1555(const ImGui_ImplCPU_SurfaceInfo& surface, int x, int y)
|
|
{
|
|
return (ImGui_ImplCPU_ReadPixelRaw(surface, x, y) & 0x8000u) ? 255 : 0;
|
|
}
|
|
|
|
static inline ImU32 ImGui_ImplCPU_PackARGB1555(const ImGui_ImplCPU_SurfaceInfo& surface, unsigned char r, unsigned char g, unsigned char b, unsigned char a)
|
|
{
|
|
IM_UNUSED(surface);
|
|
return (ImU32)(((a >= 128 ? 1u : 0u) << 15) | (ImGui_ImplCPU_CompressBits(r, 5) << 10) | (ImGui_ImplCPU_CompressBits(g, 5) << 5) | ImGui_ImplCPU_CompressBits(b, 5));
|
|
}
|
|
|
|
static inline void ImGui_ImplCPU_ReadRGBARGBA4444(const ImGui_ImplCPU_SurfaceInfo& surface, int x, int y, unsigned char* r, unsigned char* g, unsigned char* b, unsigned char* a)
|
|
{
|
|
ImU32 pixel = ImGui_ImplCPU_ReadPixelRaw(surface, x, y);
|
|
*r = ImGui_ImplCPU_ExpandBits((pixel >> 12) & 0x0Fu, 4);
|
|
*g = ImGui_ImplCPU_ExpandBits((pixel >> 8) & 0x0Fu, 4);
|
|
*b = ImGui_ImplCPU_ExpandBits((pixel >> 4) & 0x0Fu, 4);
|
|
*a = ImGui_ImplCPU_ExpandBits(pixel & 0x0Fu, 4);
|
|
}
|
|
|
|
static inline unsigned char ImGui_ImplCPU_ReadAlphaRGBA4444(const ImGui_ImplCPU_SurfaceInfo& surface, int x, int y)
|
|
{
|
|
return ImGui_ImplCPU_ExpandBits(ImGui_ImplCPU_ReadPixelRaw(surface, x, y) & 0x0Fu, 4);
|
|
}
|
|
|
|
static inline ImU32 ImGui_ImplCPU_PackRGBA4444(const ImGui_ImplCPU_SurfaceInfo& surface, unsigned char r, unsigned char g, unsigned char b, unsigned char a)
|
|
{
|
|
IM_UNUSED(surface);
|
|
return (ImU32)((ImGui_ImplCPU_CompressBits(r, 4) << 12) | (ImGui_ImplCPU_CompressBits(g, 4) << 8) | (ImGui_ImplCPU_CompressBits(b, 4) << 4) | ImGui_ImplCPU_CompressBits(a, 4));
|
|
}
|
|
|
|
static inline void ImGui_ImplCPU_ReadRGBARGB888(const ImGui_ImplCPU_SurfaceInfo& surface, int x, int y, unsigned char* r, unsigned char* g, unsigned char* b, unsigned char* a)
|
|
{
|
|
const unsigned char* p = surface.Pixels + (size_t)y * (size_t)surface.Pitch + (size_t)x * 3u;
|
|
#if IMGUI_IMPL_CPU_BIG_ENDIAN
|
|
*r = p[0];
|
|
*g = p[1];
|
|
*b = p[2];
|
|
#else
|
|
*r = p[0];
|
|
*g = p[1];
|
|
*b = p[2];
|
|
#endif
|
|
*a = 255;
|
|
}
|
|
|
|
static inline ImU32 ImGui_ImplCPU_PackRGB888(const ImGui_ImplCPU_SurfaceInfo& surface, unsigned char r, unsigned char g, unsigned char b, unsigned char a)
|
|
{
|
|
IM_UNUSED(surface);
|
|
IM_UNUSED(a);
|
|
#if IMGUI_IMPL_CPU_BIG_ENDIAN
|
|
return (ImU32)((r << 16) | (g << 8) | b);
|
|
#else
|
|
return (ImU32)(r | (g << 8) | (b << 16));
|
|
#endif
|
|
}
|
|
|
|
static inline void ImGui_ImplCPU_ReadRGBABGR888(const ImGui_ImplCPU_SurfaceInfo& surface, int x, int y, unsigned char* r, unsigned char* g, unsigned char* b, unsigned char* a)
|
|
{
|
|
const unsigned char* p = surface.Pixels + (size_t)y * (size_t)surface.Pitch + (size_t)x * 3u;
|
|
#if IMGUI_IMPL_CPU_BIG_ENDIAN
|
|
*b = p[0];
|
|
*g = p[1];
|
|
*r = p[2];
|
|
#else
|
|
*b = p[0];
|
|
*g = p[1];
|
|
*r = p[2];
|
|
#endif
|
|
*a = 255;
|
|
}
|
|
|
|
static inline ImU32 ImGui_ImplCPU_PackBGR888(const ImGui_ImplCPU_SurfaceInfo& surface, unsigned char r, unsigned char g, unsigned char b, unsigned char a)
|
|
{
|
|
IM_UNUSED(surface);
|
|
IM_UNUSED(a);
|
|
#if IMGUI_IMPL_CPU_BIG_ENDIAN
|
|
return (ImU32)((b << 16) | (g << 8) | r);
|
|
#else
|
|
return (ImU32)(b | (g << 8) | (r << 16));
|
|
#endif
|
|
}
|
|
|
|
static void ImGui_ImplCPU_InitSurfaceInfo(ImGui_ImplCPU_SurfaceInfo* out, const unsigned char* pixels, int pitch, int width, int height, const ImGui_ImplCPU_PixelFormat* format)
|
|
{
|
|
out->Pixels = (unsigned char*)pixels;
|
|
out->Pitch = pitch;
|
|
out->Width = width;
|
|
out->Height = height;
|
|
out->Format = format ? format : ImGui_ImplCPU_GetDefaultPixelFormat();
|
|
out->Class = ImGui_ImplCPU_ClassifyFormat(out->Format);
|
|
out->FastFormat = ImGui_ImplCPU_BuildFastFormat(out->Format);
|
|
out->HasAlpha = out->Format->Amask != 0 || out->Class == ImGui_ImplCPU_FormatClass_Alpha8;
|
|
out->IsAlphaOnly = out->Class == ImGui_ImplCPU_FormatClass_Alpha8;
|
|
out->IsIndexed = out->Class == ImGui_ImplCPU_FormatClass_Indexed;
|
|
out->IsFast = (out->Class == ImGui_ImplCPU_FormatClass_FastRGBA32
|
|
|| out->Class == ImGui_ImplCPU_FormatClass_FastBGRA32
|
|
|| out->Class == ImGui_ImplCPU_FormatClass_FastARGB32
|
|
|| out->Class == ImGui_ImplCPU_FormatClass_FastABGR32)
|
|
&& out->FastFormat.Valid
|
|
&& ImGui_ImplCPU_CanUseFastPath(out->Pixels, out->Pitch);
|
|
|
|
switch (out->Class)
|
|
{
|
|
case ImGui_ImplCPU_FormatClass_FastRGBA32:
|
|
case ImGui_ImplCPU_FormatClass_FastBGRA32:
|
|
case ImGui_ImplCPU_FormatClass_FastARGB32:
|
|
case ImGui_ImplCPU_FormatClass_FastABGR32:
|
|
out->ReadRGBAFn = ImGui_ImplCPU_ReadRGBAFast32;
|
|
out->ReadAlphaFn = ImGui_ImplCPU_ReadAlphaFast32;
|
|
out->PackRGBAFn = ImGui_ImplCPU_PackFast32;
|
|
break;
|
|
case ImGui_ImplCPU_FormatClass_RGB565:
|
|
out->ReadRGBAFn = ImGui_ImplCPU_ReadRGBARGB565;
|
|
out->ReadAlphaFn = ImGui_ImplCPU_ReadAlphaOpaqueSurface;
|
|
out->PackRGBAFn = ImGui_ImplCPU_PackRGB565;
|
|
break;
|
|
case ImGui_ImplCPU_FormatClass_ARGB1555:
|
|
out->ReadRGBAFn = ImGui_ImplCPU_ReadRGBAARGB1555;
|
|
out->ReadAlphaFn = ImGui_ImplCPU_ReadAlphaARGB1555;
|
|
out->PackRGBAFn = ImGui_ImplCPU_PackARGB1555;
|
|
break;
|
|
case ImGui_ImplCPU_FormatClass_RGBA4444:
|
|
out->ReadRGBAFn = ImGui_ImplCPU_ReadRGBARGBA4444;
|
|
out->ReadAlphaFn = ImGui_ImplCPU_ReadAlphaRGBA4444;
|
|
out->PackRGBAFn = ImGui_ImplCPU_PackRGBA4444;
|
|
break;
|
|
case ImGui_ImplCPU_FormatClass_RGB888:
|
|
out->ReadRGBAFn = ImGui_ImplCPU_ReadRGBARGB888;
|
|
out->ReadAlphaFn = ImGui_ImplCPU_ReadAlphaOpaqueSurface;
|
|
out->PackRGBAFn = ImGui_ImplCPU_PackRGB888;
|
|
break;
|
|
case ImGui_ImplCPU_FormatClass_BGR888:
|
|
out->ReadRGBAFn = ImGui_ImplCPU_ReadRGBABGR888;
|
|
out->ReadAlphaFn = ImGui_ImplCPU_ReadAlphaOpaqueSurface;
|
|
out->PackRGBAFn = ImGui_ImplCPU_PackBGR888;
|
|
break;
|
|
case ImGui_ImplCPU_FormatClass_Alpha8:
|
|
out->ReadRGBAFn = ImGui_ImplCPU_ReadRGBAAlpha8Surface;
|
|
out->ReadAlphaFn = ImGui_ImplCPU_ReadAlphaAlpha8Surface;
|
|
out->PackRGBAFn = ImGui_ImplCPU_PackAlpha8Surface;
|
|
break;
|
|
case ImGui_ImplCPU_FormatClass_Indexed:
|
|
out->ReadRGBAFn = ImGui_ImplCPU_ReadRGBAIndexedSurface;
|
|
out->ReadAlphaFn = ImGui_ImplCPU_ReadAlphaIndexedSurface;
|
|
out->PackRGBAFn = ImGui_ImplCPU_PackIndexedSurface;
|
|
break;
|
|
case ImGui_ImplCPU_FormatClass_Generic:
|
|
default:
|
|
out->ReadRGBAFn = ImGui_ImplCPU_ReadRGBAGenericSurface;
|
|
out->ReadAlphaFn = ImGui_ImplCPU_ReadAlphaGenericSurface;
|
|
out->PackRGBAFn = ImGui_ImplCPU_PackGenericSurface;
|
|
break;
|
|
}
|
|
}
|
|
|
|
static inline void ImGui_ImplCPU_InitTextureInfo(ImGui_ImplCPU_SurfaceInfo* out, const ImGui_ImplCPU_Texture* texture)
|
|
{
|
|
ImGui_ImplCPU_InitSurfaceInfo(out,
|
|
texture ? texture->Pixels : nullptr,
|
|
texture ? texture->Pitch : 0,
|
|
texture ? texture->Width : 0,
|
|
texture ? texture->Height : 0,
|
|
texture ? texture->Format : nullptr);
|
|
}
|
|
|
|
static inline void ImGui_ImplCPU_InitBufferInfo(ImGui_ImplCPU_SurfaceInfo* out, ImGui_ImplCPU_Framebuffer* framebuffer)
|
|
{
|
|
ImGui_ImplCPU_InitSurfaceInfo(out,
|
|
framebuffer ? framebuffer->Pixels : nullptr,
|
|
framebuffer ? framebuffer->Pitch : 0,
|
|
framebuffer ? framebuffer->Width : 0,
|
|
framebuffer ? framebuffer->Height : 0,
|
|
framebuffer ? framebuffer->Format : nullptr);
|
|
}
|
|
|
|
static inline void ImGui_ImplCPU_ReadPixelRGBA(const ImGui_ImplCPU_SurfaceInfo& surface, int x, int y, unsigned char* r, unsigned char* g, unsigned char* b, unsigned char* a)
|
|
{
|
|
surface.ReadRGBAFn(surface, x, y, r, g, b, a);
|
|
}
|
|
|
|
static inline unsigned char ImGui_ImplCPU_ReadPixelAlpha(const ImGui_ImplCPU_SurfaceInfo& surface, int x, int y)
|
|
{
|
|
return surface.ReadAlphaFn(surface, x, y);
|
|
}
|
|
|
|
static inline void ImGui_ImplCPU_BlendPixelFast(const ImGui_ImplCPU_SurfaceInfo& target, ImU32* dst, unsigned char sr, unsigned char sg, unsigned char sb, unsigned char sa)
|
|
{
|
|
if (sa == 0)
|
|
return;
|
|
if (sa == 255)
|
|
{
|
|
*dst = ImGui_ImplCPU_PackFastRGBA(target.FastFormat, sr, sg, sb, target.FastFormat.HasAlpha ? 255 : 255);
|
|
return;
|
|
}
|
|
|
|
unsigned char dr, dg, db, da;
|
|
ImGui_ImplCPU_UnpackFastRGBA(target.FastFormat, *dst, &dr, &dg, &db, &da);
|
|
unsigned char inv_a = (unsigned char)(255 - sa);
|
|
unsigned char out_r = (unsigned char)(ImGui_ImplCPU_Mul255(sr, sa) + ImGui_ImplCPU_Mul255(dr, inv_a));
|
|
unsigned char out_g = (unsigned char)(ImGui_ImplCPU_Mul255(sg, sa) + ImGui_ImplCPU_Mul255(dg, inv_a));
|
|
unsigned char out_b = (unsigned char)(ImGui_ImplCPU_Mul255(sb, sa) + ImGui_ImplCPU_Mul255(db, inv_a));
|
|
unsigned char out_a = target.FastFormat.HasAlpha ? (unsigned char)(sa + ImGui_ImplCPU_Mul255(da, inv_a)) : 255;
|
|
*dst = ImGui_ImplCPU_PackFastRGBA(target.FastFormat, out_r, out_g, out_b, out_a);
|
|
}
|
|
|
|
static inline void ImGui_ImplCPU_BlendPixelGeneric(const ImGui_ImplCPU_SurfaceInfo& target, int x, int y, unsigned char sr, unsigned char sg, unsigned char sb, unsigned char sa)
|
|
{
|
|
if (sa == 0)
|
|
return;
|
|
if (sa == 255)
|
|
{
|
|
ImU32 pixel = target.PackRGBAFn(target, sr, sg, sb, target.HasAlpha ? 255 : 255);
|
|
ImGui_ImplCPU_WritePixelRaw(target, x, y, pixel);
|
|
return;
|
|
}
|
|
|
|
unsigned char dr, dg, db, da;
|
|
ImGui_ImplCPU_ReadPixelRGBA(target, x, y, &dr, &dg, &db, &da);
|
|
unsigned char inv_a = (unsigned char)(255 - sa);
|
|
unsigned char out_r = (unsigned char)(ImGui_ImplCPU_Mul255(sr, sa) + ImGui_ImplCPU_Mul255(dr, inv_a));
|
|
unsigned char out_g = (unsigned char)(ImGui_ImplCPU_Mul255(sg, sa) + ImGui_ImplCPU_Mul255(dg, inv_a));
|
|
unsigned char out_b = (unsigned char)(ImGui_ImplCPU_Mul255(sb, sa) + ImGui_ImplCPU_Mul255(db, inv_a));
|
|
unsigned char out_a = target.HasAlpha ? (unsigned char)(sa + ImGui_ImplCPU_Mul255(da, inv_a)) : 255;
|
|
ImU32 pixel = target.PackRGBAFn(target, out_r, out_g, out_b, out_a);
|
|
ImGui_ImplCPU_WritePixelRaw(target, x, y, pixel);
|
|
}
|
|
|
|
static inline bool ImGui_ImplCPU_SameColor(const ImGui_ImplCPU_RasterVertex& a, const ImGui_ImplCPU_RasterVertex& b)
|
|
{
|
|
return a.R == b.R && a.G == b.G && a.B == b.B && a.A == b.A;
|
|
}
|
|
|
|
static inline void ImGui_ImplCPU_SetupRasterVertex(ImGui_ImplCPU_RasterVertex* out, const ImDrawVert& v, const ImVec2& display_pos, const ImVec2& framebuffer_scale)
|
|
{
|
|
out->X = (v.pos.x - display_pos.x) * framebuffer_scale.x;
|
|
out->Y = (v.pos.y - display_pos.y) * framebuffer_scale.y;
|
|
out->U = v.uv.x;
|
|
out->V = v.uv.y;
|
|
out->R = (float)((v.col >> IM_COL32_R_SHIFT) & 0xFF);
|
|
out->G = (float)((v.col >> IM_COL32_G_SHIFT) & 0xFF);
|
|
out->B = (float)((v.col >> IM_COL32_B_SHIFT) & 0xFF);
|
|
out->A = (float)((v.col >> IM_COL32_A_SHIFT) & 0xFF);
|
|
}
|
|
|
|
static void ImGui_ImplCPU_BuildVertexCache(ImVector<ImGui_ImplCPU_RasterVertex>* out, const ImDrawList* draw_list, const ImVec2& display_pos, const ImVec2& framebuffer_scale)
|
|
{
|
|
out->resize(draw_list->VtxBuffer.Size);
|
|
for (int vtx_i = 0; vtx_i < draw_list->VtxBuffer.Size; vtx_i++)
|
|
ImGui_ImplCPU_SetupRasterVertex(&out->Data[vtx_i], draw_list->VtxBuffer[vtx_i], display_pos, framebuffer_scale);
|
|
}
|
|
|
|
static void ImGui_ImplCPU_RenderTriangleFast(const ImGui_ImplCPU_SurfaceInfo& target, const ImGui_ImplCPU_SurfaceInfo* texture, bool texture_is_alpha, const ImGui_ImplCPU_RasterVertex& v0, const ImGui_ImplCPU_RasterVertex& v1, const ImGui_ImplCPU_RasterVertex& v2, int clip_min_x, int clip_min_y, int clip_max_x, int clip_max_y)
|
|
{
|
|
int min_x = std::max((int)std::floor(std::min(v0.X, std::min(v1.X, v2.X))), clip_min_x);
|
|
int min_y = std::max((int)std::floor(std::min(v0.Y, std::min(v1.Y, v2.Y))), clip_min_y);
|
|
int max_x = std::min((int)std::ceil(std::max(v0.X, std::max(v1.X, v2.X))) - 1, clip_max_x - 1);
|
|
int max_y = std::min((int)std::ceil(std::max(v0.Y, std::max(v1.Y, v2.Y))) - 1, clip_max_y - 1);
|
|
if (min_x > max_x || min_y > max_y)
|
|
return;
|
|
|
|
float area = ImGui_ImplCPU_Edge(v0.X, v0.Y, v1.X, v1.Y, v2.X, v2.Y);
|
|
if (area == 0.0f)
|
|
return;
|
|
|
|
float sign = (area < 0.0f) ? -1.0f : 1.0f;
|
|
area *= sign;
|
|
|
|
float e0_dx = (v1.Y - v2.Y) * sign;
|
|
float e0_dy = (v2.X - v1.X) * sign;
|
|
float e1_dx = (v2.Y - v0.Y) * sign;
|
|
float e1_dy = (v0.X - v2.X) * sign;
|
|
float e2_dx = (v0.Y - v1.Y) * sign;
|
|
float e2_dy = (v1.X - v0.X) * sign;
|
|
|
|
float inv_area = 1.0f / area;
|
|
float dw0_dx = e0_dx * inv_area;
|
|
float dw0_dy = e0_dy * inv_area;
|
|
float dw1_dx = e1_dx * inv_area;
|
|
float dw1_dy = e1_dy * inv_area;
|
|
float dw2_dx = e2_dx * inv_area;
|
|
float dw2_dy = e2_dy * inv_area;
|
|
|
|
float dr_dx = dw0_dx * v0.R + dw1_dx * v1.R + dw2_dx * v2.R;
|
|
float dg_dx = dw0_dx * v0.G + dw1_dx * v1.G + dw2_dx * v2.G;
|
|
float db_dx = dw0_dx * v0.B + dw1_dx * v1.B + dw2_dx * v2.B;
|
|
float da_dx = dw0_dx * v0.A + dw1_dx * v1.A + dw2_dx * v2.A;
|
|
float du_dx = dw0_dx * v0.U + dw1_dx * v1.U + dw2_dx * v2.U;
|
|
float dv_dx = dw0_dx * v0.V + dw1_dx * v1.V + dw2_dx * v2.V;
|
|
|
|
float dr_dy = dw0_dy * v0.R + dw1_dy * v1.R + dw2_dy * v2.R;
|
|
float dg_dy = dw0_dy * v0.G + dw1_dy * v1.G + dw2_dy * v2.G;
|
|
float db_dy = dw0_dy * v0.B + dw1_dy * v1.B + dw2_dy * v2.B;
|
|
float da_dy = dw0_dy * v0.A + dw1_dy * v1.A + dw2_dy * v2.A;
|
|
float du_dy = dw0_dy * v0.U + dw1_dy * v1.U + dw2_dy * v2.U;
|
|
float dv_dy = dw0_dy * v0.V + dw1_dy * v1.V + dw2_dy * v2.V;
|
|
|
|
float start_x = (float)min_x + 0.5f;
|
|
float start_y = (float)min_y + 0.5f;
|
|
|
|
float e0_row = ImGui_ImplCPU_Edge(v1.X, v1.Y, v2.X, v2.Y, start_x, start_y) * sign;
|
|
float e1_row = ImGui_ImplCPU_Edge(v2.X, v2.Y, v0.X, v0.Y, start_x, start_y) * sign;
|
|
float e2_row = ImGui_ImplCPU_Edge(v0.X, v0.Y, v1.X, v1.Y, start_x, start_y) * sign;
|
|
|
|
float w0_row = e0_row * inv_area;
|
|
float w1_row = e1_row * inv_area;
|
|
float w2_row = e2_row * inv_area;
|
|
|
|
float r_row = w0_row * v0.R + w1_row * v1.R + w2_row * v2.R;
|
|
float g_row = w0_row * v0.G + w1_row * v1.G + w2_row * v2.G;
|
|
float b_row = w0_row * v0.B + w1_row * v1.B + w2_row * v2.B;
|
|
float a_row = w0_row * v0.A + w1_row * v1.A + w2_row * v2.A;
|
|
float u_row = w0_row * v0.U + w1_row * v1.U + w2_row * v2.U;
|
|
float v_row = w0_row * v0.V + w1_row * v1.V + w2_row * v2.V;
|
|
|
|
int texture_max_x = texture ? (texture->Width - 1) : 0;
|
|
int texture_max_y = texture ? (texture->Height - 1) : 0;
|
|
|
|
if (texture == nullptr)
|
|
{
|
|
for (int y = min_y; y <= max_y; y++)
|
|
{
|
|
float e0 = e0_row;
|
|
float e1 = e1_row;
|
|
float e2 = e2_row;
|
|
float r = r_row;
|
|
float g = g_row;
|
|
float b = b_row;
|
|
float a = a_row;
|
|
ImU32* dst = (ImU32*)(void*)(target.Pixels + (size_t)y * (size_t)target.Pitch) + min_x;
|
|
|
|
for (int x = min_x; x <= max_x; x++)
|
|
{
|
|
if (e0 >= 0.0f && e1 >= 0.0f && e2 >= 0.0f)
|
|
ImGui_ImplCPU_BlendPixelFast(target, dst, ImGui_ImplCPU_ClampByte(r), ImGui_ImplCPU_ClampByte(g), ImGui_ImplCPU_ClampByte(b), ImGui_ImplCPU_ClampByte(a));
|
|
|
|
dst++;
|
|
e0 += e0_dx;
|
|
e1 += e1_dx;
|
|
e2 += e2_dx;
|
|
r += dr_dx;
|
|
g += dg_dx;
|
|
b += db_dx;
|
|
a += da_dx;
|
|
}
|
|
|
|
e0_row += e0_dy;
|
|
e1_row += e1_dy;
|
|
e2_row += e2_dy;
|
|
r_row += dr_dy;
|
|
g_row += dg_dy;
|
|
b_row += db_dy;
|
|
a_row += da_dy;
|
|
}
|
|
return;
|
|
}
|
|
|
|
if (texture_is_alpha)
|
|
{
|
|
for (int y = min_y; y <= max_y; y++)
|
|
{
|
|
float e0 = e0_row;
|
|
float e1 = e1_row;
|
|
float e2 = e2_row;
|
|
float r = r_row;
|
|
float g = g_row;
|
|
float b = b_row;
|
|
float a = a_row;
|
|
float u = u_row;
|
|
float v = v_row;
|
|
ImU32* dst = (ImU32*)(void*)(target.Pixels + (size_t)y * (size_t)target.Pitch) + min_x;
|
|
|
|
for (int x = min_x; x <= max_x; x++)
|
|
{
|
|
if (e0 >= 0.0f && e1 >= 0.0f && e2 >= 0.0f)
|
|
{
|
|
int tx = ImGui_ImplCPU_ClampInt((int)(u * (float)texture_max_x + 0.5f), 0, texture_max_x);
|
|
int ty = ImGui_ImplCPU_ClampInt((int)(v * (float)texture_max_y + 0.5f), 0, texture_max_y);
|
|
ImGui_ImplCPU_BlendPixelFast(target, dst,
|
|
ImGui_ImplCPU_ClampByte(r),
|
|
ImGui_ImplCPU_ClampByte(g),
|
|
ImGui_ImplCPU_ClampByte(b),
|
|
ImGui_ImplCPU_Mul255(ImGui_ImplCPU_ClampByte(a), ImGui_ImplCPU_ReadPixelAlpha(*texture, tx, ty)));
|
|
}
|
|
|
|
dst++;
|
|
e0 += e0_dx;
|
|
e1 += e1_dx;
|
|
e2 += e2_dx;
|
|
r += dr_dx;
|
|
g += dg_dx;
|
|
b += db_dx;
|
|
a += da_dx;
|
|
u += du_dx;
|
|
v += dv_dx;
|
|
}
|
|
|
|
e0_row += e0_dy;
|
|
e1_row += e1_dy;
|
|
e2_row += e2_dy;
|
|
r_row += dr_dy;
|
|
g_row += dg_dy;
|
|
b_row += db_dy;
|
|
a_row += da_dy;
|
|
u_row += du_dy;
|
|
v_row += dv_dy;
|
|
}
|
|
return;
|
|
}
|
|
|
|
for (int y = min_y; y <= max_y; y++)
|
|
{
|
|
float e0 = e0_row;
|
|
float e1 = e1_row;
|
|
float e2 = e2_row;
|
|
float r = r_row;
|
|
float g = g_row;
|
|
float b = b_row;
|
|
float a = a_row;
|
|
float u = u_row;
|
|
float v = v_row;
|
|
ImU32* dst = (ImU32*)(void*)(target.Pixels + (size_t)y * (size_t)target.Pitch) + min_x;
|
|
|
|
for (int x = min_x; x <= max_x; x++)
|
|
{
|
|
if (e0 >= 0.0f && e1 >= 0.0f && e2 >= 0.0f)
|
|
{
|
|
int tx = ImGui_ImplCPU_ClampInt((int)(u * (float)texture_max_x + 0.5f), 0, texture_max_x);
|
|
int ty = ImGui_ImplCPU_ClampInt((int)(v * (float)texture_max_y + 0.5f), 0, texture_max_y);
|
|
unsigned char tr, tg, tb, ta;
|
|
ImGui_ImplCPU_ReadPixelRGBA(*texture, tx, ty, &tr, &tg, &tb, &ta);
|
|
ImGui_ImplCPU_BlendPixelFast(target, dst,
|
|
ImGui_ImplCPU_Mul255(ImGui_ImplCPU_ClampByte(r), tr),
|
|
ImGui_ImplCPU_Mul255(ImGui_ImplCPU_ClampByte(g), tg),
|
|
ImGui_ImplCPU_Mul255(ImGui_ImplCPU_ClampByte(b), tb),
|
|
ImGui_ImplCPU_Mul255(ImGui_ImplCPU_ClampByte(a), ta));
|
|
}
|
|
|
|
dst++;
|
|
e0 += e0_dx;
|
|
e1 += e1_dx;
|
|
e2 += e2_dx;
|
|
r += dr_dx;
|
|
g += dg_dx;
|
|
b += db_dx;
|
|
a += da_dx;
|
|
u += du_dx;
|
|
v += dv_dx;
|
|
}
|
|
|
|
e0_row += e0_dy;
|
|
e1_row += e1_dy;
|
|
e2_row += e2_dy;
|
|
r_row += dr_dy;
|
|
g_row += dg_dy;
|
|
b_row += db_dy;
|
|
a_row += da_dy;
|
|
u_row += du_dy;
|
|
v_row += dv_dy;
|
|
}
|
|
}
|
|
|
|
static void ImGui_ImplCPU_RenderTriangleGeneric(const ImGui_ImplCPU_SurfaceInfo& target, const ImGui_ImplCPU_SurfaceInfo* texture, bool texture_is_alpha, const ImGui_ImplCPU_RasterVertex& v0, const ImGui_ImplCPU_RasterVertex& v1, const ImGui_ImplCPU_RasterVertex& v2, int clip_min_x, int clip_min_y, int clip_max_x, int clip_max_y)
|
|
{
|
|
int min_x = std::max((int)std::floor(std::min(v0.X, std::min(v1.X, v2.X))), clip_min_x);
|
|
int min_y = std::max((int)std::floor(std::min(v0.Y, std::min(v1.Y, v2.Y))), clip_min_y);
|
|
int max_x = std::min((int)std::ceil(std::max(v0.X, std::max(v1.X, v2.X))) - 1, clip_max_x - 1);
|
|
int max_y = std::min((int)std::ceil(std::max(v0.Y, std::max(v1.Y, v2.Y))) - 1, clip_max_y - 1);
|
|
if (min_x > max_x || min_y > max_y)
|
|
return;
|
|
|
|
float area = ImGui_ImplCPU_Edge(v0.X, v0.Y, v1.X, v1.Y, v2.X, v2.Y);
|
|
if (area == 0.0f)
|
|
return;
|
|
|
|
float sign = (area < 0.0f) ? -1.0f : 1.0f;
|
|
area *= sign;
|
|
|
|
float e0_dx = (v1.Y - v2.Y) * sign;
|
|
float e0_dy = (v2.X - v1.X) * sign;
|
|
float e1_dx = (v2.Y - v0.Y) * sign;
|
|
float e1_dy = (v0.X - v2.X) * sign;
|
|
float e2_dx = (v0.Y - v1.Y) * sign;
|
|
float e2_dy = (v1.X - v0.X) * sign;
|
|
|
|
float inv_area = 1.0f / area;
|
|
float dw0_dx = e0_dx * inv_area;
|
|
float dw0_dy = e0_dy * inv_area;
|
|
float dw1_dx = e1_dx * inv_area;
|
|
float dw1_dy = e1_dy * inv_area;
|
|
float dw2_dx = e2_dx * inv_area;
|
|
float dw2_dy = e2_dy * inv_area;
|
|
|
|
float dr_dx = dw0_dx * v0.R + dw1_dx * v1.R + dw2_dx * v2.R;
|
|
float dg_dx = dw0_dx * v0.G + dw1_dx * v1.G + dw2_dx * v2.G;
|
|
float db_dx = dw0_dx * v0.B + dw1_dx * v1.B + dw2_dx * v2.B;
|
|
float da_dx = dw0_dx * v0.A + dw1_dx * v1.A + dw2_dx * v2.A;
|
|
float du_dx = dw0_dx * v0.U + dw1_dx * v1.U + dw2_dx * v2.U;
|
|
float dv_dx = dw0_dx * v0.V + dw1_dx * v1.V + dw2_dx * v2.V;
|
|
|
|
float dr_dy = dw0_dy * v0.R + dw1_dy * v1.R + dw2_dy * v2.R;
|
|
float dg_dy = dw0_dy * v0.G + dw1_dy * v1.G + dw2_dy * v2.G;
|
|
float db_dy = dw0_dy * v0.B + dw1_dy * v1.B + dw2_dy * v2.B;
|
|
float da_dy = dw0_dy * v0.A + dw1_dy * v1.A + dw2_dy * v2.A;
|
|
float du_dy = dw0_dy * v0.U + dw1_dy * v1.U + dw2_dy * v2.U;
|
|
float dv_dy = dw0_dy * v0.V + dw1_dy * v1.V + dw2_dy * v2.V;
|
|
|
|
float start_x = (float)min_x + 0.5f;
|
|
float start_y = (float)min_y + 0.5f;
|
|
|
|
float e0_row = ImGui_ImplCPU_Edge(v1.X, v1.Y, v2.X, v2.Y, start_x, start_y) * sign;
|
|
float e1_row = ImGui_ImplCPU_Edge(v2.X, v2.Y, v0.X, v0.Y, start_x, start_y) * sign;
|
|
float e2_row = ImGui_ImplCPU_Edge(v0.X, v0.Y, v1.X, v1.Y, start_x, start_y) * sign;
|
|
|
|
float w0_row = e0_row * inv_area;
|
|
float w1_row = e1_row * inv_area;
|
|
float w2_row = e2_row * inv_area;
|
|
|
|
float r_row = w0_row * v0.R + w1_row * v1.R + w2_row * v2.R;
|
|
float g_row = w0_row * v0.G + w1_row * v1.G + w2_row * v2.G;
|
|
float b_row = w0_row * v0.B + w1_row * v1.B + w2_row * v2.B;
|
|
float a_row = w0_row * v0.A + w1_row * v1.A + w2_row * v2.A;
|
|
float u_row = w0_row * v0.U + w1_row * v1.U + w2_row * v2.U;
|
|
float v_row = w0_row * v0.V + w1_row * v1.V + w2_row * v2.V;
|
|
|
|
int texture_max_x = texture ? (texture->Width - 1) : 0;
|
|
int texture_max_y = texture ? (texture->Height - 1) : 0;
|
|
|
|
if (texture == nullptr)
|
|
{
|
|
for (int y = min_y; y <= max_y; y++)
|
|
{
|
|
float e0 = e0_row;
|
|
float e1 = e1_row;
|
|
float e2 = e2_row;
|
|
float r = r_row;
|
|
float g = g_row;
|
|
float b = b_row;
|
|
float a = a_row;
|
|
|
|
for (int x = min_x; x <= max_x; x++)
|
|
{
|
|
if (e0 >= 0.0f && e1 >= 0.0f && e2 >= 0.0f)
|
|
ImGui_ImplCPU_BlendPixelGeneric(target, x, y, ImGui_ImplCPU_ClampByte(r), ImGui_ImplCPU_ClampByte(g), ImGui_ImplCPU_ClampByte(b), ImGui_ImplCPU_ClampByte(a));
|
|
|
|
e0 += e0_dx;
|
|
e1 += e1_dx;
|
|
e2 += e2_dx;
|
|
r += dr_dx;
|
|
g += dg_dx;
|
|
b += db_dx;
|
|
a += da_dx;
|
|
}
|
|
|
|
e0_row += e0_dy;
|
|
e1_row += e1_dy;
|
|
e2_row += e2_dy;
|
|
r_row += dr_dy;
|
|
g_row += dg_dy;
|
|
b_row += db_dy;
|
|
a_row += da_dy;
|
|
}
|
|
return;
|
|
}
|
|
|
|
if (texture_is_alpha)
|
|
{
|
|
for (int y = min_y; y <= max_y; y++)
|
|
{
|
|
float e0 = e0_row;
|
|
float e1 = e1_row;
|
|
float e2 = e2_row;
|
|
float r = r_row;
|
|
float g = g_row;
|
|
float b = b_row;
|
|
float a = a_row;
|
|
float u = u_row;
|
|
float v = v_row;
|
|
|
|
for (int x = min_x; x <= max_x; x++)
|
|
{
|
|
if (e0 >= 0.0f && e1 >= 0.0f && e2 >= 0.0f)
|
|
{
|
|
int tx = ImGui_ImplCPU_ClampInt((int)(u * (float)texture_max_x + 0.5f), 0, texture_max_x);
|
|
int ty = ImGui_ImplCPU_ClampInt((int)(v * (float)texture_max_y + 0.5f), 0, texture_max_y);
|
|
ImGui_ImplCPU_BlendPixelGeneric(target, x, y,
|
|
ImGui_ImplCPU_ClampByte(r),
|
|
ImGui_ImplCPU_ClampByte(g),
|
|
ImGui_ImplCPU_ClampByte(b),
|
|
ImGui_ImplCPU_Mul255(ImGui_ImplCPU_ClampByte(a), ImGui_ImplCPU_ReadPixelAlpha(*texture, tx, ty)));
|
|
}
|
|
|
|
e0 += e0_dx;
|
|
e1 += e1_dx;
|
|
e2 += e2_dx;
|
|
r += dr_dx;
|
|
g += dg_dx;
|
|
b += db_dx;
|
|
a += da_dx;
|
|
u += du_dx;
|
|
v += dv_dx;
|
|
}
|
|
|
|
e0_row += e0_dy;
|
|
e1_row += e1_dy;
|
|
e2_row += e2_dy;
|
|
r_row += dr_dy;
|
|
g_row += dg_dy;
|
|
b_row += db_dy;
|
|
a_row += da_dy;
|
|
u_row += du_dy;
|
|
v_row += dv_dy;
|
|
}
|
|
return;
|
|
}
|
|
|
|
for (int y = min_y; y <= max_y; y++)
|
|
{
|
|
float e0 = e0_row;
|
|
float e1 = e1_row;
|
|
float e2 = e2_row;
|
|
float r = r_row;
|
|
float g = g_row;
|
|
float b = b_row;
|
|
float a = a_row;
|
|
float u = u_row;
|
|
float v = v_row;
|
|
|
|
for (int x = min_x; x <= max_x; x++)
|
|
{
|
|
if (e0 >= 0.0f && e1 >= 0.0f && e2 >= 0.0f)
|
|
{
|
|
int tx = ImGui_ImplCPU_ClampInt((int)(u * (float)texture_max_x + 0.5f), 0, texture_max_x);
|
|
int ty = ImGui_ImplCPU_ClampInt((int)(v * (float)texture_max_y + 0.5f), 0, texture_max_y);
|
|
unsigned char tr, tg, tb, ta;
|
|
ImGui_ImplCPU_ReadPixelRGBA(*texture, tx, ty, &tr, &tg, &tb, &ta);
|
|
ImGui_ImplCPU_BlendPixelGeneric(target, x, y,
|
|
ImGui_ImplCPU_Mul255(ImGui_ImplCPU_ClampByte(r), tr),
|
|
ImGui_ImplCPU_Mul255(ImGui_ImplCPU_ClampByte(g), tg),
|
|
ImGui_ImplCPU_Mul255(ImGui_ImplCPU_ClampByte(b), tb),
|
|
ImGui_ImplCPU_Mul255(ImGui_ImplCPU_ClampByte(a), ta));
|
|
}
|
|
|
|
e0 += e0_dx;
|
|
e1 += e1_dx;
|
|
e2 += e2_dx;
|
|
r += dr_dx;
|
|
g += dg_dx;
|
|
b += db_dx;
|
|
a += da_dx;
|
|
u += du_dx;
|
|
v += dv_dx;
|
|
}
|
|
|
|
e0_row += e0_dy;
|
|
e1_row += e1_dy;
|
|
e2_row += e2_dy;
|
|
r_row += dr_dy;
|
|
g_row += dg_dy;
|
|
b_row += db_dy;
|
|
a_row += da_dy;
|
|
u_row += du_dy;
|
|
v_row += dv_dy;
|
|
}
|
|
}
|
|
|
|
static bool ImGui_ImplCPU_DetectQuad(const ImGui_ImplCPU_RasterVertex* vertices, const ImDrawIdx* idx_buffer, int vtx_offset, unsigned int elem_offset, ImGui_ImplCPU_Quad* out)
|
|
{
|
|
int unique_indices[4];
|
|
int unique_count = 0;
|
|
for (int i = 0; i < 6; i++)
|
|
{
|
|
int idx = vtx_offset + idx_buffer[elem_offset + i];
|
|
bool found = false;
|
|
for (int j = 0; j < unique_count; j++)
|
|
if (unique_indices[j] == idx)
|
|
found = true;
|
|
if (!found)
|
|
{
|
|
if (unique_count >= 4)
|
|
return false;
|
|
unique_indices[unique_count++] = idx;
|
|
}
|
|
}
|
|
if (unique_count != 4)
|
|
return false;
|
|
|
|
const ImGui_ImplCPU_RasterVertex* candidates[4];
|
|
for (int i = 0; i < 4; i++)
|
|
candidates[i] = &vertices[unique_indices[i]];
|
|
|
|
float min_x = candidates[0]->X;
|
|
float max_x = candidates[0]->X;
|
|
float min_y = candidates[0]->Y;
|
|
float max_y = candidates[0]->Y;
|
|
for (int i = 1; i < 4; i++)
|
|
{
|
|
min_x = std::min(min_x, candidates[i]->X);
|
|
max_x = std::max(max_x, candidates[i]->X);
|
|
min_y = std::min(min_y, candidates[i]->Y);
|
|
max_y = std::max(max_y, candidates[i]->Y);
|
|
}
|
|
if (!(max_x > min_x) || !(max_y > min_y))
|
|
return false;
|
|
|
|
out->TL = nullptr;
|
|
out->TR = nullptr;
|
|
out->BR = nullptr;
|
|
out->BL = nullptr;
|
|
for (int i = 0; i < 4; i++)
|
|
{
|
|
const ImGui_ImplCPU_RasterVertex* v = candidates[i];
|
|
if (ImGui_ImplCPU_NearEqual(v->X, min_x) && ImGui_ImplCPU_NearEqual(v->Y, min_y))
|
|
out->TL = v;
|
|
else if (ImGui_ImplCPU_NearEqual(v->X, max_x) && ImGui_ImplCPU_NearEqual(v->Y, min_y))
|
|
out->TR = v;
|
|
else if (ImGui_ImplCPU_NearEqual(v->X, max_x) && ImGui_ImplCPU_NearEqual(v->Y, max_y))
|
|
out->BR = v;
|
|
else if (ImGui_ImplCPU_NearEqual(v->X, min_x) && ImGui_ImplCPU_NearEqual(v->Y, max_y))
|
|
out->BL = v;
|
|
else
|
|
return false;
|
|
}
|
|
return out->TL != nullptr && out->TR != nullptr && out->BR != nullptr && out->BL != nullptr;
|
|
}
|
|
|
|
static bool ImGui_ImplCPU_QuadHasConstantColor(const ImGui_ImplCPU_Quad& quad)
|
|
{
|
|
return ImGui_ImplCPU_SameColor(*quad.TL, *quad.TR) && ImGui_ImplCPU_SameColor(*quad.TL, *quad.BR) && ImGui_ImplCPU_SameColor(*quad.TL, *quad.BL);
|
|
}
|
|
|
|
static bool ImGui_ImplCPU_QuadHasLinearUV(const ImGui_ImplCPU_Quad& quad)
|
|
{
|
|
if (!ImGui_ImplCPU_NearEqual(quad.TL->Y, quad.TR->Y) || !ImGui_ImplCPU_NearEqual(quad.BL->Y, quad.BR->Y) || !ImGui_ImplCPU_NearEqual(quad.TL->X, quad.BL->X) || !ImGui_ImplCPU_NearEqual(quad.TR->X, quad.BR->X))
|
|
return false;
|
|
float u = quad.TL->U + (quad.TR->U - quad.TL->U) + (quad.BL->U - quad.TL->U);
|
|
float v = quad.TL->V + (quad.TR->V - quad.TL->V) + (quad.BL->V - quad.TL->V);
|
|
return ImGui_ImplCPU_NearEqual(u, quad.BR->U) && ImGui_ImplCPU_NearEqual(v, quad.BR->V);
|
|
}
|
|
|
|
static bool ImGui_ImplCPU_QuadGetConstantTexel(const ImGui_ImplCPU_SurfaceInfo& texture, const ImGui_ImplCPU_Quad& quad, int* out_x, int* out_y)
|
|
{
|
|
int max_x = texture.Width - 1;
|
|
int max_y = texture.Height - 1;
|
|
int tx = ImGui_ImplCPU_ClampInt((int)(quad.TL->U * (float)max_x + 0.5f), 0, max_x);
|
|
int ty = ImGui_ImplCPU_ClampInt((int)(quad.TL->V * (float)max_y + 0.5f), 0, max_y);
|
|
int corner_tx[3] =
|
|
{
|
|
ImGui_ImplCPU_ClampInt((int)(quad.TR->U * (float)max_x + 0.5f), 0, max_x),
|
|
ImGui_ImplCPU_ClampInt((int)(quad.BR->U * (float)max_x + 0.5f), 0, max_x),
|
|
ImGui_ImplCPU_ClampInt((int)(quad.BL->U * (float)max_x + 0.5f), 0, max_x)
|
|
};
|
|
int corner_ty[3] =
|
|
{
|
|
ImGui_ImplCPU_ClampInt((int)(quad.TR->V * (float)max_y + 0.5f), 0, max_y),
|
|
ImGui_ImplCPU_ClampInt((int)(quad.BR->V * (float)max_y + 0.5f), 0, max_y),
|
|
ImGui_ImplCPU_ClampInt((int)(quad.BL->V * (float)max_y + 0.5f), 0, max_y)
|
|
};
|
|
for (int i = 0; i < 3; i++)
|
|
if (corner_tx[i] != tx || corner_ty[i] != ty)
|
|
return false;
|
|
*out_x = tx;
|
|
*out_y = ty;
|
|
return true;
|
|
}
|
|
|
|
static void ImGui_ImplCPU_RenderSolidRectFast(const ImGui_ImplCPU_SurfaceInfo& target, const ImGui_ImplCPU_Quad& quad, int clip_min_x, int clip_min_y, int clip_max_x, int clip_max_y, unsigned char r, unsigned char g, unsigned char b, unsigned char a)
|
|
{
|
|
int min_x = std::max((int)ceilf(quad.TL->X - 0.5f), clip_min_x);
|
|
int max_x = std::min((int)floorf(quad.TR->X - 0.5f), clip_max_x - 1);
|
|
int min_y = std::max((int)ceilf(quad.TL->Y - 0.5f), clip_min_y);
|
|
int max_y = std::min((int)floorf(quad.BL->Y - 0.5f), clip_max_y - 1);
|
|
if (min_x > max_x || min_y > max_y)
|
|
return;
|
|
|
|
int count = max_x - min_x + 1;
|
|
if (a == 255)
|
|
{
|
|
ImU32 pixel = ImGui_ImplCPU_PackFastRGBA(target.FastFormat, r, g, b, target.FastFormat.HasAlpha ? 255 : 255);
|
|
for (int y = min_y; y <= max_y; y++)
|
|
{
|
|
ImU32* dst = (ImU32*)(void*)(target.Pixels + (size_t)y * (size_t)target.Pitch) + min_x;
|
|
std::fill_n(dst, count, pixel);
|
|
}
|
|
return;
|
|
}
|
|
|
|
for (int y = min_y; y <= max_y; y++)
|
|
{
|
|
ImU32* dst = (ImU32*)(void*)(target.Pixels + (size_t)y * (size_t)target.Pitch) + min_x;
|
|
for (int x = 0; x < count; x++)
|
|
ImGui_ImplCPU_BlendPixelFast(target, dst + x, r, g, b, a);
|
|
}
|
|
}
|
|
|
|
static void ImGui_ImplCPU_RenderSolidRectGeneric(const ImGui_ImplCPU_SurfaceInfo& target, const ImGui_ImplCPU_Quad& quad, int clip_min_x, int clip_min_y, int clip_max_x, int clip_max_y, unsigned char r, unsigned char g, unsigned char b, unsigned char a)
|
|
{
|
|
int min_x = std::max((int)ceilf(quad.TL->X - 0.5f), clip_min_x);
|
|
int max_x = std::min((int)floorf(quad.TR->X - 0.5f), clip_max_x - 1);
|
|
int min_y = std::max((int)ceilf(quad.TL->Y - 0.5f), clip_min_y);
|
|
int max_y = std::min((int)floorf(quad.BL->Y - 0.5f), clip_max_y - 1);
|
|
if (min_x > max_x || min_y > max_y)
|
|
return;
|
|
|
|
ImU32 opaque_pixel = 0;
|
|
if (a == 255)
|
|
opaque_pixel = target.PackRGBAFn(target, r, g, b, target.HasAlpha ? 255 : 255);
|
|
|
|
for (int y = min_y; y <= max_y; y++)
|
|
for (int x = min_x; x <= max_x; x++)
|
|
if (a == 255)
|
|
ImGui_ImplCPU_WritePixelRaw(target, x, y, opaque_pixel);
|
|
else
|
|
ImGui_ImplCPU_BlendPixelGeneric(target, x, y, r, g, b, a);
|
|
}
|
|
|
|
static void ImGui_ImplCPU_RenderTexturedRectFast(const ImGui_ImplCPU_SurfaceInfo& target, const ImGui_ImplCPU_SurfaceInfo& texture, bool texture_is_alpha, const ImGui_ImplCPU_Quad& quad, int clip_min_x, int clip_min_y, int clip_max_x, int clip_max_y)
|
|
{
|
|
int min_x = std::max((int)ceilf(quad.TL->X - 0.5f), clip_min_x);
|
|
int max_x = std::min((int)floorf(quad.TR->X - 0.5f), clip_max_x - 1);
|
|
int min_y = std::max((int)ceilf(quad.TL->Y - 0.5f), clip_min_y);
|
|
int max_y = std::min((int)floorf(quad.BL->Y - 0.5f), clip_max_y - 1);
|
|
if (min_x > max_x || min_y > max_y)
|
|
return;
|
|
|
|
unsigned char color_r = (unsigned char)quad.TL->R;
|
|
unsigned char color_g = (unsigned char)quad.TL->G;
|
|
unsigned char color_b = (unsigned char)quad.TL->B;
|
|
unsigned char color_a = (unsigned char)quad.TL->A;
|
|
float du_dx = (quad.TR->U - quad.TL->U) / (quad.TR->X - quad.TL->X);
|
|
float dv_dx = (quad.TR->V - quad.TL->V) / (quad.TR->X - quad.TL->X);
|
|
float du_dy = (quad.BL->U - quad.TL->U) / (quad.BL->Y - quad.TL->Y);
|
|
float dv_dy = (quad.BL->V - quad.TL->V) / (quad.BL->Y - quad.TL->Y);
|
|
float u_const = quad.TL->U - quad.TL->X * du_dx - quad.TL->Y * du_dy;
|
|
float v_const = quad.TL->V - quad.TL->X * dv_dx - quad.TL->Y * dv_dy;
|
|
int texture_max_x = texture.Width - 1;
|
|
int texture_max_y = texture.Height - 1;
|
|
|
|
for (int y = min_y; y <= max_y; y++)
|
|
{
|
|
float py = (float)y + 0.5f;
|
|
float px = (float)min_x + 0.5f;
|
|
float u = u_const + px * du_dx + py * du_dy;
|
|
float v = v_const + px * dv_dx + py * dv_dy;
|
|
ImU32* dst = (ImU32*)(void*)(target.Pixels + (size_t)y * (size_t)target.Pitch) + min_x;
|
|
|
|
if (texture_is_alpha)
|
|
{
|
|
for (int x = min_x; x <= max_x; x++)
|
|
{
|
|
int tx = ImGui_ImplCPU_ClampInt((int)(u * (float)texture_max_x + 0.5f), 0, texture_max_x);
|
|
int ty = ImGui_ImplCPU_ClampInt((int)(v * (float)texture_max_y + 0.5f), 0, texture_max_y);
|
|
ImGui_ImplCPU_BlendPixelFast(target, dst, color_r, color_g, color_b, ImGui_ImplCPU_Mul255(color_a, ImGui_ImplCPU_ReadPixelAlpha(texture, tx, ty)));
|
|
dst++;
|
|
u += du_dx;
|
|
v += dv_dx;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (int x = min_x; x <= max_x; x++)
|
|
{
|
|
int tx = ImGui_ImplCPU_ClampInt((int)(u * (float)texture_max_x + 0.5f), 0, texture_max_x);
|
|
int ty = ImGui_ImplCPU_ClampInt((int)(v * (float)texture_max_y + 0.5f), 0, texture_max_y);
|
|
unsigned char tr, tg, tb, ta;
|
|
ImGui_ImplCPU_ReadPixelRGBA(texture, tx, ty, &tr, &tg, &tb, &ta);
|
|
ImGui_ImplCPU_BlendPixelFast(target, dst,
|
|
ImGui_ImplCPU_Mul255(color_r, tr),
|
|
ImGui_ImplCPU_Mul255(color_g, tg),
|
|
ImGui_ImplCPU_Mul255(color_b, tb),
|
|
ImGui_ImplCPU_Mul255(color_a, ta));
|
|
dst++;
|
|
u += du_dx;
|
|
v += dv_dx;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static void ImGui_ImplCPU_RenderTexturedRectGeneric(const ImGui_ImplCPU_SurfaceInfo& target, const ImGui_ImplCPU_SurfaceInfo& texture, bool texture_is_alpha, const ImGui_ImplCPU_Quad& quad, int clip_min_x, int clip_min_y, int clip_max_x, int clip_max_y)
|
|
{
|
|
int min_x = std::max((int)ceilf(quad.TL->X - 0.5f), clip_min_x);
|
|
int max_x = std::min((int)floorf(quad.TR->X - 0.5f), clip_max_x - 1);
|
|
int min_y = std::max((int)ceilf(quad.TL->Y - 0.5f), clip_min_y);
|
|
int max_y = std::min((int)floorf(quad.BL->Y - 0.5f), clip_max_y - 1);
|
|
if (min_x > max_x || min_y > max_y)
|
|
return;
|
|
|
|
unsigned char color_r = (unsigned char)quad.TL->R;
|
|
unsigned char color_g = (unsigned char)quad.TL->G;
|
|
unsigned char color_b = (unsigned char)quad.TL->B;
|
|
unsigned char color_a = (unsigned char)quad.TL->A;
|
|
float du_dx = (quad.TR->U - quad.TL->U) / (quad.TR->X - quad.TL->X);
|
|
float dv_dx = (quad.TR->V - quad.TL->V) / (quad.TR->X - quad.TL->X);
|
|
float du_dy = (quad.BL->U - quad.TL->U) / (quad.BL->Y - quad.TL->Y);
|
|
float dv_dy = (quad.BL->V - quad.TL->V) / (quad.BL->Y - quad.TL->Y);
|
|
float u_const = quad.TL->U - quad.TL->X * du_dx - quad.TL->Y * du_dy;
|
|
float v_const = quad.TL->V - quad.TL->X * dv_dx - quad.TL->Y * dv_dy;
|
|
int texture_max_x = texture.Width - 1;
|
|
int texture_max_y = texture.Height - 1;
|
|
|
|
for (int y = min_y; y <= max_y; y++)
|
|
{
|
|
float py = (float)y + 0.5f;
|
|
float px = (float)min_x + 0.5f;
|
|
float u = u_const + px * du_dx + py * du_dy;
|
|
float v = v_const + px * dv_dx + py * dv_dy;
|
|
|
|
if (texture_is_alpha)
|
|
{
|
|
for (int x = min_x; x <= max_x; x++)
|
|
{
|
|
int tx = ImGui_ImplCPU_ClampInt((int)(u * (float)texture_max_x + 0.5f), 0, texture_max_x);
|
|
int ty = ImGui_ImplCPU_ClampInt((int)(v * (float)texture_max_y + 0.5f), 0, texture_max_y);
|
|
ImGui_ImplCPU_BlendPixelGeneric(target, x, y, color_r, color_g, color_b, ImGui_ImplCPU_Mul255(color_a, ImGui_ImplCPU_ReadPixelAlpha(texture, tx, ty)));
|
|
u += du_dx;
|
|
v += dv_dx;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (int x = min_x; x <= max_x; x++)
|
|
{
|
|
int tx = ImGui_ImplCPU_ClampInt((int)(u * (float)texture_max_x + 0.5f), 0, texture_max_x);
|
|
int ty = ImGui_ImplCPU_ClampInt((int)(v * (float)texture_max_y + 0.5f), 0, texture_max_y);
|
|
unsigned char tr, tg, tb, ta;
|
|
ImGui_ImplCPU_ReadPixelRGBA(texture, tx, ty, &tr, &tg, &tb, &ta);
|
|
ImGui_ImplCPU_BlendPixelGeneric(target, x, y,
|
|
ImGui_ImplCPU_Mul255(color_r, tr),
|
|
ImGui_ImplCPU_Mul255(color_g, tg),
|
|
ImGui_ImplCPU_Mul255(color_b, tb),
|
|
ImGui_ImplCPU_Mul255(color_a, ta));
|
|
u += du_dx;
|
|
v += dv_dx;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static bool ImGui_ImplCPU_TryRenderQuadFast(const ImGui_ImplCPU_SurfaceInfo& target, const ImGui_ImplCPU_SurfaceInfo* texture, bool texture_is_alpha, const ImGui_ImplCPU_Quad& quad, int clip_min_x, int clip_min_y, int clip_max_x, int clip_max_y)
|
|
{
|
|
if (!ImGui_ImplCPU_QuadHasConstantColor(quad))
|
|
return false;
|
|
|
|
unsigned char r = (unsigned char)quad.TL->R;
|
|
unsigned char g = (unsigned char)quad.TL->G;
|
|
unsigned char b = (unsigned char)quad.TL->B;
|
|
unsigned char a = (unsigned char)quad.TL->A;
|
|
if (texture == nullptr)
|
|
{
|
|
ImGui_ImplCPU_RenderSolidRectFast(target, quad, clip_min_x, clip_min_y, clip_max_x, clip_max_y, r, g, b, a);
|
|
return true;
|
|
}
|
|
|
|
int tx = 0;
|
|
int ty = 0;
|
|
if (ImGui_ImplCPU_QuadGetConstantTexel(*texture, quad, &tx, &ty))
|
|
{
|
|
if (texture_is_alpha)
|
|
a = ImGui_ImplCPU_Mul255(a, ImGui_ImplCPU_ReadPixelAlpha(*texture, tx, ty));
|
|
else
|
|
{
|
|
unsigned char tr, tg, tb, ta;
|
|
ImGui_ImplCPU_ReadPixelRGBA(*texture, tx, ty, &tr, &tg, &tb, &ta);
|
|
r = ImGui_ImplCPU_Mul255(r, tr);
|
|
g = ImGui_ImplCPU_Mul255(g, tg);
|
|
b = ImGui_ImplCPU_Mul255(b, tb);
|
|
a = ImGui_ImplCPU_Mul255(a, ta);
|
|
}
|
|
ImGui_ImplCPU_RenderSolidRectFast(target, quad, clip_min_x, clip_min_y, clip_max_x, clip_max_y, r, g, b, a);
|
|
return true;
|
|
}
|
|
|
|
if (!ImGui_ImplCPU_QuadHasLinearUV(quad))
|
|
return false;
|
|
ImGui_ImplCPU_RenderTexturedRectFast(target, *texture, texture_is_alpha, quad, clip_min_x, clip_min_y, clip_max_x, clip_max_y);
|
|
return true;
|
|
}
|
|
|
|
static bool ImGui_ImplCPU_TryRenderQuadGeneric(const ImGui_ImplCPU_SurfaceInfo& target, const ImGui_ImplCPU_SurfaceInfo* texture, bool texture_is_alpha, const ImGui_ImplCPU_Quad& quad, int clip_min_x, int clip_min_y, int clip_max_x, int clip_max_y)
|
|
{
|
|
if (!ImGui_ImplCPU_QuadHasConstantColor(quad))
|
|
return false;
|
|
|
|
unsigned char r = (unsigned char)quad.TL->R;
|
|
unsigned char g = (unsigned char)quad.TL->G;
|
|
unsigned char b = (unsigned char)quad.TL->B;
|
|
unsigned char a = (unsigned char)quad.TL->A;
|
|
if (texture == nullptr)
|
|
{
|
|
ImGui_ImplCPU_RenderSolidRectGeneric(target, quad, clip_min_x, clip_min_y, clip_max_x, clip_max_y, r, g, b, a);
|
|
return true;
|
|
}
|
|
|
|
int tx = 0;
|
|
int ty = 0;
|
|
if (ImGui_ImplCPU_QuadGetConstantTexel(*texture, quad, &tx, &ty))
|
|
{
|
|
if (texture_is_alpha)
|
|
a = ImGui_ImplCPU_Mul255(a, ImGui_ImplCPU_ReadPixelAlpha(*texture, tx, ty));
|
|
else
|
|
{
|
|
unsigned char tr, tg, tb, ta;
|
|
ImGui_ImplCPU_ReadPixelRGBA(*texture, tx, ty, &tr, &tg, &tb, &ta);
|
|
r = ImGui_ImplCPU_Mul255(r, tr);
|
|
g = ImGui_ImplCPU_Mul255(g, tg);
|
|
b = ImGui_ImplCPU_Mul255(b, tb);
|
|
a = ImGui_ImplCPU_Mul255(a, ta);
|
|
}
|
|
ImGui_ImplCPU_RenderSolidRectGeneric(target, quad, clip_min_x, clip_min_y, clip_max_x, clip_max_y, r, g, b, a);
|
|
return true;
|
|
}
|
|
|
|
if (!ImGui_ImplCPU_QuadHasLinearUV(quad))
|
|
return false;
|
|
ImGui_ImplCPU_RenderTexturedRectGeneric(target, *texture, texture_is_alpha, quad, clip_min_x, clip_min_y, clip_max_x, clip_max_y);
|
|
return true;
|
|
}
|
|
|
|
bool ImGui_ImplCPU_Init()
|
|
{
|
|
ImGuiIO& io = ImGui::GetIO();
|
|
IMGUI_CHECKVERSION();
|
|
IM_ASSERT(io.BackendRendererUserData == nullptr && "Already initialized a renderer backend!");
|
|
|
|
ImGui_ImplCPU_Data* bd = IM_NEW(ImGui_ImplCPU_Data)();
|
|
io.BackendRendererUserData = (void*)bd;
|
|
io.BackendRendererName = "imgui_impl_cpu";
|
|
io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset;
|
|
io.BackendFlags |= ImGuiBackendFlags_RendererHasTextures;
|
|
return true;
|
|
}
|
|
|
|
void ImGui_ImplCPU_UpdateTexture(ImTextureData* tex)
|
|
{
|
|
const ImGui_ImplCPU_PixelFormat* format = nullptr;
|
|
if (tex->Format == ImTextureFormat_RGBA32)
|
|
format = ImGui_ImplCPU_GetBuiltinPixelFormat(ImGui_ImplCPU_BuiltinFormat_RGBA8888);
|
|
else if (tex->Format == ImTextureFormat_Alpha8)
|
|
format = ImGui_ImplCPU_GetBuiltinPixelFormat(ImGui_ImplCPU_BuiltinFormat_Alpha8);
|
|
else
|
|
IM_ASSERT(false && "Unsupported ImTextureData format for imgui_impl_cpu");
|
|
|
|
if (tex->Status == ImTextureStatus_WantCreate)
|
|
{
|
|
IM_ASSERT(tex->TexID == ImTextureID_Invalid && tex->BackendUserData == nullptr);
|
|
|
|
ImGui_ImplCPU_Texture* cpu_texture = IM_NEW(ImGui_ImplCPU_Texture)();
|
|
cpu_texture->Pixels = (const unsigned char*)tex->GetPixels();
|
|
cpu_texture->Width = tex->Width;
|
|
cpu_texture->Height = tex->Height;
|
|
cpu_texture->Pitch = tex->GetPitch();
|
|
cpu_texture->Format = format;
|
|
tex->BackendUserData = cpu_texture;
|
|
tex->SetTexID((ImTextureID)(intptr_t)cpu_texture);
|
|
tex->SetStatus(ImTextureStatus_OK);
|
|
}
|
|
else if (tex->Status == ImTextureStatus_WantUpdates)
|
|
{
|
|
ImGui_ImplCPU_Texture* cpu_texture = (ImGui_ImplCPU_Texture*)tex->BackendUserData;
|
|
IM_ASSERT(cpu_texture != nullptr);
|
|
cpu_texture->Pixels = (const unsigned char*)tex->GetPixels();
|
|
cpu_texture->Width = tex->Width;
|
|
cpu_texture->Height = tex->Height;
|
|
cpu_texture->Pitch = tex->GetPitch();
|
|
cpu_texture->Format = format;
|
|
tex->SetStatus(ImTextureStatus_OK);
|
|
}
|
|
else if (tex->Status == ImTextureStatus_WantDestroy)
|
|
{
|
|
ImGui_ImplCPU_Texture* cpu_texture = (ImGui_ImplCPU_Texture*)tex->BackendUserData;
|
|
if (cpu_texture != nullptr)
|
|
IM_DELETE(cpu_texture);
|
|
tex->BackendUserData = nullptr;
|
|
tex->SetTexID(ImTextureID_Invalid);
|
|
tex->SetStatus(ImTextureStatus_Destroyed);
|
|
}
|
|
}
|
|
|
|
static void ImGui_ImplCPU_DestroyDeviceObjects()
|
|
{
|
|
for (ImTextureData* tex : ImGui::GetPlatformIO().Textures)
|
|
if (tex->RefCount == 1)
|
|
{
|
|
tex->SetStatus(ImTextureStatus_WantDestroy);
|
|
ImGui_ImplCPU_UpdateTexture(tex);
|
|
}
|
|
}
|
|
|
|
void ImGui_ImplCPU_Shutdown()
|
|
{
|
|
ImGui_ImplCPU_Data* bd = ImGui_ImplCPU_GetBackendData();
|
|
IM_ASSERT(bd != nullptr && "No renderer backend to shutdown, or already shutdown?");
|
|
ImGuiIO& io = ImGui::GetIO();
|
|
ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
|
|
|
|
ImGui_ImplCPU_DestroyDeviceObjects();
|
|
|
|
io.BackendRendererName = nullptr;
|
|
io.BackendRendererUserData = nullptr;
|
|
io.BackendFlags &= ~(ImGuiBackendFlags_RendererHasVtxOffset | ImGuiBackendFlags_RendererHasTextures);
|
|
platform_io.ClearRendererHandlers();
|
|
IM_DELETE(bd);
|
|
}
|
|
|
|
void ImGui_ImplCPU_NewFrame()
|
|
{
|
|
ImGui_ImplCPU_Data* bd = ImGui_ImplCPU_GetBackendData();
|
|
IM_ASSERT(bd != nullptr && "Context or backend not initialized! Did you call ImGui_ImplCPU_Init()?");
|
|
IM_UNUSED(bd);
|
|
}
|
|
|
|
void ImGui_ImplCPU_RenderDrawData(ImDrawData* draw_data, ImGui_ImplCPU_Framebuffer* framebuffer)
|
|
{
|
|
ImGui_ImplCPU_Data* bd = ImGui_ImplCPU_GetBackendData();
|
|
if (bd == nullptr || draw_data == nullptr)
|
|
return;
|
|
|
|
if (draw_data->Textures != nullptr)
|
|
for (ImTextureData* tex : *draw_data->Textures)
|
|
if (tex->Status != ImTextureStatus_OK)
|
|
ImGui_ImplCPU_UpdateTexture(tex);
|
|
|
|
if (framebuffer == nullptr || framebuffer->Pixels == nullptr || framebuffer->Width <= 0 || framebuffer->Height <= 0 || framebuffer->Pitch <= 0)
|
|
return;
|
|
|
|
ImGui_ImplCPU_SurfaceInfo target;
|
|
ImGui_ImplCPU_InitBufferInfo(&target, framebuffer);
|
|
if (target.Format == nullptr || target.Format->BytesPerPixel <= 0)
|
|
return;
|
|
|
|
const ImVec2 clip_off = draw_data->DisplayPos;
|
|
const ImVec2 clip_scale = draw_data->FramebufferScale;
|
|
|
|
const ImGui_ImplCPU_Texture* active_texture = nullptr;
|
|
ImGui_ImplCPU_SurfaceInfo active_texture_info;
|
|
bool active_texture_valid = false;
|
|
bool active_texture_is_alpha = false;
|
|
|
|
for (int n = 0; n < draw_data->CmdListsCount; n++)
|
|
{
|
|
const ImDrawList* draw_list = draw_data->CmdLists[n];
|
|
const ImDrawIdx* idx_buffer = draw_list->IdxBuffer.Data;
|
|
ImGui_ImplCPU_BuildVertexCache(&bd->VertexCache, draw_list, clip_off, clip_scale);
|
|
const ImGui_ImplCPU_RasterVertex* vertex_cache = bd->VertexCache.Data;
|
|
|
|
for (int cmd_i = 0; cmd_i < draw_list->CmdBuffer.Size; cmd_i++)
|
|
{
|
|
const ImDrawCmd* pcmd = &draw_list->CmdBuffer[cmd_i];
|
|
if (pcmd->UserCallback != nullptr)
|
|
{
|
|
if (pcmd->UserCallback != ImDrawCallback_ResetRenderState)
|
|
pcmd->UserCallback(draw_list, pcmd);
|
|
continue;
|
|
}
|
|
if (pcmd->ElemCount == 0)
|
|
continue;
|
|
|
|
ImVec2 clip_min((pcmd->ClipRect.x - clip_off.x) * clip_scale.x, (pcmd->ClipRect.y - clip_off.y) * clip_scale.y);
|
|
ImVec2 clip_max((pcmd->ClipRect.z - clip_off.x) * clip_scale.x, (pcmd->ClipRect.w - clip_off.y) * clip_scale.y);
|
|
if (clip_min.x < 0.0f) clip_min.x = 0.0f;
|
|
if (clip_min.y < 0.0f) clip_min.y = 0.0f;
|
|
if (clip_max.x > (float)target.Width) clip_max.x = (float)target.Width;
|
|
if (clip_max.y > (float)target.Height) clip_max.y = (float)target.Height;
|
|
if (clip_max.x <= clip_min.x || clip_max.y <= clip_min.y)
|
|
continue;
|
|
|
|
int clip_min_x = (int)clip_min.x;
|
|
int clip_min_y = (int)clip_min.y;
|
|
int clip_max_x = (int)clip_max.x;
|
|
int clip_max_y = (int)clip_max.y;
|
|
|
|
const ImGui_ImplCPU_Texture* texture = (const ImGui_ImplCPU_Texture*)(intptr_t)pcmd->GetTexID();
|
|
if (texture != active_texture)
|
|
{
|
|
active_texture = texture;
|
|
active_texture_valid = false;
|
|
active_texture_is_alpha = false;
|
|
if (texture != nullptr)
|
|
{
|
|
ImGui_ImplCPU_InitTextureInfo(&active_texture_info, texture);
|
|
active_texture_valid = active_texture_info.Pixels != nullptr && active_texture_info.Width > 0 && active_texture_info.Height > 0 && active_texture_info.Pitch > 0 && active_texture_info.Format != nullptr;
|
|
active_texture_is_alpha = active_texture_valid && active_texture_info.IsAlphaOnly;
|
|
}
|
|
}
|
|
|
|
const ImGui_ImplCPU_SurfaceInfo* texture_ptr = active_texture_valid ? &active_texture_info : nullptr;
|
|
for (unsigned int idx = 0; idx + 2 < (unsigned int)pcmd->ElemCount;)
|
|
{
|
|
if (idx + 5 < (unsigned int)pcmd->ElemCount)
|
|
{
|
|
ImGui_ImplCPU_Quad quad;
|
|
if (ImGui_ImplCPU_DetectQuad(vertex_cache, idx_buffer, pcmd->VtxOffset, pcmd->IdxOffset + idx, &quad))
|
|
{
|
|
bool rendered = target.IsFast
|
|
? ImGui_ImplCPU_TryRenderQuadFast(target, texture_ptr, active_texture_is_alpha, quad, clip_min_x, clip_min_y, clip_max_x, clip_max_y)
|
|
: ImGui_ImplCPU_TryRenderQuadGeneric(target, texture_ptr, active_texture_is_alpha, quad, clip_min_x, clip_min_y, clip_max_x, clip_max_y);
|
|
if (rendered)
|
|
{
|
|
idx += 6;
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
|
|
ImDrawIdx idx0 = idx_buffer[pcmd->IdxOffset + idx + 0];
|
|
ImDrawIdx idx1 = idx_buffer[pcmd->IdxOffset + idx + 1];
|
|
ImDrawIdx idx2 = idx_buffer[pcmd->IdxOffset + idx + 2];
|
|
const ImGui_ImplCPU_RasterVertex& v0 = vertex_cache[pcmd->VtxOffset + idx0];
|
|
const ImGui_ImplCPU_RasterVertex& v1 = vertex_cache[pcmd->VtxOffset + idx1];
|
|
const ImGui_ImplCPU_RasterVertex& v2 = vertex_cache[pcmd->VtxOffset + idx2];
|
|
if (target.IsFast)
|
|
ImGui_ImplCPU_RenderTriangleFast(target, texture_ptr, active_texture_is_alpha, v0, v1, v2, clip_min_x, clip_min_y, clip_max_x, clip_max_y);
|
|
else
|
|
ImGui_ImplCPU_RenderTriangleGeneric(target, texture_ptr, active_texture_is_alpha, v0, v1, v2, clip_min_x, clip_min_y, clip_max_x, clip_max_y);
|
|
idx += 3;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#if defined(__clang__)
|
|
#pragma clang diagnostic pop
|
|
#endif
|
|
|
|
#endif // #ifndef IMGUI_DISABLE
|