Imgui(1) | 基于imgui-SFML改进自由落体小球

Imgui(1) | 基于imgui-SFML改进自由落体小球

0. 简介

使用 SFML 做2D图形渲染的同时,还想添加一个按钮之类的 GUI Widget, 需要用 Dear Imgui。由于 Imgui 对于2D图形渲染并没有提供类似 SFML 的 API, 结合它们两个使用是一个比较好的方法, 找到了 imgui-SFML 这个开源项目。

本篇在先前的自由落体小球基础上,增加两个按钮来控制启动、 停止。 规划如下:

  • imgui-SFML 简介
  • 构建:编译和跑通 imgui-SFML 官方例子
  • 界面设计和实现

1. imgui-SFML 简介

1.1 区分图形库和 GUI 库

Imgui 是一个 GUI 库, 所谓 GUI 库, 一个直观理解是, 看这个库是否提供了 button 这样的 widget, 以及 layout 的设定。

图形库: 通常是基于 OpenGL 或 Vulkan 的封装,不需要提供 button 和 layout, 可以认为它们就是对于 texture 进行操控和显示。

Qt 比较特殊,既能作为 GUI 库, 又能作为图形库。 不过 Qt 的 license 不友好, 不推荐使用。

1.2 Dear ImGui 简介

Dear ImGui Dear ImGui是一个用于C++的即时模式图形用户界面库,主要用于游戏和实时应用程序的开发。它以代码即UI的方式简化界面创建,广泛用于工具和调试界面的快速开发。

Dear ImGui 是一种 imgui 库,但是大家通常也直接管它叫 imgui。 它只提供源代码不提供库。 官方推荐做法是用户直接用它的源码, 但是我感觉这样非常容易造成符号冲突,也容易存在误修改、 重复编译的问题, 因此我会把它构建为一个静态库使用。

1.3 imgui-SFML 简介

imgui-sfml 官方仓库.

imgui-SFML 是让你同时使用 Dear ImGui 和 SFML 的一个库, 是 SFML 官方维护的。

1.4 一些失败的记录

只用 SFML 确实可以绘制简陋的 button, 但是开发效率太低。

只用 imgui 确实可以绘制2D图形,不过感觉那是和 opengl/vulkan 直接交互, 感觉没必要。

很幸运发现了 imgui-SFML 项目。

2. 构建:编译和跑通 imgui-SFML 官方例子

2.1 准备 imgui

cd ~/work/github
git clone https://github.com/ocornut/imgui
# 注意,如果使用 gitee 镜像, https://gitee.com/mirrors/imgui 这个网址有2个月没更新,在 mac arm64 下vulkan例子跑不起来,要用官方最新代码

imgui 的后端,包括两个类型的: 一个类型是渲染后端,另一个类型是平台后端

  • Renderers: DirectX9, DirectX10, DirectX11, DirectX12, Metal, OpenGL/ES/ES2, SDL_Renderer, Vulkan, WebGPU.
  • Platforms: GLFW, SDL2/SDL3, Win32, Glut, OSX, Android.

我的选择是: OpenGL 作为渲染后端,GLFW 作为平台后端:

  • backends/imgui_impl_glfw.cpp
  • backends/imgui_impl_opengl3.cpp
    等下 CMakeLists.txt 用到他俩

2.2 准备 sfml-IMGUI

cd ~/work/github
git clone https://github.com/SFML/imgui-sfml

看了下 sfml-IMGUI 的 README.md, 说 conan, vcpkg 和 bazel 提供了预编译包。 不过这三个包管理器, 个人都没怎么用过, 也没空学, 采用源代码的方式配置 imgui-sfml.

2.3 组织 CMakeLists.txt

相比于官方的 cmake 使用方式, 我的方式有一些不一样的地方:我是从 imgui 和 imgui-SFML 的源代码创建了两个库 (target), 并且这两个 target 之间有依赖关系。 然后在创建的可执行目标上, 直接依赖 sfml-IMGUI 这个 target:

cmake_minimum_required(VERSION 3.25)
project(imgui_demos)
set(CMAKE_CXX_STANDARD 17)

find_package(OpenGL REQUIRED)
find_package(glfw3 REQUIRED)
find_package(Vulkan REQUIRED)
find_package(SFML COMPONENTS audio graphics window system)

