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

news2024/11/30 6:53:26

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.coloradmin.cn/o/1447663.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

nvm 安装nodejs教程【详细】

目录 一、安装nvm 二、配置镜像 三、安装nodejs 安装 查看正在用的nodejs版本 切换版本 一、安装nvm 双击安装包&#xff1a; 无脑下一步即可&#xff0c;当然你可以自定义你自己的安装目录。 安装完后&#xff0c;打开环境变量&#xff0c;你会发现nvm为我们自动配置好…

【51单片机】定时器(江科大)

7.1定时器 1.定时器介绍: 51单片机的定时器属于单片机的内部资源,其电路的连接和运转均在单片机内部完成 2. 定时器作用: (1)用于计时系统,可实现软件计时,或者使程序每隔一固定时间完成一项操作 (2)替代长时间的Delay,提高CPU的运行效率和处理速度 定时器在单片机内部就像一个…

Rust入门:如何在windows + vscode中关闭程序codelldb.exe

在windows中用vscode单步调试rust程序的时候&#xff0c;发现无论是按下stop键&#xff0c;还是运行完程序&#xff0c;调试器codelldb.exe一直霸占着主程序不退出&#xff0c;如果此时对代码进行修改&#xff0c;后续就没法再编译调试了。 目前我也不知道要怎么处理这个事&am…

javaspringbootMySQL高考志愿选择系统68335-计算机毕业设计项目选题推荐(附源码)

目 录 摘要 第1章 绪论 1.1 研究背景与意义 1.2 研究现状 1.3论文结构与章节安排 第2章 相关技术 2.1开发技术 2.2 Java简介 2.3 MVVM模式 2.4 B/S结构 2.5 MySQL数据库 2.6 SpringBoot框架介绍 第3章 系统分析 3.1 可行性分析 3.2 系统流程分析 3.2.1 数…

机械革命混合模式和独显直连互相切换

原文&#xff1a;https://blog.iyatt.com/?p13773 默认状态是混合输出&#xff0c;在任务管理器中可以看到两个 GPU&#xff0c;分别是核显和独显 从混合模式切换到独显直连可以通过机械革命电竞控制台&#xff08;重装过系统的需要去官网下载安装驱动&#xff09; 打开后…

4核8G服务器支持多少人同时在线访问?

腾讯云4核8G服务器支持多少人在线访问&#xff1f;支持25人同时访问。实际上程序效率不同支持人数在线人数不同&#xff0c;公网带宽也是影响4核8G服务器并发数的一大因素&#xff0c;假设公网带宽太小&#xff0c;流量直接卡在入口&#xff0c;4核8G配置的CPU内存也会造成计算…

神经网络 | CNN 与 RNN——深度学习主力军

Hi&#xff0c;大家好&#xff0c;我是半亩花海。本文主要将卷积神经网络&#xff08;CNN&#xff09;和循环神经网络&#xff08;RNN&#xff09;这两个深度学习主力军进行对比。我们知道&#xff0c;从应用方面上来看&#xff0c;CNN 用于图像识别较多&#xff0c;而 RNN 用于…

leetcode(数组)128.最长连续序列(c++详细解释)DAY8

文章目录 1.题目示例提示 2.解答思路3.实现代码结果 4.总结 1.题目 给定一个未排序的整数数组 nums &#xff0c;找出数字连续的最长序列&#xff08;不要求序列元素在原数组中连续&#xff09;的长度。 请你设计并实现时间复杂度为 O(n) 的算法解决此问题。 示例 示例 1&a…

《UE5_C++多人TPS完整教程》学习笔记14 ——《P15 创建我们自己的子系统(Creating Our Own Subsystem)》

本文为B站系列教学视频 《UE5_C多人TPS完整教程》 —— 《P15 创建我们自己的子系统&#xff08;Creating Our Own Subsystem&#xff09;》 的学习笔记&#xff0c;该系列教学视频为 Udemy 课程 《Unreal Engine 5 C Multiplayer Shooter》 的中文字幕翻译版&#xff0c;UP主&…

GraphicsMagick 的 OpenCL 开发记录(结语)

所有代码及开发记录见&#xff1a;“gm-ocl”。

