5.8 KiB
Introduction
The 2D GUI works by showing multiple 'screens' or 'layers' on top of each other. Each 'screen' usually contains one or more widgets. (e.g. a 'ButtonWidget' for a 'Close' button)
Here's an example of multiple screens:
The example above consists of three screens:
PauseScreen
- Top layer which consists of button widgets. Also draws a background to darken the screens/layers underneath it.ChatScreen
- Text widgets in the bottom left area (Only one is currently used though)HUDScreen
- Text in the top left and hotbar at the bottom
TODO: Explain event processing architecture
TODO: Explain pointer IDs. maybe a separate input-architecture.md file?
TODO: Explain dynamic vertex buffer
Screen interface
void Init(void* screen)
Where you initialise state and objects that lasts for the entire duration the screen is open
E.g. Hooking into events
void Free(void* screen)
Where you undo the allocating/event hooking you did in Init
.
void ContextRecreated(void* screen)
Where you allocate resources used for rendering, such as fonts, textures of widgets, and the screen's dynamic vertex buffer.
E.g. where you should call ButtonWidget_SetConst
, TextWidget_SetConst
, etc.
void ContextLost(void* screen)
Where you destroy/release all that resources that were allocated in ContextRecreated
.
Note: You MUST destroy all the textures/vertex buffers that you allocated, as otherwise you will get an error later with 'recreating context failed' with the Direct3D9 backend when you next try to resize the window or go fullscreen. TODO: rewrite this note
void Layout(void* screen)
Where you reposition all the elements (i.e. widgets + anything else) of this screen.
Note: This is called when initially showing this screen, and whenever the window is resized
int HandlesInputDown(void* screen, int button)
Called whenever a input button (keyboard/mouse/gamepad) is pressed.
void OnInputUp(void* screen, int button)
Called whenever a input button (keyboard/mouse/gamepad) is released.
int HandlesKeyPress(void* screen, char keyChar)
Called when a key character is entered on the keyboard.
E.g. you'd get '$' here if user pressed 4 while holding shift)
int HandlesTextChanged(void* screen, const cc_string* str)
Called when the text changes in the on-screen keyboard. (i.e. KeyPress but for mobile text input)
int HandlesMouseScroll(void* screen, float wheelDelta)
Called when the wheel is scrolled on the mouse.
int HandlesPointerDown(void* screen, int pointerID, int x, int y)
Called whenever the left mouse or a touch finger is pressed.
void OnPointerUp(void* screen, int pointerID, int x, int y)
Called whenever the left mouse or a touch finger is released.
int HandlesPointerMove(void* screen, int pointerID, int x, int y)
Called whenever the left mouse or a touch finger is moved.
void BuildMesh(void* screen)
Where you fill out the screen's dynamic vertex buffer with the vertices of all the widgets.
Note: This gets called just before Render()
whenever the dirty
field is set to true
.
Note: Pointer/Input events automatically set the dirty
field to true
for the next frame
void Update(void* screen, double delta)
Called just before Render()
every frame and also provides the elapsed time since last render.
Typically you'd use this to update simple stuff that depends on accumulated time. (E.g. whether the flashing caret should appear or not for input widgets)
void Render(void* screen)
Called every frame and is where you actually draw the widgets and other stuff on-screen.
Screen members
struct ScreenVTABLE* VTABLE
Set to a ScreenVTABLE
instance which implements all of the Screen interface
functions
cc_bool grabsInput
Whether this screen grabs all input.
Note: If any screen grabs all input, then the mouse cursor becomes visible, W/A/S/D stops causing player movement, etc.
cc_bool blocksWorld
Whether this screen completely and opaquely covers the game world behind it.
E.g. loading screen and disconnect screen
cc_bool closable
Whether this screen is automatically closed when pressing Escape.
Note: Usually should be true for screens that are menus (e.g. pause screen)
cc_bool dirty
Whether this screen will have BuildMesh()
called on the next frame
Note: This should be set to true
whenever any event/actions that might alter the screen's appearance occurs TODO explain when automatically called?
int maxVertices
The maximum number of vertices that this screen's dynamic vertex buffer may use
GfxResourceID vb
This screen's dynamic vertex buffer
struct Widget** widgets;
Pointer to the array of pointers to widgets that are contained in this screen
int numWidgets;
The number of widgets that are contained in this screen
Screen notes
-
When the screen is shown via
Gui_Add
, the following functions are called- Init
- ContextRecreated
- Layout
- HandlesPointerMove
-
When the screen is removed via
Gui_Remove
, the following functions are called- ContextLost
- Free
-
When the screen is refreshed via
Gui_Refresh
, the following functions are called- ContextLost
- ContextRecreated
- Layout
Note: Whenever default.png
(font texture) changes, Gui_Refresh
is called for all screens. Therefore, fonts should usually be allocated/freed in ContextRecreated/ContextLost
instead of Init/Free
to ensure that the screen still looks correct after the texture pack changes.
TODO: Move this note earlier?
Putting it altogether
TODO Add example of screen
Simple menu example that grabs all input
More complicated example too