#--- imgui
set(IMGUI_DIR "/Users/zz/work/github/imgui")
add_library(imgui STATIC
  ${IMGUI_DIR}/backends/imgui_impl_glfw.cpp
  ${IMGUI_DIR}/backends/imgui_impl_opengl3.cpp
  ${IMGUI_DIR}/imgui.cpp
  ${IMGUI_DIR}/imgui_demo.cpp
  ${IMGUI_DIR}/imgui_draw.cpp
  ${IMGUI_DIR}/imgui_tables.cpp
  ${IMGUI_DIR}/imgui_widgets.cpp
)
target_include_directories(imgui PUBLIC
  ${IMGUI_DIR}
  ${IMGUI_DIR}/backends
)
target_link_libraries(imgui PUBLIC glfw OpenGL::GL)

#--- imgui-SFML
set(IMGUI_SFML_DIR "/Users/zz/work/github/imgui-sfml")
add_library(ImGui-SFML STATIC
  ${IMGUI_SFML_DIR}/imgui-SFML.cpp
  ${IMGUI_SFML_DIR}/imconfig-SFML.h
)
target_include_directories(ImGui-SFML PUBLIC ${IMGUI_SFML_DIR})
target_link_libraries(ImGui-SFML PUBLIC sfml-graphics sfml-window sfml-system imgui)

#--- imgui-sfml-demo
add_executable(imgui-sfml-demo imgui-sfml-demo.cpp)
target_link_libraries(imgui-sfml-demo PUBLIC ImGui-SFML)

2.4 imgui-SFML 官方demo代码

代码来自 README.md,在先前熟悉了 SFML 的前提下,这里列出 demo 代码里增加的 imgui 和 imgui-SFML 的内容.

头文件:

#include "imgui.h" // [imgui]
#include "imgui-SFML.h" // [imgui-SFML]

初始化:

    ImGui::SFML::Init(window); // [imgui-SFML]

事件处理:

    while (window.isOpen())
    {
        sf::Event event;
        while (window.pollEvent(event))
        {
            ImGui::SFML::ProcessEvent(window, event); // [imgui-SFML]

            if (event.type == sf::Event::Closed)
            {
                window.close();
            }
        }
        ...
    }

窗口的清屏、 渲染、 显示: 增加了好几个 imgui 和 imgui-SFML 的调用:

        ImGui::SFML::Update(window, deltaClock.restart()); // [imgui-SFML]

        ImGui::ShowDemoWindow(); // [imgui]

        ImGui::Begin("Hello, world!"); // [imgui]
        ImGui::Button("Look at this pretty button"); // [imgui]
        ImGui::End(); // [imgui]

        window.clear();
        window.draw(shape);
        ImGui::SFML::Render(window); // [imgui-SFML]
        window.display();

资源释放:

ImGui::SFML::Shutdown(); // [imgui-SFML]

完整的代码如下:

#include "imgui.h"
#include "imgui-SFML.h"

#include <SFML/Graphics/CircleShape.hpp>
#include <SFML/Graphics/RenderWindow.hpp>
#include <SFML/System/Clock.hpp>
#include <SFML/Window/Event.hpp>

