| 1 |
|
| 2 |
|
| 3 |
|
| 4 |
|
| 5 |
|
| 6 |
|
| 7 |
|
| 8 |
|
| 9 |
|
| 10 |
|
| 11 |
|
| 12 |
|
| 13 |
|
| 14 |
|
| 15 |
|
| 16 |
|
| 17 |
|
| 18 |
|
| 19 |
|
| 20 |
|
| 21 |
|
| 22 |
|
| 23 |
|
| 24 |
|
| 25 |
|
| 26 |
|
| 27 |
|
| 28 |
|
| 29 |
|
| 30 |
|
| 31 |
|
| 32 |
|
| 33 |
|
| 34 |
|
| 35 |
#include "imgui.h" |
| 36 |
#ifndef IMGUI_DISABLE |
| 37 |
#include "imgui_impl_sdlrenderer2.h" |
| 38 |
#include <stdint.h> |
| 39 |
|
| 40 |
|
| 41 |
#if defined(__clang__) |
| 42 |
#pragma clang diagnostic push |
| 43 |
#pragma clang diagnostic ignored "-Wsign-conversion" |
| 44 |
#endif |
| 45 |
|
| 46 |
|
| 47 |
#include <SDL.h> |
| 48 |
#if !SDL_VERSION_ATLEAST(2,0,17) |
| 49 |
#error This backend requires SDL 2.0.17+ because of SDL_RenderGeometry() function |
| 50 |
#endif |
| 51 |
|
| 52 |
|
| 53 |
struct ImGui_ImplSDLRenderer2_Data |
| 54 |
{ |
| 55 |
SDL_Renderer* Renderer; |
| 56 |
SDL_Texture* FontTexture; |
| 57 |
ImGui_ImplSDLRenderer2_Data() { memset((void*)this, 0, sizeof(*this)); } |
| 58 |
}; |
| 59 |
|
| 60 |
|
| 61 |
|
| 62 |
static ImGui_ImplSDLRenderer2_Data* ImGui_ImplSDLRenderer2_GetBackendData() |
| 63 |
{ |
| 64 |
return ImGui::GetCurrentContext() ? (ImGui_ImplSDLRenderer2_Data*)ImGui::GetIO().BackendRendererUserData : nullptr; |
| 65 |
} |
| 66 |
|
| 67 |
|
| 68 |
bool ImGui_ImplSDLRenderer2_Init(SDL_Renderer* renderer) |
| 69 |
{ |
| 70 |
ImGuiIO& io = ImGui::GetIO(); |
| 71 |
IMGUI_CHECKVERSION(); |
| 72 |
IM_ASSERT(io.BackendRendererUserData == nullptr && "Already initialized a renderer backend!"); |
| 73 |
IM_ASSERT(renderer != nullptr && "SDL_Renderer not initialized!"); |
| 74 |
|
| 75 |
|
| 76 |
ImGui_ImplSDLRenderer2_Data* bd = IM_NEW(ImGui_ImplSDLRenderer2_Data)(); |
| 77 |
io.BackendRendererUserData = (void*)bd; |
| 78 |
io.BackendRendererName = "imgui_impl_sdlrenderer2"; |
| 79 |
io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset; |
| 80 |
|
| 81 |
bd->Renderer = renderer; |
| 82 |
|
| 83 |
return true; |
| 84 |
} |
| 85 |
|
| 86 |
void ImGui_ImplSDLRenderer2_Shutdown() |
| 87 |
{ |
| 88 |
ImGui_ImplSDLRenderer2_Data* bd = ImGui_ImplSDLRenderer2_GetBackendData(); |
| 89 |
IM_ASSERT(bd != nullptr && "No renderer backend to shutdown, or already shutdown?"); |
| 90 |
ImGuiIO& io = ImGui::GetIO(); |
| 91 |
|
| 92 |
ImGui_ImplSDLRenderer2_DestroyDeviceObjects(); |
| 93 |
|
| 94 |
io.BackendRendererName = nullptr; |
| 95 |
io.BackendRendererUserData = nullptr; |
| 96 |
io.BackendFlags &= ~ImGuiBackendFlags_RendererHasVtxOffset; |
| 97 |
IM_DELETE(bd); |
| 98 |
} |
| 99 |
|
| 100 |
static void ImGui_ImplSDLRenderer2_SetupRenderState(SDL_Renderer* renderer) |
| 101 |
{ |
| 102 |
|
| 103 |
|
| 104 |
SDL_RenderSetViewport(renderer, nullptr); |
| 105 |
SDL_RenderSetClipRect(renderer, nullptr); |
| 106 |
} |
| 107 |
|
| 108 |
void ImGui_ImplSDLRenderer2_NewFrame() |
| 109 |
{ |
| 110 |
ImGui_ImplSDLRenderer2_Data* bd = ImGui_ImplSDLRenderer2_GetBackendData(); |
| 111 |
IM_ASSERT(bd != nullptr && "Context or backend not initialized! Did you call ImGui_ImplSDLRenderer2_Init()?"); |
| 112 |
|
| 113 |
if (!bd->FontTexture) |
| 114 |
ImGui_ImplSDLRenderer2_CreateDeviceObjects(); |
| 115 |
} |
| 116 |
|
| 117 |
void ImGui_ImplSDLRenderer2_RenderDrawData(ImDrawData* draw_data, SDL_Renderer* renderer) |
| 118 |
{ |
| 119 |
|
| 120 |
|
| 121 |
|
| 122 |
float rsx = 1.0f; |
| 123 |
float rsy = 1.0f; |
| 124 |
SDL_RenderGetScale(renderer, &rsx, &rsy); |
| 125 |
ImVec2 render_scale; |
| 126 |
render_scale.x = (rsx == 1.0f) ? draw_data->FramebufferScale.x : 1.0f; |
| 127 |
render_scale.y = (rsy == 1.0f) ? draw_data->FramebufferScale.y : 1.0f; |
| 128 |
|
| 129 |
|
| 130 |
int fb_width = (int)(draw_data->DisplaySize.x * render_scale.x); |
| 131 |
int fb_height = (int)(draw_data->DisplaySize.y * render_scale.y); |
| 132 |
if (fb_width == 0 || fb_height == 0) |
| 133 |
return; |
| 134 |
|
| 135 |
|
| 136 |
struct BackupSDLRendererState |
| 137 |
{ |
| 138 |
SDL_Rect Viewport; |
| 139 |
bool ClipEnabled; |
| 140 |
SDL_Rect ClipRect; |
| 141 |
}; |
| 142 |
BackupSDLRendererState old = {}; |
| 143 |
old.ClipEnabled = SDL_RenderIsClipEnabled(renderer) == SDL_TRUE; |
| 144 |
SDL_RenderGetViewport(renderer, &old.Viewport); |
| 145 |
SDL_RenderGetClipRect(renderer, &old.ClipRect); |
| 146 |
|
| 147 |
|
| 148 |
ImGui_ImplSDLRenderer2_SetupRenderState(renderer); |
| 149 |
|
| 150 |
|
| 151 |
ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); |
| 152 |
ImGui_ImplSDLRenderer2_RenderState render_state; |
| 153 |
render_state.Renderer = renderer; |
| 154 |
platform_io.Renderer_RenderState = &render_state; |
| 155 |
|
| 156 |
|
| 157 |
ImVec2 clip_off = draw_data->DisplayPos; |
| 158 |
ImVec2 clip_scale = render_scale; |
| 159 |
|
| 160 |
|
| 161 |
for (int n = 0; n < draw_data->CmdListsCount; n++) |
| 162 |
{ |
| 163 |
const ImDrawList* draw_list = draw_data->CmdLists[n]; |
| 164 |
const ImDrawVert* vtx_buffer = draw_list->VtxBuffer.Data; |
| 165 |
const ImDrawIdx* idx_buffer = draw_list->IdxBuffer.Data; |
| 166 |
|
| 167 |
for (int cmd_i = 0; cmd_i < draw_list->CmdBuffer.Size; cmd_i++) |
| 168 |
{ |
| 169 |
const ImDrawCmd* pcmd = &draw_list->CmdBuffer[cmd_i]; |
| 170 |
if (pcmd->UserCallback) |
| 171 |
{ |
| 172 |
|
| 173 |
|
| 174 |
if (pcmd->UserCallback == ImDrawCallback_ResetRenderState) |
| 175 |
ImGui_ImplSDLRenderer2_SetupRenderState(renderer); |
| 176 |
else |
| 177 |
pcmd->UserCallback(draw_list, pcmd); |
| 178 |
} |
| 179 |
else |
| 180 |
{ |
| 181 |
|
| 182 |
ImVec2 clip_min((pcmd->ClipRect.x - clip_off.x) * clip_scale.x, (pcmd->ClipRect.y - clip_off.y) * clip_scale.y); |
| 183 |
ImVec2 clip_max((pcmd->ClipRect.z - clip_off.x) * clip_scale.x, (pcmd->ClipRect.w - clip_off.y) * clip_scale.y); |
| 184 |
if (clip_min.x < 0.0f) { clip_min.x = 0.0f; } |
| 185 |
if (clip_min.y < 0.0f) { clip_min.y = 0.0f; } |
| 186 |
if (clip_max.x > (float)fb_width) { clip_max.x = (float)fb_width; } |
| 187 |
if (clip_max.y > (float)fb_height) { clip_max.y = (float)fb_height; } |
| 188 |
if (clip_max.x <= clip_min.x || clip_max.y <= clip_min.y) |
| 189 |
continue; |
| 190 |
|
| 191 |
SDL_Rect r = { (int)(clip_min.x), (int)(clip_min.y), (int)(clip_max.x - clip_min.x), (int)(clip_max.y - clip_min.y) }; |
| 192 |
SDL_RenderSetClipRect(renderer, &r); |
| 193 |
|
| 194 |
const float* xy = (const float*)(const void*)((const char*)(vtx_buffer + pcmd->VtxOffset) + offsetof(ImDrawVert, pos)); |
| 195 |
const float* uv = (const float*)(const void*)((const char*)(vtx_buffer + pcmd->VtxOffset) + offsetof(ImDrawVert, uv)); |
| 196 |
#if SDL_VERSION_ATLEAST(2,0,19) |
| 197 |
const SDL_Color* color = (const SDL_Color*)(const void*)((const char*)(vtx_buffer + pcmd->VtxOffset) + offsetof(ImDrawVert, col)); |
| 198 |
#else |
| 199 |
const int* color = (const int*)(const void*)((const char*)(vtx_buffer + pcmd->VtxOffset) + offsetof(ImDrawVert, col)); |
| 200 |
#endif |
| 201 |
|
| 202 |
|
| 203 |
SDL_Texture* tex = (SDL_Texture*)pcmd->GetTexID(); |
| 204 |
SDL_RenderGeometryRaw(renderer, tex, |
| 205 |
xy, (int)sizeof(ImDrawVert), |
| 206 |
color, (int)sizeof(ImDrawVert), |
| 207 |
uv, (int)sizeof(ImDrawVert), |
| 208 |
draw_list->VtxBuffer.Size - pcmd->VtxOffset, |
| 209 |
idx_buffer + pcmd->IdxOffset, pcmd->ElemCount, sizeof(ImDrawIdx)); |
| 210 |
} |
| 211 |
} |
| 212 |
} |
| 213 |
platform_io.Renderer_RenderState = NULL; |
| 214 |
|
| 215 |
|
| 216 |
SDL_RenderSetViewport(renderer, &old.Viewport); |
| 217 |
SDL_RenderSetClipRect(renderer, old.ClipEnabled ? &old.ClipRect : nullptr); |
| 218 |
} |
| 219 |
|
| 220 |
|
| 221 |
bool ImGui_ImplSDLRenderer2_CreateFontsTexture() |
| 222 |
{ |
| 223 |
ImGuiIO& io = ImGui::GetIO(); |
| 224 |
ImGui_ImplSDLRenderer2_Data* bd = ImGui_ImplSDLRenderer2_GetBackendData(); |
| 225 |
|
| 226 |
|
| 227 |
unsigned char* pixels; |
| 228 |
int width, height; |
| 229 |
io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height); |
| 230 |
|
| 231 |
|
| 232 |
|
| 233 |
bd->FontTexture = SDL_CreateTexture(bd->Renderer, SDL_PIXELFORMAT_ABGR8888, SDL_TEXTUREACCESS_STATIC, width, height); |
| 234 |
if (bd->FontTexture == nullptr) |
| 235 |
{ |
| 236 |
SDL_Log("error creating texture"); |
| 237 |
return false; |
| 238 |
} |
| 239 |
SDL_UpdateTexture(bd->FontTexture, nullptr, pixels, 4 * width); |
| 240 |
SDL_SetTextureBlendMode(bd->FontTexture, SDL_BLENDMODE_BLEND); |
| 241 |
SDL_SetTextureScaleMode(bd->FontTexture, SDL_ScaleModeLinear); |
| 242 |
|
| 243 |
|
| 244 |
io.Fonts->SetTexID((ImTextureID)(intptr_t)bd->FontTexture); |
| 245 |
|
| 246 |
return true; |
| 247 |
} |
| 248 |
|
| 249 |
void ImGui_ImplSDLRenderer2_DestroyFontsTexture() |
| 250 |
{ |
| 251 |
ImGuiIO& io = ImGui::GetIO(); |
| 252 |
ImGui_ImplSDLRenderer2_Data* bd = ImGui_ImplSDLRenderer2_GetBackendData(); |
| 253 |
if (bd->FontTexture) |
| 254 |
{ |
| 255 |
io.Fonts->SetTexID(0); |
| 256 |
SDL_DestroyTexture(bd->FontTexture); |
| 257 |
bd->FontTexture = nullptr; |
| 258 |
} |
| 259 |
} |
| 260 |
|
| 261 |
bool ImGui_ImplSDLRenderer2_CreateDeviceObjects() |
| 262 |
{ |
| 263 |
return ImGui_ImplSDLRenderer2_CreateFontsTexture(); |
| 264 |
} |
| 265 |
|
| 266 |
void ImGui_ImplSDLRenderer2_DestroyDeviceObjects() |
| 267 |
{ |
| 268 |
ImGui_ImplSDLRenderer2_DestroyFontsTexture(); |
| 269 |
} |
| 270 |
|
| 271 |
|
| 272 |
|
| 273 |
#if defined(__clang__) |
| 274 |
#pragma clang diagnostic pop |
| 275 |
#endif |
| 276 |
|
| 277 |
#endif |