Merge pull request #601 from UnknownShadow200/ScreenRewrite

Merge screen rewrite stuff
This commit is contained in:
UnknownShadow200 2019-08-25 10:44:12 +10:00 committed by GitHub
commit d1fb95092e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 2010 additions and 2304 deletions

View File

@ -7,4 +7,10 @@
* catbox.moe texture packs/terrain.png links insta-crash the game * catbox.moe texture packs/terrain.png links insta-crash the game
* Sometimes you randomly crash reading leveldatachunk packet on OSX * Sometimes you randomly crash reading leveldatachunk packet on OSX
* Models with size of over 2 are not supported at all * Models with size of over 2 are not supported at all
* Direct3D9 backend uses an ill-formed vertex format that works by accident * Direct3D9 backend uses an ill-formed vertex format that works by accident
* Alt text doesn't update its Y position if you click on chat
* Menu inputs (save, edit hotkey, water level, etc) are reset on window resize
* Chat input caret is reset on window resize
* Position in chat (if you scrolled up into history) is reset on window resize
* Two blank lines get shown in chat when you type /client cuboid
* Alt text is closed on window resize

View File

@ -97,8 +97,7 @@ static void PerspectiveCamera_UpdateMouseRotation(double delta) {
} }
static void PerspectiveCamera_UpdateMouse(double delta) { static void PerspectiveCamera_UpdateMouse(double delta) {
struct Screen* s = Gui_GetActiveScreen(); if (!Gui_GetInputGrab() && Window_Focused) Window_UpdateRawMouse();
if (!s->handlesAllInput && Window_Focused) Window_UpdateRawMouse();
PerspectiveCamera_UpdateMouseRotation(delta); PerspectiveCamera_UpdateMouseRotation(delta);
cam_deltaX = 0; cam_deltaY = 0; cam_deltaX = 0; cam_deltaY = 0;
@ -273,7 +272,7 @@ void Camera_Register(struct Camera* cam) {
static bool cam_focussed; static bool cam_focussed;
void Camera_CheckFocus(void) { void Camera_CheckFocus(void) {
bool focus = !Gui_GetActiveScreen()->handlesAllInput; bool focus = Gui_GetInputGrab() == NULL;
if (focus == cam_focussed) return; if (focus == cam_focussed) return;
cam_focussed = focus; cam_focussed = focus;

View File

@ -591,6 +591,10 @@ int Drawer2D_TextWidth(struct DrawTextArgs* args) {
return width; return width;
} }
int Drawer2D_TextHeight(struct DrawTextArgs* args) {
return Drawer2D_FontHeight(&args->font, args->useShadow);
}
int Drawer2D_FontHeight(const FontDesc* font, bool useShadow) { int Drawer2D_FontHeight(const FontDesc* font, bool useShadow) {
int height, point; int height, point;
if (Drawer2D_BitmappedText) { if (Drawer2D_BitmappedText) {
@ -609,7 +613,7 @@ int Drawer2D_FontHeight(const FontDesc* font, bool useShadow) {
Size2D Drawer2D_MeasureText(struct DrawTextArgs* args) { Size2D Drawer2D_MeasureText(struct DrawTextArgs* args) {
Size2D size; Size2D size;
size.Width = Drawer2D_TextWidth(args); size.Width = Drawer2D_TextWidth(args);
size.Height = Drawer2D_FontHeight(&args->font, args->useShadow); size.Height = Drawer2D_TextHeight(args);
if (!size.Width) size.Height = 0; if (!size.Width) size.Height = 0;
return size; return size;

View File

@ -63,8 +63,11 @@ void Drawer2D_Underline(Bitmap* bmp, int x, int y, int width, int height, Bitmap
CC_API void Drawer2D_DrawText(Bitmap* bmp, struct DrawTextArgs* args, int x, int y); CC_API void Drawer2D_DrawText(Bitmap* bmp, struct DrawTextArgs* args, int x, int y);
/* Returns how wide the given text would be when drawn. */ /* Returns how wide the given text would be when drawn. */
int Drawer2D_TextWidth(struct DrawTextArgs* args); int Drawer2D_TextWidth(struct DrawTextArgs* args);
/* Returns how tall the given text would be when drawn. */
/* NOTE: Height returned only depends on the font. (see Drawer2D_FontHeight). */
int Drawer2D_TextHeight(struct DrawTextArgs* args);
/* Returns size the given text would be when drawn. */ /* Returns size the given text would be when drawn. */
/* NOTE: Height returned only depends on the font. (see Drawer2D_FontHeight).*/ /* NOTE: Height returned only depends on the font. (see Drawer2D_FontHeight). */
CC_API Size2D Drawer2D_MeasureText(struct DrawTextArgs* args); CC_API Size2D Drawer2D_MeasureText(struct DrawTextArgs* args);
/* Similar to Drawer2D_DrawText, but trims the text with trailing ".." if wider than maxWidth. */ /* Similar to Drawer2D_DrawText, but trims the text with trailing ".." if wider than maxWidth. */
void Drawer2D_DrawClippedText(Bitmap* bmp, struct DrawTextArgs* args, int x, int y, int maxWidth); void Drawer2D_DrawClippedText(Bitmap* bmp, struct DrawTextArgs* args, int x, int y, int maxWidth);

View File

@ -781,7 +781,7 @@ static void LocalPlayer_HandleInput(float* xMoving, float* zMoving) {
struct LocalPlayer* p = &LocalPlayer_Instance; struct LocalPlayer* p = &LocalPlayer_Instance;
struct HacksComp* hacks = &p->Hacks; struct HacksComp* hacks = &p->Hacks;
if (Gui_GetActiveScreen()->handlesAllInput) { if (Gui_GetInputGrab()) {
p->Physics.Jumping = false; hacks->Speeding = false; p->Physics.Jumping = false; hacks->Speeding = false;
hacks->FlyingUp = false; hacks->FlyingDown = false; hacks->FlyingUp = false; hacks->FlyingDown = false;
} else { } else {

View File

@ -177,9 +177,8 @@ void Game_UpdateProjection(void) {
void Game_Disconnect(const String* title, const String* reason) { void Game_Disconnect(const String* title, const String* reason) {
Event_RaiseVoid(&NetEvents.Disconnected); Event_RaiseVoid(&NetEvents.Disconnected);
Gui_FreeActive();
DisconnectScreen_Show(title, reason);
Game_Reset(); Game_Reset();
DisconnectScreen_Show(title, reason);
} }
void Game_Reset(void) { void Game_Reset(void) {
@ -619,7 +618,6 @@ void Game_TakeScreenshot(void) {
static void Game_RenderFrame(double delta) { static void Game_RenderFrame(double delta) {
struct ScheduledTask entTask; struct ScheduledTask entTask;
bool allowZoom, visible;
float t; float t;
/* TODO: Should other tasks get called back too? */ /* TODO: Should other tasks get called back too? */
@ -637,13 +635,9 @@ static void Game_RenderFrame(double delta) {
Game_Vertices = 0; Game_Vertices = 0;
Camera.Active->UpdateMouse(delta); Camera.Active->UpdateMouse(delta);
if (!Window_Focused && !Gui_GetActiveScreen()->handlesAllInput) { if (!Window_Focused && !Gui_GetInputGrab()) PauseScreen_Show();
Gui_FreeActive();
Gui_SetActive(PauseScreen_MakeInstance());
}
allowZoom = !Gui_Active && !Gui_HUD->handlesAllInput; if (KeyBind_IsPressed(KEYBIND_ZOOM_SCROLL) && !Gui_GetInputGrab()) {
if (allowZoom && KeyBind_IsPressed(KEYBIND_ZOOM_SCROLL)) {
InputHandler_SetFOV(Game_ZoomFov); InputHandler_SetFOV(Game_ZoomFov);
} }
@ -656,8 +650,7 @@ static void Game_RenderFrame(double delta) {
Camera.CurrentPos = Camera.Active->GetPosition(t); Camera.CurrentPos = Camera.Active->GetPosition(t);
Game_UpdateViewMatrix(); Game_UpdateViewMatrix();
visible = !Gui_Active || !Gui_Active->blocksWorld; if (!Gui_GetBlocksWorld() && World.Blocks) {
if (visible && World.Blocks) {
Game_Render3D(delta, t); Game_Render3D(delta, t);
} else { } else {
PickedPos_SetAsInvalid(&Game_SelectedPos); PickedPos_SetAsInvalid(&Game_SelectedPos);

249
src/Gui.c
View File

@ -19,30 +19,9 @@ bool Gui_ClickableChat, Gui_TabAutocomplete, Gui_ShowFPS;
GfxResourceID Gui_GuiTex, Gui_GuiClassicTex, Gui_IconsTex; GfxResourceID Gui_GuiTex, Gui_GuiClassicTex, Gui_IconsTex;
struct Screen* Gui_Status; struct Screen* Gui_Status;
struct Screen* Gui_HUD; struct Screen* Gui_HUD;
struct Screen* Gui_Active; struct Screen* Gui_Screens[GUI_MAX_SCREENS];
struct Screen* Gui_Overlays[GUI_MAX_OVERLAYS]; int Gui_ScreensCount;
int Gui_OverlaysCount; static uint8_t priorities[GUI_MAX_SCREENS];
void Gui_DefaultRecreate(void* elem) {
struct GuiElem* e = (struct GuiElem*)elem;
Elem_Free(e); Elem_Init(e);
}
void Screen_CommonInit(void* screen) {
struct Screen* s = (struct Screen*)screen;
Event_RegisterVoid(&GfxEvents.ContextLost, s, s->VTABLE->ContextLost);
Event_RegisterVoid(&GfxEvents.ContextRecreated, s, s->VTABLE->ContextRecreated);
if (Gfx.LostContext) return;
s->VTABLE->ContextRecreated(s);
}
void Screen_CommonFree(void* screen) {
struct Screen* s = (struct Screen*)screen;
Event_UnregisterVoid(&GfxEvents.ContextLost, s, s->VTABLE->ContextLost);
Event_UnregisterVoid(&GfxEvents.ContextRecreated, s, s->VTABLE->ContextRecreated);
s->VTABLE->ContextLost(s);
}
void Widget_SetLocation(void* widget, uint8_t horAnchor, uint8_t verAnchor, int xOffset, int yOffset) { void Widget_SetLocation(void* widget, uint8_t horAnchor, uint8_t verAnchor, int xOffset, int yOffset) {
struct Widget* w = (struct Widget*)widget; struct Widget* w = (struct Widget*)widget;
@ -91,9 +70,29 @@ bool Gui_Contains(int recX, int recY, int width, int height, int x, int y) {
return x >= recX && y >= recY && x < (recX + width) && y < (recY + height); return x >= recX && y >= recY && x < (recX + width) && y < (recY + height);
} }
CC_NOINLINE static void Gui_RecreateScreen(struct Screen* screen) { void Gui_ShowDefault(void) {
if (Gfx.LostContext || !screen) return; StatusScreen_Show();
Elem_Recreate(screen); HUDScreen_Show();
}
static void Gui_ContextLost(void* obj) {
struct Screen* s;
int i;
for (i = 0; i < Gui_ScreensCount; i++) {
s = Gui_Screens[i];
s->VTABLE->ContextLost(s);
}
}
static void Gui_ContextRecreated(void* obj) {
struct Screen* s;
int i;
for (i = 0; i < Gui_ScreensCount; i++) {
s = Gui_Screens[i];
s->VTABLE->ContextRecreated(s);
}
} }
static void Gui_LoadOptions(void) { static void Gui_LoadOptions(void) {
@ -108,11 +107,7 @@ static void Gui_LoadOptions(void) {
Gui_ShowFPS = Options_GetBool(OPT_SHOW_FPS, true); Gui_ShowFPS = Options_GetBool(OPT_SHOW_FPS, true);
} }
static void Gui_FontChanged(void* obj) { static void Gui_FontChanged(void* obj) { Gui_RefreshAll(); }
Gui_RecreateScreen(Gui_Active);
Gui_RecreateScreen(Gui_Status);
Gui_RecreateScreen(Gui_HUD);
}
static void Gui_FileChanged(void* obj, struct Stream* stream, const String* name) { static void Gui_FileChanged(void* obj, struct Stream* stream, const String* name) {
if (String_CaselessEqualsConst(name, "gui.png")) { if (String_CaselessEqualsConst(name, "gui.png")) {
@ -127,29 +122,23 @@ static void Gui_FileChanged(void* obj, struct Stream* stream, const String* name
static void Gui_Init(void) { static void Gui_Init(void) {
Event_RegisterVoid(&ChatEvents.FontChanged, NULL, Gui_FontChanged); Event_RegisterVoid(&ChatEvents.FontChanged, NULL, Gui_FontChanged);
Event_RegisterEntry(&TextureEvents.FileChanged, NULL, Gui_FileChanged); Event_RegisterEntry(&TextureEvents.FileChanged, NULL, Gui_FileChanged);
Event_RegisterVoid(&GfxEvents.ContextLost, NULL, Gui_ContextLost);
Event_RegisterVoid(&GfxEvents.ContextRecreated, NULL, Gui_ContextRecreated);
Gui_LoadOptions(); Gui_LoadOptions();
Gui_ShowDefault();
StatusScreen_Show();
HUDScreen_Show();
Elem_Init(Gui_Status);
Elem_Init(Gui_HUD);
} }
static void Gui_Reset(void) { static void Gui_Reset(void) {
int i; /* TODO:Should we reset all screens here.. ? */
for (i = 0; i < Gui_OverlaysCount; i++) {
Elem_TryFree(Gui_Overlays[i]);
}
Gui_OverlaysCount = 0;
} }
static void Gui_Free(void) { static void Gui_Free(void) {
Event_UnregisterVoid(&ChatEvents.FontChanged, NULL, Gui_FontChanged); Event_UnregisterVoid(&ChatEvents.FontChanged, NULL, Gui_FontChanged);
Event_UnregisterEntry(&TextureEvents.FileChanged, NULL, Gui_FileChanged); Event_UnregisterEntry(&TextureEvents.FileChanged, NULL, Gui_FileChanged);
Event_UnregisterVoid(&GfxEvents.ContextLost, NULL, Gui_ContextLost);
Event_UnregisterVoid(&GfxEvents.ContextRecreated, NULL, Gui_ContextRecreated);
if (Gui_Active) Elem_TryFree(Gui_Active); while (Gui_ScreensCount) Gui_Remove(Gui_Screens[0]);
Elem_TryFree(Gui_Status);
Elem_TryFree(Gui_HUD);
Gfx_DeleteTexture(&Gui_GuiTex); Gfx_DeleteTexture(&Gui_GuiTex);
Gfx_DeleteTexture(&Gui_GuiClassicTex); Gfx_DeleteTexture(&Gui_GuiClassicTex);
@ -165,95 +154,135 @@ struct IGameComponent Gui_Component = {
NULL, /* OnNewMapLoaded */ NULL, /* OnNewMapLoaded */
}; };
struct Screen* Gui_GetActiveScreen(void) { void Gui_RefreshAll(void) {
return Gui_OverlaysCount ? Gui_Overlays[0] : Gui_GetUnderlyingScreen(); Gui_ContextLost(NULL);
Gui_ContextRecreated(NULL);
} }
struct Screen* Gui_GetUnderlyingScreen(void) { void Gui_RefreshHud(void) { Gui_Refresh(Gui_HUD); }
return Gui_Active ? Gui_Active : Gui_HUD; void Gui_Refresh(struct Screen* s) {
s->VTABLE->ContextLost(s);
s->VTABLE->ContextRecreated(s);
} }
void Gui_FreeActive(void) { int Gui_Index(struct Screen* s) {
if (Gui_Active) { Elem_TryFree(Gui_Active); }
}
void Gui_Close(void* screen) {
struct Screen* s = (struct Screen*)screen;
if (s) { Elem_TryFree(s); }
if (s == Gui_Active) Gui_SetActive(NULL);
}
void Gui_CloseActive(void) { Gui_Close(Gui_Active); }
void Gui_SetActive(struct Screen* screen) {
InputHandler_ScreenChanged(Gui_Active, screen);
Gui_Active = screen;
if (screen) {
Elem_Init(screen);
/* for selecting active button etc */
Elem_HandlesMouseMove(screen, Mouse_X, Mouse_Y);
}
Camera_CheckFocus();
}
void Gui_RefreshHud(void) { Elem_Recreate(Gui_HUD); }
void Gui_ShowOverlay(struct Screen* screen) {
if (Gui_OverlaysCount == GUI_MAX_OVERLAYS) {
Logger_Abort("Gui_ShowOverlay - hit max count");
}
Gui_Overlays[Gui_OverlaysCount] = screen;
Gui_OverlaysCount++;
Elem_Init(screen);
Camera_CheckFocus();
}
int Gui_IndexOverlay(const void* screen) {
int i; int i;
for (i = 0; i < Gui_ScreensCount; i++) {
for (i = 0; i < Gui_OverlaysCount; i++) { if (Gui_Screens[i] == s) return i;
if (Gui_Overlays[i] == screen) return i;
} }
return -1; return -1;
} }
void Gui_RemoveOverlay(const void* screen) { static void Gui_AddCore(struct Screen* s, int priority) {
int i = Gui_IndexOverlay(screen); int i, j;
if (i == -1) return; if (Gui_ScreensCount >= GUI_MAX_SCREENS) Logger_Abort("Hit max screens");
for (; i < Gui_OverlaysCount - 1; i++) { for (i = 0; i < Gui_ScreensCount; i++) {
Gui_Overlays[i] = Gui_Overlays[i + 1]; if (priority <= priorities[i]) continue;
/* Shift lower priority screens right */
for (j = Gui_ScreensCount; j > i; j--) {
Gui_Screens[j] = Gui_Screens[j - 1];
priorities[j] = priorities[j - 1];
}
break;
} }
Gui_OverlaysCount--; Gui_Screens[i] = s;
Gui_Overlays[Gui_OverlaysCount] = NULL; priorities[i] = priority;
Gui_ScreensCount++;
s->VTABLE->Init(s);
s->VTABLE->ContextRecreated(s);
/* for selecting active button etc */
s->VTABLE->HandlesMouseMove(s, Mouse_X, Mouse_Y);
}
static void Gui_RemoveCore(struct Screen* s) {
int i = Gui_Index(s);
if (i == -1) return;
for (; i < Gui_ScreensCount - 1; i++) {
Gui_Screens[i] = Gui_Screens[i + 1];
priorities[i] = priorities[i + 1];
}
Gui_ScreensCount--;
s->VTABLE->ContextLost(s);
s->VTABLE->Free(s);
}
CC_NOINLINE static void Gui_OnScreensChanged(void) {
Camera_CheckFocus(); Camera_CheckFocus();
InputHandler_OnScreensChanged();
}
void Gui_Add(struct Screen* s, int priority) {
Gui_AddCore(s, priority);
Gui_OnScreensChanged();
}
void Gui_Remove(struct Screen* s) {
Gui_RemoveCore(s);
Gui_OnScreensChanged();
}
void Gui_Replace(struct Screen* s, int priority) {
int i;
Gui_RemoveCore(s);
/* Backwards loop since removing changes count and gui_screens */
for (i = Gui_ScreensCount - 1; i >= 0; i--) {
if (priorities[i] == priority) Gui_RemoveCore(Gui_Screens[i]);
}
Gui_AddCore(s, priority);
Gui_OnScreensChanged();
}
struct Screen* Gui_GetInputGrab(void) {
int i;
for (i = 0; i < Gui_ScreensCount; i++) {
if (Gui_Screens[i]->grabsInput) return Gui_Screens[i];
}
return NULL;
}
struct Screen* Gui_GetBlocksWorld(void) {
int i;
for (i = 0; i < Gui_ScreensCount; i++) {
if (Gui_Screens[i]->blocksWorld) return Gui_Screens[i];
}
return NULL;
}
struct Screen* Gui_GetClosable(void) {
int i;
for (i = 0; i < Gui_ScreensCount; i++) {
if (Gui_Screens[i]->closable) return Gui_Screens[i];
}
return NULL;
} }
void Gui_RenderGui(double delta) { void Gui_RenderGui(double delta) {
bool showHUD, hudBefore; struct Screen* s;
int i;
Gfx_Mode2D(Game.Width, Game.Height); Gfx_Mode2D(Game.Width, Game.Height);
showHUD = !Gui_Active || !Gui_Active->hidesHUD; /* Draw back to front so highest priority screen is on top */
hudBefore = !Gui_Active || !Gui_Active->renderHUDOver; for (i = Gui_ScreensCount - 1; i >= 0; i--) {
if (showHUD) { Elem_Render(Gui_Status, delta); } s = Gui_Screens[i];
s->VTABLE->Render(s, delta);
if (showHUD && hudBefore) { Elem_Render(Gui_HUD, delta); } }
if (Gui_Active) { Elem_Render(Gui_Active, delta); }
if (showHUD && !hudBefore) { Elem_Render(Gui_HUD, delta); }
if (Gui_OverlaysCount) { Elem_Render(Gui_Overlays[0], delta); }
Gfx_Mode3D(); Gfx_Mode3D();
} }
void Gui_OnResize(void) { void Gui_OnResize(void) {
struct Screen* s;
int i; int i;
if (Gui_Active) { Screen_OnResize(Gui_Active); }
Screen_OnResize(Gui_HUD);
for (i = 0; i < Gui_OverlaysCount; i++) { for (i = 0; i < Gui_ScreensCount; i++) {
Screen_OnResize(Gui_Overlays[i]); s = Gui_Screens[i];
s->VTABLE->OnResize(s);
} }
} }

145
src/Gui.h
View File

@ -16,7 +16,7 @@ enum GuiAnchor {
}; };
struct IGameComponent; struct IGameComponent;
struct GuiElem; struct Widget;
extern struct IGameComponent Gui_Component; extern struct IGameComponent Gui_Component;
/* Whether vanilla Minecraft Classic gui texture is used. */ /* Whether vanilla Minecraft Classic gui texture is used. */
@ -34,50 +34,44 @@ extern bool Gui_TabAutocomplete;
/* Whether FPS counter (and other info) is shown in top left. */ /* Whether FPS counter (and other info) is shown in top left. */
extern bool Gui_ShowFPS; extern bool Gui_ShowFPS;
#define GuiElemVTABLE_Layout() \
void (*Init)(void* elem); \
void (*Render)(void* elem, double delta); \
void (*Free)(void* elem); \
void (*Recreate)(void* elem); \
bool (*HandlesKeyDown)(void* elem, Key key, bool wasDown); \
bool (*HandlesKeyUp)(void* elem, Key key); \
bool (*HandlesKeyPress)(void* elem, char keyChar); \
bool (*HandlesMouseDown)(void* elem, int x, int y, MouseButton btn); \
bool (*HandlesMouseUp)(void* elem, int x, int y, MouseButton btn); \
bool (*HandlesMouseMove)(void* elem, int x, int y); \
bool (*HandlesMouseScroll)(void* elem, float delta);
struct GuiElemVTABLE { GuiElemVTABLE_Layout() };
struct GuiElem { struct GuiElemVTABLE* VTABLE; };
void Gui_DefaultRecreate(void* elem);
struct ScreenVTABLE { struct ScreenVTABLE {
GuiElemVTABLE_Layout() void (*Init)(void* elem);
void (*Render)(void* elem, double delta);
void (*Free)(void* elem);
bool (*HandlesKeyDown)(void* elem, Key key);
bool (*HandlesKeyUp)(void* elem, Key key);
bool (*HandlesKeyPress)(void* elem, char keyChar);
bool (*HandlesMouseDown)(void* elem, int x, int y, MouseButton btn);
bool (*HandlesMouseUp)(void* elem, int x, int y, MouseButton btn);
bool (*HandlesMouseMove)(void* elem, int x, int y);
bool (*HandlesMouseScroll)(void* elem, float delta);
void (*OnResize)(void* elem); void (*OnResize)(void* elem);
Event_Void_Callback ContextLost; Event_Void_Callback ContextLost;
Event_Void_Callback ContextRecreated; Event_Void_Callback ContextRecreated;
}; };
#define Screen_Layout struct ScreenVTABLE* VTABLE; \ #define Screen_Layout const struct ScreenVTABLE* VTABLE; \
bool handlesAllInput; /* Whether this screen handles all input. Prevents user interacting with the world. */ \ bool grabsInput; /* Whether this screen grabs input. Causes the cursor to become visible. */ \
bool blocksWorld; /* Whether this screen completely and opaquely covers the game world behind it. */ \ bool blocksWorld; /* Whether this screen completely and opaquely covers the game world behind it. */ \
bool hidesHUD; /* Whether this screen hides the normal in-game HUD. */ \ bool closable; /* Whether this screen is automatically closed when pressing Escape */ \
bool renderHUDOver; /* Whether the normal in-game HUD should be drawn over the top of this screen. */ \ struct Widget** widgets; int numWidgets;
bool closable; /* Whether this screen is automatically closed when pressing Escape */
/* Represents a container of widgets and other 2D elements. May cover entire window. */ /* Represents a container of widgets and other 2D elements. May cover entire window. */
struct Screen { Screen_Layout }; struct Screen { Screen_Layout };
void Screen_CommonInit(void* screen);
void Screen_CommonFree(void* screen);
typedef void (*Widget_LeftClick)(void* screen, void* widget); typedef void (*Widget_LeftClick)(void* screen, void* widget);
struct Widget;
struct WidgetVTABLE { struct WidgetVTABLE {
GuiElemVTABLE_Layout() void (*Init)(void* elem);
void (*Render)(void* elem, double delta);
void (*Free)(void* elem);
bool (*HandlesKeyDown)(void* elem, Key key);
bool (*HandlesKeyUp)(void* elem, Key key);
bool (*HandlesMouseDown)(void* elem, int x, int y, MouseButton btn);
bool (*HandlesMouseUp)(void* elem, int x, int y, MouseButton btn);
bool (*HandlesMouseMove)(void* elem, int x, int y);
bool (*HandlesMouseScroll)(void* elem, float delta);
void (*Reposition)(void* elem); void (*Reposition)(void* elem);
}; };
#define Widget_Layout struct WidgetVTABLE* VTABLE; \ #define Widget_Layout const struct WidgetVTABLE* VTABLE; \
int x, y, width, height; /* Top left corner, and dimensions, of this widget */ \ int x, y, width, height; /* Top left corner, and dimensions, of this widget */ \
bool active; /* Whether this widget is currently being moused over */ \ bool active; /* Whether this widget is currently being moused over */ \
bool disabled; /* Whether widget is prevented from being interacted with */ \ bool disabled; /* Whether widget is prevented from being interacted with */ \
@ -97,54 +91,55 @@ bool Widget_Contains(void* widget, int x, int y);
extern GfxResourceID Gui_GuiTex, Gui_GuiClassicTex, Gui_IconsTex; extern GfxResourceID Gui_GuiTex, Gui_GuiClassicTex, Gui_IconsTex;
/* Higher priority handles input first and draws on top */
enum GuiPriority { enum GuiPriority {
GUI_PRIORITY_STATUS = 1, GUI_PRIORITY_DISCONNECT = 50,
GUI_PRIORITY_DISCONNECT = 3, GUI_PRIORITY_OLDLOADING = 45,
GUI_PRIORITY_URLWARNING = 5, GUI_PRIORITY_URLWARNING = 40,
GUI_PRIORITY_TEXPACK = 7, GUI_PRIORITY_TEXPACK = 35,
GUI_PRIORITY_TEXIDS = 9, GUI_PRIORITY_TEXIDS = 30,
GUI_PRIORITY_MENU = 11, GUI_PRIORITY_MENU = 25,
GUI_PRIORITY_INVENTORY = 13, GUI_PRIORITY_INVENTORY = 20,
GUI_PRIORITY_HUD = 15, GUI_PRIORITY_STATUS = 15,
GUI_PRIORITY_LOADING = 17, GUI_PRIORITY_HUD = 10,
GUI_PRIORITY_LOADING = 5,
}; };
extern struct Screen* Gui_Status; extern struct Screen* Gui_Status;
extern struct Screen* Gui_HUD; extern struct Screen* Gui_HUD;
extern struct Screen* Gui_Active; #define GUI_MAX_SCREENS 10
#define GUI_MAX_OVERLAYS 4 extern struct Screen* Gui_Screens[GUI_MAX_SCREENS];
extern struct Screen* Gui_Overlays[GUI_MAX_OVERLAYS]; extern int Gui_ScreensCount;
extern int Gui_OverlaysCount;
/* Calculates position of an element on a particular axis */ /* Calculates position of an element on a particular axis */
/* For example, to calculate X position of a text widget on screen */ /* For example, to calculate X position of a text widget on screen */
int Gui_CalcPos(uint8_t anchor, int offset, int size, int axisLen); int Gui_CalcPos(uint8_t anchor, int offset, int size, int axisLen);
/* Returns whether the given rectangle contains the given point. */ /* Returns whether the given rectangle contains the given point. */
bool Gui_Contains(int recX, int recY, int width, int height, int x, int y); bool Gui_Contains(int recX, int recY, int width, int height, int x, int y);
/* Gets the screen that the user is currently interacting with. */ /* Shows HUD and Status screens. */
/* This means if an overlay is active, it will be over the top of other screens. */ void Gui_ShowDefault(void);
struct Screen* Gui_GetActiveScreen(void);
/* Gets the non-overlay screen that the user is currently interacting with. */
/* This means if an overlay is active, the screen under it is returned. */
struct Screen* Gui_GetUnderlyingScreen(void);
/* Frees the active screen if it is not NULL. */ /* Returns index of the given screen in the screens list, -1 if not */
/* NOTE: You should usually use Gui_CloseActive instead. */ int Gui_Index(struct Screen* screen);
CC_NOINLINE void Gui_FreeActive(void); /* Inserts a screen into the screen lists with the given priority. */
/* Sets the active screen/menu that the user interacts with. */ /* NOTE: You MUST ensure a screen isn't added twice. Or use Gui_Replace. */
/* NOTE: This doesn't free old active screen - must call Gui_FreeActive() first */ void Gui_Add(struct Screen* screen, int priority);
CC_NOINLINE void Gui_SetActive(struct Screen* screen); /* Removes the screen from the screens list. */
/* Shortcut for Gui_Close(Gui_Active) */ void Gui_Remove(struct Screen* screen);
CC_NOINLINE void Gui_CloseActive(void); /* Shorthand for Gui_Remove then Gui_Add. */
/* Frees the given screen, and if == Gui_Active, calls Gui_SetActive(NULL) */ void Gui_Replace(struct Screen* screen, int priority);
CC_NOINLINE void Gui_Close(void* screen);
/* Returns highest priority screen that has grabbed input. */
struct Screen* Gui_GetInputGrab(void);
/* Returns highest priority screen that blocks world rendering. */
struct Screen* Gui_GetBlocksWorld(void);
/* Returns highest priority screen that is closable. */
struct Screen* Gui_GetClosable(void);
void Gui_RefreshAll(void);
void Gui_RefreshHud(void); void Gui_RefreshHud(void);
void Gui_ShowOverlay(struct Screen* screen); void Gui_Refresh(struct Screen* s);
/* Returns index of the given screen in the overlays list, -1 if not */
int Gui_IndexOverlay(const void* screen);
/* Removes given screen from the overlays list */
void Gui_RemoveOverlay(const void* screen);
void Gui_RenderGui(double delta); void Gui_RenderGui(double delta);
void Gui_OnResize(void); void Gui_OnResize(void);
@ -153,8 +148,8 @@ struct TextAtlas {
struct Texture tex; struct Texture tex;
int offset, curX; int offset, curX;
float uScale; float uScale;
int16_t widths[TEXTATLAS_MAX_WIDTHS]; short widths[TEXTATLAS_MAX_WIDTHS];
int16_t offsets[TEXTATLAS_MAX_WIDTHS]; short offsets[TEXTATLAS_MAX_WIDTHS];
}; };
void TextAtlas_Make(struct TextAtlas* atlas, const String* chars, const FontDesc* font, const String* prefix); void TextAtlas_Make(struct TextAtlas* atlas, const String* chars, const FontDesc* font, const String* prefix);
void TextAtlas_Free(struct TextAtlas* atlas); void TextAtlas_Free(struct TextAtlas* atlas);
@ -162,19 +157,17 @@ void TextAtlas_Add(struct TextAtlas* atlas, int charI, VertexP3fT2fC4b** vertice
void TextAtlas_AddInt(struct TextAtlas* atlas, int value, VertexP3fT2fC4b** vertices); void TextAtlas_AddInt(struct TextAtlas* atlas, int value, VertexP3fT2fC4b** vertices);
#define Elem_Init(elem) (elem)->VTABLE->Init(elem) #define Elem_Init(elem) (elem)->VTABLE->Init(elem)
#define Elem_Render(elem, delta) (elem)->VTABLE->Render(elem, delta) #define Elem_Render(elem, delta) (elem)->VTABLE->Render(elem, delta)
#define Elem_Free(elem) (elem)->VTABLE->Free(elem) #define Elem_Free(elem) (elem)->VTABLE->Free(elem)
#define Elem_Recreate(elem) (elem)->VTABLE->Recreate(elem) #define Elem_HandlesKeyPress(elem, key) (elem)->VTABLE->HandlesKeyPress(elem, key)
#define Elem_HandlesKeyPress(elem, key) (elem)->VTABLE->HandlesKeyPress(elem, key) #define Elem_HandlesKeyDown(elem, key) (elem)->VTABLE->HandlesKeyDown(elem, key)
#define Elem_HandlesKeyDown(elem, key, was) (elem)->VTABLE->HandlesKeyDown(elem, key, was) #define Elem_HandlesKeyUp(elem, key) (elem)->VTABLE->HandlesKeyUp(elem, key)
#define Elem_HandlesKeyUp(elem, key) (elem)->VTABLE->HandlesKeyUp(elem, key)
#define Elem_HandlesMouseDown(elem, x, y, btn) (elem)->VTABLE->HandlesMouseDown(elem, x, y, btn) #define Elem_HandlesMouseDown(elem, x, y, btn) (elem)->VTABLE->HandlesMouseDown(elem, x, y, btn)
#define Elem_HandlesMouseUp(elem, x, y, btn) (elem)->VTABLE->HandlesMouseUp(elem, x, y, btn) #define Elem_HandlesMouseUp(elem, x, y, btn) (elem)->VTABLE->HandlesMouseUp(elem, x, y, btn)
#define Elem_HandlesMouseMove(elem, x, y) (elem)->VTABLE->HandlesMouseMove(elem, x, y) #define Elem_HandlesMouseMove(elem, x, y) (elem)->VTABLE->HandlesMouseMove(elem, x, y)
#define Elem_HandlesMouseScroll(elem, delta) (elem)->VTABLE->HandlesMouseScroll(elem, delta) #define Elem_HandlesMouseScroll(elem, delta) (elem)->VTABLE->HandlesMouseScroll(elem, delta)
#define Screen_OnResize(screen) (screen)->VTABLE->OnResize(screen);
#define Widget_Reposition(widget) (widget)->VTABLE->Reposition(widget); #define Widget_Reposition(widget) (widget)->VTABLE->Reposition(widget);
#define Elem_TryFree(elem) if ((elem)->VTABLE) { Elem_Free(elem); } #define Elem_TryFree(elem) if ((elem)->VTABLE) { Elem_Free(elem); }
#endif #endif

View File

@ -62,10 +62,8 @@ static void InputHandler_ButtonStateChanged(MouseButton button, bool pressed) {
} }
} }
void InputHandler_ScreenChanged(struct Screen* oldScreen, struct Screen* newScreen) { void InputHandler_OnScreensChanged(void) {
if (oldScreen && oldScreen->handlesAllInput) { input_lastClick = DateTime_CurrentUTC_MS();
input_lastClick = DateTime_CurrentUTC_MS();
}
if (Server.SupportsPlayerClick) { if (Server.SupportsPlayerClick) {
input_pickingId = -1; input_pickingId = -1;
@ -172,8 +170,7 @@ static bool InputHandler_HandleNonClassicKey(Key key) {
Event_RaiseVoid(&UserEvents.HeldBlockChanged); Event_RaiseVoid(&UserEvents.HeldBlockChanged);
} }
} else if (key == KeyBinds[KEYBIND_IDOVERLAY]) { } else if (key == KeyBinds[KEYBIND_IDOVERLAY]) {
if (Gui_OverlaysCount) return true; TexIdsOverlay_Show();
Gui_ShowOverlay(TexIdsOverlay_MakeInstance());
} else if (key == KeyBinds[KEYBIND_BREAK_LIQUIDS]) { } else if (key == KeyBinds[KEYBIND_BREAK_LIQUIDS]) {
InputHandler_Toggle(key, &Game_BreakableLiquids, InputHandler_Toggle(key, &Game_BreakableLiquids,
" &eBreakable liquids is &aenabled", " &eBreakable liquids is &aenabled",
@ -185,8 +182,6 @@ static bool InputHandler_HandleNonClassicKey(Key key) {
} }
static bool InputHandler_HandleCoreKey(Key key) { static bool InputHandler_HandleCoreKey(Key key) {
struct Screen* active = Gui_GetActiveScreen();
if (key == KeyBinds[KEYBIND_HIDE_FPS]) { if (key == KeyBinds[KEYBIND_HIDE_FPS]) {
Gui_ShowFPS = !Gui_ShowFPS; Gui_ShowFPS = !Gui_ShowFPS;
} else if (key == KeyBinds[KEYBIND_FULLSCREEN]) { } else if (key == KeyBinds[KEYBIND_FULLSCREEN]) {
@ -206,9 +201,6 @@ static bool InputHandler_HandleCoreKey(Key key) {
} else { } else {
InputHandler_CycleDistanceForwards(viewDists, count); InputHandler_CycleDistanceForwards(viewDists, count);
} }
} else if (key == KeyBinds[KEYBIND_INVENTORY] && active == Gui_HUD) {
Gui_FreeActive();
InventoryScreen_Show();
} else if (key == KEY_F5 && Game_ClassicMode) { } else if (key == KEY_F5 && Game_ClassicMode) {
int weather = Env.Weather == WEATHER_SUNNY ? WEATHER_RAINY : WEATHER_SUNNY; int weather = Env.Weather == WEATHER_SUNNY ? WEATHER_RAINY : WEATHER_SUNNY;
Env_SetWeather(weather); Env_SetWeather(weather);
@ -331,16 +323,15 @@ void InputHandler_PickBlocks(bool cooldown, bool left, bool middle, bool right)
if (cooldown && delta < 250) return; /* 4 times per second */ if (cooldown && delta < 250) return; /* 4 times per second */
input_lastClick = now; input_lastClick = now;
if (Gui_GetInputGrab()) return;
if (Server.SupportsPlayerClick && !Gui_GetActiveScreen()->handlesAllInput) { if (Server.SupportsPlayerClick) {
input_pickingId = -1; input_pickingId = -1;
InputHandler_ButtonStateChanged(MOUSE_LEFT, left); InputHandler_ButtonStateChanged(MOUSE_LEFT, left);
InputHandler_ButtonStateChanged(MOUSE_RIGHT, right); InputHandler_ButtonStateChanged(MOUSE_RIGHT, right);
InputHandler_ButtonStateChanged(MOUSE_MIDDLE, middle); InputHandler_ButtonStateChanged(MOUSE_MIDDLE, middle);
} }
if (Gui_GetActiveScreen()->handlesAllInput) return;
if (left) { if (left) {
/* always play delete animations, even if we aren't picking a block */ /* always play delete animations, even if we aren't picking a block */
HeldBlockRenderer_ClickAnim(true); HeldBlockRenderer_ClickAnim(true);
@ -401,10 +392,15 @@ void InputHandler_PickBlocks(bool cooldown, bool left, bool middle, bool right)
} }
static void InputHandler_MouseWheel(void* obj, float delta) { static void InputHandler_MouseWheel(void* obj, float delta) {
struct Screen* active = Gui_GetActiveScreen(); struct Screen* s;
int i;
struct Widget* widget; struct Widget* widget;
bool hotbar; bool hotbar;
if (Elem_HandlesMouseScroll(active, delta)) return;
for (i = 0; i < Gui_ScreensCount; i++) {
s = Gui_Screens[i];
if (s->VTABLE->HandlesMouseScroll(s, delta)) return;
}
hotbar = Key_IsAltPressed() || Key_IsControlPressed() || Key_IsShiftPressed(); hotbar = Key_IsAltPressed() || Key_IsControlPressed() || Key_IsShiftPressed();
if (!hotbar && Camera.Active->Zoom(delta)) return; if (!hotbar && Camera.Active->Zoom(delta)) return;
@ -415,31 +411,43 @@ static void InputHandler_MouseWheel(void* obj, float delta) {
} }
static void InputHandler_MouseMove(void* obj, int xDelta, int yDelta) { static void InputHandler_MouseMove(void* obj, int xDelta, int yDelta) {
struct Screen* active = Gui_GetActiveScreen(); struct Screen* s;
/* In case MouseMove is called before game is fully initialised */ int i;
if (active) Elem_HandlesMouseMove(active, Mouse_X, Mouse_Y);
}
static void InputHandler_MouseDown(void* obj, int button) { for (i = 0; i < Gui_ScreensCount; i++) {
struct Screen* active = Gui_GetActiveScreen(); s = Gui_Screens[i];
if (!Elem_HandlesMouseDown(active, Mouse_X, Mouse_Y, button)) { if (s->VTABLE->HandlesMouseMove(s, Mouse_X, Mouse_Y)) return;
bool left = button == MOUSE_LEFT;
bool middle = button == MOUSE_MIDDLE;
bool right = button == MOUSE_RIGHT;
InputHandler_PickBlocks(false, left, middle, right);
} else {
input_lastClick = DateTime_CurrentUTC_MS();
} }
} }
static void InputHandler_MouseUp(void* obj, int button) { static void InputHandler_MouseDown(void* obj, int btn) {
struct Screen* active = Gui_GetActiveScreen(); struct Screen* s;
if (!Elem_HandlesMouseUp(active, Mouse_X, Mouse_Y, button)) { int i;
if (Server.SupportsPlayerClick && button <= MOUSE_MIDDLE) {
input_pickingId = -1; for (i = 0; i < Gui_ScreensCount; i++) {
InputHandler_ButtonStateChanged(button, false); s = Gui_Screens[i];
if (s->VTABLE->HandlesMouseDown(s, Mouse_X, Mouse_Y, btn)) {
input_lastClick = DateTime_CurrentUTC_MS(); return;
} }
} }
InputHandler_PickBlocks(false, btn == MOUSE_LEFT,
btn == MOUSE_MIDDLE, btn == MOUSE_RIGHT);
}
static void InputHandler_MouseUp(void* obj, int btn) {
struct Screen* s;
int i;
for (i = 0; i < Gui_ScreensCount; i++) {
s = Gui_Screens[i];
if (s->VTABLE->HandlesMouseUp(s, Mouse_X, Mouse_Y, btn)) return;
}
if (Server.SupportsPlayerClick && btn <= MOUSE_MIDDLE) {
input_pickingId = -1;
InputHandler_ButtonStateChanged(btn, false);
}
} }
static bool InputHandler_SimulateMouse(Key key, bool pressed) { static bool InputHandler_SimulateMouse(Key key, bool pressed) {
@ -456,18 +464,16 @@ static bool InputHandler_SimulateMouse(Key key, bool pressed) {
} }
static void InputHandler_KeyDown(void* obj, int key, bool was) { static void InputHandler_KeyDown(void* obj, int key, bool was) {
struct Screen* active; struct Screen* s;
int idx; int i;
struct HotkeyData* hkey; struct HotkeyData* hkey;
String text; String text;
if (!was && InputHandler_SimulateMouse(key, true)) return; if (!was && InputHandler_SimulateMouse(key, true)) return;
active = Gui_GetActiveScreen();
#ifndef CC_BUILD_WEB #ifndef CC_BUILD_WEB
if (key == KEY_ESCAPE && active->closable) { if (key == KEY_ESCAPE && (s = Gui_GetClosable())) {
/* Don't want holding down escape to go in and out of pause menu */ /* Don't want holding down escape to go in and out of pause menu */
if (!was) Gui_Close(active); if (!was) Gui_Remove(s);
return; return;
} }
#endif #endif
@ -477,9 +483,14 @@ static void InputHandler_KeyDown(void* obj, int key, bool was) {
Window_Close(); return; Window_Close(); return;
} else if (key == KeyBinds[KEYBIND_SCREENSHOT] && !was) { } else if (key == KeyBinds[KEYBIND_SCREENSHOT] && !was) {
Game_ScreenshotRequested = true; return; Game_ScreenshotRequested = true; return;
} else if (Elem_HandlesKeyDown(active, key, was)) { }
return;
} else if ((key == KEY_ESCAPE || key == KEY_PAUSE) && !active->handlesAllInput) { for (i = 0; i < Gui_ScreensCount; i++) {
s = Gui_Screens[i];
if (s->VTABLE->HandlesKeyDown(s, key)) return;
}
if ((key == KEY_ESCAPE || key == KEY_PAUSE) && !Gui_GetInputGrab()) {
#ifdef CC_BUILD_WEB #ifdef CC_BUILD_WEB
/* Can't do this in KeyUp, because pressing escape without having */ /* Can't do this in KeyUp, because pressing escape without having */
/* explicitly disabled mouse lock means a KeyUp event isn't sent. */ /* explicitly disabled mouse lock means a KeyUp event isn't sent. */
@ -488,8 +499,7 @@ static void InputHandler_KeyDown(void* obj, int key, bool was) {
/* closes the pause screen. Hence why the next KeyUp must be supressed. */ /* closes the pause screen. Hence why the next KeyUp must be supressed. */
suppressEscape = true; suppressEscape = true;
#endif #endif
Gui_FreeActive(); PauseScreen_Show(); return;
Gui_SetActive(PauseScreen_MakeInstance()); return;
} }
/* These should not be triggered multiple times when holding down */ /* These should not be triggered multiple times when holding down */
@ -497,42 +507,51 @@ static void InputHandler_KeyDown(void* obj, int key, bool was) {
if (InputHandler_HandleCoreKey(key)) { if (InputHandler_HandleCoreKey(key)) {
} else if (LocalPlayer_HandlesKey(key)) { } else if (LocalPlayer_HandlesKey(key)) {
} else { } else {
idx = Hotkeys_FindPartial(key); i = Hotkeys_FindPartial(key);
if (idx == -1) return; if (i == -1) return;
hkey = &HotkeysList[idx]; hkey = &HotkeysList[i];
text = StringsBuffer_UNSAFE_Get(&HotkeysText, hkey->TextIndex); text = StringsBuffer_UNSAFE_Get(&HotkeysText, hkey->TextIndex);
if (!hkey->StaysOpen) { if (!hkey->StaysOpen) {
Chat_Send(&text, false); Chat_Send(&text, false);
} else if (!Gui_Active) { } else if (!Gui_GetInputGrab()) {
HUDScreen_OpenInput(&text); HUDScreen_OpenInput(&text);
} }
} }
} }
static void InputHandler_KeyUp(void* obj, int key) { static void InputHandler_KeyUp(void* obj, int key) {
struct Screen* active; struct Screen* s;
if (InputHandler_SimulateMouse(key, false)) return; int i;
if (InputHandler_SimulateMouse(key, false)) return;
if (key == KeyBinds[KEYBIND_ZOOM_SCROLL]) Game_SetFov(Game_DefaultFov); if (key == KeyBinds[KEYBIND_ZOOM_SCROLL]) Game_SetFov(Game_DefaultFov);
active = Gui_GetActiveScreen();
#ifdef CC_BUILD_WEB #ifdef CC_BUILD_WEB
/* When closing menus (which reacquires mouse focus) in key down, */ /* When closing menus (which reacquires mouse focus) in key down, */
/* this still leaves the cursor visible. But if this is instead */ /* this still leaves the cursor visible. But if this is instead */
/* done in key up, the cursor disappears as expected. */ /* done in key up, the cursor disappears as expected. */
if (key == KEY_ESCAPE && active->closable) { if (key == KEY_ESCAPE && (s = Gui_GetClosable())) {
if (suppressEscape) { suppressEscape = false; return; } if (suppressEscape) { suppressEscape = false; return; }
Gui_Close(active); return; Gui_Remove(s); return;
} }
#endif #endif
Elem_HandlesKeyUp(active, key);
for (i = 0; i < Gui_ScreensCount; i++) {
s = Gui_Screens[i];
if (s->VTABLE->HandlesKeyUp(s, key)) return;
}
} }
static void InputHandler_KeyPress(void* obj, int keyChar) { static void InputHandler_KeyPress(void* obj, int keyChar) {
struct Screen* active = Gui_GetActiveScreen(); struct Screen* s;
Elem_HandlesKeyPress(active, keyChar); int i;
for (i = 0; i < Gui_ScreensCount; i++) {
s = Gui_Screens[i];
if (s->VTABLE->HandlesKeyPress(s, keyChar)) return;
}
} }
void InputHandler_Init(void) { void InputHandler_Init(void) {

View File

@ -10,5 +10,5 @@ bool InputHandler_IsMousePressed(MouseButton button);
bool InputHandler_SetFOV(int fov); bool InputHandler_SetFOV(int fov);
void InputHandler_PickBlocks(bool cooldown, bool left, bool middle, bool right); void InputHandler_PickBlocks(bool cooldown, bool left, bool middle, bool right);
void InputHandler_Init(void); void InputHandler_Init(void);
void InputHandler_ScreenChanged(struct Screen* oldScreen, struct Screen* newScreen); void InputHandler_OnScreensChanged(void);
#endif #endif

View File

@ -235,7 +235,7 @@ static void LInput_BlendBoxTop(struct LInput* w) {
} }
static void LInput_DrawText(struct LInput* w, struct DrawTextArgs* args) { static void LInput_DrawText(struct LInput* w, struct DrawTextArgs* args) {
int hintHeight, y; int y, hintHeight;
if (w->Text.length || !w->HintText) { if (w->Text.length || !w->HintText) {
y = w->Y + (w->Height - w->_TextHeight) / 2; y = w->Y + (w->Height - w->_TextHeight) / 2;
@ -244,7 +244,7 @@ static void LInput_DrawText(struct LInput* w, struct DrawTextArgs* args) {
args->text = String_FromReadonly(w->HintText); args->text = String_FromReadonly(w->HintText);
args->font = Launcher_HintFont; args->font = Launcher_HintFont;
hintHeight = Drawer2D_MeasureText(args).Height; hintHeight = Drawer2D_TextHeight(args);
y = w->Y + (w->Height - hintHeight) / 2; y = w->Y + (w->Height - hintHeight) / 2;
Drawer2D_DrawText(&Launcher_Framebuffer, args, w->X + 5, y); Drawer2D_DrawText(&Launcher_Framebuffer, args, w->X + 5, y);
} }

File diff suppressed because it is too large Load Diff

View File

@ -7,33 +7,33 @@
*/ */
struct Screen; struct Screen;
struct Screen* PauseScreen_MakeInstance(void); void PauseScreen_Show(void);
struct Screen* OptionsGroupScreen_MakeInstance(void); void OptionsGroupScreen_Show(void);
struct Screen* ClassicOptionsScreen_MakeInstance(void); void ClassicOptionsScreen_Show(void);
struct Screen* ClassicKeyBindingsScreen_MakeInstance(void); void ClassicKeyBindingsScreen_Show(void);
struct Screen* ClassicHacksKeyBindingsScreen_MakeInstance(void); void ClassicHacksKeyBindingsScreen_Show(void);
struct Screen* NormalKeyBindingsScreen_MakeInstance(void); void NormalKeyBindingsScreen_Show(void);
struct Screen* HacksKeyBindingsScreen_MakeInstance(void); void HacksKeyBindingsScreen_Show(void);
struct Screen* OtherKeyBindingsScreen_MakeInstance(void); void OtherKeyBindingsScreen_Show(void);
struct Screen* MouseKeyBindingsScreen_MakeInstance(void); void MouseKeyBindingsScreen_Show(void);
struct Screen* GenLevelScreen_MakeInstance(void); void GenLevelScreen_Show(void);
struct Screen* ClassicGenScreen_MakeInstance(void); void ClassicGenScreen_Show(void);
struct Screen* LoadLevelScreen_MakeInstance(void); void LoadLevelScreen_Show(void);
struct Screen* SaveLevelScreen_MakeInstance(void); void SaveLevelScreen_Show(void);
struct Screen* TexturePackScreen_MakeInstance(void); void TexturePackScreen_Show(void);
struct Screen* FontListScreen_MakeInstance(void); void FontListScreen_Show(void);
struct Screen* HotkeyListScreen_MakeInstance(void); void HotkeyListScreen_Show(void);
struct Screen* MiscOptionsScreen_MakeInstance(void); void MiscOptionsScreen_Show(void);
struct Screen* GuiOptionsScreen_MakeInstance(void); void GuiOptionsScreen_Show(void);
struct Screen* GraphicsOptionsScreen_MakeInstance(void); void GraphicsOptionsScreen_Show(void);
struct Screen* HacksSettingsScreen_MakeInstance(void); void HacksSettingsScreen_Show(void);
struct Screen* EnvSettingsScreen_MakeInstance(void); void EnvSettingsScreen_Show(void);
struct Screen* NostalgiaScreen_MakeInstance(void); void NostalgiaScreen_Show(void);
struct Screen* UrlWarningOverlay_MakeInstance(const String* url); void UrlWarningOverlay_Show(const String* url);
struct Screen* TexIdsOverlay_MakeInstance(void); void TexIdsOverlay_Show(void);
struct Screen* TexPackOverlay_MakeInstance(const String* url); void TexPackOverlay_Show(const String* url);
#endif #endif

View File

@ -105,9 +105,9 @@ static int Program_Run(int argc, char** argv) {
int argsCount = Platform_GetCommandLineArgs(argc, argv, args); int argsCount = Platform_GetCommandLineArgs(argc, argv, args);
/* NOTE: Make sure to comment this out before pushing a commit */ /* NOTE: Make sure to comment this out before pushing a commit */
/* String rawArgs = String_FromConst("UnknownShadow200 fffff 127.0.0.1 25565"); */ String rawArgs = String_FromConst("UnknownShadow200 fffff 127.0.0.1 25565");
/* String rawArgs = String_FromConst("UnknownShadow200"); */ //String rawArgs = String_FromConst("UnknownShadow200");
/* argsCount = String_UNSAFE_Split(&rawArgs, ' ', args, 4); */ argsCount = String_UNSAFE_Split(&rawArgs, ' ', args, 4);
if (argsCount == 0) { if (argsCount == 0) {
#ifdef CC_BUILD_WEB #ifdef CC_BUILD_WEB

View File

@ -27,7 +27,6 @@
/* Classic state */ /* Classic state */
static uint8_t classic_tabList[ENTITIES_MAX_COUNT >> 3]; static uint8_t classic_tabList[ENTITIES_MAX_COUNT >> 3];
static struct Screen* classic_prevScreen;
static bool classic_receivedFirstPos; static bool classic_receivedFirstPos;
/* Map state */ /* Map state */
@ -424,13 +423,6 @@ static void Classic_StartLoading(void) {
Event_RaiseVoid(&WorldEvents.NewMap); Event_RaiseVoid(&WorldEvents.NewMap);
Stream_ReadonlyMemory(&map_part, NULL, 0); Stream_ReadonlyMemory(&map_part, NULL, 0);
classic_prevScreen = Gui_Active;
if (classic_prevScreen == LoadingScreen_UNSAFE_RawPointer) {
/* otherwise replacing LoadingScreen with LoadingScreen will cause issues */
Gui_FreeActive();
classic_prevScreen = NULL;
}
LoadingScreen_Show(&Server.Name, &Server.MOTD); LoadingScreen_Show(&Server.Name, &Server.MOTD);
WoM_CheckMotd(); WoM_CheckMotd();
classic_receivedFirstPos = false; classic_receivedFirstPos = false;
@ -511,9 +503,7 @@ static void Classic_LevelFinalise(uint8_t* data) {
int width, height, length; int width, height, length;
int loadingMs; int loadingMs;
Gui_CloseActive(); Gui_Remove(LoadingScreen_UNSAFE_RawPointer);
Gui_Active = classic_prevScreen;
classic_prevScreen = NULL;
Camera_CheckFocus(); Camera_CheckFocus();
loadingMs = (int)(DateTime_CurrentUTC_MS() - map_receiveStart); loadingMs = (int)(DateTime_CurrentUTC_MS() - map_receiveStart);

File diff suppressed because it is too large Load Diff

View File

@ -7,6 +7,20 @@
struct Screen; struct Screen;
struct Widget; struct Widget;
/* These always return false */
bool Screen_FKey(void* elem, int key);
bool Screen_FKeyPress(void* elem, char keyChar);
bool Screen_FMouseScroll(void* elem, float delta);
bool Screen_FMouse(void* elem, int x, int y, int btn);
bool Screen_FMouseMove(void* elem, int x, int y);
/* These always return true */
bool Screen_TKeyPress(void* elem, char keyChar);
bool Screen_TKey(void* s, int key);
bool Screen_TMouseScroll(void* screen, float delta);
bool Screen_TMouse(void* screen, int x, int y, int btn);
bool Screen_TMouseMove(void* elem, int x, int y);
void InventoryScreen_Show(void); void InventoryScreen_Show(void);
void StatusScreen_Show(void); void StatusScreen_Show(void);
void LoadingScreen_Show(const String* title, const String* message); void LoadingScreen_Show(const String* title, const String* message);
@ -14,13 +28,12 @@ void GeneratingScreen_Show(void);
void HUDScreen_Show(void); void HUDScreen_Show(void);
void DisconnectScreen_Show(const String* title, const String* message); void DisconnectScreen_Show(const String* title, const String* message);
/* Raw pointer to inventory screen. DO NOT USE THIS. Use InventoryScreen_MakeInstance() */
extern struct Screen* InventoryScreen_UNSAFE_RawPointer;
/* Raw pointer to loading screen. DO NOT USE THIS. Use LoadingScreen_MakeInstance() */ /* Raw pointer to loading screen. DO NOT USE THIS. Use LoadingScreen_MakeInstance() */
extern struct Screen* LoadingScreen_UNSAFE_RawPointer; extern struct Screen* LoadingScreen_UNSAFE_RawPointer;
/* Opens chat input for the HUD with the given initial text. */ /* Opens chat input for the HUD with the given initial text. */
void HUDScreen_OpenInput(const String* text); void HUDScreen_OpenInput(const String* text);
/* Appends text to the chat input in the HUD. */ /* Appends text to the chat input in the HUD. */
void HUDScreen_AppendInput(const String* text); void HUDScreen_AppendInput(const String* text);
void HUDScreen_SetChatlines(int lines);
struct Widget* HUDScreen_GetHotbar(void); struct Widget* HUDScreen_GetHotbar(void);
#endif #endif

View File

@ -46,7 +46,7 @@ void Server_RetrieveTexturePack(const String* url) {
if (!url->length || TextureCache_HasAccepted(url)) { if (!url->length || TextureCache_HasAccepted(url)) {
World_ApplyTexturePack(url); World_ApplyTexturePack(url);
} else { } else {
Gui_ShowOverlay(TexPackOverlay_MakeInstance(url)); TexPackOverlay_Show(url);
} }
} }
@ -139,7 +139,6 @@ static void SPConnection_BeginConnect(void) {
path = Game_Username; path = Game_Username;
if (SP_HasDir(path) && File_Exists(&path)) { if (SP_HasDir(path) && File_Exists(&path)) {
Map_LoadFrom(&path); Map_LoadFrom(&path);
Gui_CloseActive();
return; return;
} }
@ -147,8 +146,6 @@ static void SPConnection_BeginConnect(void) {
World_SetDimensions(128, 64, 128); World_SetDimensions(128, 64, 128);
Gen_Vanilla = true; Gen_Vanilla = true;
Gen_Seed = Random_Next(&rnd, Int32_MaxValue); Gen_Seed = Random_Next(&rnd, Int32_MaxValue);
Gui_FreeActive();
GeneratingScreen_Show(); GeneratingScreen_Show();
} }
@ -316,7 +313,6 @@ static void MPConnection_BeginConnect(void) {
MPConnection_FailConnect(res); MPConnection_FailConnect(res);
} else { } else {
String_Format2(&title, "Connecting to %s:%i..", &Server.IP, &Server.Port); String_Format2(&title, "Connecting to %s:%i..", &Server.IP, &Server.Port);
Gui_FreeActive();
LoadingScreen_Show(&title, &String_Empty); LoadingScreen_Show(&title, &String_Empty);
} }
} }

View File

@ -63,7 +63,7 @@ CC_VAR extern struct _ServerConnectionData {
/* Sends a position update to the server. */ /* Sends a position update to the server. */
void (*SendPosition)(Vec3 pos, float rotY, float headX); void (*SendPosition)(Vec3 pos, float rotY, float headX);
/* Sends raw data to the server. */ /* Sends raw data to the server. */
/* NOTE: Prefer SendBlock/Position/Chat instead, this does not work in singleplayer. */ /* NOTE: Prefer SendBlock/Position/Chat instead, this does NOT work in singleplayer. */
void (*SendData)(const uint8_t* data, uint32_t len); void (*SendData)(const uint8_t* data, uint32_t len);
/* The current name of the server. (Shows as first line when loading) */ /* The current name of the server. (Shows as first line when loading) */
@ -71,7 +71,7 @@ CC_VAR extern struct _ServerConnectionData {
/* The current MOTD of the server. (Shows as second line when loading) */ /* The current MOTD of the server. (Shows as second line when loading) */
String MOTD; String MOTD;
/* The software name the client identifies itself as being to the server. */ /* The software name the client identifies itself as being to the server. */
/* By default this is the same as GAME_APP_NAME */ /* By default this is GAME_APP_NAME. */
String AppName; String AppName;
/* Buffer to data to send to the server. */ /* Buffer to data to send to the server. */

File diff suppressed because it is too large Load Diff

View File

@ -11,17 +11,17 @@
/* A text label. */ /* A text label. */
struct TextWidget { struct TextWidget {
Widget_Layout Widget_Layout
struct Texture texture; struct Texture tex;
bool reducePadding; bool reducePadding;
PackedCol col; PackedCol col;
}; };
/* Resets state of the given text widget to default. */ /* Initialises a text widget. */
CC_NOINLINE void TextWidget_Make(struct TextWidget* w); CC_NOINLINE void TextWidget_Make(struct TextWidget* w,
uint8_t horAnchor, uint8_t verAnchor, int xOffset, int yOffset);
/* Draws the given text into a texture, then updates the position and size of this widget. */ /* Draws the given text into a texture, then updates the position and size of this widget. */
CC_NOINLINE void TextWidget_Set(struct TextWidget* w, const String* text, const FontDesc* font); CC_NOINLINE void TextWidget_Set(struct TextWidget* w, const String* text, const FontDesc* font);
/* Shorthand for TextWidget_Make then TextWidget_Set */ /* Shorthand for TextWidget_Set using String_FromReadonly */
CC_NOINLINE void TextWidget_Create(struct TextWidget* w, const String* text, const FontDesc* font); CC_NOINLINE void TextWidget_SetConst(struct TextWidget* w, const char* text, const FontDesc* font);
typedef void (*Button_Get)(String* raw); typedef void (*Button_Get)(String* raw);
@ -29,19 +29,19 @@ typedef void (*Button_Set)(const String* raw);
/* A labelled button that can be clicked on. */ /* A labelled button that can be clicked on. */
struct ButtonWidget { struct ButtonWidget {
Widget_Layout Widget_Layout
struct Texture texture; struct Texture tex;
int minWidth; int minWidth;
const char* optName; const char* optName;
Button_Get GetValue; Button_Get GetValue;
Button_Set SetValue; Button_Set SetValue;
}; };
/* Resets state of the given button widget to default. */ /* Initialises a button widget. */
CC_NOINLINE void ButtonWidget_Make(struct ButtonWidget* w, int minWidth, Widget_LeftClick onClick); CC_NOINLINE void ButtonWidget_Make(struct ButtonWidget* w, int minWidth, Widget_LeftClick onClick,
uint8_t horAnchor, uint8_t verAnchor, int xOffset, int yOffset);
/* Draws the given text into a texture, then updates the position and size of this widget. */ /* Draws the given text into a texture, then updates the position and size of this widget. */
CC_NOINLINE void ButtonWidget_Set(struct ButtonWidget* w, const String* text, const FontDesc* font); CC_NOINLINE void ButtonWidget_Set(struct ButtonWidget* w, const String* text, const FontDesc* font);
/* Resets state of the given button widget, then calls ButtonWidget_Set */ /* Shorthand for ButtonWidget_Set using String_FromReadonly */
CC_NOINLINE void ButtonWidget_Create(struct ButtonWidget* w, int minWidth, const String* text, const FontDesc* font, Widget_LeftClick onClick); CC_NOINLINE void ButtonWidget_SetConst(struct ButtonWidget* w, const char* text, const FontDesc* font);
/* Clickable and draggable scrollbar. */ /* Clickable and draggable scrollbar. */
struct ScrollbarWidget { struct ScrollbarWidget {
@ -70,7 +70,7 @@ CC_NOINLINE void HotbarWidget_Create(struct HotbarWidget* w);
/* A table of blocks. */ /* A table of blocks. */
struct TableWidget { struct TableWidget {
Widget_Layout Widget_Layout
int elementsCount, elementsPerRow, rowsCount; int blocksCount, blocksPerRow, rowsCount;
int lastCreatedIndex; int lastCreatedIndex;
FontDesc* font; FontDesc* font;
int selectedIndex, cellSize; int selectedIndex, cellSize;
@ -78,7 +78,7 @@ struct TableWidget {
GfxResourceID vb; GfxResourceID vb;
bool pendingClose; bool pendingClose;
BlockID elements[BLOCK_COUNT]; BlockID blocks[BLOCK_COUNT];
struct ScrollbarWidget scroll; struct ScrollbarWidget scroll;
struct Texture descTex; struct Texture descTex;
int lastX, lastY; int lastX, lastY;
@ -88,8 +88,10 @@ CC_NOINLINE void TableWidget_Create(struct TableWidget* w);
/* Sets the selected block in the table to the given block. */ /* Sets the selected block in the table to the given block. */
/* Also adjusts scrollbar and moves cursor to be over the given block. */ /* Also adjusts scrollbar and moves cursor to be over the given block. */
CC_NOINLINE void TableWidget_SetBlockTo(struct TableWidget* w, BlockID block); CC_NOINLINE void TableWidget_SetBlockTo(struct TableWidget* w, BlockID block);
CC_NOINLINE void TableWidget_RecreateBlocks(struct TableWidget* w);
CC_NOINLINE void TableWidget_OnInventoryChanged(struct TableWidget* w); CC_NOINLINE void TableWidget_OnInventoryChanged(struct TableWidget* w);
CC_NOINLINE void TableWidget_MakeDescTex(struct TableWidget* w, BlockID block); CC_NOINLINE void TableWidget_MakeDescTex(struct TableWidget* w, BlockID block);
CC_NOINLINE void TableWidget_Recreate(struct TableWidget* w);
#define INPUTWIDGET_MAX_LINES 3 #define INPUTWIDGET_MAX_LINES 3
@ -103,11 +105,11 @@ struct InputWidget {
bool (*AllowedChar)(void* elem, char c); bool (*AllowedChar)(void* elem, char c);
String text; String text;
String lines[INPUTWIDGET_MAX_LINES]; /* raw text of each line */ String lines[INPUTWIDGET_MAX_LINES]; /* raw text of each line */
Size2D lineSizes[INPUTWIDGET_MAX_LINES]; /* size of each line in pixels */ int lineWidths[INPUTWIDGET_MAX_LINES]; /* Width of each line in pixels */
int lineHeight;
struct Texture inputTex; struct Texture inputTex;
String prefix; int prefixWidth;
int prefixWidth, prefixHeight;
bool convertPercents; bool convertPercents;
uint8_t padding; uint8_t padding;
@ -126,6 +128,8 @@ CC_NOINLINE void InputWidget_Clear(struct InputWidget* w);
CC_NOINLINE void InputWidget_AppendString(struct InputWidget* w, const String* text); CC_NOINLINE void InputWidget_AppendString(struct InputWidget* w, const String* text);
/* Tries appending the given character, then updates the input texture. */ /* Tries appending the given character, then updates the input texture. */
CC_NOINLINE void InputWidget_Append(struct InputWidget* w, char c); CC_NOINLINE void InputWidget_Append(struct InputWidget* w, char c);
/* Redraws text and recalculates associated state. */
CC_NOINLINE void InputWidget_UpdateText(struct InputWidget* w);
struct MenuInputDesc; struct MenuInputDesc;
@ -185,7 +189,8 @@ struct ChatInputWidget {
char _origBuffer[INPUTWIDGET_MAX_LINES * INPUTWIDGET_LEN]; char _origBuffer[INPUTWIDGET_MAX_LINES * INPUTWIDGET_LEN];
}; };
CC_NOINLINE void ChatInputWidget_Create(struct ChatInputWidget* w, FontDesc* font); CC_NOINLINE void ChatInputWidget_Create(struct ChatInputWidget* w);
CC_NOINLINE void ChatInputWidget_SetFont(struct ChatInputWidget* w, FontDesc* font);
/* Retrieves the text for the i'th line in the group */ /* Retrieves the text for the i'th line in the group */
@ -198,17 +203,16 @@ struct TextGroupWidget {
Widget_Layout Widget_Layout
int lines, defaultHeight; int lines, defaultHeight;
FontDesc* font; FontDesc* font;
bool placeholderHeight[TEXTGROUPWIDGET_MAX_LINES]; /* Whether a line has zero height when that line has no text in it. */
bool collapsible[TEXTGROUPWIDGET_MAX_LINES];
bool underlineUrls; bool underlineUrls;
struct Texture* textures; struct Texture* textures;
TextGroupWidget_Get GetLine; TextGroupWidget_Get GetLine;
void* getLineObj; void* getLineObj;
}; };
CC_NOINLINE void TextGroupWidget_Create(struct TextGroupWidget* w, int lines, FontDesc* font, struct Texture* textures, TextGroupWidget_Get getLine); CC_NOINLINE void TextGroupWidget_Create(struct TextGroupWidget* w, int lines, struct Texture* textures, TextGroupWidget_Get getLine);
/* Sets whether the given line has non-zero height when that line has no text in it. */ CC_NOINLINE void TextGroupWidget_SetFont(struct TextGroupWidget* w, FontDesc* font);
/* By default, all lines are placeholder lines. */
CC_NOINLINE void TextGroupWidget_SetUsePlaceHolder(struct TextGroupWidget* w, int index, bool placeHolder);
/* Deletes first line, then moves all other lines upwards, then redraws last line. */ /* Deletes first line, then moves all other lines upwards, then redraws last line. */
/* NOTE: GetLine must also adjust the lines it returns for this to behave properly. */ /* NOTE: GetLine must also adjust the lines it returns for this to behave properly. */
CC_NOINLINE void TextGroupWidget_ShiftUp(struct TextGroupWidget* w); CC_NOINLINE void TextGroupWidget_ShiftUp(struct TextGroupWidget* w);
@ -246,8 +250,7 @@ CC_NOINLINE void PlayerListWidget_GetNameUnder(struct PlayerListWidget* w, int m
typedef void (*SpecialInputAppendFunc)(void* userData, char c); typedef void (*SpecialInputAppendFunc)(void* userData, char c);
struct SpecialInputTab { struct SpecialInputTab {
int itemsPerRow, charsPerItem; int itemsPerRow, charsPerItem, titleWidth;
Size2D titleSize;
String title, contents; String title, contents;
}; };
@ -259,12 +262,14 @@ struct SpecialInputWidget {
struct InputWidget* target; struct InputWidget* target;
struct Texture tex; struct Texture tex;
FontDesc* font; FontDesc* font;
int titleHeight;
struct SpecialInputTab tabs[5]; struct SpecialInputTab tabs[5];
String colString; String colString;
char _colBuffer[DRAWER2D_MAX_COLS * 4]; char _colBuffer[DRAWER2D_MAX_COLS * 4];
}; };
CC_NOINLINE void SpecialInputWidget_Create(struct SpecialInputWidget* w, FontDesc* font, struct InputWidget* target); CC_NOINLINE void SpecialInputWidget_Create(struct SpecialInputWidget* w, FontDesc* font, struct InputWidget* target);
CC_NOINLINE void SpecialInputWidget_Redraw(struct SpecialInputWidget* w);
CC_NOINLINE void SpecialInputWidget_UpdateCols(struct SpecialInputWidget* w); CC_NOINLINE void SpecialInputWidget_UpdateCols(struct SpecialInputWidget* w);
CC_NOINLINE void SpecialInputWidget_SetActive(struct SpecialInputWidget* w, bool active); CC_NOINLINE void SpecialInputWidget_SetActive(struct SpecialInputWidget* w, bool active);
#endif #endif