- Created imgui_impl_sdlsurface3.h and corresponding implementation file. - Added Makefile for building the SDL3 surface example on Linux and macOS. - Included README.md with build instructions for Windows, Linux, and macOS. - Added build script for Windows (build_win32.bat) and Visual Studio project files. - Implemented main application logic in main.cpp to demonstrate ImGui with SDL3 and surface rendering.
716 lines
27 KiB
C++
716 lines
27 KiB
C++
#include "imgui_impl_sdlsurface3.h"
|
|
#include "imgui.h"
|
|
#ifndef IMGUI_DISABLE
|
|
#include <SDL3/SDL.h>
|
|
#include <stdint.h>
|
|
#include <algorithm>
|
|
#include <cmath>
|
|
#include <cstring>
|
|
|
|
struct ImGui_ImplSDLSurface3_FastFormat32
|
|
{
|
|
Uint32 Rmask;
|
|
Uint32 Gmask;
|
|
Uint32 Bmask;
|
|
Uint32 Amask;
|
|
Uint8 Rshift;
|
|
Uint8 Gshift;
|
|
Uint8 Bshift;
|
|
Uint8 Ashift;
|
|
bool HasAlpha;
|
|
bool Valid;
|
|
|
|
ImGui_ImplSDLSurface3_FastFormat32() { memset((void*)this, 0, sizeof(*this)); }
|
|
};
|
|
|
|
struct ImGui_ImplSDLSurface3_SurfaceInfo
|
|
{
|
|
SDL_Surface* Surface;
|
|
Uint8* Pixels;
|
|
int Pitch;
|
|
int Width;
|
|
int Height;
|
|
const SDL_PixelFormatDetails* Format;
|
|
SDL_Palette* Palette;
|
|
ImGui_ImplSDLSurface3_FastFormat32 FastFormat;
|
|
bool IsFast;
|
|
|
|
ImGui_ImplSDLSurface3_SurfaceInfo() { memset((void*)this, 0, sizeof(*this)); }
|
|
};
|
|
|
|
struct ImGui_ImplSDLSurface3_Data
|
|
{
|
|
SDL_Surface* TargetSurface;
|
|
SDL_Surface* FontSurface;
|
|
ImGui_ImplSDLSurface3_SurfaceInfo TargetInfo;
|
|
|
|
ImGui_ImplSDLSurface3_Data() { memset((void*)this, 0, sizeof(*this)); }
|
|
};
|
|
|
|
struct ImGui_ImplSDLSurface3_RasterVertex
|
|
{
|
|
float X;
|
|
float Y;
|
|
float U;
|
|
float V;
|
|
float R;
|
|
float G;
|
|
float B;
|
|
float A;
|
|
};
|
|
|
|
static ImGui_ImplSDLSurface3_Data* ImGui_ImplSDLSurface3_GetBackendData()
|
|
{
|
|
return ImGui::GetCurrentContext() ? (ImGui_ImplSDLSurface3_Data*)ImGui::GetIO().BackendRendererUserData : nullptr;
|
|
}
|
|
|
|
static inline float ImGui_ImplSDLSurface3_Edge(float ax, float ay, float bx, float by, float px, float py)
|
|
{
|
|
return (bx - ax) * (py - ay) - (by - ay) * (px - ax);
|
|
}
|
|
|
|
static inline int ImGui_ImplSDLSurface3_ClampInt(int v, int lo, int hi)
|
|
{
|
|
return (v < lo) ? lo : (v > hi ? hi : v);
|
|
}
|
|
|
|
static inline Uint8 ImGui_ImplSDLSurface3_ClampByte(float v)
|
|
{
|
|
if (v <= 0.0f)
|
|
return 0;
|
|
if (v >= 255.0f)
|
|
return 255;
|
|
return (Uint8)(v + 0.5f);
|
|
}
|
|
|
|
static inline Uint8 ImGui_ImplSDLSurface3_Mul255(Uint32 a, Uint32 b)
|
|
{
|
|
Uint32 t = a * b + 128;
|
|
return (Uint8)((t + (t >> 8)) >> 8);
|
|
}
|
|
|
|
static ImGui_ImplSDLSurface3_FastFormat32 ImGui_ImplSDLSurface3_BuildFastFormat(const SDL_PixelFormatDetails* format)
|
|
{
|
|
ImGui_ImplSDLSurface3_FastFormat32 out;
|
|
if (format == nullptr)
|
|
return out;
|
|
if (format->bits_per_pixel != 32 || format->bytes_per_pixel != 4)
|
|
return out;
|
|
if (format->Rbits != 8 || format->Gbits != 8 || format->Bbits != 8)
|
|
return out;
|
|
if (format->Amask != 0 && format->Abits != 8)
|
|
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 bool ImGui_ImplSDLSurface3_CanUseFastPath(SDL_Surface* surface, const ImGui_ImplSDLSurface3_FastFormat32& format)
|
|
{
|
|
#ifdef IMGUI_IMPL_SDLSURFACE_DISABLE_FAST_PATH
|
|
IM_UNUSED(surface);
|
|
IM_UNUSED(format);
|
|
return false;
|
|
#else
|
|
if (surface == nullptr || !format.Valid)
|
|
return false;
|
|
if ((surface->pitch & 3) != 0)
|
|
return false;
|
|
if ((((uintptr_t)surface->pixels) & 3) != 0)
|
|
return false;
|
|
return true;
|
|
#endif
|
|
}
|
|
|
|
static void ImGui_ImplSDLSurface3_InitSurfaceInfo(ImGui_ImplSDLSurface3_SurfaceInfo* out, SDL_Surface* surface)
|
|
{
|
|
out->Surface = surface;
|
|
out->Pixels = surface ? (Uint8*)surface->pixels : nullptr;
|
|
out->Pitch = surface ? surface->pitch : 0;
|
|
out->Width = surface ? surface->w : 0;
|
|
out->Height = surface ? surface->h : 0;
|
|
out->Format = surface ? SDL_GetPixelFormatDetails(surface->format) : nullptr;
|
|
out->Palette = surface ? SDL_GetSurfacePalette(surface) : nullptr;
|
|
out->FastFormat = ImGui_ImplSDLSurface3_BuildFastFormat(out->Format);
|
|
out->IsFast = ImGui_ImplSDLSurface3_CanUseFastPath(surface, out->FastFormat);
|
|
}
|
|
|
|
static inline Uint32 ImGui_ImplSDLSurface3_ReadPixelRaw(const ImGui_ImplSDLSurface3_SurfaceInfo& surface, int x, int y)
|
|
{
|
|
const Uint8* p = surface.Pixels + y * surface.Pitch + x * surface.Format->bytes_per_pixel;
|
|
switch (surface.Format->bytes_per_pixel)
|
|
{
|
|
case 1:
|
|
return *p;
|
|
case 2:
|
|
return *(const Uint16*)p;
|
|
case 3:
|
|
if (SDL_BYTEORDER == SDL_BIG_ENDIAN)
|
|
return (Uint32)((p[0] << 16) | (p[1] << 8) | p[2]);
|
|
return (Uint32)(p[0] | (p[1] << 8) | (p[2] << 16));
|
|
case 4:
|
|
return *(const Uint32*)p;
|
|
default:
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
static inline void ImGui_ImplSDLSurface3_WritePixelRaw(const ImGui_ImplSDLSurface3_SurfaceInfo& surface, int x, int y, Uint32 pixel)
|
|
{
|
|
Uint8* p = surface.Pixels + y * surface.Pitch + x * surface.Format->bytes_per_pixel;
|
|
switch (surface.Format->bytes_per_pixel)
|
|
{
|
|
case 1:
|
|
*p = (Uint8)pixel;
|
|
return;
|
|
case 2:
|
|
*(Uint16*)p = (Uint16)pixel;
|
|
return;
|
|
case 3:
|
|
if (SDL_BYTEORDER == SDL_BIG_ENDIAN)
|
|
{
|
|
p[0] = (Uint8)((pixel >> 16) & 0xFF);
|
|
p[1] = (Uint8)((pixel >> 8) & 0xFF);
|
|
p[2] = (Uint8)(pixel & 0xFF);
|
|
}
|
|
else
|
|
{
|
|
p[0] = (Uint8)(pixel & 0xFF);
|
|
p[1] = (Uint8)((pixel >> 8) & 0xFF);
|
|
p[2] = (Uint8)((pixel >> 16) & 0xFF);
|
|
}
|
|
return;
|
|
case 4:
|
|
*(Uint32*)p = pixel;
|
|
return;
|
|
default:
|
|
return;
|
|
}
|
|
}
|
|
|
|
static inline void ImGui_ImplSDLSurface3_UnpackFastRGBA(const ImGui_ImplSDLSurface3_FastFormat32& format, Uint32 pixel, Uint8* r, Uint8* g, Uint8* b, Uint8* a)
|
|
{
|
|
*r = (Uint8)((pixel & format.Rmask) >> format.Rshift);
|
|
*g = (Uint8)((pixel & format.Gmask) >> format.Gshift);
|
|
*b = (Uint8)((pixel & format.Bmask) >> format.Bshift);
|
|
*a = format.HasAlpha ? (Uint8)((pixel & format.Amask) >> format.Ashift) : 255;
|
|
}
|
|
|
|
static inline Uint32 ImGui_ImplSDLSurface3_PackFastRGBA(const ImGui_ImplSDLSurface3_FastFormat32& format, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
|
|
{
|
|
Uint32 pixel = (((Uint32)r << format.Rshift) & format.Rmask)
|
|
| (((Uint32)g << format.Gshift) & format.Gmask)
|
|
| (((Uint32)b << format.Bshift) & format.Bmask);
|
|
if (format.HasAlpha)
|
|
pixel |= (((Uint32)a << format.Ashift) & format.Amask);
|
|
return pixel;
|
|
}
|
|
|
|
static inline void ImGui_ImplSDLSurface3_ReadPixelRGBA(const ImGui_ImplSDLSurface3_SurfaceInfo& surface, int x, int y, Uint8* r, Uint8* g, Uint8* b, Uint8* a)
|
|
{
|
|
if (surface.IsFast)
|
|
{
|
|
const Uint32* src = (const Uint32*)(surface.Pixels + y * surface.Pitch) + x;
|
|
ImGui_ImplSDLSurface3_UnpackFastRGBA(surface.FastFormat, *src, r, g, b, a);
|
|
return;
|
|
}
|
|
|
|
Uint32 pixel = ImGui_ImplSDLSurface3_ReadPixelRaw(surface, x, y);
|
|
SDL_GetRGBA(pixel, surface.Format, surface.Palette, r, g, b, a);
|
|
}
|
|
|
|
static inline void ImGui_ImplSDLSurface3_BlendPixelFast(const ImGui_ImplSDLSurface3_SurfaceInfo& target, Uint32* dst, Uint8 sr, Uint8 sg, Uint8 sb, Uint8 sa)
|
|
{
|
|
if (sa == 0)
|
|
return;
|
|
if (sa == 255)
|
|
{
|
|
*dst = ImGui_ImplSDLSurface3_PackFastRGBA(target.FastFormat, sr, sg, sb, 255);
|
|
return;
|
|
}
|
|
|
|
Uint8 dr, dg, db, da;
|
|
ImGui_ImplSDLSurface3_UnpackFastRGBA(target.FastFormat, *dst, &dr, &dg, &db, &da);
|
|
Uint8 inv_a = (Uint8)(255 - sa);
|
|
Uint8 out_r = (Uint8)(ImGui_ImplSDLSurface3_Mul255(sr, sa) + ImGui_ImplSDLSurface3_Mul255(dr, inv_a));
|
|
Uint8 out_g = (Uint8)(ImGui_ImplSDLSurface3_Mul255(sg, sa) + ImGui_ImplSDLSurface3_Mul255(dg, inv_a));
|
|
Uint8 out_b = (Uint8)(ImGui_ImplSDLSurface3_Mul255(sb, sa) + ImGui_ImplSDLSurface3_Mul255(db, inv_a));
|
|
Uint8 out_a = (target.Format != nullptr && target.Format->Amask != 0) ? (Uint8)(sa + ImGui_ImplSDLSurface3_Mul255(da, inv_a)) : 255;
|
|
*dst = ImGui_ImplSDLSurface3_PackFastRGBA(target.FastFormat, out_r, out_g, out_b, out_a);
|
|
}
|
|
|
|
static inline void ImGui_ImplSDLSurface3_BlendPixelGeneric(const ImGui_ImplSDLSurface3_SurfaceInfo& target, int x, int y, Uint8 sr, Uint8 sg, Uint8 sb, Uint8 sa)
|
|
{
|
|
if (sa == 0)
|
|
return;
|
|
if (sa == 255)
|
|
{
|
|
Uint32 pixel = SDL_MapRGBA(target.Format, target.Palette, sr, sg, sb, 255);
|
|
ImGui_ImplSDLSurface3_WritePixelRaw(target, x, y, pixel);
|
|
return;
|
|
}
|
|
|
|
Uint8 dr, dg, db, da;
|
|
Uint32 dst_pixel = ImGui_ImplSDLSurface3_ReadPixelRaw(target, x, y);
|
|
SDL_GetRGBA(dst_pixel, target.Format, target.Palette, &dr, &dg, &db, &da);
|
|
Uint8 inv_a = (Uint8)(255 - sa);
|
|
Uint8 out_r = (Uint8)(ImGui_ImplSDLSurface3_Mul255(sr, sa) + ImGui_ImplSDLSurface3_Mul255(dr, inv_a));
|
|
Uint8 out_g = (Uint8)(ImGui_ImplSDLSurface3_Mul255(sg, sa) + ImGui_ImplSDLSurface3_Mul255(dg, inv_a));
|
|
Uint8 out_b = (Uint8)(ImGui_ImplSDLSurface3_Mul255(sb, sa) + ImGui_ImplSDLSurface3_Mul255(db, inv_a));
|
|
Uint8 out_a = target.FastFormat.HasAlpha ? (Uint8)(sa + ImGui_ImplSDLSurface3_Mul255(da, inv_a)) : 255;
|
|
Uint32 pixel = SDL_MapRGBA(target.Format, target.Palette, out_r, out_g, out_b, out_a);
|
|
ImGui_ImplSDLSurface3_WritePixelRaw(target, x, y, pixel);
|
|
}
|
|
|
|
static inline void ImGui_ImplSDLSurface3_SetupRasterVertex(ImGui_ImplSDLSurface3_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_ImplSDLSurface3_RenderTriangleFast(const ImGui_ImplSDLSurface3_SurfaceInfo& target, const ImGui_ImplSDLSurface3_SurfaceInfo* texture, const ImGui_ImplSDLSurface3_RasterVertex& v0, const ImGui_ImplSDLSurface3_RasterVertex& v1, const ImGui_ImplSDLSurface3_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_ImplSDLSurface3_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_ImplSDLSurface3_Edge(v1.X, v1.Y, v2.X, v2.Y, start_x, start_y) * sign;
|
|
float e1_row = ImGui_ImplSDLSurface3_Edge(v2.X, v2.Y, v0.X, v0.Y, start_x, start_y) * sign;
|
|
float e2_row = ImGui_ImplSDLSurface3_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;
|
|
|
|
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;
|
|
Uint32* dst = (Uint32*)(target.Pixels + y * target.Pitch) + min_x;
|
|
|
|
for (int x = min_x; x <= max_x; x++)
|
|
{
|
|
if (e0 >= 0.0f && e1 >= 0.0f && e2 >= 0.0f)
|
|
{
|
|
Uint8 out_r = ImGui_ImplSDLSurface3_ClampByte(r);
|
|
Uint8 out_g = ImGui_ImplSDLSurface3_ClampByte(g);
|
|
Uint8 out_b = ImGui_ImplSDLSurface3_ClampByte(b);
|
|
Uint8 out_a = ImGui_ImplSDLSurface3_ClampByte(a);
|
|
|
|
if (texture != nullptr)
|
|
{
|
|
int tx = ImGui_ImplSDLSurface3_ClampInt((int)(u * (float)texture_max_x + 0.5f), 0, texture_max_x);
|
|
int ty = ImGui_ImplSDLSurface3_ClampInt((int)(v * (float)texture_max_y + 0.5f), 0, texture_max_y);
|
|
Uint8 tr, tg, tb, ta;
|
|
ImGui_ImplSDLSurface3_ReadPixelRGBA(*texture, tx, ty, &tr, &tg, &tb, &ta);
|
|
out_r = ImGui_ImplSDLSurface3_Mul255(out_r, tr);
|
|
out_g = ImGui_ImplSDLSurface3_Mul255(out_g, tg);
|
|
out_b = ImGui_ImplSDLSurface3_Mul255(out_b, tb);
|
|
out_a = ImGui_ImplSDLSurface3_Mul255(out_a, ta);
|
|
}
|
|
|
|
ImGui_ImplSDLSurface3_BlendPixelFast(target, dst, out_r, out_g, out_b, out_a);
|
|
}
|
|
|
|
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_ImplSDLSurface3_RenderTriangleGeneric(const ImGui_ImplSDLSurface3_SurfaceInfo& target, const ImGui_ImplSDLSurface3_SurfaceInfo* texture, const ImGui_ImplSDLSurface3_RasterVertex& v0, const ImGui_ImplSDLSurface3_RasterVertex& v1, const ImGui_ImplSDLSurface3_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_ImplSDLSurface3_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_ImplSDLSurface3_Edge(v1.X, v1.Y, v2.X, v2.Y, start_x, start_y) * sign;
|
|
float e1_row = ImGui_ImplSDLSurface3_Edge(v2.X, v2.Y, v0.X, v0.Y, start_x, start_y) * sign;
|
|
float e2_row = ImGui_ImplSDLSurface3_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;
|
|
|
|
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)
|
|
{
|
|
Uint8 out_r = ImGui_ImplSDLSurface3_ClampByte(r);
|
|
Uint8 out_g = ImGui_ImplSDLSurface3_ClampByte(g);
|
|
Uint8 out_b = ImGui_ImplSDLSurface3_ClampByte(b);
|
|
Uint8 out_a = ImGui_ImplSDLSurface3_ClampByte(a);
|
|
|
|
if (texture != nullptr)
|
|
{
|
|
int tx = ImGui_ImplSDLSurface3_ClampInt((int)(u * (float)texture_max_x + 0.5f), 0, texture_max_x);
|
|
int ty = ImGui_ImplSDLSurface3_ClampInt((int)(v * (float)texture_max_y + 0.5f), 0, texture_max_y);
|
|
Uint8 tr, tg, tb, ta;
|
|
ImGui_ImplSDLSurface3_ReadPixelRGBA(*texture, tx, ty, &tr, &tg, &tb, &ta);
|
|
out_r = ImGui_ImplSDLSurface3_Mul255(out_r, tr);
|
|
out_g = ImGui_ImplSDLSurface3_Mul255(out_g, tg);
|
|
out_b = ImGui_ImplSDLSurface3_Mul255(out_b, tb);
|
|
out_a = ImGui_ImplSDLSurface3_Mul255(out_a, ta);
|
|
}
|
|
|
|
ImGui_ImplSDLSurface3_BlendPixelGeneric(target, x, y, out_r, out_g, out_b, out_a);
|
|
}
|
|
|
|
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;
|
|
}
|
|
}
|
|
|
|
SDL_Surface* ImGui_ImplSDLSurface3_CreateFontAtlasSurface()
|
|
{
|
|
ImGuiIO& io = ImGui::GetIO();
|
|
unsigned char* pixels = nullptr;
|
|
int width = 0;
|
|
int height = 0;
|
|
io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height);
|
|
if (pixels == nullptr || width <= 0 || height <= 0)
|
|
return nullptr;
|
|
|
|
SDL_Surface* surface = SDL_CreateSurface(width, height, SDL_PIXELFORMAT_RGBA32);
|
|
if (surface == nullptr)
|
|
return nullptr;
|
|
if (SDL_MUSTLOCK(surface) && !SDL_LockSurface(surface))
|
|
{
|
|
SDL_DestroySurface(surface);
|
|
return nullptr;
|
|
}
|
|
|
|
for (int y = 0; y < height; y++)
|
|
memcpy((Uint8*)surface->pixels + y * surface->pitch, pixels + (size_t)y * (size_t)width * 4, (size_t)width * 4);
|
|
|
|
if (SDL_MUSTLOCK(surface))
|
|
SDL_UnlockSurface(surface);
|
|
|
|
SDL_SetSurfaceBlendMode(surface, SDL_BLENDMODE_NONE);
|
|
return surface;
|
|
}
|
|
|
|
bool ImGui_ImplSDLSurface3_Init(SDL_Surface* surface)
|
|
{
|
|
if (surface == nullptr)
|
|
return false;
|
|
|
|
ImGuiIO& io = ImGui::GetIO();
|
|
IMGUI_CHECKVERSION();
|
|
IM_ASSERT(io.BackendRendererUserData == nullptr && "Already initialized a renderer backend!");
|
|
|
|
ImGui_ImplSDLSurface3_Data* bd = IM_NEW(ImGui_ImplSDLSurface3_Data)();
|
|
io.BackendRendererUserData = (void*)bd;
|
|
io.BackendRendererName = "imgui_impl_sdlsurface3";
|
|
|
|
bd->TargetSurface = surface;
|
|
ImGui_ImplSDLSurface3_InitSurfaceInfo(&bd->TargetInfo, surface);
|
|
bd->FontSurface = ImGui_ImplSDLSurface3_CreateFontAtlasSurface();
|
|
if (bd->FontSurface != nullptr)
|
|
io.Fonts->TexID = (ImTextureID)bd->FontSurface;
|
|
|
|
return true;
|
|
}
|
|
|
|
void ImGui_ImplSDLSurface3_Shutdown()
|
|
{
|
|
ImGui_ImplSDLSurface3_Data* bd = ImGui_ImplSDLSurface3_GetBackendData();
|
|
IM_ASSERT(bd != nullptr && "No renderer backend to shutdown, or already shutdown?");
|
|
ImGuiIO& io = ImGui::GetIO();
|
|
ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
|
|
|
|
io.Fonts->TexID = nullptr;
|
|
io.BackendRendererName = nullptr;
|
|
io.BackendRendererUserData = nullptr;
|
|
platform_io.ClearRendererHandlers();
|
|
|
|
if (bd->FontSurface != nullptr)
|
|
SDL_DestroySurface(bd->FontSurface);
|
|
|
|
IM_DELETE(bd);
|
|
}
|
|
|
|
void ImGui_ImplSDLSurface3_NewFrame()
|
|
{
|
|
ImGui_ImplSDLSurface3_Data* bd = ImGui_ImplSDLSurface3_GetBackendData();
|
|
IM_ASSERT(bd != nullptr && "Context or backend not initialized! Did you call ImGui_ImplSDLSurface3_Init()?");
|
|
IM_UNUSED(bd);
|
|
}
|
|
|
|
void ImGui_ImplSDLSurface3_RenderDrawData(ImDrawData* draw_data)
|
|
{
|
|
ImGui_ImplSDLSurface3_Data* bd = ImGui_ImplSDLSurface3_GetBackendData();
|
|
if (bd == nullptr || draw_data == nullptr || bd->TargetSurface == nullptr)
|
|
return;
|
|
|
|
if (SDL_MUSTLOCK(bd->TargetSurface) && !SDL_LockSurface(bd->TargetSurface))
|
|
return;
|
|
|
|
ImGui_ImplSDLSurface3_InitSurfaceInfo(&bd->TargetInfo, bd->TargetSurface);
|
|
if (bd->TargetInfo.Width <= 0 || bd->TargetInfo.Height <= 0)
|
|
{
|
|
if (SDL_MUSTLOCK(bd->TargetSurface))
|
|
SDL_UnlockSurface(bd->TargetSurface);
|
|
return;
|
|
}
|
|
|
|
const ImVec2 clip_off = draw_data->DisplayPos;
|
|
const ImVec2 clip_scale = draw_data->FramebufferScale;
|
|
|
|
for (int n = 0; n < draw_data->CmdListsCount; n++)
|
|
{
|
|
const ImDrawList* draw_list = draw_data->CmdLists[n];
|
|
const ImDrawVert* vtx_buffer = draw_list->VtxBuffer.Data;
|
|
const ImDrawIdx* idx_buffer = draw_list->IdxBuffer.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)bd->TargetInfo.Width) clip_max.x = (float)bd->TargetInfo.Width;
|
|
if (clip_max.y > (float)bd->TargetInfo.Height) clip_max.y = (float)bd->TargetInfo.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;
|
|
|
|
SDL_Surface* texture_surface = (SDL_Surface*)pcmd->GetTexID();
|
|
ImGui_ImplSDLSurface3_SurfaceInfo texture_info;
|
|
ImGui_ImplSDLSurface3_SurfaceInfo* texture_ptr = nullptr;
|
|
bool texture_locked = false;
|
|
|
|
if (texture_surface != nullptr)
|
|
{
|
|
if (SDL_MUSTLOCK(texture_surface))
|
|
{
|
|
if (!SDL_LockSurface(texture_surface))
|
|
texture_surface = nullptr;
|
|
else
|
|
texture_locked = true;
|
|
}
|
|
if (texture_surface != nullptr)
|
|
{
|
|
ImGui_ImplSDLSurface3_InitSurfaceInfo(&texture_info, texture_surface);
|
|
if (texture_info.Width > 0 && texture_info.Height > 0)
|
|
texture_ptr = &texture_info;
|
|
}
|
|
}
|
|
|
|
for (unsigned int idx = 0; idx + 2 < (unsigned int)pcmd->ElemCount; idx += 3)
|
|
{
|
|
ImDrawIdx idx0 = idx_buffer[pcmd->IdxOffset + idx + 0];
|
|
ImDrawIdx idx1 = idx_buffer[pcmd->IdxOffset + idx + 1];
|
|
ImDrawIdx idx2 = idx_buffer[pcmd->IdxOffset + idx + 2];
|
|
|
|
ImGui_ImplSDLSurface3_RasterVertex v0;
|
|
ImGui_ImplSDLSurface3_RasterVertex v1;
|
|
ImGui_ImplSDLSurface3_RasterVertex v2;
|
|
ImGui_ImplSDLSurface3_SetupRasterVertex(&v0, vtx_buffer[pcmd->VtxOffset + idx0], clip_off, clip_scale);
|
|
ImGui_ImplSDLSurface3_SetupRasterVertex(&v1, vtx_buffer[pcmd->VtxOffset + idx1], clip_off, clip_scale);
|
|
ImGui_ImplSDLSurface3_SetupRasterVertex(&v2, vtx_buffer[pcmd->VtxOffset + idx2], clip_off, clip_scale);
|
|
|
|
if (bd->TargetInfo.IsFast)
|
|
ImGui_ImplSDLSurface3_RenderTriangleFast(bd->TargetInfo, texture_ptr, v0, v1, v2, clip_min_x, clip_min_y, clip_max_x, clip_max_y);
|
|
else
|
|
ImGui_ImplSDLSurface3_RenderTriangleGeneric(bd->TargetInfo, texture_ptr, v0, v1, v2, clip_min_x, clip_min_y, clip_max_x, clip_max_y);
|
|
}
|
|
|
|
if (texture_locked)
|
|
SDL_UnlockSurface(texture_surface);
|
|
}
|
|
}
|
|
|
|
if (SDL_MUSTLOCK(bd->TargetSurface))
|
|
SDL_UnlockSurface(bd->TargetSurface);
|
|
}
|
|
|
|
#endif
|