#include "imgui_impl_sdlsurface2.h" #include "imgui.h" #ifndef IMGUI_DISABLE #include #include #include #include #include struct ImGui_ImplSDLSurface2_FastFormat32 { Uint32 Rmask; Uint32 Gmask; Uint32 Bmask; Uint32 Amask; Uint8 Rshift; Uint8 Gshift; Uint8 Bshift; Uint8 Ashift; bool HasAlpha; bool Valid; ImGui_ImplSDLSurface2_FastFormat32() { memset((void*)this, 0, sizeof(*this)); } }; struct ImGui_ImplSDLSurface2_SurfaceInfo { SDL_Surface* Surface; Uint8* Pixels; int Pitch; int Width; int Height; SDL_PixelFormat* Format; SDL_Palette* Palette; ImGui_ImplSDLSurface2_FastFormat32 FastFormat; bool IsFast; ImGui_ImplSDLSurface2_SurfaceInfo() { memset((void*)this, 0, sizeof(*this)); } }; struct ImGui_ImplSDLSurface2_RasterVertex { float X; float Y; float U; float V; float R; float G; float B; float A; }; struct ImGui_ImplSDLSurface2_Quad { const ImGui_ImplSDLSurface2_RasterVertex* TL; const ImGui_ImplSDLSurface2_RasterVertex* TR; const ImGui_ImplSDLSurface2_RasterVertex* BR; const ImGui_ImplSDLSurface2_RasterVertex* BL; }; struct ImGui_ImplSDLSurface2_Data { SDL_Surface* TargetSurface; SDL_Surface* FontSurface; ImGui_ImplSDLSurface2_SurfaceInfo TargetInfo; ImVector VertexCache; ImGui_ImplSDLSurface2_Data() { memset((void*)this, 0, sizeof(*this)); } }; static ImGui_ImplSDLSurface2_Data* ImGui_ImplSDLSurface2_GetBackendData() { return ImGui::GetCurrentContext() ? (ImGui_ImplSDLSurface2_Data*)ImGui::GetIO().BackendRendererUserData : nullptr; } static inline float ImGui_ImplSDLSurface2_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_ImplSDLSurface2_NearEqual(float a, float b) { return fabsf(a - b) <= 0.0001f; } static inline int ImGui_ImplSDLSurface2_ClampInt(int v, int lo, int hi) { return (v < lo) ? lo : (v > hi ? hi : v); } static inline Uint8 ImGui_ImplSDLSurface2_ClampByte(float v) { if (v <= 0.0f) return 0; if (v >= 255.0f) return 255; return (Uint8)(v + 0.5f); } static inline Uint8 ImGui_ImplSDLSurface2_Mul255(Uint32 a, Uint32 b) { Uint32 t = a * b + 128; return (Uint8)((t + (t >> 8)) >> 8); } static ImGui_ImplSDLSurface2_FastFormat32 ImGui_ImplSDLSurface2_BuildFastFormat(SDL_PixelFormat* format) { ImGui_ImplSDLSurface2_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 bool ImGui_ImplSDLSurface2_CanUseFastPath(SDL_Surface* surface, const ImGui_ImplSDLSurface2_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_ImplSDLSurface2_InitSurfaceInfo(ImGui_ImplSDLSurface2_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 ? surface->format : nullptr; out->Palette = (surface && surface->format) ? surface->format->palette : nullptr; out->FastFormat = ImGui_ImplSDLSurface2_BuildFastFormat(out->Format); out->IsFast = ImGui_ImplSDLSurface2_CanUseFastPath(surface, out->FastFormat); } static inline Uint32 ImGui_ImplSDLSurface2_ReadPixelRaw(const ImGui_ImplSDLSurface2_SurfaceInfo& surface, int x, int y) { const Uint8* p = surface.Pixels + y * surface.Pitch + x * surface.Format->BytesPerPixel; switch (surface.Format->BytesPerPixel) { 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_ImplSDLSurface2_WritePixelRaw(const ImGui_ImplSDLSurface2_SurfaceInfo& surface, int x, int y, Uint32 pixel) { Uint8* p = surface.Pixels + y * surface.Pitch + x * surface.Format->BytesPerPixel; switch (surface.Format->BytesPerPixel) { 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_ImplSDLSurface2_UnpackFastRGBA(const ImGui_ImplSDLSurface2_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_ImplSDLSurface2_PackFastRGBA(const ImGui_ImplSDLSurface2_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_ImplSDLSurface2_ReadPixelRGBA(const ImGui_ImplSDLSurface2_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_ImplSDLSurface2_UnpackFastRGBA(surface.FastFormat, *src, r, g, b, a); return; } Uint32 pixel = ImGui_ImplSDLSurface2_ReadPixelRaw(surface, x, y); SDL_GetRGBA(pixel, surface.Format, r, g, b, a); } static inline Uint8 ImGui_ImplSDLSurface2_ReadPixelAlpha(const ImGui_ImplSDLSurface2_SurfaceInfo& surface, int x, int y) { if (surface.IsFast) { const Uint32* src = (const Uint32*)(surface.Pixels + y * surface.Pitch) + x; return surface.FastFormat.HasAlpha ? (Uint8)((*src & surface.FastFormat.Amask) >> surface.FastFormat.Ashift) : 255; } Uint8 a = 255; Uint32 pixel = ImGui_ImplSDLSurface2_ReadPixelRaw(surface, x, y); SDL_GetRGBA(pixel, surface.Format, nullptr, nullptr, nullptr, &a); return a; } static inline void ImGui_ImplSDLSurface2_BlendPixelFast(const ImGui_ImplSDLSurface2_SurfaceInfo& target, Uint32* dst, Uint8 sr, Uint8 sg, Uint8 sb, Uint8 sa) { if (sa == 0) return; if (sa == 255) { *dst = ImGui_ImplSDLSurface2_PackFastRGBA(target.FastFormat, sr, sg, sb, 255); return; } Uint8 dr, dg, db, da; ImGui_ImplSDLSurface2_UnpackFastRGBA(target.FastFormat, *dst, &dr, &dg, &db, &da); Uint8 inv_a = (Uint8)(255 - sa); Uint8 out_r = (Uint8)(ImGui_ImplSDLSurface2_Mul255(sr, sa) + ImGui_ImplSDLSurface2_Mul255(dr, inv_a)); Uint8 out_g = (Uint8)(ImGui_ImplSDLSurface2_Mul255(sg, sa) + ImGui_ImplSDLSurface2_Mul255(dg, inv_a)); Uint8 out_b = (Uint8)(ImGui_ImplSDLSurface2_Mul255(sb, sa) + ImGui_ImplSDLSurface2_Mul255(db, inv_a)); Uint8 out_a = target.FastFormat.HasAlpha ? (Uint8)(sa + ImGui_ImplSDLSurface2_Mul255(da, inv_a)) : 255; *dst = ImGui_ImplSDLSurface2_PackFastRGBA(target.FastFormat, out_r, out_g, out_b, out_a); } static inline void ImGui_ImplSDLSurface2_BlendPixelGeneric(const ImGui_ImplSDLSurface2_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, sr, sg, sb, 255); ImGui_ImplSDLSurface2_WritePixelRaw(target, x, y, pixel); return; } Uint8 dr, dg, db, da; Uint32 dst_pixel = ImGui_ImplSDLSurface2_ReadPixelRaw(target, x, y); SDL_GetRGBA(dst_pixel, target.Format, &dr, &dg, &db, &da); Uint8 inv_a = (Uint8)(255 - sa); Uint8 out_r = (Uint8)(ImGui_ImplSDLSurface2_Mul255(sr, sa) + ImGui_ImplSDLSurface2_Mul255(dr, inv_a)); Uint8 out_g = (Uint8)(ImGui_ImplSDLSurface2_Mul255(sg, sa) + ImGui_ImplSDLSurface2_Mul255(dg, inv_a)); Uint8 out_b = (Uint8)(ImGui_ImplSDLSurface2_Mul255(sb, sa) + ImGui_ImplSDLSurface2_Mul255(db, inv_a)); Uint8 out_a = target.Format->Amask ? (Uint8)(sa + ImGui_ImplSDLSurface2_Mul255(da, inv_a)) : 255; Uint32 pixel = SDL_MapRGBA(target.Format, out_r, out_g, out_b, out_a); ImGui_ImplSDLSurface2_WritePixelRaw(target, x, y, pixel); } static inline bool ImGui_ImplSDLSurface2_SameColor(const ImGui_ImplSDLSurface2_RasterVertex& a, const ImGui_ImplSDLSurface2_RasterVertex& b) { return a.R == b.R && a.G == b.G && a.B == b.B && a.A == b.A; } static inline void ImGui_ImplSDLSurface2_SetupRasterVertex(ImGui_ImplSDLSurface2_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_ImplSDLSurface2_BuildVertexCache(ImVector* 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_ImplSDLSurface2_SetupRasterVertex(&out->Data[vtx_i], draw_list->VtxBuffer[vtx_i], display_pos, framebuffer_scale); } static void ImGui_ImplSDLSurface2_RenderTriangleFast(const ImGui_ImplSDLSurface2_SurfaceInfo& target, const ImGui_ImplSDLSurface2_SurfaceInfo* texture, bool texture_is_font, const ImGui_ImplSDLSurface2_RasterVertex& v0, const ImGui_ImplSDLSurface2_RasterVertex& v1, const ImGui_ImplSDLSurface2_RasterVertex& v2, int clip_min_x, int clip_min_y, int clip_max_x, int clip_max_y) { IM_UNUSED(texture_is_font); 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_ImplSDLSurface2_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_ImplSDLSurface2_Edge(v1.X, v1.Y, v2.X, v2.Y, start_x, start_y) * sign; float e1_row = ImGui_ImplSDLSurface2_Edge(v2.X, v2.Y, v0.X, v0.Y, start_x, start_y) * sign; float e2_row = ImGui_ImplSDLSurface2_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_ImplSDLSurface2_ClampByte(r); Uint8 out_g = ImGui_ImplSDLSurface2_ClampByte(g); Uint8 out_b = ImGui_ImplSDLSurface2_ClampByte(b); Uint8 out_a = ImGui_ImplSDLSurface2_ClampByte(a); if (texture != nullptr) { int tx = ImGui_ImplSDLSurface2_ClampInt((int)(u * (float)texture_max_x + 0.5f), 0, texture_max_x); int ty = ImGui_ImplSDLSurface2_ClampInt((int)(v * (float)texture_max_y + 0.5f), 0, texture_max_y); Uint8 tr, tg, tb, ta; ImGui_ImplSDLSurface2_ReadPixelRGBA(*texture, tx, ty, &tr, &tg, &tb, &ta); out_r = ImGui_ImplSDLSurface2_Mul255(out_r, tr); out_g = ImGui_ImplSDLSurface2_Mul255(out_g, tg); out_b = ImGui_ImplSDLSurface2_Mul255(out_b, tb); out_a = ImGui_ImplSDLSurface2_Mul255(out_a, ta); } ImGui_ImplSDLSurface2_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_ImplSDLSurface2_RenderTriangleGeneric(const ImGui_ImplSDLSurface2_SurfaceInfo& target, const ImGui_ImplSDLSurface2_SurfaceInfo* texture, bool texture_is_font, const ImGui_ImplSDLSurface2_RasterVertex& v0, const ImGui_ImplSDLSurface2_RasterVertex& v1, const ImGui_ImplSDLSurface2_RasterVertex& v2, int clip_min_x, int clip_min_y, int clip_max_x, int clip_max_y) { IM_UNUSED(texture_is_font); 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_ImplSDLSurface2_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_ImplSDLSurface2_Edge(v1.X, v1.Y, v2.X, v2.Y, start_x, start_y) * sign; float e1_row = ImGui_ImplSDLSurface2_Edge(v2.X, v2.Y, v0.X, v0.Y, start_x, start_y) * sign; float e2_row = ImGui_ImplSDLSurface2_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_ImplSDLSurface2_ClampByte(r); Uint8 out_g = ImGui_ImplSDLSurface2_ClampByte(g); Uint8 out_b = ImGui_ImplSDLSurface2_ClampByte(b); Uint8 out_a = ImGui_ImplSDLSurface2_ClampByte(a); if (texture != nullptr) { int tx = ImGui_ImplSDLSurface2_ClampInt((int)(u * (float)texture_max_x + 0.5f), 0, texture_max_x); int ty = ImGui_ImplSDLSurface2_ClampInt((int)(v * (float)texture_max_y + 0.5f), 0, texture_max_y); Uint8 tr, tg, tb, ta; ImGui_ImplSDLSurface2_ReadPixelRGBA(*texture, tx, ty, &tr, &tg, &tb, &ta); out_r = ImGui_ImplSDLSurface2_Mul255(out_r, tr); out_g = ImGui_ImplSDLSurface2_Mul255(out_g, tg); out_b = ImGui_ImplSDLSurface2_Mul255(out_b, tb); out_a = ImGui_ImplSDLSurface2_Mul255(out_a, ta); } ImGui_ImplSDLSurface2_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; } } static bool ImGui_ImplSDLSurface2_DetectQuad(const ImGui_ImplSDLSurface2_RasterVertex* vertices, const ImDrawIdx* idx_buffer, int vtx_offset, unsigned int elem_offset, ImGui_ImplSDLSurface2_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_ImplSDLSurface2_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_ImplSDLSurface2_RasterVertex* v = candidates[i]; if (ImGui_ImplSDLSurface2_NearEqual(v->X, min_x) && ImGui_ImplSDLSurface2_NearEqual(v->Y, min_y)) out->TL = v; else if (ImGui_ImplSDLSurface2_NearEqual(v->X, max_x) && ImGui_ImplSDLSurface2_NearEqual(v->Y, min_y)) out->TR = v; else if (ImGui_ImplSDLSurface2_NearEqual(v->X, max_x) && ImGui_ImplSDLSurface2_NearEqual(v->Y, max_y)) out->BR = v; else if (ImGui_ImplSDLSurface2_NearEqual(v->X, min_x) && ImGui_ImplSDLSurface2_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_ImplSDLSurface2_QuadHasConstantColor(const ImGui_ImplSDLSurface2_Quad& quad) { return ImGui_ImplSDLSurface2_SameColor(*quad.TL, *quad.TR) && ImGui_ImplSDLSurface2_SameColor(*quad.TL, *quad.BR) && ImGui_ImplSDLSurface2_SameColor(*quad.TL, *quad.BL); } static bool ImGui_ImplSDLSurface2_QuadHasLinearUV(const ImGui_ImplSDLSurface2_Quad& quad) { if (!ImGui_ImplSDLSurface2_NearEqual(quad.TL->Y, quad.TR->Y) || !ImGui_ImplSDLSurface2_NearEqual(quad.BL->Y, quad.BR->Y) || !ImGui_ImplSDLSurface2_NearEqual(quad.TL->X, quad.BL->X) || !ImGui_ImplSDLSurface2_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_ImplSDLSurface2_NearEqual(u, quad.BR->U) && ImGui_ImplSDLSurface2_NearEqual(v, quad.BR->V); } static bool ImGui_ImplSDLSurface2_QuadGetConstantTexel(const ImGui_ImplSDLSurface2_SurfaceInfo& texture, const ImGui_ImplSDLSurface2_Quad& quad, int* out_x, int* out_y) { int max_x = texture.Width - 1; int max_y = texture.Height - 1; int tx = ImGui_ImplSDLSurface2_ClampInt((int)(quad.TL->U * (float)max_x + 0.5f), 0, max_x); int ty = ImGui_ImplSDLSurface2_ClampInt((int)(quad.TL->V * (float)max_y + 0.5f), 0, max_y); int corner_tx[3] = { ImGui_ImplSDLSurface2_ClampInt((int)(quad.TR->U * (float)max_x + 0.5f), 0, max_x), ImGui_ImplSDLSurface2_ClampInt((int)(quad.BR->U * (float)max_x + 0.5f), 0, max_x), ImGui_ImplSDLSurface2_ClampInt((int)(quad.BL->U * (float)max_x + 0.5f), 0, max_x) }; int corner_ty[3] = { ImGui_ImplSDLSurface2_ClampInt((int)(quad.TR->V * (float)max_y + 0.5f), 0, max_y), ImGui_ImplSDLSurface2_ClampInt((int)(quad.BR->V * (float)max_y + 0.5f), 0, max_y), ImGui_ImplSDLSurface2_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_ImplSDLSurface2_RenderSolidRectFast(const ImGui_ImplSDLSurface2_SurfaceInfo& target, const ImGui_ImplSDLSurface2_Quad& quad, int clip_min_x, int clip_min_y, int clip_max_x, int clip_max_y, Uint8 r, Uint8 g, Uint8 b, Uint8 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) { Uint32 pixel = ImGui_ImplSDLSurface2_PackFastRGBA(target.FastFormat, r, g, b, 255); for (int y = min_y; y <= max_y; y++) { Uint32* dst = (Uint32*)(target.Pixels + y * target.Pitch) + min_x; std::fill_n(dst, count, pixel); } return; } for (int y = min_y; y <= max_y; y++) { Uint32* dst = (Uint32*)(target.Pixels + y * target.Pitch) + min_x; for (int x = 0; x < count; x++) ImGui_ImplSDLSurface2_BlendPixelFast(target, dst + x, r, g, b, a); } } static void ImGui_ImplSDLSurface2_RenderSolidRectGeneric(const ImGui_ImplSDLSurface2_SurfaceInfo& target, const ImGui_ImplSDLSurface2_Quad& quad, int clip_min_x, int clip_min_y, int clip_max_x, int clip_max_y, Uint8 r, Uint8 g, Uint8 b, Uint8 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; Uint32 opaque_pixel = 0; if (a == 255) opaque_pixel = SDL_MapRGBA(target.Format, r, g, b, 255); for (int y = min_y; y <= max_y; y++) { for (int x = min_x; x <= max_x; x++) { if (a == 255) ImGui_ImplSDLSurface2_WritePixelRaw(target, x, y, opaque_pixel); else ImGui_ImplSDLSurface2_BlendPixelGeneric(target, x, y, r, g, b, a); } } } static void ImGui_ImplSDLSurface2_RenderTexturedRectFast(const ImGui_ImplSDLSurface2_SurfaceInfo& target, const ImGui_ImplSDLSurface2_SurfaceInfo& texture, bool texture_is_font, const ImGui_ImplSDLSurface2_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; Uint8 color_r = (Uint8)quad.TL->R; Uint8 color_g = (Uint8)quad.TL->G; Uint8 color_b = (Uint8)quad.TL->B; Uint8 color_a = (Uint8)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; Uint32* dst = (Uint32*)(target.Pixels + y * target.Pitch) + min_x; for (int x = min_x; x <= max_x; x++) { int tx = ImGui_ImplSDLSurface2_ClampInt((int)(u * (float)texture_max_x + 0.5f), 0, texture_max_x); int ty = ImGui_ImplSDLSurface2_ClampInt((int)(v * (float)texture_max_y + 0.5f), 0, texture_max_y); Uint8 out_r = color_r; Uint8 out_g = color_g; Uint8 out_b = color_b; Uint8 out_a = color_a; if (texture_is_font) { out_a = ImGui_ImplSDLSurface2_Mul255(out_a, ImGui_ImplSDLSurface2_ReadPixelAlpha(texture, tx, ty)); ImGui_ImplSDLSurface2_BlendPixelFast(target, dst, out_r, out_g, out_b, out_a); } else { Uint8 tr, tg, tb, ta; ImGui_ImplSDLSurface2_ReadPixelRGBA(texture, tx, ty, &tr, &tg, &tb, &ta); out_r = ImGui_ImplSDLSurface2_Mul255(out_r, tr); out_g = ImGui_ImplSDLSurface2_Mul255(out_g, tg); out_b = ImGui_ImplSDLSurface2_Mul255(out_b, tb); out_a = ImGui_ImplSDLSurface2_Mul255(out_a, ta); ImGui_ImplSDLSurface2_BlendPixelFast(target, dst, out_r, out_g, out_b, out_a); } dst++; u += du_dx; v += dv_dx; } } } static void ImGui_ImplSDLSurface2_RenderTexturedRectGeneric(const ImGui_ImplSDLSurface2_SurfaceInfo& target, const ImGui_ImplSDLSurface2_SurfaceInfo& texture, bool texture_is_font, const ImGui_ImplSDLSurface2_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; Uint8 color_r = (Uint8)quad.TL->R; Uint8 color_g = (Uint8)quad.TL->G; Uint8 color_b = (Uint8)quad.TL->B; Uint8 color_a = (Uint8)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; for (int x = min_x; x <= max_x; x++) { int tx = ImGui_ImplSDLSurface2_ClampInt((int)(u * (float)texture_max_x + 0.5f), 0, texture_max_x); int ty = ImGui_ImplSDLSurface2_ClampInt((int)(v * (float)texture_max_y + 0.5f), 0, texture_max_y); Uint8 out_r = color_r; Uint8 out_g = color_g; Uint8 out_b = color_b; Uint8 out_a = color_a; if (texture_is_font) { out_a = ImGui_ImplSDLSurface2_Mul255(out_a, ImGui_ImplSDLSurface2_ReadPixelAlpha(texture, tx, ty)); } else { Uint8 tr, tg, tb, ta; ImGui_ImplSDLSurface2_ReadPixelRGBA(texture, tx, ty, &tr, &tg, &tb, &ta); out_r = ImGui_ImplSDLSurface2_Mul255(out_r, tr); out_g = ImGui_ImplSDLSurface2_Mul255(out_g, tg); out_b = ImGui_ImplSDLSurface2_Mul255(out_b, tb); out_a = ImGui_ImplSDLSurface2_Mul255(out_a, ta); } ImGui_ImplSDLSurface2_BlendPixelGeneric(target, x, y, out_r, out_g, out_b, out_a); u += du_dx; v += dv_dx; } } } static bool ImGui_ImplSDLSurface2_TryRenderQuadFast(const ImGui_ImplSDLSurface2_SurfaceInfo& target, const ImGui_ImplSDLSurface2_SurfaceInfo* texture, bool texture_is_font, const ImGui_ImplSDLSurface2_Quad& quad, int clip_min_x, int clip_min_y, int clip_max_x, int clip_max_y) { if (!ImGui_ImplSDLSurface2_QuadHasConstantColor(quad)) return false; Uint8 r = (Uint8)quad.TL->R; Uint8 g = (Uint8)quad.TL->G; Uint8 b = (Uint8)quad.TL->B; Uint8 a = (Uint8)quad.TL->A; if (texture == nullptr) { ImGui_ImplSDLSurface2_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_ImplSDLSurface2_QuadGetConstantTexel(*texture, quad, &tx, &ty)) { if (texture_is_font) { a = ImGui_ImplSDLSurface2_Mul255(a, ImGui_ImplSDLSurface2_ReadPixelAlpha(*texture, tx, ty)); } else { Uint8 tr, tg, tb, ta; ImGui_ImplSDLSurface2_ReadPixelRGBA(*texture, tx, ty, &tr, &tg, &tb, &ta); r = ImGui_ImplSDLSurface2_Mul255(r, tr); g = ImGui_ImplSDLSurface2_Mul255(g, tg); b = ImGui_ImplSDLSurface2_Mul255(b, tb); a = ImGui_ImplSDLSurface2_Mul255(a, ta); } ImGui_ImplSDLSurface2_RenderSolidRectFast(target, quad, clip_min_x, clip_min_y, clip_max_x, clip_max_y, r, g, b, a); return true; } if (!ImGui_ImplSDLSurface2_QuadHasLinearUV(quad)) return false; ImGui_ImplSDLSurface2_RenderTexturedRectFast(target, *texture, texture_is_font, quad, clip_min_x, clip_min_y, clip_max_x, clip_max_y); return true; } static bool ImGui_ImplSDLSurface2_TryRenderQuadGeneric(const ImGui_ImplSDLSurface2_SurfaceInfo& target, const ImGui_ImplSDLSurface2_SurfaceInfo* texture, bool texture_is_font, const ImGui_ImplSDLSurface2_Quad& quad, int clip_min_x, int clip_min_y, int clip_max_x, int clip_max_y) { if (!ImGui_ImplSDLSurface2_QuadHasConstantColor(quad)) return false; Uint8 r = (Uint8)quad.TL->R; Uint8 g = (Uint8)quad.TL->G; Uint8 b = (Uint8)quad.TL->B; Uint8 a = (Uint8)quad.TL->A; if (texture == nullptr) { ImGui_ImplSDLSurface2_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_ImplSDLSurface2_QuadGetConstantTexel(*texture, quad, &tx, &ty)) { if (texture_is_font) { a = ImGui_ImplSDLSurface2_Mul255(a, ImGui_ImplSDLSurface2_ReadPixelAlpha(*texture, tx, ty)); } else { Uint8 tr, tg, tb, ta; ImGui_ImplSDLSurface2_ReadPixelRGBA(*texture, tx, ty, &tr, &tg, &tb, &ta); r = ImGui_ImplSDLSurface2_Mul255(r, tr); g = ImGui_ImplSDLSurface2_Mul255(g, tg); b = ImGui_ImplSDLSurface2_Mul255(b, tb); a = ImGui_ImplSDLSurface2_Mul255(a, ta); } ImGui_ImplSDLSurface2_RenderSolidRectGeneric(target, quad, clip_min_x, clip_min_y, clip_max_x, clip_max_y, r, g, b, a); return true; } if (!ImGui_ImplSDLSurface2_QuadHasLinearUV(quad)) return false; ImGui_ImplSDLSurface2_RenderTexturedRectGeneric(target, *texture, texture_is_font, quad, clip_min_x, clip_min_y, clip_max_x, clip_max_y); return true; } SDL_Surface* ImGui_ImplSDLSurface2_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_CreateRGBSurfaceWithFormat(0, width, height, 32, SDL_PIXELFORMAT_RGBA32); if (surface == nullptr) return nullptr; if (SDL_MUSTLOCK(surface) && SDL_LockSurface(surface) != 0) { SDL_FreeSurface(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_ImplSDLSurface2_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_ImplSDLSurface2_Data* bd = IM_NEW(ImGui_ImplSDLSurface2_Data)(); io.BackendRendererUserData = (void*)bd; io.BackendRendererName = "imgui_impl_sdlsurface2"; bd->TargetSurface = surface; ImGui_ImplSDLSurface2_InitSurfaceInfo(&bd->TargetInfo, surface); bd->FontSurface = ImGui_ImplSDLSurface2_CreateFontAtlasSurface(); if (bd->FontSurface != nullptr) io.Fonts->SetTexID((ImTextureID)bd->FontSurface); return true; } void ImGui_ImplSDLSurface2_Shutdown() { ImGui_ImplSDLSurface2_Data* bd = ImGui_ImplSDLSurface2_GetBackendData(); IM_ASSERT(bd != nullptr && "No renderer backend to shutdown, or already shutdown?"); ImGuiIO& io = ImGui::GetIO(); ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); if (io.Fonts->TexData != nullptr) io.Fonts->TexData->SetTexID(ImTextureID_Invalid); io.BackendRendererName = nullptr; io.BackendRendererUserData = nullptr; platform_io.ClearRendererHandlers(); if (bd->FontSurface != nullptr) SDL_FreeSurface(bd->FontSurface); IM_DELETE(bd); } void ImGui_ImplSDLSurface2_NewFrame() { ImGui_ImplSDLSurface2_Data* bd = ImGui_ImplSDLSurface2_GetBackendData(); IM_ASSERT(bd != nullptr && "Context or backend not initialized! Did you call ImGui_ImplSDLSurface2_Init()?"); IM_UNUSED(bd); } void ImGui_ImplSDLSurface2_RenderDrawData(ImDrawData* draw_data) { ImGui_ImplSDLSurface2_Data* bd = ImGui_ImplSDLSurface2_GetBackendData(); if (bd == nullptr || draw_data == nullptr || bd->TargetSurface == nullptr) return; if (SDL_MUSTLOCK(bd->TargetSurface) && SDL_LockSurface(bd->TargetSurface) != 0) return; ImGui_ImplSDLSurface2_InitSurfaceInfo(&bd->TargetInfo, bd->TargetSurface); if (bd->TargetInfo.Width <= 0 || bd->TargetInfo.Height <= 0) { if (SDL_MUSTLOCK(bd->TargetSurface)) SDL_UnlockSurface(bd->TargetSurface); return; } SDL_Surface* active_texture_surface = nullptr; ImGui_ImplSDLSurface2_SurfaceInfo active_texture_info; bool active_texture_valid = false; bool active_texture_locked = false; bool active_texture_is_font = false; 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 ImDrawIdx* idx_buffer = draw_list->IdxBuffer.Data; ImGui_ImplSDLSurface2_BuildVertexCache(&bd->VertexCache, draw_list, clip_off, clip_scale); const ImGui_ImplSDLSurface2_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)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(); if (texture_surface != active_texture_surface) { if (active_texture_locked && active_texture_surface != nullptr) SDL_UnlockSurface(active_texture_surface); active_texture_surface = texture_surface; active_texture_valid = false; active_texture_locked = false; active_texture_is_font = false; if (texture_surface != nullptr) { if (SDL_MUSTLOCK(texture_surface)) { if (SDL_LockSurface(texture_surface) != 0) active_texture_surface = texture_surface; else active_texture_locked = true; } if (!SDL_MUSTLOCK(texture_surface) || active_texture_locked) { ImGui_ImplSDLSurface2_InitSurfaceInfo(&active_texture_info, texture_surface); active_texture_valid = active_texture_info.Width > 0 && active_texture_info.Height > 0; active_texture_is_font = texture_surface == bd->FontSurface; } } } const ImGui_ImplSDLSurface2_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_ImplSDLSurface2_Quad quad; if (ImGui_ImplSDLSurface2_DetectQuad(vertex_cache, idx_buffer, pcmd->VtxOffset, pcmd->IdxOffset + idx, &quad)) { bool rendered = bd->TargetInfo.IsFast ? ImGui_ImplSDLSurface2_TryRenderQuadFast(bd->TargetInfo, texture_ptr, active_texture_is_font, quad, clip_min_x, clip_min_y, clip_max_x, clip_max_y) : ImGui_ImplSDLSurface2_TryRenderQuadGeneric(bd->TargetInfo, texture_ptr, active_texture_is_font, 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_ImplSDLSurface2_RasterVertex& v0 = vertex_cache[pcmd->VtxOffset + idx0]; const ImGui_ImplSDLSurface2_RasterVertex& v1 = vertex_cache[pcmd->VtxOffset + idx1]; const ImGui_ImplSDLSurface2_RasterVertex& v2 = vertex_cache[pcmd->VtxOffset + idx2]; if (bd->TargetInfo.IsFast) ImGui_ImplSDLSurface2_RenderTriangleFast(bd->TargetInfo, texture_ptr, active_texture_is_font, v0, v1, v2, clip_min_x, clip_min_y, clip_max_x, clip_max_y); else ImGui_ImplSDLSurface2_RenderTriangleGeneric(bd->TargetInfo, texture_ptr, active_texture_is_font, v0, v1, v2, clip_min_x, clip_min_y, clip_max_x, clip_max_y); idx += 3; } } } if (active_texture_locked && active_texture_surface != nullptr) SDL_UnlockSurface(active_texture_surface); if (SDL_MUSTLOCK(bd->TargetSurface)) SDL_UnlockSurface(bd->TargetSurface); } #endif