diff --git a/backends/imgui_impl_sdlsurface2.cpp b/backends/imgui_impl_sdlsurface2.cpp index 05e55c17..e9ea0488 100644 --- a/backends/imgui_impl_sdlsurface2.cpp +++ b/backends/imgui_impl_sdlsurface2.cpp @@ -1,324 +1,715 @@ -// imgui_impl_sdlsurface2.cpp -// CPU-only SDL_Surface backend for Dear ImGui - #include "imgui_impl_sdlsurface2.h" #include "imgui.h" +#ifndef IMGUI_DISABLE #include -#include +#include #include +#include +#include -// No clamp in C++11 -template -static inline T ImClamp(T v, T lo, T hi) +struct ImGui_ImplSDLSurface2_FastFormat32 { - if (v < lo) return lo; - if (v > hi) return hi; - return v; + 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_Data +{ + SDL_Surface* TargetSurface; + SDL_Surface* FontSurface; + ImGui_ImplSDLSurface2_SurfaceInfo TargetInfo; + + ImGui_ImplSDLSurface2_Data() { 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; +}; + +static ImGui_ImplSDLSurface2_Data* ImGui_ImplSDLSurface2_GetBackendData() +{ + return ImGui::GetCurrentContext() ? (ImGui_ImplSDLSurface2_Data*)ImGui::GetIO().BackendRendererUserData : nullptr; } - -static SDL_Surface* g_TargetSurface = nullptr; -static SDL_Surface* g_FontSurface = nullptr; - -static inline Uint32 GetPixel(SDL_Surface* s, int x, int y) +static inline float ImGui_ImplSDLSurface2_Edge(float ax, float ay, float bx, float by, float px, float py) { - Uint8* p = (Uint8*)s->pixels + y * s->pitch + x * s->format->BytesPerPixel; - switch (s->format->BytesPerPixel) + return (bx - ax) * (py - ay) - (by - ay) * (px - ax); +} + +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 *(Uint16*)p; - case 3: - if (SDL_BYTEORDER == SDL_BIG_ENDIAN) - return (p[0] << 16) | (p[1] << 8) | p[2]; - else - return p[0] | (p[1] << 8) | (p[2] << 16); - case 4: return *(Uint32*)p; + 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; } - return 0; } -static inline void BlendPixel(SDL_Surface* s, int x, int y, - Uint8 sr, Uint8 sg, Uint8 sb, Uint8 sa) +static inline void ImGui_ImplSDLSurface2_WritePixelRaw(const ImGui_ImplSDLSurface2_SurfaceInfo& surface, int x, int y, Uint32 pixel) { - if (!s || sa == 0) return; - if (x < 0 || y < 0 || x >= s->w || y >= s->h) return; - - if (sa == 255) + Uint8* p = surface.Pixels + y * surface.Pitch + x * surface.Format->BytesPerPixel; + switch (surface.Format->BytesPerPixel) { - Uint32 out_pix = SDL_MapRGBA(s->format, sr, sg, sb, sa); - Uint8* p = (Uint8*)s->pixels + y * s->pitch + x * s->format->BytesPerPixel; - switch (s->format->BytesPerPixel) + case 1: + *p = (Uint8)pixel; + return; + case 2: + *(Uint16*)p = (Uint16)pixel; + return; + case 3: + if (SDL_BYTEORDER == SDL_BIG_ENDIAN) { - case 1: *p = (Uint8)out_pix; break; - case 2: *(Uint16*)p = (Uint16)out_pix; break; - case 3: - if (SDL_BYTEORDER == SDL_BIG_ENDIAN) - { - p[0] = (out_pix >> 16) & 0xFF; - p[1] = (out_pix >> 8) & 0xFF; - p[2] = out_pix & 0xFF; - } - else - { - p[0] = out_pix & 0xFF; - p[1] = (out_pix >> 8) & 0xFF; - p[2] = (out_pix >> 16) & 0xFF; - } - break; - case 4: *(Uint32*)p = out_pix; break; + 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 dst_pix = GetPixel(s, x, y); - Uint8 dr, dg, db, da; - SDL_GetRGBA(dst_pix, s->format, &dr, &dg, &db, &da); + Uint32 pixel = ImGui_ImplSDLSurface2_ReadPixelRaw(surface, x, y); + SDL_GetRGBA(pixel, surface.Format, r, g, b, a); +} - Uint8 out_r = (Uint8)((sr * sa + dr * (255 - sa)) / 255); - Uint8 out_g = (Uint8)((sg * sa + dg * (255 - sa)) / 255); - Uint8 out_b = (Uint8)((sb * sa + db * (255 - sa)) / 255); - Uint8 out_a = (Uint8)((sa + (da * (255 - sa)) / 255)); - - Uint32 out_pix = SDL_MapRGBA(s->format, out_r, out_g, out_b, out_a); - Uint8* p = (Uint8*)s->pixels + y * s->pitch + x * s->format->BytesPerPixel; - switch (s->format->BytesPerPixel) +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) { - case 1: *p = (Uint8)out_pix; break; - case 2: *(Uint16*)p = (Uint16)out_pix; break; - case 3: - if (SDL_BYTEORDER == SDL_BIG_ENDIAN) + *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 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_RenderTriangleFast(const ImGui_ImplSDLSurface2_SurfaceInfo& target, const ImGui_ImplSDLSurface2_SurfaceInfo* texture, 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) +{ + 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) { - p[0] = (out_pix >> 16) & 0xFF; - p[1] = (out_pix >> 8) & 0xFF; - p[2] = out_pix & 0xFF; + 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); } - else - { - p[0] = out_pix & 0xFF; - p[1] = (out_pix >> 8) & 0xFF; - p[2] = (out_pix >> 16) & 0xFF; - } - break; - case 4: *(Uint32*)p = out_pix; break; + + 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 inline float Edge(const ImVec2& a, const ImVec2& b, float x, float y) +static void ImGui_ImplSDLSurface2_RenderTriangleGeneric(const ImGui_ImplSDLSurface2_SurfaceInfo& target, const ImGui_ImplSDLSurface2_SurfaceInfo* texture, 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) { - return (b.x - a.x) * (y - a.y) - (b.y - a.y) * (x - a.x); + 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; + } } SDL_Surface* ImGui_ImplSDLSurface2_CreateFontAtlasSurface() { ImGuiIO& io = ImGui::GetIO(); unsigned char* pixels = nullptr; - int width = 0, height = 0; + int width = 0; + int height = 0; io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height); - if (!pixels || width <= 0 || height <= 0) return nullptr; + if (pixels == nullptr || width <= 0 || height <= 0) + return nullptr; - SDL_Surface* surf = SDL_CreateRGBSurfaceWithFormat(0, width, height, 32, SDL_PIXELFORMAT_RGBA32); - if (!surf) 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; + } - SDL_LockSurface(surf); - std::memcpy(surf->pixels, pixels, width * height * 4); - SDL_UnlockSurface(surf); - SDL_SetSurfaceBlendMode(surf, SDL_BLENDMODE_NONE); - return surf; + 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) return false; + if (surface == nullptr) + return false; ImGuiIO& io = ImGui::GetIO(); - IM_ASSERT(io.BackendRendererName == nullptr && "Already initialized a renderer backend!"); + 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"; - g_TargetSurface = surface; - g_FontSurface = ImGui_ImplSDLSurface2_CreateFontAtlasSurface(); - if (g_FontSurface) - { - if (g_TargetSurface && g_FontSurface->format->format != g_TargetSurface->format->format) - { - SDL_Surface* converted = SDL_ConvertSurfaceFormat(g_FontSurface, g_TargetSurface->format->format, 0); - if (converted) - { - SDL_FreeSurface(g_FontSurface); - g_FontSurface = converted; - } - } - ImGui::GetIO().Fonts->TexID = (ImTextureID)g_FontSurface; - } + bd->TargetSurface = surface; + ImGui_ImplSDLSurface2_InitSurfaceInfo(&bd->TargetInfo, surface); + bd->FontSurface = ImGui_ImplSDLSurface2_CreateFontAtlasSurface(); + if (bd->FontSurface != nullptr) + io.Fonts->TexID = (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(); - io.BackendRendererName = nullptr; - io.BackendFlags &= ~ImGuiBackendFlags_RendererHasTextures; + ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); - ImGui::GetIO().Fonts->TexID = nullptr; - if (g_FontSurface) - { - SDL_FreeSurface(g_FontSurface); - g_FontSurface = nullptr; - } - g_TargetSurface = nullptr; + io.Fonts->TexID = nullptr; + io.BackendRendererName = nullptr; + io.BackendRendererUserData = nullptr; + platform_io.ClearRendererHandlers(); + + if (bd->FontSurface != nullptr) + SDL_FreeSurface(bd->FontSurface); + + IM_DELETE(bd); } void ImGui_ImplSDLSurface2_NewFrame() { - // noop + 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) { - if (!draw_data || !g_TargetSurface) return; + ImGui_ImplSDLSurface2_Data* bd = ImGui_ImplSDLSurface2_GetBackendData(); + if (bd == nullptr || draw_data == nullptr || bd->TargetSurface == nullptr) + return; - if (SDL_MUSTLOCK(g_TargetSurface)) SDL_LockSurface(g_TargetSurface); + if (SDL_MUSTLOCK(bd->TargetSurface) && SDL_LockSurface(bd->TargetSurface) != 0) + return; - const ImVec2 display_pos = draw_data->DisplayPos; - const ImVec2 fb_scale = draw_data->FramebufferScale; + 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; + } + + 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* cmd_list = draw_data->CmdLists[n]; - const ImDrawVert* vtx_buffer = cmd_list->VtxBuffer.Data; - const ImDrawIdx* idx_buffer = cmd_list->IdxBuffer.Data; + const ImDrawList* draw_list = draw_data->CmdLists[n]; + const ImDrawVert* vtx_buffer = draw_list->VtxBuffer.Data; + const ImDrawIdx* idx_buffer = draw_list->IdxBuffer.Data; - int idx_offset = 0; - - for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++) + for (int cmd_i = 0; cmd_i < draw_list->CmdBuffer.Size; cmd_i++) { - const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[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 = ImVec2( - (pcmd->ClipRect.x - display_pos.x) * fb_scale.x, - (pcmd->ClipRect.y - display_pos.y) * fb_scale.y); - ImVec2 clip_max = ImVec2( - (pcmd->ClipRect.z - display_pos.x) * fb_scale.x, - (pcmd->ClipRect.w - display_pos.y) * fb_scale.y); - - int cx0 = (int)std::floor(clip_min.x); - int cy0 = (int)std::floor(clip_min.y); - int cx1 = (int)std::ceil (clip_max.x); - int cy1 = (int)std::ceil (clip_max.y); - - cx0 = std::max(cx0, 0); - cy0 = std::max(cy0, 0); - cx1 = std::min(cx1, g_TargetSurface->w); - cy1 = std::min(cy1, g_TargetSurface->h); - - if (cx0 >= cx1 || cy0 >= cy1) - { - idx_offset += pcmd->ElemCount; + 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; - } - SDL_Rect srect{ cx0, cy0, cx1 - cx0, cy1 - cy0 }; - SDL_SetClipRect(g_TargetSurface, &srect); + 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* tex = (SDL_Surface*)pcmd->GetTexID(); + SDL_Surface* texture_surface = (SDL_Surface*)pcmd->GetTexID(); + ImGui_ImplSDLSurface2_SurfaceInfo texture_info; + ImGui_ImplSDLSurface2_SurfaceInfo* texture_ptr = nullptr; + bool texture_locked = false; - for (unsigned int i = 0; i + 2 < (unsigned int)pcmd->ElemCount; i += 3) + if (texture_surface != nullptr) { - ImDrawIdx i0 = idx_buffer[idx_offset + i + 0]; - ImDrawIdx i1 = idx_buffer[idx_offset + i + 1]; - ImDrawIdx i2 = idx_buffer[idx_offset + i + 2]; - - const ImDrawVert& v0 = vtx_buffer[i0]; - const ImDrawVert& v1 = vtx_buffer[i1]; - const ImDrawVert& v2 = vtx_buffer[i2]; - - ImVec2 p0 = ImVec2((v0.pos.x - display_pos.x) * fb_scale.x, (v0.pos.y - display_pos.y) * fb_scale.y); - ImVec2 p1 = ImVec2((v1.pos.x - display_pos.x) * fb_scale.x, (v1.pos.y - display_pos.y) * fb_scale.y); - ImVec2 p2 = ImVec2((v2.pos.x - display_pos.x) * fb_scale.x, (v2.pos.y - display_pos.y) * fb_scale.y); - - int minx = (int)std::floor(std::min({ p0.x, p1.x, p2.x })); - int miny = (int)std::floor(std::min({ p0.y, p1.y, p2.y })); - int maxx = (int)std::ceil (std::max({ p0.x, p1.x, p2.x })); - int maxy = (int)std::ceil (std::max({ p0.y, p1.y, p2.y })); - - minx = std::max(minx, cx0); - miny = std::max(miny, cy0); - maxx = std::min(maxx, cx1 - 1); - maxy = std::min(maxy, cy1 - 1); - - if (minx > maxx || miny > maxy) continue; - - float area = Edge(p0, p1, p2.x, p2.y); - if (area == 0.0f) continue; - - auto unpack_col = [](ImU32 c, float out[4]) { - out[0] = (float)((c >> IM_COL32_R_SHIFT) & 0xFF) / 255.0f; - out[1] = (float)((c >> IM_COL32_G_SHIFT) & 0xFF) / 255.0f; - out[2] = (float)((c >> IM_COL32_B_SHIFT) & 0xFF) / 255.0f; - out[3] = (float)((c >> IM_COL32_A_SHIFT) & 0xFF) / 255.0f; - }; - - float c0[4], c1[4], c2[4]; - unpack_col(v0.col, c0); unpack_col(v1.col, c1); unpack_col(v2.col, c2); - - for (int y = miny; y <= maxy; y++) + if (SDL_MUSTLOCK(texture_surface)) { - for (int x = minx; x <= maxx; x++) - { - float px = (float)x + 0.5f; - float py = (float)y + 0.5f; - - float w0 = Edge(p1, p2, px, py) / area; - float w1 = Edge(p2, p0, px, py) / area; - float w2 = Edge(p0, p1, px, py) / area; - - if (w0 < 0.0f || w1 < 0.0f || w2 < 0.0f) continue; - - float r = w0 * c0[0] + w1 * c1[0] + w2 * c2[0]; - float g = w0 * c0[1] + w1 * c1[1] + w2 * c2[1]; - float b = w0 * c0[2] + w1 * c1[2] + w2 * c2[2]; - float a = w0 * c0[3] + w1 * c1[3] + w2 * c2[3]; - - Uint8 out_r = (Uint8)(ImClamp(r, 0.0f, 1.0f) * 255.0f); - Uint8 out_g = (Uint8)(ImClamp(g, 0.0f, 1.0f) * 255.0f); - Uint8 out_b = (Uint8)(ImClamp(b, 0.0f, 1.0f) * 255.0f); - Uint8 out_a = (Uint8)(ImClamp(a, 0.0f, 1.0f) * 255.0f); - - if (tex) - { - ImVec2 uv0 = v0.uv, uv1 = v1.uv, uv2 = v2.uv; - float u = w0 * uv0.x + w1 * uv1.x + w2 * uv2.x; - float v = w0 * uv0.y + w1 * uv1.y + w2 * uv2.y; - - int tx = (int)(u * (tex->w - 1) + 0.5f); - int ty = (int)(v * (tex->h - 1) + 0.5f); - tx = ImClamp(tx, 0, tex->w - 1); - ty = ImClamp(ty, 0, tex->h - 1); - - Uint32 tpx = GetPixel(tex, tx, ty); - Uint8 tr, tg, tb, ta; - SDL_GetRGBA(tpx, tex->format, &tr, &tg, &tb, &ta); - - Uint8 final_r = (Uint8)((tr * out_r) / 255); - Uint8 final_g = (Uint8)((tg * out_g) / 255); - Uint8 final_b = (Uint8)((tb * out_b) / 255); - Uint8 final_a = (Uint8)((ta * out_a) / 255); - - BlendPixel(g_TargetSurface, x, y, final_r, final_g, final_b, final_a); - } - else - { - BlendPixel(g_TargetSurface, x, y, out_r, out_g, out_b, out_a); - } - } + if (SDL_LockSurface(texture_surface) != 0) + texture_surface = nullptr; + else + texture_locked = true; + } + if (texture_surface != nullptr) + { + ImGui_ImplSDLSurface2_InitSurfaceInfo(&texture_info, texture_surface); + if (texture_info.Width > 0 && texture_info.Height > 0) + texture_ptr = &texture_info; } } - idx_offset += pcmd->ElemCount; + 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_ImplSDLSurface2_RasterVertex v0; + ImGui_ImplSDLSurface2_RasterVertex v1; + ImGui_ImplSDLSurface2_RasterVertex v2; + ImGui_ImplSDLSurface2_SetupRasterVertex(&v0, vtx_buffer[pcmd->VtxOffset + idx0], clip_off, clip_scale); + ImGui_ImplSDLSurface2_SetupRasterVertex(&v1, vtx_buffer[pcmd->VtxOffset + idx1], clip_off, clip_scale); + ImGui_ImplSDLSurface2_SetupRasterVertex(&v2, vtx_buffer[pcmd->VtxOffset + idx2], clip_off, clip_scale); + + if (bd->TargetInfo.IsFast) + ImGui_ImplSDLSurface2_RenderTriangleFast(bd->TargetInfo, texture_ptr, v0, v1, v2, clip_min_x, clip_min_y, clip_max_x, clip_max_y); + else + ImGui_ImplSDLSurface2_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); } } - SDL_SetClipRect(g_TargetSurface, nullptr); - if (SDL_MUSTLOCK(g_TargetSurface)) SDL_UnlockSurface(g_TargetSurface); + if (SDL_MUSTLOCK(bd->TargetSurface)) + SDL_UnlockSurface(bd->TargetSurface); } + +#endif diff --git a/backends/imgui_impl_sdlsurface3.cpp b/backends/imgui_impl_sdlsurface3.cpp new file mode 100644 index 00000000..cea8d2c6 --- /dev/null +++ b/backends/imgui_impl_sdlsurface3.cpp @@ -0,0 +1,715 @@ +#include "imgui_impl_sdlsurface3.h" +#include "imgui.h" +#ifndef IMGUI_DISABLE +#include +#include +#include +#include +#include + +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 diff --git a/backends/imgui_impl_sdlsurface3.h b/backends/imgui_impl_sdlsurface3.h new file mode 100644 index 00000000..558af50c --- /dev/null +++ b/backends/imgui_impl_sdlsurface3.h @@ -0,0 +1,11 @@ +#pragma once + +#include "imgui.h" +#include + +IMGUI_API bool ImGui_ImplSDLSurface3_Init(SDL_Surface* surface); +IMGUI_API void ImGui_ImplSDLSurface3_Shutdown(); +IMGUI_API void ImGui_ImplSDLSurface3_NewFrame(); +IMGUI_API void ImGui_ImplSDLSurface3_RenderDrawData(ImDrawData* draw_data); + +IMGUI_API SDL_Surface* ImGui_ImplSDLSurface3_CreateFontAtlasSurface(); diff --git a/docs/BACKENDS.md b/docs/BACKENDS.md index 7839764c..c599210d 100644 --- a/docs/BACKENDS.md +++ b/docs/BACKENDS.md @@ -94,6 +94,8 @@ List of Renderer Backends: imgui_impl_sdlgpu3.cpp ; SDL_GPU (portable 3D graphics API of SDL3) imgui_impl_sdlrenderer2.cpp ; SDL_Renderer (optional component of SDL2 available from SDL 2.0.18+) imgui_impl_sdlrenderer3.cpp ; SDL_Renderer (optional component of SDL3. Prefer using SDL_GPU!). + imgui_impl_sdlsurface2.cpp ; SDL_Surface CPU renderer for SDL2 + imgui_impl_sdlsurface3.cpp ; SDL_Surface CPU renderer for SDL3 imgui_impl_vulkan.cpp ; Vulkan imgui_impl_wgpu.cpp ; WebGPU (web + desktop) diff --git a/docs/EXAMPLES.md b/docs/EXAMPLES.md index 676d745b..c745fcb0 100644 --- a/docs/EXAMPLES.md +++ b/docs/EXAMPLES.md @@ -145,6 +145,10 @@ SDL2 (Win32, Mac, Linux, etc.) + SDL_Renderer for SDL2 example.
= main.cpp + imgui_impl_sdl2.cpp + imgui_impl_sdlrenderer2.cpp
This requires SDL 2.0.18+ (released November 2021)
+[example_sdl2_surface/](https://github.com/ocornut/imgui/blob/master/examples/example_sdl2_surface/)
+SDL2 (Win32, Mac, Linux, etc.) + SDL_Surface CPU renderer example.
+= main.cpp + imgui_impl_sdl2.cpp + imgui_impl_sdlsurface2.cpp
+ [example_sdl2_vulkan/](https://github.com/ocornut/imgui/blob/master/examples/example_sdl2_vulkan/)
SDL2 (Win32, Mac, Linux, etc.) + Vulkan example.
= main.cpp + imgui_impl_sdl2.cpp + imgui_impl_vulkan.cpp
@@ -178,6 +182,10 @@ SDL3 (Win32, Mac, Linux, etc.) + SDL_GPU for SDL3 example.
SDL3 (Win32, Mac, Linux, etc.) + SDL_Renderer for SDL3 example.
= main.cpp + imgui_impl_sdl3.cpp + imgui_impl_sdlrenderer3.cpp
+[example_sdl3_surface/](https://github.com/ocornut/imgui/blob/master/examples/example_sdl3_surface/)
+SDL3 (Win32, Mac, Linux, etc.) + SDL_Surface CPU renderer example.
+= main.cpp + imgui_impl_sdl3.cpp + imgui_impl_sdlsurface3.cpp
+ [example_sdl3_vulkan/](https://github.com/ocornut/imgui/blob/master/examples/example_sdl3_vulkan/)
SDL3 (Win32, Mac, Linux, etc.) + Vulkan example.
= main.cpp + imgui_impl_sdl3.cpp + imgui_impl_vulkan.cpp
@@ -253,4 +261,3 @@ when an interactive drag is in progress. Note that some setup configurations or GPU drivers may introduce additional display lag depending on their settings. If you notice that dragging windows is laggy and you are not sure what the cause is: try drawing a simple 2D shape directly under the mouse cursor to help identify the issue! - diff --git a/examples/example_sdl3_surface/Makefile b/examples/example_sdl3_surface/Makefile new file mode 100644 index 00000000..5aed33f0 --- /dev/null +++ b/examples/example_sdl3_surface/Makefile @@ -0,0 +1,53 @@ +EXE = example_sdl3_surface +IMGUI_DIR = ../.. +SOURCES = main.cpp +SOURCES += $(IMGUI_DIR)/imgui.cpp $(IMGUI_DIR)/imgui_demo.cpp $(IMGUI_DIR)/imgui_draw.cpp $(IMGUI_DIR)/imgui_tables.cpp $(IMGUI_DIR)/imgui_widgets.cpp +SOURCES += $(IMGUI_DIR)/backends/imgui_impl_sdl3.cpp $(IMGUI_DIR)/backends/imgui_impl_sdlsurface3.cpp +OBJS = $(addsuffix .o, $(basename $(notdir $(SOURCES)))) +UNAME_S := $(shell uname -s) + +CXXFLAGS = -std=c++11 -I$(IMGUI_DIR) -I$(IMGUI_DIR)/backends +CXXFLAGS += -g -Wall -Wformat +LIBS = + +ifeq ($(UNAME_S), Linux) + ECHO_MESSAGE = "Linux" + LIBS += -ldl `pkg-config sdl3 --libs` + CXXFLAGS += `pkg-config sdl3 --cflags` + CFLAGS = $(CXXFLAGS) +endif + +ifeq ($(UNAME_S), Darwin) + ECHO_MESSAGE = "Mac OS X" + LIBS += -framework Cocoa -framework IOKit -framework CoreVideo + LIBS += `pkg-config --libs sdl3` + LIBS += -L/usr/local/lib -L/opt/local/lib + CXXFLAGS += `pkg-config --cflags sdl3` + CXXFLAGS += -I/usr/local/include -I/opt/local/include + CFLAGS = $(CXXFLAGS) +endif + +ifeq ($(OS), Windows_NT) + ECHO_MESSAGE = "MinGW" + LIBS += -lgdi32 -limm32 `pkg-config --static --libs sdl3` + CXXFLAGS += `pkg-config --cflags sdl3` + CFLAGS = $(CXXFLAGS) +endif + +%.o:%.cpp + $(CXX) $(CXXFLAGS) -c -o $@ $< + +%.o:$(IMGUI_DIR)/%.cpp + $(CXX) $(CXXFLAGS) -c -o $@ $< + +%.o:$(IMGUI_DIR)/backends/%.cpp + $(CXX) $(CXXFLAGS) -c -o $@ $< + +all: $(EXE) + @echo Build complete for $(ECHO_MESSAGE) + +$(EXE): $(OBJS) + $(CXX) -o $@ $^ $(CXXFLAGS) $(LIBS) + +clean: + rm -f $(EXE) $(OBJS) diff --git a/examples/example_sdl3_surface/README.md b/examples/example_sdl3_surface/README.md new file mode 100644 index 00000000..b50eb5dd --- /dev/null +++ b/examples/example_sdl3_surface/README.md @@ -0,0 +1,33 @@ +# How to Build + +## Windows with Visual Studio's IDE + +Use the provided project file (`example_sdl3_surface.vcxproj`) or open `imgui_examples.sln`. + +## Windows with Visual Studio's CLI + +Use `build_win32.bat` or directly: +```bat +set SDL3_DIR=path_to_your_sdl3_folder +cl /Zi /MD /utf-8 /I.. /I..\.. /I%SDL3_DIR%\include main.cpp ..\..\backends\imgui_impl_sdl3.cpp ..\..\backends\imgui_impl_sdlsurface3.cpp ..\..\imgui*.cpp /FeDebug/example_sdl3_surface.exe /FoDebug/ /link /libpath:%SDL3_DIR%\lib\x86 SDL3.lib /subsystem:console +cl /Zi /MD /utf-8 /I.. /I..\.. /I%SDL3_DIR%\include main.cpp ..\..\backends\imgui_impl_sdl3.cpp ..\..\backends\imgui_impl_sdlsurface3.cpp ..\..\imgui*.cpp /FeDebug/example_sdl3_surface.exe /FoDebug/ /link /libpath:%SDL3_DIR%\lib\x64 SDL3.lib /subsystem:console +``` + +## Linux and similar Unixes + +Use the provided `Makefile` or directly: +```sh +c++ `pkg-config --cflags sdl3` -I .. -I ../.. -I ../../backends \ + main.cpp ../../backends/imgui_impl_sdl3.cpp ../../backends/imgui_impl_sdlsurface3.cpp ../../imgui*.cpp \ + -ldl `pkg-config --libs sdl3` +``` + +## macOS + +Use the provided `Makefile` or directly: +```sh +brew install sdl3 +c++ `pkg-config --cflags sdl3` -I .. -I ../.. -I ../../backends \ + main.cpp ../../backends/imgui_impl_sdl3.cpp ../../backends/imgui_impl_sdlsurface3.cpp ../../imgui*.cpp \ + -framework Cocoa -framework IOKit -framework CoreVideo `pkg-config --libs sdl3` +``` diff --git a/examples/example_sdl3_surface/build_win32.bat b/examples/example_sdl3_surface/build_win32.bat new file mode 100644 index 00000000..98c087a9 --- /dev/null +++ b/examples/example_sdl3_surface/build_win32.bat @@ -0,0 +1,7 @@ +@set OUT_DIR=Debug +@set OUT_EXE=example_sdl3_surface +@set INCLUDES=/I..\.. /I..\..\backends /I%SDL3_DIR%\include +@set SOURCES=main.cpp ..\..\backends\imgui_impl_sdl3.cpp ..\..\backends\imgui_impl_sdlsurface3.cpp ..\..\imgui*.cpp +@set LIBS=/LIBPATH:%SDL3_DIR%\lib\x86 SDL3.lib +mkdir %OUT_DIR% +cl /nologo /Zi /MD /utf-8 %INCLUDES% %SOURCES% /Fe%OUT_DIR%/%OUT_EXE%.exe /Fo%OUT_DIR%/ /link %LIBS% /subsystem:console diff --git a/examples/example_sdl3_surface/example_sdl3_surface.vcxproj b/examples/example_sdl3_surface/example_sdl3_surface.vcxproj new file mode 100644 index 00000000..cad1dec1 --- /dev/null +++ b/examples/example_sdl3_surface/example_sdl3_surface.vcxproj @@ -0,0 +1,187 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {08DD87C0-C734-45D6-9B44-D23F19F2D4B6} + example_sdl3_surface + 8.1 + example_sdl3_surface + + + + Application + true + MultiByte + v140 + + + Application + true + MultiByte + v140 + + + Application + false + true + MultiByte + v140 + + + Application + false + true + MultiByte + v140 + + + + + + + + + + + + + + + + + + + $(ProjectDir)$(Configuration)\ + $(ProjectDir)$(Configuration)\ + $(IncludePath) + + + $(ProjectDir)$(Configuration)\ + $(ProjectDir)$(Configuration)\ + $(IncludePath) + + + $(ProjectDir)$(Configuration)\ + $(ProjectDir)$(Configuration)\ + $(IncludePath) + + + $(ProjectDir)$(Configuration)\ + $(ProjectDir)$(Configuration)\ + $(IncludePath) + + + + Level4 + Disabled + ..\..;..\..\backends;%SDL3_DIR%\include;$(VcpkgCurrentInstalledDir)include\SDL3;%(AdditionalIncludeDirectories) + /utf-8 %(AdditionalOptions) + + + true + %SDL3_DIR%\lib\x86;%(AdditionalLibraryDirectories) + SDL3.lib;%(AdditionalDependencies) + Console + msvcrt.lib + + + + + Level4 + Disabled + ..\..;..\..\backends;%SDL3_DIR%\include;$(VcpkgCurrentInstalledDir)include\SDL3;%(AdditionalIncludeDirectories) + /utf-8 %(AdditionalOptions) + + + true + %SDL3_DIR%\lib\x64;%(AdditionalLibraryDirectories) + SDL3.lib;%(AdditionalDependencies) + Console + msvcrt.lib + + + + + Level4 + MaxSpeed + true + true + ..\..;..\..\backends;%SDL3_DIR%\include;$(VcpkgCurrentInstalledDir)include\SDL3;%(AdditionalIncludeDirectories) + false + /utf-8 %(AdditionalOptions) + + + true + true + true + %SDL3_DIR%\lib\x86;%(AdditionalLibraryDirectories) + SDL3.lib;%(AdditionalDependencies) + Console + + + + + + + Level4 + MaxSpeed + true + true + ..\..;..\..\backends;%SDL3_DIR%\include;$(VcpkgCurrentInstalledDir)include\SDL3;%(AdditionalIncludeDirectories) + false + /utf-8 %(AdditionalOptions) + + + true + true + true + %SDL3_DIR%\lib\x64;%(AdditionalLibraryDirectories) + SDL3.lib;%(AdditionalDependencies) + Console + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/example_sdl3_surface/example_sdl3_surface.vcxproj.filters b/examples/example_sdl3_surface/example_sdl3_surface.vcxproj.filters new file mode 100644 index 00000000..f1b1e382 --- /dev/null +++ b/examples/example_sdl3_surface/example_sdl3_surface.vcxproj.filters @@ -0,0 +1,64 @@ + + + + + {20b90ce4-7fcb-4731-b9a0-075f875de82d} + + + {f18ab499-84e1-499f-8eff-9754361e0e52} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + + + imgui + + + imgui + + + imgui + + + sources + + + imgui + + + imgui + + + sources + + + sources + + + + + imgui + + + imgui + + + imgui + + + sources + + + sources + + + + + + imgui + + + imgui + + + diff --git a/examples/example_sdl3_surface/main.cpp b/examples/example_sdl3_surface/main.cpp new file mode 100644 index 00000000..506e7351 --- /dev/null +++ b/examples/example_sdl3_surface/main.cpp @@ -0,0 +1,176 @@ +#include "imgui.h" +#include "imgui_impl_sdl3.h" +#include "imgui_impl_sdlsurface3.h" +#include +#include + +int main(int, char**) +{ + if (!SDL_Init(SDL_INIT_VIDEO | SDL_INIT_GAMEPAD)) + { + printf("Error: SDL_Init(): %s\n", SDL_GetError()); + return 1; + } + + float main_scale = SDL_GetDisplayContentScale(SDL_GetPrimaryDisplay()); + SDL_WindowFlags window_flags = SDL_WINDOW_RESIZABLE | SDL_WINDOW_HIDDEN | SDL_WINDOW_HIGH_PIXEL_DENSITY; + SDL_Window* window = SDL_CreateWindow("Dear ImGui SDL3+Surface Example", (int)(1280 * main_scale), (int)(800 * main_scale), window_flags); + if (window == nullptr) + { + printf("Error: SDL_CreateWindow(): %s\n", SDL_GetError()); + return 1; + } + + SDL_SetWindowPosition(window, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED); + SDL_ShowWindow(window); + + SDL_Surface* window_surface = SDL_GetWindowSurface(window); + if (window_surface == nullptr) + { + printf("Error: SDL_GetWindowSurface(): %s\n", SDL_GetError()); + SDL_DestroyWindow(window); + SDL_Quit(); + return 1; + } + + SDL_SetWindowSurfaceVSync(window, 1); + + int framebuffer_w = window_surface->w; + int framebuffer_h = window_surface->h; + SDL_Surface* framebuffer = SDL_CreateSurface(framebuffer_w, framebuffer_h, SDL_PIXELFORMAT_RGBA32); + if (framebuffer == nullptr) + { + printf("Error: SDL_CreateSurface(): %s\n", SDL_GetError()); + SDL_DestroyWindow(window); + SDL_Quit(); + return 1; + } + + IMGUI_CHECKVERSION(); + ImGui::CreateContext(); + ImGuiIO& io = ImGui::GetIO(); + io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; + io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; + + ImGui::StyleColorsDark(); + + ImGuiStyle& style = ImGui::GetStyle(); + style.ScaleAllSizes(main_scale); + style.FontScaleDpi = main_scale; + + ImGui_ImplSDL3_InitForOther(window); + ImGui_ImplSDLSurface3_Init(framebuffer); + + bool show_demo_window = true; + bool show_another_window = false; + ImVec4 clear_color = ImVec4(0.45f, 0.55f, 0.60f, 1.00f); + bool done = false; + + while (!done) + { + SDL_Event event; + while (SDL_PollEvent(&event)) + { + ImGui_ImplSDL3_ProcessEvent(&event); + if (event.type == SDL_EVENT_QUIT) + done = true; + if (event.type == SDL_EVENT_WINDOW_CLOSE_REQUESTED && event.window.windowID == SDL_GetWindowID(window)) + done = true; + if ((event.type == SDL_EVENT_WINDOW_RESIZED || event.type == SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED) && event.window.windowID == SDL_GetWindowID(window)) + { + window_surface = SDL_GetWindowSurface(window); + if (window_surface != nullptr) + { + int new_w = window_surface->w; + int new_h = window_surface->h; + if (new_w != framebuffer_w || new_h != framebuffer_h) + { + SDL_DestroySurface(framebuffer); + framebuffer = SDL_CreateSurface(new_w, new_h, SDL_PIXELFORMAT_RGBA32); + if (framebuffer == nullptr) + { + printf("Error: SDL_CreateSurface(): %s\n", SDL_GetError()); + done = true; + break; + } + framebuffer_w = new_w; + framebuffer_h = new_h; + ImGui_ImplSDLSurface3_Shutdown(); + ImGui_ImplSDLSurface3_Init(framebuffer); + } + } + } + } + + if (done) + break; + + if (SDL_GetWindowFlags(window) & SDL_WINDOW_MINIMIZED) + { + SDL_Delay(10); + continue; + } + + ImGui_ImplSDLSurface3_NewFrame(); + ImGui_ImplSDL3_NewFrame(); + ImGui::NewFrame(); + + if (show_demo_window) + ImGui::ShowDemoWindow(&show_demo_window); + + { + static float f = 0.0f; + static int counter = 0; + + ImGui::Begin("Hello, world!"); + ImGui::Text("This is some useful text."); + ImGui::Checkbox("Demo Window", &show_demo_window); + ImGui::Checkbox("Another Window", &show_another_window); + ImGui::SliderFloat("float", &f, 0.0f, 1.0f); + ImGui::ColorEdit3("clear color", (float*)&clear_color); + if (ImGui::Button("Button")) + counter++; + ImGui::SameLine(); + ImGui::Text("counter = %d", counter); + ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / io.Framerate, io.Framerate); + ImGui::End(); + } + + if (show_another_window) + { + ImGui::Begin("Another Window", &show_another_window); + ImGui::Text("Hello from another window!"); + if (ImGui::Button("Close Me")) + show_another_window = false; + ImGui::End(); + } + + ImGui::Render(); + + SDL_FillSurfaceRect(framebuffer, nullptr, SDL_MapSurfaceRGBA(framebuffer, + (Uint8)(clear_color.x * 255.0f), + (Uint8)(clear_color.y * 255.0f), + (Uint8)(clear_color.z * 255.0f), + (Uint8)(clear_color.w * 255.0f))); + + ImGui_ImplSDLSurface3_RenderDrawData(ImGui::GetDrawData()); + + window_surface = SDL_GetWindowSurface(window); + if (window_surface != nullptr) + { + SDL_BlitSurface(framebuffer, nullptr, window_surface, nullptr); + SDL_UpdateWindowSurface(window); + } + } + + ImGui_ImplSDLSurface3_Shutdown(); + ImGui_ImplSDL3_Shutdown(); + ImGui::DestroyContext(); + + SDL_DestroySurface(framebuffer); + SDL_DestroyWindowSurface(window); + SDL_DestroyWindow(window); + SDL_Quit(); + + return 0; +} diff --git a/examples/imgui_examples.sln b/examples/imgui_examples.sln index f0b3c148..3def734f 100644 --- a/examples/imgui_examples.sln +++ b/examples/imgui_examples.sln @@ -35,6 +35,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "example_sdl3_opengl3", "exa EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "example_sdl3_sdlrenderer3", "example_sdl3_sdlrenderer3\example_sdl3_sdlrenderer3.vcxproj", "{C0290D21-3AD2-4A35-ABBC-A2F5F48326DA}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "example_sdl3_surface", "example_sdl3_surface\example_sdl3_surface.vcxproj", "{08DD87C0-C734-45D6-9B44-D23F19F2D4B6}" +EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "example_sdl3_vulkan", "example_sdl3_vulkan\example_sdl3_vulkan.vcxproj", "{663A7E89-1E42-4222-921C-177F5B5910DF}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "example_win32_vulkan", "example_win32_vulkan\example_win32_vulkan.vcxproj", "{0A1E32DF-E0F4-4CCE-B3DC-9644C503BD88}" @@ -181,6 +183,14 @@ Global {C0290D21-3AD2-4A35-ABBC-A2F5F48326DA}.Release|Win32.Build.0 = Release|Win32 {C0290D21-3AD2-4A35-ABBC-A2F5F48326DA}.Release|x64.ActiveCfg = Release|x64 {C0290D21-3AD2-4A35-ABBC-A2F5F48326DA}.Release|x64.Build.0 = Release|x64 + {08DD87C0-C734-45D6-9B44-D23F19F2D4B6}.Debug|Win32.ActiveCfg = Debug|Win32 + {08DD87C0-C734-45D6-9B44-D23F19F2D4B6}.Debug|Win32.Build.0 = Debug|Win32 + {08DD87C0-C734-45D6-9B44-D23F19F2D4B6}.Debug|x64.ActiveCfg = Debug|x64 + {08DD87C0-C734-45D6-9B44-D23F19F2D4B6}.Debug|x64.Build.0 = Debug|x64 + {08DD87C0-C734-45D6-9B44-D23F19F2D4B6}.Release|Win32.ActiveCfg = Release|Win32 + {08DD87C0-C734-45D6-9B44-D23F19F2D4B6}.Release|Win32.Build.0 = Release|Win32 + {08DD87C0-C734-45D6-9B44-D23F19F2D4B6}.Release|x64.ActiveCfg = Release|x64 + {08DD87C0-C734-45D6-9B44-D23F19F2D4B6}.Release|x64.Build.0 = Release|x64 {663A7E89-1E42-4222-921C-177F5B5910DF}.Debug|Win32.ActiveCfg = Debug|Win32 {663A7E89-1E42-4222-921C-177F5B5910DF}.Debug|Win32.Build.0 = Debug|Win32 {663A7E89-1E42-4222-921C-177F5B5910DF}.Debug|x64.ActiveCfg = Debug|x64