首页 > Personal > Game > 游戏引擎设计系列10-UI系统
2018
09-27

游戏引擎设计系列10-UI系统

以Widget作为基本的UI单元,所有子Widget会被父Widget剪裁,父Widget先绘制,同级Widget按顺序绘制,后面的会覆盖前面的,
Widget {
Vector2 Location; // parent下的相对位置,修改会调用parent->Validate(null)和Invalid
Vector2 Size; // 大小,修改会调用parent->Validate(null)
Vector2 ClientOffset;
Vector2 ClientScale;
bool Enable; // 是否可用,修改会调用Invalid
bool Transparent; // 是否透明,修改会调用parent->Validate(null)
/* 只读
Widget* Parent;
Widget* Next;
Widget* Previous;
Widget* FirstChild;
Widget* LastChild;
*/
Event Paint;
Event Input;
bool Validate(Widget* child); // child为null从最后一个child开始,计算child的遮挡关系,算出自己和Child的TotalRegion,VisibleRegion,和需要InvalidRegion的部分。
void Invalid(); // 将DirtyRegion重置为Widget当前大小,并刷新屏幕
void InvalidRegion(Region region) // 把region并入DirtyRegion,并刷新屏幕
BeginRender() // 通过DirtyRegion和VisibleRegion相交算出需要渲染的Region,在转到世界坐标系,渲染在Viewport中,结束后DirtyRegion设为空

Region VisibleRegion; // 提出被遮挡的部分后的,可视部分
Region TotalRegion; // 全部的Region
Region DirtyRegion; // 标识变化的Region,为Parent下的Local坐标
Rectangle Viewport;
};
Rectangle是长方形数据结构,Region是Rectangle的操作集合,如可以通过多个Rectangle生成Region,Region提供多种修改函数(未优化的Region内部也是一个大的Rectangle,通过Linux上的X11的YX方法优化,内部是多个Rectangle的集合)。所有的优化遇到Widget透明都会失效。
因为时基于引擎设计的UI系统,为了优化,渲染时并不清理显存,只是将Dirty的Region重新渲染而已,如果Region是Rectangle就用Rect剪裁,如果Region是Rectangle就用Rect剪裁加Stencil Test剔除。

Desktop,包含Widget的窗口类,
Desktop {
Widget CreateWidget(); // 创建Widget
void OnScreenSizeChanged(); // 屏幕大小改变,修改Root大小,调用Root->Invalid()
void RefreshScreen(); // 刷新屏幕,从Root节点开始渲染所有Widget->BeginRender(),并调用Present()置换显存

Screen Screen; // 屏幕信息,大小等
Widget Root; // Widget跟节点
Widget InputFocus; // 获得焦点的Widget
GuiRender UIRender; // 渲染类
}

GUIRender,UI渲染类,可以封装渲染为Task(不过需考虑重复task问题)
GUIRender {
void BeginRender(Widget* widget);
void EndRender();
void Present();

}

Control,Widget的封装,
Control {
void OnPaint(RenderEventArgs & e); // 处理绘制,派生的Control只要修改这个接口
void OnInputEvent(InputEventArgs & e); // 处理输入

}
RenderEventArgs {
bool NeedRender;
Region DirtyRegion;
GuiRender UIRender; // 渲染类
}

Layout,处理Control Dock功能的类
Layout {
enum Direction {
kHorizontal,
kVertical,
};

enum Anchor {
kAnchorNone = 0,
kAnchorTop = 1,
kAnchorBottom = 2,
kAnchorLeft = 3,
kAnchorRight = 4,
};

enum Dock {
kDockNone = 0,
kDockTop = 1,
kDockBottom = 2,
kDockLeft = 3,
kDockRight = 4,
kDockFill = 5,
};
void CalculateDock(); // 计算Dock后的位置和大小

Vector4 Margin // Dock时Top,Bottom,Left,Right和间隔值
Dock Dock // Dock值
}
从Layout派生FlowLayout

Font,字体的描述类
Font {
void SetScale(float xscale, float yscale); // 计算scale并调用FT_Request_Size
CharInfo GetCharacterInfo(U16 Character); //
U32 BuildStringVertex(DrawingVertex *pVertexArray, U32 arraySize, ARGB color, ARGB background, const Core::Rectangle &dst, const CHAR* text, size_t length, U32 format); // 通过CharInfo构建文字的Vertex信息
Rectangle MeasureString(Rectangle &dst, const char* text, U32 length, U32 format = 0); // 预估文字的Rectangle
int MeasureFindFirstExceedingChar( Vector2 &boundary, const char* text, U32 length); // 在boundary里有几个字
F32 GetLastLineWidth(const char* text); // 获取最后一行的宽度
bool CPtoX(const CHAR * text, size_t cp, Vector2 & position); // char的位置计算实际的位置x
bool XtoCP(const CHAR * text, const Vector2 & position, size_t & cp); // 实际位置x计算char的位置
void CheckText(const CHAR* text, size_t length); // 检查char是否缓存,如果没有调用MakeFontTexture,如果再调用ResetFontTexture、ReSizeTexture,再次MakeFontTexture
bool MakeFontTexture(const CHAR * str); // 获取char的CharInfo信息并缓存,并将FT_BitmapGlyph获得的FT_Bitmap写入缓存贴图中
void ResetFontTexture(); // 重置缓存
void ClearCache; // 清除缓存

void * FontLibrary; // freetype2的FT_Library
void * FontFace; // freetype2的FT_Face
float LineHeight = FontFace->size->metrics.height / 64.f; // 行高度
float Baseline = FontFace->size->metrics.ascender / 64.f;
}

/// 文字大小的描述
struct CharInfo {
U16 character; // 文字编码
F32 width = bmpWidth * font_xscale;
F32 height = bmpHeight * font_yscale;
F32 horiAdvance = metrics.horiAdvance / 64.f * font_xscale;
F32 horiBearingX = metrics.horiBearingX / 64.f * font_xscale;
F32 horiBearingY = metrics.horiBearingY / 64.f * font_yscale;
F32 tx,ty,tx1,ty1; // 缓存贴图中的位置
};

/// 字体类型描述
struct FontDesc {
Identifier Family;
F32 Size;
U8 Style;
};

FontManager {
void ResetFontTexture(); // 重置文字缓存贴图
Font GetFont(Identifier family, float size, uint style); // 获取字体,如果没有缓存创建
void SetFontScale(float scale); // 设置所有字体的缩放

PackTexture font_texture; // 用来缓存已经渲染过的文字的贴图,会根据大小优化插入
HashSet font_set; // 字体缓存
Core::HashSet font_data; // 字体文件数据缓存
float font_scale; // 字体的缩放大小
}

最后编辑:
作者:wy182000
这个作者貌似有点懒,什么都没有留下。