int main() {
    sf::RenderWindow window(sf::VideoMode(640, 480), "ImGui + SFML = <3");
    window.setFramerateLimit(60);
    ImGui::SFML::Init(window);

    sf::CircleShape shape(100.f);
    shape.setFillColor(sf::Color::Green);

    sf::Clock deltaClock;
    while (window.isOpen()) {
 imgui-sfml-demo.cpp
        sf::Event event;
 imgui-sfml-demo.cpp

int main()
{
    sf::RenderWindow window(sf::VideoMode(640, 480), "ImGui + SFML = <3");
    window.setFramerateLimit(60);
    ImGui::SFML::Init(window); // [imgui-SFML]

    sf::CircleShape shape(100.f);
    shape.setFillColor(sf::Color::Green);

    sf::Clock deltaClock;
    while (window.isOpen())
    {
        sf::Event event;
        while (window.pollEvent(event))
        {
            ImGui::SFML::ProcessEvent(window, event); // [imgui-SFML]

            if (event.type == sf::Event::Closed)
            {
                window.close();
            }
        }

        ImGui::SFML::Update(window, deltaClock.restart()); // [imgui-SFML]

        ImGui::ShowDemoWindow(); // [imgui]

        ImGui::Begin("Hello, world!"); // [imgui]
        ImGui::Button("Look at this pretty button"); // [imgui]
        ImGui::End(); // [imgui]

        window.clear();
        window.draw(shape);
        ImGui::SFML::Render(window); // [imgui-SFML]
        window.display();
    }

    ImGui::SFML::Shutdown(); // [imgui-SFML]
}

2.5 编译运行

cmake -S . -B build
cmake --build build
./build/imgui-sfml-demo.cpp

请添加图片描述

3. 界面设计和实现

请添加图片描述

imgui 的 button 默认是悬浮的, 这是和以往的 GUI (如 java swing, Qt, Tkinter) 不同的地方, 习惯就好。

增加了两个按钮,并定义了点击它们后的函数, 分别让全局变量 running 为1或0:

constexpr float radius = 20.0f;
int running = 0;
float vy = 0;
float y = radius;

void start()
{
    running = 1;
    vy = 0;
    y = radius;
}

void stop()
{
    running = 0;
}

int main()
{
    ...
        ImGui::Begin("Hello"); // [imgui]
        ImGui::Button("Start"); // [imgui]
        ImGui::Button("Stop"); // [imgui]
        ImGui::End(); // [imgui]

        if (ImGui::Button("Start"))
        {
            start();
        }
        if (ImGui::Button("Stop"))
        {
            stop();
        }
}

而更新小球位置的代码, 和以前一样的:

int main()
{
    ...
        if (running)
        {
            sf::CircleShape circle(radius);
            circle.setFillColor(sf::Color::White);

            vy = vy + g;
            y = y + vy;
            if (y >= win_height - radius)
            {
                vy = -0.95 * vy;
            }
            if (y > win_height - radius)
            {
                y = win_height - radius;
            }
            circle.setPosition(win_width/2-radius, y);
            window.draw(circle);
        }
    ...
}

完整代码:

#include "imgui.h" // [imgui]
#include "imgui-SFML.h" // [imgui-SFML]

#include <SFML/Graphics/CircleShape.hpp>
#include <SFML/Graphics/RenderWindow.hpp>
#include <SFML/System/Clock.hpp>
#include <SFML/Window/Event.hpp>
#include <SFML/Graphics.hpp>

constexpr float radius = 20.0f;
int running = 0;
float vy = 0;
float y = radius;

void start()
{
    running = 1;
    vy = 0;
    y = radius;
}

void stop()
{
    running = 0;
}

int main()
{
    constexpr int win_width = 600;
    constexpr int win_height = 600;
    sf::RenderWindow window(sf::VideoMode(win_width, win_height), "free falling ball - imgui-SFML");
    window.setFramerateLimit(60);
    bool success = ImGui::SFML::Init(window); // [imgui-SFML]
    if (!success)
        return -1;

    constexpr float g = 0.5;
    sf::Clock deltaClock;
    while (window.isOpen())
    {
        sf::Event event;
        while (window.pollEvent(event))
        {
            ImGui::SFML::ProcessEvent(window, event); // [imgui-SFML]

            if (event.type == sf::Event::Closed)
            {
                window.close();
            }
        }

        ImGui::SFML::Update(window, deltaClock.restart()); // [imgui-SFML]

        // ImGui::ShowDemoWindow(); // [imgui]

        ImGui::Begin("Hello"); // [imgui]
        ImGui::Button("Start"); // [imgui]
        ImGui::Button("Stop"); // [imgui]
        ImGui::End(); // [imgui]

        if (ImGui::Button("Start"))
        {
            start();
        }
        if (ImGui::Button("Stop"))
        {
            stop();
        }

        window.clear();

        if (running)
        {
            sf::CircleShape circle(radius);
            circle.setFillColor(sf::Color::White);

            vy = vy + g;
            y = y + vy;
            if (y >= win_height - radius)
            {
                vy = -0.95 * vy;
            }
            if (y > win_height - radius)
            {
                y = win_height - radius;
            }
            circle.setPosition(win_width/2-radius, y);
            window.draw(circle);
        }

        ImGui::SFML::Render(window); // [imgui-SFML]
        window.display();
    }

    ImGui::SFML::Shutdown(); // [imgui-SFML]
    return 0;
}

4. 总结

经过尝试和查找, 发现了 imgui-SFML 这个仓库, 使用它时要求用户同时会 imgui, imgui-SFML, SFML 三个库, 不过 imgui-SFML 代码很少,SFML 文档齐全. 对于 Imgui 的使用, 官方没有文档, 以例子代码为参考即可。

在使用 imgui-SFML 时, 首先在 CMakeLists.txt 里以 imgui 和 imgui-SFML 源码方式构建了静态库, 然后在可执行目标上依赖它们, 相比于折腾 conan, vcpkg, bazel 这些包管理器, 更加简单方便。

在改进小球自由下落界面时,通过增加了 start、stop 按钮, 在按下 start 后开启下落, 在按下 stop 后停止下落, 实现了交互式的界面控制, 使得 GUI 交互 和 2D 渲染在同一个程序中得意表达。 这个例子没有直接的食用价值, 不过稍加改造,可以用于算法或复杂过程的模拟和调试。

References

  • Dear Imgui 官方仓库
  • imgui-SFML 官方仓库
  • ImGui给按钮添加点击事件

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/386044.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

阿里云服务器公网带宽收费价格表_2024更新报价

阿里云服务器公网带宽怎么收费&#xff1f;北京地域服务器按固定带宽计费一个月23元/M&#xff0c;按使用流量计费0.8元/GB&#xff0c;云服务器地域不同实际带宽价格也不同&#xff0c;阿里云服务器网aliyunfuwuqi.com分享不同带宽计费模式下带宽收费价格表&#xff1a; 公网…

Android---QUMI实现沉浸式状态栏

沉浸式状态栏是指将 App 的状态栏与应用界面进行融合&#xff0c;使得应用界面能够占据整个屏幕的控件&#xff0c;从而提供更加沉浸式的用户体验。通过使用沉浸式状态栏&#xff0c;应用界面可以延伸到状态栏的区域&#xff0c;使得应用界面的内容更加丰富&#xff0c;同时也能…

【开源】SpringBoot框架开发校园疫情防控管理系统

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 学生2.2 老师2.3 学校管理部门 三、系统展示四、核心代码4.1 新增健康情况上报4.2 查询健康咨询4.3 新增离返校申请4.4 查询防疫物资4.5 查询防控宣传数据 五、免责说明 一、摘要 1.1 项目介绍 基于JAVAVueSpringBoot…

web3知识体系汇总

web3.0知识体系 1.行业发展 2. web3的特点&#xff1a; 1、统一身份认证系统 2、数据确权与授权 3、隐私保护与抗审查 4、去中心化运行 Web3.0思维技术思维✖金融思维✖社群思维✖产业思维”&#xff0c;才能从容理解未来Web3.0时代的大趋势。 3.技术栈 Web3.jsSolidit…

【大数据】Flink on Kubernetes 原理剖析

Flink on Kubernetes 原理剖析 1.基本概念2.架构图3.核心概念4.架构5.JobManager6.TaskManager7.交互8.实践8.1 Session Cluster8.2 Job Cluster 9.问题解答 Kubernetes 是 Google 开源的 容器集群管理系统&#xff0c;其提供应用部署、维护、扩展机制等功能&#xff0c;利用 K…

深入理解梯度加权类激活热图(Grad-CAM)

深入理解梯度加权类激活热图&#xff08;Grad-CAM&#xff09; 项目背景与意义 在深度学习领域&#xff0c;模型的预测能力往往是黑盒子&#xff0c;难以解释。梯度加权类激活热图&#xff08;Grad-CAM&#xff09;作为一种可解释性技术&#xff0c;能够帮助模型开发者更好地…

js中事件循环的详解

文章目录 一、是什么二、宏任务与微任务微任务宏任务 三、async与awaitasyncawait 四、流程分析 一、是什么 首先&#xff0c;JavaScript是一门单线程的语言&#xff0c;意味着同一时间内只能做一件事&#xff0c;但是这并不意味着单线程就是阻塞&#xff0c;而实现单线程非阻…

java数据结构与算法刷题-----LeetCode18. 四数之和

java数据结构与算法刷题目录&#xff08;剑指Offer、LeetCode、ACM&#xff09;-----主目录-----持续更新(进不去说明我没写完)&#xff1a;https://blog.csdn.net/grd_java/article/details/123063846 解题思路 此题为三数之和的衍生题&#xff0c;代码完全一样&#xff0c;只…

Github 2024-02-13 开源项目日报 Top9

根据Github Trendings的统计&#xff0c;今日(2024-02-13统计)共有9个项目上榜。根据开发语言中项目的数量&#xff0c;汇总情况如下&#xff1a; 开发语言项目数量JavaScript项目2Python项目2C项目2TypeScript项目2Rust项目1Go项目1Dart项目1Java项目1C项目1 系统设计指南 …

JavaScript 的点击劫持(Clickjacking)

&#x1f9d1;‍&#x1f393; 个人主页&#xff1a;《爱蹦跶的大A阿》 &#x1f525;当前正在更新专栏&#xff1a;《VUE》 、《JavaScript保姆级教程》、《krpano》、《krpano中文文档》 ​ ​ ✨ 前言 点击劫持是一种恶意攻击&#xff0c;攻击者会在用户不知情的情况下诱…

Stable Diffusion 模型下载:majicMIX sombre 麦橘唯美

本文收录于《AI绘画从入门到精通》专栏,专栏总目录:点这里。 文章目录 模型介绍生成案例案例一案例二案例三案例四案例五案例六案例七案例八案例九案例十

LeetCode、452. 用最少数量的箭引爆气球【中等,贪心,区间问题】

文章目录 前言LeetCode、452. 用最少数量的箭引爆气球【中等&#xff0c;贪心&#xff0c;区间问题】题目链接与分类思路贪心&#xff0c;连续区间数量问题 资料获取 前言 博主介绍&#xff1a;✌目前全网粉丝2W&#xff0c;csdn博客专家、Java领域优质创作者&#xff0c;博客…

ARMv8-AArch64 的异常处理模型详解之异常处理概述Handling exceptions

异常处理模型详解之异常处理概述 一&#xff0c;异常处理相关概念二&#xff0c;异常处理概述 一&#xff0c;异常处理相关概念 在介绍异常处理之前&#xff0c;有必要了解一些关于异常处理状态的术语&#xff1a; 当处理器响应一个异常时&#xff0c;我们称该异常被获取了&a…

python 经典老人言

python 经典老人言 import tkinter as tkclass FlipBook:def __init__(self, master):self.master master master.title("经 典 老 人 言")self.pages ["经 典 老 人 言","求学无笨者&#xff0c;努力就成功","读 书 百 遍&am…

数据结构在JavaScript中的体现

一.概述 数据结构是计算机中存储、组织数据的方式。通常情况下&#xff0c;精心选择的数据结构可以带来最优效率的算法&#xff0c;其实算法并不是一个很高级的东西&#xff0c;它充斥在每一种代码组织方式中&#xff1b;而且各种语言关于数据结构方面的内容都是大同小异的&…

Prompt Tuning:深度解读一种新的微调范式

阅读该博客&#xff0c;您将系统地掌握如下知识点&#xff1a; 什么是预训练语言模型&#xff1f; 什么是prompt&#xff1f;为什么要引入prompt&#xff1f;相比传统fine-tuning有什么优势&#xff1f; 自20年底开始&#xff0c;prompt的发展历程&#xff0c;哪些经典的代表…

Linux_进程间通信

管道 System V 共享内存 System V IPC 接口介绍 由于进程地址空间的存在&#xff0c;所以进程间有具有独立性&#xff0c;一个进程看不到另一个进程的数据。那么如果我们想让进程间通信&#xff0c;就必须先让它们先看到同一份资源。常见的进程间通信的方法有管道&#xff0c;…

“bound drug/molecule”or “unbound drug/molecule”、molecule shape、sketching是什么?

“bound drug/molecule”or “unbound drug/molecule” For clarity, the following terms will be used throughout this study: “bound drug/molecule” (or “unbound drug/molecule”) refers to the drug/molecule that is bound (or unbound) to proteins [48]. 意思就是…

力扣精选算法100道——【模板】前缀和 (二维)

目录 &#x1f388;题目解析 &#x1f388;算法原理 &#x1f388;实现代码 二维前缀和【模板】 &#x1f388;题目解析 上一题我们讲述了一维的前缀和求法。 第一行三个参数&#xff0c;n是行数3&#xff0c;m是列数4&#xff0c;q3代表查询次数 接下来就是n行m列的矩阵…

用shell脚本批量修改文件名

今天继续分享一个实用的shell脚本哈 示例&#xff1a;# touch file{1..3}.txt # ls file1.txt file2.txt file3.txt 脚本内容&#xff1a; #!/bin/bash #方法1&#xff1a;for file in $(ls *txt); domv $file bbs_${file#*_}# mv $file $(echo $file |sed -r s/.*(_.*)/b…