diff --git a/ClassicalSharp/2D/Screens/Overlays/TexIdsOverlay.cs b/ClassicalSharp/2D/Screens/Overlays/TexIdsOverlay.cs index d0e1bec21..5cb2facd4 100644 --- a/ClassicalSharp/2D/Screens/Overlays/TexIdsOverlay.cs +++ b/ClassicalSharp/2D/Screens/Overlays/TexIdsOverlay.cs @@ -15,6 +15,7 @@ namespace ClassicalSharp.Gui.Screens { const int verticesCount = TerrainAtlas2D.TilesPerRow * TerrainAtlas2D.RowsCount * 4; static VertexP3fT2fC4b[] vertices; int dynamicVb; + int xOffset, yOffset, tileSize; public override void Init() { textFont = new Font(game.FontName, 8); @@ -24,15 +25,6 @@ namespace ClassicalSharp.Gui.Screens { } } - const int textOffset = 3; - int xOffset, yOffset, tileSize; - - void UpdateTileSize() { - tileSize = game.window.Height / TerrainAtlas2D.RowsCount; - tileSize = (tileSize / 8) * 8; - Utils.Clamp(ref tileSize, 8, 40); - } - public override void Render(double delta) { RenderMenuBounds(); game.Graphics.Texturing = true; @@ -54,9 +46,12 @@ namespace ClassicalSharp.Gui.Screens { idAtlas = new TextAtlas(game, 16); idAtlas.Pack("0123456789", textFont, "f"); - UpdateTileSize(); - xOffset = (game.Width / 2) - (tileSize * TerrainAtlas2D.TilesPerRow) / 2; - yOffset = (game.Height / 2) - (tileSize * TerrainAtlas2D.RowsCount) / 2; + tileSize = game.Height / TerrainAtlas2D.RowsCount; + tileSize = (tileSize / 8) * 8; + Utils.Clamp(ref tileSize, 8, 40); + + xOffset = CalcPos(Anchor.Centre, 0, tileSize * TerrainAtlas2D.TilesPerRow, game.Width); + yOffset = CalcPos(Anchor.Centre, 0, tileSize * TerrainAtlas2D.RowsCount, game.Height); widgets[0] = TextWidget.Create(game, "Texture ID reference sheet", titleFont) .SetLocation(Anchor.Centre, Anchor.Min, 0, yOffset - 30); @@ -83,6 +78,7 @@ namespace ClassicalSharp.Gui.Screens { } } + const int textOffset = 3; void RenderTextOverlay() { int index = 0; idAtlas.tex.Y = (short)(yOffset + (tileSize - idAtlas.tex.Height)); diff --git a/ClassicalSharp/2D/Utils/TextAtlas.cs b/ClassicalSharp/2D/Utils/TextAtlas.cs index 39849c546..0b411d3e4 100644 --- a/ClassicalSharp/2D/Utils/TextAtlas.cs +++ b/ClassicalSharp/2D/Utils/TextAtlas.cs @@ -24,7 +24,7 @@ namespace ClassicalSharp { args.Text = prefix; Size size = game.Drawer2D.MeasureSize(ref args); offset = size.Width; - size.Width += 16 * chars.Length; + size.Width += fontSize * chars.Length; using (Bitmap bmp = IDrawer2D.CreatePow2Bitmap(size)) { drawer.SetBitmap(bmp); diff --git a/src/Client/Game.c b/src/Client/Game.c index 7ef7429b4..ab5d4d5d5 100644 --- a/src/Client/Game.c +++ b/src/Client/Game.c @@ -775,8 +775,9 @@ DateTime DateTime_FromTotalMs(Int64 ms) { DateTime time; return time; } void Gfx_MakeApiInfo(void) { } void AdvLightingBuilder_SetActive(void) { } -Screen* UrlWarningOverlay_MakeInstance(STRING_PURE String* url) { return NULL; } -Screen* TexIdsOverlay_MakeInstance(void) { return NULL; } -Screen* TexPackOverlay_MakeInstance(STRING_PURE String* url) { return NULL; } /* TODO: Real function is already in Gui.c - this is just stubbed until Overlays are implemented */ -/* remember to fix it in ServerConnection.c*/ \ No newline at end of file +/* remember to fix it in ServerConnection.c*/ +Screen* TexPackOverlay_MakeInstance(STRING_PURE String* url) { return NULL; } +/* TODO: Initalise Shell, see https://msdn.microsoft.com/en-us/library/windows/desktop/bb762153(v=vs.85).aspx +https://stackoverflow.com/questions/24590059/c-opening-a-url-in-default-browser-on-windows-without-admin-privileges */ +ReturnCode Platform_StartShell(STRING_PURE String* args) { return 0; } \ No newline at end of file diff --git a/src/Client/Menus.c b/src/Client/Menus.c index 272c86d18..dc76eb242 100644 --- a/src/Client/Menus.c +++ b/src/Client/Menus.c @@ -26,6 +26,7 @@ #include "MapRenderer.h" #include "TexturePack.h" #include "Audio.h" +#include "Screens.h" #define LIST_SCREEN_ITEMS 5 #define LIST_SCREEN_BUTTONS (LIST_SCREEN_ITEMS + 3) @@ -128,6 +129,21 @@ typedef struct MenuOptionsScreen_ { UInt8 ExtHelp_Buffer[String_BufferSize(MENUOPTIONS_MAX_DESC * TEXTGROUPWIDGET_LEN)]; } MenuOptionsScreen; +typedef struct TexIdsOverlay_ { + MenuScreen_Layout + GfxResourceID DynamicVb; + Int32 XOffset, YOffset, TileSize; + TextAtlas IdAtlas; + TextWidget Title; +} TexIdsOverlay; + +typedef struct UrlWarningOverlay_ { + MenuScreen_Layout + TextWidget Labels[4]; + ButtonWidget Buttons[2]; + UInt8 UrlBuffer[String_BufferSize(STRING_SIZE * 4)]; +} UrlWarningOverlay; + /*########################################################################################################################* *--------------------------------------------------------Menu base--------------------------------------------------------* @@ -2939,7 +2955,8 @@ Screen* NostalgiaScreen_MakeInstance(void) { void Overlay_Init(GuiElement* elem) { MenuScreen_Init(elem); if (Gfx_LostContext) return; - ContextRecreated(); + MenuScreen* screen = (MenuScreen*)elem; + screen->ContextRecreated(elem); } bool Overlay_HandlesKeyDown(Key key) { return true; } @@ -2967,3 +2984,198 @@ void Overlay_MakeLabels(MenuScreen* screen, TextWidget* labels, STRING_PURE Stri } } + +/*########################################################################################################################* +*------------------------------------------------------TexIdsOverlay------------------------------------------------------* +*#########################################################################################################################*/ +#define TEXID_OVERLAY_VERTICES_COUNT (ATLAS2D_ELEMENTS_PER_ROW * ATLAS2D_ROWS_COUNT * 4) +GuiElementVTABLE TexIdsOverlay_VTABLE; +TexIdsOverlay TexIdsOverlay_Instance; +void TexIdsOverlay_ContextLost(void* obj) { + TexIdsOverlay* screen = (TexIdsOverlay*)obj; + MenuScreen_ContextLost(obj); + Gfx_DeleteVb(&screen->DynamicVb); + TextAtlas_Free(&screen->IdAtlas); +} + +void TexIdsOverlay_ContextRecreated(void* obj) { + TexIdsOverlay* screen = (TexIdsOverlay*)obj; + screen->DynamicVb = Gfx_CreateDynamicVb(VERTEX_FORMAT_P3FT2FC4B, TEXID_OVERLAY_VERTICES_COUNT); + + String chars = String_FromConst("0123456789"); + String prefix = String_FromConst("f"); + TextAtlas_Make(&screen->IdAtlas, &chars, &screen->TextFont, &prefix); + + Int32 size = Game_Height / ATLAS2D_ROWS_COUNT; + size = (size / 8) * 8; + Math_Clamp(size, 8, 40); + + screen->XOffset = Gui_CalcPos(ANCHOR_CENTRE, 0, size * ATLAS2D_ELEMENTS_PER_ROW, Game_Width); + screen->YOffset = Gui_CalcPos(ANCHOR_CENTRE, 0, size * ATLAS2D_ROWS_COUNT, Game_Height); + screen->TileSize = size; + + String title = String_FromConst("Texture ID reference sheet"); + TextWidget_Create(&screen->Title, &title, &screen->TitleFont); + screen->Widgets[0] = (Widget*)(&screen->Title); + Widget_SetLocation(screen->Widgets[0], ANCHOR_CENTRE, ANCHOR_CENTRE, 0, screen->YOffset - 30); +} + +void TexIdsOverlay_RenderTerrain(TexIdsOverlay* screen) { + VertexP3fT2fC4b vertices[TEXID_OVERLAY_VERTICES_COUNT]; + Int32 elemsPerAtlas = Atlas1D_ElementsPerAtlas, i; + for (i = 0; i < ATLAS2D_ELEMENTS_PER_ROW * ATLAS2D_ROWS_COUNT;) { + VertexP3fT2fC4b* ptr = vertices; + Int32 j, ignored, size = screen->TileSize; + + for (j = 0; j < elemsPerAtlas; j++) { + TextureRec rec = Atlas1D_TexRec(i + j, 1, &ignored); + Int32 x = (i + j) % ATLAS2D_ELEMENTS_PER_ROW; + Int32 y = (i + j) / ATLAS2D_ELEMENTS_PER_ROW; + + Texture tex = Texture_FromRec(NULL, screen->XOffset + x * size, + screen->YOffset + y * size, size, size, rec); + PackedCol col = PACKEDCOL_WHITE; + GfxCommon_Make2DQuad(&tex, col, &ptr); + } + + Gfx_BindTexture(Atlas1D_TexIds[i / elemsPerAtlas]); + i += elemsPerAtlas; + Int32 count = (Int32)(ptr - vertices); + GfxCommon_UpdateDynamicVb_IndexedTris(screen->DynamicVb, vertices, count); + } +} + +void TexIdsOverlay_RenderTextOverlay(TexIdsOverlay* screen) { + Int32 x, y, size = screen->TileSize; + VertexP3fT2fC4b vertices[TEXID_OVERLAY_VERTICES_COUNT]; + VertexP3fT2fC4b* ptr = vertices; + + TextAtlas* idAtlas = &screen->IdAtlas; + idAtlas->Tex.Y = (screen->YOffset + (size - idAtlas->Tex.Height)); + for (y = 0; y < ATLAS2D_ROWS_COUNT; y++) { + for (x = 0; x < ATLAS2D_ELEMENTS_PER_ROW; x++) { + idAtlas->CurX = screen->XOffset + size * x + 3; /* offset text by 3 pixels */ + Int32 id = x + y * ATLAS2D_ELEMENTS_PER_ROW; + TextAtlas_AddInt(idAtlas, id, &ptr); + } + idAtlas->Tex.Y += size; + + if ((y % 4) != 3) continue; + Gfx_BindTexture(idAtlas->Tex.ID); + Int32 count = (Int32)(ptr - vertices); + GfxCommon_UpdateDynamicVb_IndexedTris(screen->DynamicVb, vertices, count); + ptr = vertices; + } +} + +void TexIdsOverlay_Init(GuiElement* elem) { + MenuScreen* screen = (MenuScreen*)elem; + Platform_MakeFont(&screen->TextFont, &Game_FontName, 8, FONT_STYLE_NORMAL); + Overlay_Init(elem); +} + +void TexIdsOverlay_Render(GuiElement* elem, Real64 delta) { + TexIdsOverlay* screen = (TexIdsOverlay*)elem; + Menu_RenderBounds(); + Gfx_SetTexturing(true); + Gfx_SetBatchFormat(VERTEX_FORMAT_P3FT2FC4B); + Menu_RenderWidgets(screen->Widgets, screen->WidgetsCount, delta); + TexIdsOverlay_RenderTerrain(screen); + TexIdsOverlay_RenderTextOverlay(screen); + Gfx_SetTexturing(false); +} + +bool TexIdsOverlay_HandlesKeyDown(GuiElement* elem, Key key) { + if (key == KeyBind_Get(KeyBind_IDOverlay) || key == KeyBind_Get(KeyBind_PauseOrExit)) { + Overlay_Close(elem); + return true; + } + Screen* screen = Gui_GetUnderlyingScreen(); + return Elem_HandlesKeyDown(screen, key); +} + +bool TexIdsOverlay_HandlesKeyPress(GuiElement* elem, UInt8 key) { + Screen* screen = Gui_GetUnderlyingScreen(); + return Elem_HandlesKeyPress(screen, key); +} + +bool TexIdsOverlay_HandlesKeyUp(GuiElement* elem, Key key) { + Screen* screen = Gui_GetUnderlyingScreen(); + return Elem_HandlesKeyUp(screen, key); +} + +Screen* TexIdsOverlay_MakeInstance(void) { + static Widget* widgets[1]; + TexIdsOverlay* screen = &TexIdsOverlay_Instance; + MenuScreen_MakeInstance((MenuScreen*)screen, widgets, + Array_Elems(widgets), TexIdsOverlay_ContextRecreated); + screen->ContextLost = TexIdsOverlay_ContextLost; + + TexIdsOverlay_VTABLE = *screen->VTABLE; + screen->VTABLE = &TexIdsOverlay_VTABLE; + + screen->VTABLE->Init = TexIdsOverlay_Init; + screen->VTABLE->Render = TexIdsOverlay_Render; + screen->VTABLE->HandlesKeyDown = TexIdsOverlay_HandlesKeyDown; + screen->VTABLE->HandlesKeyPress = TexIdsOverlay_HandlesKeyPress; + screen->VTABLE->HandlesKeyUp = TexIdsOverlay_HandlesKeyUp; + return (Screen*)screen; +} + + +/*########################################################################################################################* +*----------------------------------------------------UrlWarningOverlay----------------------------------------------------* +*#########################################################################################################################*/ +GuiElementVTABLE UrlWarningOverlay_VTABLE; +UrlWarningOverlay UrlWarningOverlay_Instance; +void UrlWarningOverlay_OpenUrl(GuiElement* screenElem, GuiElement* widget) { + Overlay_Close(screenElem); + UrlWarningOverlay* screen = (UrlWarningOverlay*)screenElem; + String url = String_FromRawArray(screen->UrlBuffer); + Platform_StartShell(&url); +} + +void UrlWarningOverlay_AppendUrl(GuiElement* screenElem, GuiElement* widget) { + Overlay_Close(screenElem); + if (Game_ClickableChat) { + UrlWarningOverlay* screen = (UrlWarningOverlay*)screenElem; + String url = String_FromRawArray(screen->UrlBuffer); + HUDScreen_AppendInput(Gui_HUD, &url); + } +} + +void UrlWarningOverlay_ContextRecreated(void* obj) { + UrlWarningOverlay* screen = (UrlWarningOverlay*)obj; + String lines[4]; + lines[0] = String_FromReadonly("&eAre you sure you want to open this link?"); + lines[1] = String_FromRawArray(screen->UrlBuffer); + lines[2] = String_FromReadonly("Be careful - links from strangers may be websites that"); + lines[3] = String_FromReadonly(" have viruses, or things you may not want to open/see."); + Overlay_MakeLabels((MenuScreen*)screen, screen->Labels, lines); + + String yes = String_FromConst("Yes"); + ButtonWidget_Create(&screen->Buttons[0], 160, &yes, &screen->TitleFont, UrlWarningOverlay_OpenUrl); + screen->Widgets[4] = (Widget*)(&screen->Buttons[0]); + Widget_SetLocation(screen->Widgets[4], ANCHOR_CENTRE, ANCHOR_CENTRE, -110, 30); + + String no = String_FromConst("No"); + ButtonWidget_Create(&screen->Buttons[1], 160, &no, &screen->TitleFont, UrlWarningOverlay_AppendUrl); + screen->Widgets[5] = (Widget*)(&screen->Buttons[1]); + Widget_SetLocation(screen->Widgets[5], ANCHOR_CENTRE, ANCHOR_CENTRE, 110, 30); +} + +Screen* UrlWarningOverlay_MakeInstance(STRING_PURE String* url) { + static Widget* widgets[6]; + UrlWarningOverlay* screen = &UrlWarningOverlay_Instance; + MenuScreen_MakeInstance((MenuScreen*)screen, widgets, + Array_Elems(widgets), UrlWarningOverlay_ContextRecreated); + + String dstUrl = String_InitAndClearArray(screen->UrlBuffer); + String_Set(&dstUrl, url); + UrlWarningOverlay_VTABLE = *screen->VTABLE; + screen->VTABLE = &UrlWarningOverlay_VTABLE; + + screen->VTABLE->Init = Overlay_Init; + screen->VTABLE->HandlesKeyDown = Overlay_HandlesKeyDown; + return (Screen*)screen; +} \ No newline at end of file diff --git a/src/Client/Platform.h b/src/Client/Platform.h index e497332c9..3b1993a73 100644 --- a/src/Client/Platform.h +++ b/src/Client/Platform.h @@ -72,6 +72,7 @@ void Platform_EventWait(void* handle); typedef Int64 Stopwatch; void Stopwatch_Start(Stopwatch* timer); Int32 Stopwatch_ElapsedMicroseconds(Stopwatch* timer); +ReturnCode Platform_StartShell(STRING_PURE String* args); void Platform_MakeFont(FontDesc* desc, STRING_PURE String* fontName, UInt16 size, UInt16 style); void Platform_FreeFont(FontDesc* desc);