IMGUI介绍

动机

UI编程是一件比较困难的事情。这可能很大程度上是因为用户界面工具包往往是大型和复杂的软件系统。掌握他们会有一个陡峭的学习曲线,为了集成,通常涉及大量特定于应用程序的实现。在使用软件的时候,留意UI的表现形式,可以发现很多相同功能的UI,会有很多表现形式。通常涉及一个ui toolkit仍然是一件很困难的事情,特别针对游戏行业。通常原先设计的通用的UI,到最后会发现不在那么通用了。

随着GPU的发展,现在出现了一种新的方式来处理UI。即时模式图形用户界面(IMGUI)代表了一种范例,其中用户界面的创建(对于客户端应用程序)和实现更简单(对于工具箱设计器)。

缓存状态的悲哀

我认为,传统用户界面系统设计和使用的复杂性是由此类系统保持了各种状态引起的。程序员通常被要求在应用程序和用户界面之间来回主动地复制状态,以便用户界面反映应用程序的状态,反之,为了使用户界面中发生的更改影响应用程序的状态。

这是一个基本的问题,这样的状态(来自UI交互系统),是实际状态的一份COPY/CACHE。

从客户端应用的角度看,UI更像是一堆对象的集合(通常称为widget),这些对象分装了需要和应用交互的各种状态。这个同步过程是双向的,为了让用户了解到当前应用的状态,状态需要从应用端转移到UI端;为了让应用知道当前用户的操作,状态需要从UI端转移到应用端。 有时,根据所使用的工具包,用户界面工具包为这种“数据交换”提供了一定程度的自动化,但同步本身(更不用说重复状态)仍然是现实。

此外,通知应用程序用户与接口交互的方式(这反过来表明需要重新同步状态)通常采用回调的形式。这需要应用程序为感兴趣的任何低级交互实现“事件处理程序”,通常是通过手动或通过各种代码生成技巧将某些工具箱基类子类化;在任何一种情况下,都会使客户机应用程序的生命周期更加复杂。

应用立即模式(Immediate Mode applied)

IMGUI通过要求应用程序实时显式传递可视化和交互所需的所有状态来消除这种状态同步。 用户界面只保留了为方便系统支持的每种小部件所需的功能所需的最小状态量。

使用IMGUI,概念发生了变化。Widget不再是对象,甚至可以说是不存在的。它们采用过程方法调用的形式,用户界面本身从有状态的对象集合变成了方法调用的实时序列。

这种实现方式的基础是实时应用程序循环的概念,也就是说,应用以实时的帧率处理逻辑和绘制(30 frames per second或者更高)。在游戏场景,这个是很常见的。

乍看起来,通过传递参数的方式实现看上去很冗余,但实际上并不是这样的。看上去会影响绘制性能。但是,对于现代的CPU和GPU而言,这个不是问题。

其优点在于简单和灵活。删除用户界面系统中的隐式状态缓存可以减少与缓存相关的bug的可能性,也完全消除了工具箱将小部件作为对象公开给客户机应用程序的需要。在逻辑上,小部件从对象变为方法调用。我们将看到,这从根本上改变了客户机应用程序处理用户界面实现的方式。

Issues of acceptance

在深入内部的详细实现之前,我想要讨论下“Why”。

我意识到使用现有的用户界面工具包的一个重要原因是存在可供使用的工具箱;您不必自己编写代码,可以专注于自己的细节应用程序。这里我将要解释如何从头开始实现一个用户界面工具箱;为什么这很有趣?

这里可能不太明显,但使用IMGUI的主要好处和原因是,实际的特定于应用程序的客户端代码变得更少(更少的LOC)和更简单。对于小型应用程序来说,这可能没有什么好处,但是任何非常复杂的用户界面通常都是非常不容易实现和维护的,即使是给定了一个用户界面工具包。

An example of simplification

在我的一个游戏中,UfoPilot II : The Phadt Menace, 整个前端一开始用传统的方法实现的。和MFC对话框有点类似。在这里,我为每个特定的“screen”设置了一个class,并在用户浏览界面时实例化了每个类的一个对象。

每个screen类有多个widget成员,布局结构。通常会运行一下程序,看一下layout的正确性,然后编辑代码,然后在运行看看,重复如上操作。此时丰富的编辑器在一定程度上会帮助到我。

将这个用户界面移植到IMGUI后,在移植过程中根据需要实现了工具箱方法(我在开发过程中构建了Gui类,将代码从Widget类移到Gui类),我获得了以下几点好处:

首先,在每一个“screen”都有一个类的情况下,它从一个类分解为一个Menu类中的单个方法(它代表前端屏幕和代码的整个集合)。这样从10-15个类,缩减到了一个类。

所有的widgets类都被分解成Gui类的方法,同样,我以前有几个类,现在有一个。

前端的进一步变化和迭代从涉及小部件实例化、布局、回调等的痛苦经历转变为以“if(doButton())do something…”的形式添加或删除几行代码。

Layout仍然直接编码到应用程序中,但是由于我已经掌握了这些信息,所以只需移动代码就可以了。

How to encourage acceptance

有人将不得不实现一个参考tookit和一个或多个使用它的应用程序。此外,这些应用程序必须强调这样一个事实:这是一个范式的转变,而不仅仅是一个漂亮的把戏。事实上,纵观WPF,整个思维模式仍极为保留。

到目前为止,由于使用GDI或GDI+绘图的开销,它在win32上还不可行(除非人们转而使用DirectX)。然而,在Windows7上,新的directxapi Direct2D和DirectWrite可能是高分辨率/高性能IMGUI应用程序的一个很好的解决方案。

这个参考工具包需要“看起来不错”。这意味着小部件看起来“现代”;让艺术家参与其中可能是个好主意。。。