2
0
mirror of https://github.com/dpethes/rerogue.git synced 2025-06-07 18:58:32 +02:00
rerogue/terrain_viewer/imgui/backup/fpimgui_impl_sdlgl2.pas

306 lines
11 KiB
ObjectPascal

{
Translation of "ImGui SDL2 binding with OpenGL" example, using SDL2 headers provided by https://github.com/ev1313/Pascal-SDL-2-Headers
In this binding, ImTextureID is used to store an OpenGL 'GLuint' texture identifier. Read the FAQ about ImTextureID in imgui.cpp.
You can copy and use unmodified imgui_impl_* files in your project.
If you use this binding you'll need to call 4 functions: ImGui_ImplXXXX_Init(), ImGui_ImplXXXX_NewFrame(), Imgui_ImplSdlGL2_RenderDrawLists() and ImGui_ImplXXXX_Shutdown().
If you are new to ImGui, see examples/README.txt and documentation at the top of imgui.cpp.
https://github.com/ocornut/imgui
}
unit fpimgui_impl_sdlgl2;
{$mode objfpc}{$H+}
interface
uses
sdl2, gl, glu, GLext,
fpimgui;
procedure ImGui_ImplSdlGL2_Init();
procedure ImGui_ImplSdlGL2_Shutdown();
procedure ImGui_ImplSdlGL2_NewFrame(window: PSDL_Window);
procedure Imgui_ImplSdlGL2_RenderDrawLists(draw_data: PImDrawData); cdecl;
function ImGui_ImplSdlGL2_ProcessEvent(event: PSDL_Event): boolean;
implementation
// Data
var
g_Time: double = 0.0;
g_MousePressed: array[0..2] of bool = ( false, false, false );
g_MouseWheel: single = 0.0;
g_FontTexture: GLuint = 0;
function ImGui_ImplSdlGL2_ProcessEvent(event: PSDL_Event): boolean;
var
key: TSDL_KeyCode;
io: PImGuiIO;
begin
result := false;
io := igGetIO();
case event^.type_ of
SDL_MOUSEWHEEL: begin
if (event^.wheel.y > 0) then
g_MouseWheel := 1;
if (event^.wheel.y < 0) then
g_MouseWheel := -1;
result := true;
end;
SDL_MOUSEBUTTONDOWN: begin
if (event^.button.button = SDL_BUTTON_LEFT) then g_MousePressed[0] := true;
if (event^.button.button = SDL_BUTTON_RIGHT) then g_MousePressed[1] := true;
if (event^.button.button = SDL_BUTTON_MIDDLE) then g_MousePressed[2] := true;
result := true;
end;
SDL_TEXTINPUT: begin
ImGuiIO_AddInputCharactersUTF8(event^.text.text);
result := true;
end;
SDL_KEYDOWN, SDL_KEYUP: begin
key := event^.key.keysym.sym and (not SDLK_SCANCODE_MASK);
io^.KeysDown[key] := event^.type_ = SDL_KEYDOWN;
io^.KeyShift := (SDL_GetModState() and KMOD_SHIFT) <> 0;
io^.KeyCtrl := (SDL_GetModState() and KMOD_CTRL) <> 0;
io^.KeyAlt := (SDL_GetModState() and KMOD_ALT) <> 0;
io^.KeySuper := (SDL_GetModState() and KMOD_GUI) <> 0;
result := true;
end;
end;
end;
procedure ImGui_ImplSdlGL2_CreateDeviceObjects();
var
io: PImGuiIO;
pixels: pbyte;
width, height: integer;
font_atlas: PImFontAtlas;
last_texture: GLint;
begin
// Build texture atlas
io := igGetIO();
font_atlas := io^.Fonts;
//ImFontAtlas_AddFontDefault(font_atlas);
ImFontAtlas_GetTexDataAsAlpha8(font_atlas, @pixels, @width, @height);
// Upload texture to graphics system
glGetIntegerv(GL_TEXTURE_BINDING_2D, @last_texture);
glGenTextures(1, @g_FontTexture);
glBindTexture(GL_TEXTURE_2D, g_FontTexture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, width, height, 0, GL_ALPHA, GL_UNSIGNED_BYTE, pixels);
// Store our identifier
ImFontAtlas_SetTexID(font_atlas, Pointer(g_FontTexture));
// Restore state
glBindTexture(GL_TEXTURE_2D, last_texture);
end;
procedure ImGui_ImplSdlGL2_InvalidateDeviceObjects();
begin
if (g_FontTexture <> 0) then begin
glDeleteTextures(1, @g_FontTexture);
ImFontAtlas_SetTexID(igGetIO()^.Fonts, nil);
g_FontTexture := 0;
end;
end;
procedure ImGui_ImplSdlGL2_Init();
var
io: PImGuiIO;
begin
Load_GL_version_2_0;
io := igGetIO();
// Keyboard mapping. ImGui will use those indices to peek into the io.KeyDown[] array.
io^.KeyMap[ImGuiKey_Tab] := SDLK_TAB;
io^.KeyMap[ImGuiKey_LeftArrow] := SDL_SCANCODE_LEFT;
io^.KeyMap[ImGuiKey_RightArrow] := SDL_SCANCODE_RIGHT;
io^.KeyMap[ImGuiKey_UpArrow] := SDL_SCANCODE_UP;
io^.KeyMap[ImGuiKey_DownArrow] := SDL_SCANCODE_DOWN;
io^.KeyMap[ImGuiKey_PageUp] := SDL_SCANCODE_PAGEUP;
io^.KeyMap[ImGuiKey_PageDown] := SDL_SCANCODE_PAGEDOWN;
io^.KeyMap[ImGuiKey_Home] := SDL_SCANCODE_HOME;
io^.KeyMap[ImGuiKey_End] := SDL_SCANCODE_END;
io^.KeyMap[ImGuiKey_Delete] := SDLK_DELETE;
io^.KeyMap[ImGuiKey_Backspace] := SDLK_BACKSPACE;
io^.KeyMap[ImGuiKey_Enter] := SDLK_RETURN;
io^.KeyMap[ImGuiKey_Escape] := SDLK_ESCAPE;
io^.KeyMap[ImGuiKey_A] := SDLK_a;
io^.KeyMap[ImGuiKey_C] := SDLK_c;
io^.KeyMap[ImGuiKey_V] := SDLK_v;
io^.KeyMap[ImGuiKey_X] := SDLK_x;
io^.KeyMap[ImGuiKey_Y] := SDLK_y;
io^.KeyMap[ImGuiKey_Z] := SDLK_z;
io^.RenderDrawListsFn := @Imgui_ImplSdlGL2_RenderDrawLists;
io^.SetClipboardTextFn := nil;
io^.GetClipboardTextFn := nil;
io^.ClipboardUserData := nil;
end;
procedure ImGui_ImplSdlGL2_Shutdown();
begin
ImGui_ImplSdlGL2_InvalidateDeviceObjects();
igShutdown();
end;
procedure ImGui_ImplSdlGL2_NewFrame(window: PSDL_Window);
var
w, h: integer;
display_w, display_h: integer;
io: PImGuiIO;
time, mouseMask: UInt32;
current_time: double;
mx, my: Integer;
begin
if g_FontTexture = 0 then
ImGui_ImplSdlGL2_CreateDeviceObjects();
io := igGetIO();
// Setup display size (every frame to accommodate for window resizing)
SDL_GetWindowSize(window, @w, @h);
io^.DisplaySize := ImVec2Init(w, h);
io^.DisplayFramebufferScale := ImVec2Init(1, 1);
// SDL_GL_GetDrawableSize might be missing in pascal sdl2 headers - remove the next 3 lines in that case
SDL_GL_GetDrawableSize(window, @display_w, @display_h);
if (w <> 0) and (h <> 0) and ((w <> display_w) or (h <> display_h)) then
io^.DisplayFramebufferScale := ImVec2Init(display_w/w, display_h/h);
// Setup time step
time := SDL_GetTicks();
current_time := time / 1000.0;
if (g_Time > 0.0) then
io^.DeltaTime := current_time - g_Time
else
io^.DeltaTime := 1.0/60.0;
g_Time := current_time;
// Setup inputs
// (we already got mouse wheel, keyboard keys & characters from SDL_PollEvent())
mouseMask := SDL_GetMouseState(@mx, @my);
if ((SDL_GetWindowFlags(window) and SDL_WINDOW_MOUSE_FOCUS) <> 0) then
io^.MousePos := ImVec2Init(mx, my) // Mouse position, in pixels (set to -1,-1 if no mouse / on another screen, etc.)
else
io^.MousePos := ImVec2Init(-1,-1);
// If a mouse press event came, always pass it as "mouse held this frame", so we don't miss click-release events that are shorter than 1 frame.
io^.MouseDown[0] := g_MousePressed[0] or (mouseMask and SDL_BUTTON(SDL_BUTTON_LEFT) <> 0);
io^.MouseDown[1] := g_MousePressed[1] or (mouseMask and SDL_BUTTON(SDL_BUTTON_RIGHT) <> 0);
io^.MouseDown[2] := g_MousePressed[2] or (mouseMask and SDL_BUTTON(SDL_BUTTON_MIDDLE) <> 0);
g_MousePressed[0] := false;
g_MousePressed[1] := false;
g_MousePressed[2] := false;
io^.MouseWheel := g_MouseWheel;
g_MouseWheel := 0.0;
// Hide OS mouse cursor if ImGui is drawing it
//SDL_ShowCursor(io.MouseDrawCursor ? 0 : 1);
// Start the frame
igNewFrame();
end;
procedure Imgui_ImplSdlGL2_RenderDrawLists(draw_data: PImDrawData); cdecl;
var
last_texture: GLint;
last_viewport: array[0..3] of GLint;
last_scissor_box: array[0..3] of GLint;
io: PImGuiIO;
fb_width, fb_height, n, cmd_i: integer;
cmd_list: PImDrawList;
vtx_buffer: PImDrawVert;
idx_buffer: PImDrawIdx;
pcmd: PImDrawCmd;
begin
// Avoid rendering when minimized, scale coordinates for retina displays (screen coordinates != framebuffer coordinates)
io := igGetIO();
fb_width := trunc(io^.DisplaySize.x * io^.DisplayFramebufferScale.x);
fb_height := trunc(io^.DisplaySize.y * io^.DisplayFramebufferScale.y);
if (fb_width = 0) or (fb_height = 0) then
exit;
//draw_data->ScaleClipRects(io.DisplayFramebufferScale);
glGetIntegerv(GL_TEXTURE_BINDING_2D, @last_texture);
glGetIntegerv(GL_VIEWPORT, @last_viewport);
glGetIntegerv(GL_SCISSOR_BOX, @last_scissor_box);
glPushAttrib(GL_ENABLE_BIT or GL_COLOR_BUFFER_BIT or GL_TRANSFORM_BIT);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glDisable(GL_CULL_FACE);
glDisable(GL_DEPTH_TEST);
glEnable(GL_SCISSOR_TEST);
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glEnableClientState(GL_COLOR_ARRAY);
glEnable(GL_TEXTURE_2D);
glUseProgram(0); // You may want this if using this code in an OpenGL 3+ context
// Setup viewport, orthographic projection matrix
glViewport(0, 0, fb_width, fb_height);
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
glOrtho(0.0, io^.DisplaySize.x, io^.DisplaySize.y, 0.0, -1.0, +1.0);
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glLoadIdentity();
// Render command lists
Assert(SizeOf(ImDrawIdx) = 2);
for n := 0 to draw_data^.CmdListsCount - 1 do begin
cmd_list := draw_data^.CmdLists[n];
vtx_buffer := cmd_list^.VtxBuffer.Data;
idx_buffer := cmd_list^.IdxBuffer.Data;
//pos/uv/color offsets: 0, 8, 16
glVertexPointer(2, GL_FLOAT, sizeof(ImDrawVert), Pbyte(vtx_buffer) + 0);
glTexCoordPointer(2, GL_FLOAT, sizeof(ImDrawVert), Pbyte(vtx_buffer) + 8);
glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(ImDrawVert), Pbyte(vtx_buffer) + 16);
for cmd_i := 0 to cmd_list^.CmdBuffer.Size - 1 do begin
pcmd := @(cmd_list^.CmdBuffer.Data[cmd_i]);
if pcmd^.UserCallback <> nil then begin
pcmd^.UserCallback(cmd_list, pcmd);
end else begin
glBindTexture(GL_TEXTURE_2D, GLuint(pcmd^.TextureId));
glScissor(trunc(pcmd^.ClipRect.x), trunc(fb_height - pcmd^.ClipRect.w),
trunc(pcmd^.ClipRect.z - pcmd^.ClipRect.x), trunc(pcmd^.ClipRect.w - pcmd^.ClipRect.y));
try
glDrawElements(GL_TRIANGLES, pcmd^.ElemCount, GL_UNSIGNED_SHORT, idx_buffer);
except
Write('*');
end;
end;
idx_buffer += pcmd^.ElemCount
end;
end;
// Restore modified state
glDisableClientState(GL_COLOR_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glDisableClientState(GL_VERTEX_ARRAY);
glBindTexture(GL_TEXTURE_2D, last_texture);
glMatrixMode(GL_MODELVIEW);
glPopMatrix();
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glPopAttrib();
glViewport(last_viewport[0], last_viewport[1], GLsizei(last_viewport[2]), GLsizei(last_viewport[3]));
glScissor(last_scissor_box[0], last_scissor_box[1], GLsizei(last_scissor_box[2]), GLsizei(last_scissor_box[3]));
end;
end.