Covalent Network与卡尔加里大学建立合作,推动区块链技术创新

​Covalent Network&#xff08;CQT&#xff09;作为领先的 Web3 数据索引器和提供者&#xff0c;宣布已经与卡尔加里大学达成了具备开创性意义的合作&#xff0c;此次合作标志着推动区块链数据研究和可访问性的重要里程碑。卡尔加里大学是首个以验证者的身份加入 Covalent Net…

一、部署Oracle

部署Oracle 一、Docker部署1.Oracle11g1.1 测试环境1.1.1 拉取镜像1.1.2 启动容器1.1.3 配置容器环境变量1.1.4 修改sys、system用户密码1.1.5 创建表空间1.1.6 创建用户并授权1.1.5 使用DBeaver测试连接 二、安装包部署 一、Docker部署 1.Oracle11g 1.1 测试环境 当前只能用…

【分布式技术专题】「Zookeeper中间件」Paxos协议的原理和实际运行中的应用流程分析

Paxo算法介绍 Paxos算法是莱斯利兰伯特(Leslie Lamport)1990年提出的一种基于消息传递的一致性算法。 Paxos产生背景 Paxos算法是基于消息传递且具有高度容错特性的一致性算法&#xff0c;是目前公认的解决分布式一致性问题最有效的算法之一&#xff0c;其解决的问题就是在分…

anomalib1.0学习纪实

回顾&#xff1a;细分、纵深、高端、上游、积累、极致。 回顾&#xff1a;资本化&#xff0c;国际化&#xff0c;大干快上&#xff0c;小农思维必死无疑。 春节在深圳新地中央&#xff0c;学习anomalib1.0。 一、安装&#xff1a; 采用的是如下图的方式&#xff1a; 不过&a…

专业140+总分420+浙江大学842信号系统与数字电路考研经验电子信息与通信,真题,大纲,参考书。

今年考研已经结束&#xff0c;初试专业课842信号系统与数字电路140&#xff0c;总分420&#xff0c;很幸运实现了自己的目标&#xff0c;被浙大录取&#xff0c;这在高考是想都不敢想的学校&#xff0c;在考研时实现了&#xff0c;所以大家也要有信心&#xff0c;通过自己努力实…

Javaweb之SpringBootWeb案例之propagation属性案例演示的详细解析

案例 接下来我们就通过一个案例来演示下事务传播行为propagation属性的使用。 需求&#xff1a;解散部门时需要记录操作日志 由于解散部门是一个非常重要而且非常危险的操作&#xff0c;所以在业务当中要求每一次执行解散部门的操作都需要留下痕迹&#xff0c;就是要记录操作…

svg基础(十)滤镜-feMerge(多滤镜叠加滤镜)

feMerge:多滤镜叠加滤镜 允许同时应用滤镜效果而不是按顺序应用滤镜效果。利用result存储别的滤镜的输出可以实现这一点&#xff0c;然后在一个 <feMergeNode>子元素中访问它 1 语法 <feMerge><feMergeNode in""></feMergeNode> </feM…

去除vue自带的边距

使用vue时发现总有去不掉的外边距&#xff0c;在index.vue里面怎样设置样式都不管用 查阅资料后发现要在vue项目自带的index.html文件内添加下面的样式代码才行 <style>*{margin: 0;padding: 0;}body,html{margin: 0;padding: 0;} </style>

Vue项目创建和nodejs使用

Vue项目创建和nodejs使用 一、环境准备1.1.安装 node.js【下载历史版本node-v14.21.3-x64】1.2.安装1.3.检查是否安装成功&#xff1a;1.4.在Node下新建两个文件夹 node_global和node_cache并设置权限1.5.配置npm在安装全局模块时的路径和缓存cache的路径1.6.配置系统变量&…

红队笔记Day2 -->上线不出网机器

今天就来讲一下在企业攻防中如何上线不出网的机器&#xff01;&#xff01; 1.基本网络拓扑 基本的网络拓扑就是这样 以下是对应得的P信息&#xff0c;其中的52网段充当一个内网的网段&#xff0c;而111充当公网网段 先ping一下&#xff0c;确保外网ping不通内网&#xff0c;内…