diff --git a/Minecraft.Client/CrossPlatform/NkBrowseMenus.cpp b/Minecraft.Client/CrossPlatform/NkBrowseMenus.cpp index c415d8e..0c290bf 100644 --- a/Minecraft.Client/CrossPlatform/NkBrowseMenus.cpp +++ b/Minecraft.Client/CrossPlatform/NkBrowseMenus.cpp @@ -193,6 +193,10 @@ bool initBrowseMenuTextures(BrowseMenuTextures &out) out.tabBarSelected = loadBrowseSlot("../Assets/ui/skinHDGraphics/98_SkinSelect_TabBar_Selected.png"); out.charBg = loadBrowseSlot("../Assets/ui/skinHDGraphics/83_CharacterBackground.png"); out.charBgSmall = loadBrowseSlot("../Assets/ui/skinHDGraphics/84_CharacterBackground_Small.png"); + out.layoutBtnNorm = loadBrowseSlot("../Assets/ui/skinHDGraphics/188_Layout_Button_Bmp.png"); + out.layoutBtnOver = loadBrowseSlot("../Assets/ui/skinHDGraphics/186_LayoutButton_Over.png"); + out.layoutBtnOutline = loadBrowseSlot("../Assets/ui/skinHDGraphics/187_LayoutButton_Outline.png"); + out.controllerGraphic = loadBrowseSlot("../Assets/ui/skinHDWin/65.png"); out.skinBottomBar = loadBrowseSlot("../Assets/ui/skinHDGraphics/79_SkinSelect_BottomBar.png"); out.skinBottomBarSelected = loadBrowseSlot("../Assets/ui/skinHDGraphics/80_SkinSelect_BottomBar_Selected.png"); out.padlock = loadBrowseSlot("../Assets/ui/skinHDGraphics/162_Padlock_Small.png"); diff --git a/Minecraft.Client/CrossPlatform/NkBrowseMenus.h b/Minecraft.Client/CrossPlatform/NkBrowseMenus.h index bccdc98..98c26b9 100644 --- a/Minecraft.Client/CrossPlatform/NkBrowseMenus.h +++ b/Minecraft.Client/CrossPlatform/NkBrowseMenus.h @@ -18,6 +18,10 @@ struct BrowseMenuTextures { MenuTextureSlot tabBarSelected; MenuTextureSlot charBg; MenuTextureSlot charBgSmall; + MenuTextureSlot layoutBtnNorm; + MenuTextureSlot layoutBtnOver; + MenuTextureSlot layoutBtnOutline; + MenuTextureSlot controllerGraphic; MenuTextureSlot skinBottomBar; MenuTextureSlot skinBottomBarSelected; MenuTextureSlot padlock; diff --git a/Minecraft.Client/CrossPlatform/NkBrowseMenus2.cpp b/Minecraft.Client/CrossPlatform/NkBrowseMenus2.cpp index 0327f0e..d64a131 100644 --- a/Minecraft.Client/CrossPlatform/NkBrowseMenus2.cpp +++ b/Minecraft.Client/CrossPlatform/NkBrowseMenus2.cpp @@ -1,3 +1,4 @@ +#include "stdafx.h" #define NK_INCLUDE_FIXED_TYPES #define NK_INCLUDE_STANDARD_IO #define NK_INCLUDE_STANDARD_VARARGS @@ -11,8 +12,10 @@ #include "NkCommon.h" #include "MenuScreens.h" #include "NuklearBridge.h" +#include "../MultiplayerLocalPlayer.h" #include #include +#include namespace lve { namespace ui { @@ -53,21 +56,37 @@ static const float DLC_PRICE_H = 30.0f; static const float DLC_DESC_Y = 530.0f; static const float DLC_DESC_H = 140.0f; -static const float CTRL_IMAGE_X = 290.0f; -static const float CTRL_IMAGE_Y = 160.0f; -static const float CTRL_IMAGE_W = 700.0f; -static const float CTRL_IMAGE_H = 400.0f; - -static const float CTRL_CHECKBOX_X = 40.0f; -static const float CTRL_CHECKBOX_Y = 580.0f; -static const float CTRL_CHECKBOX_W = 250.0f; -static const float CTRL_CHECKBOX_H = 30.0f; - -static const float CTRL_LAYOUT_X = 415.0f; -static const float CTRL_LAYOUT_Y = 120.0f; +static const float CTRL_SCHEME_PANEL_X = 400.0f; +static const float CTRL_SCHEME_PANEL_Y = 194.0f; +static const float CTRL_SCHEME_PANEL_W = 480.0f; +static const float CTRL_SCHEME_PANEL_H = 124.0f; +static const float CTRL_CURRENT_LAYOUT_X = 410.0f; +static const float CTRL_CURRENT_LAYOUT_Y = 206.0f; +static const float CTRL_CURRENT_LAYOUT_W = 460.0f; +static const float CTRL_CURRENT_LAYOUT_H = 22.0f; +static const float CTRL_LAYOUT_X = 420.0f; +static const float CTRL_LAYOUT_Y = 244.0f; static const float CTRL_LAYOUT_W = 140.0f; -static const float CTRL_LAYOUT_H = 36.0f; -static const float CTRL_LAYOUT_STEP = 8.0f; +static const float CTRL_LAYOUT_H = 40.0f; +static const float CTRL_LAYOUT_STEP = 150.0f; +static const float CTRL_INVERT_X = 420.0f; +static const float CTRL_INVERT_Y = 282.0f; +static const float CTRL_INVERT_W = 216.0f; +static const float CTRL_INVERT_H = 32.0f; +static const float CTRL_SOUTHPAW_X = 644.0f; +static const float CTRL_SOUTHPAW_Y = 282.0f; +static const float CTRL_SOUTHPAW_W = 215.0f; +static const float CTRL_SOUTHPAW_H = 32.0f; +static const float CTRL_IMAGE_X = 448.0f; +static const float CTRL_IMAGE_Y = 338.0f; +static const float CTRL_IMAGE_W = 400.0f; +static const float CTRL_IMAGE_H = 270.0f; +static const float CTRL_LEFT_RAIL_X = 430.0f; +static const float CTRL_RIGHT_RAIL_X = 850.0f; +static const float CTRL_RAIL_Y = 236.0f; +static const float CTRL_RAIL_H = 408.0f; +static const float CTRL_LABEL_W = 300.0f; +static const float CTRL_LABEL_H = 24.0f; static void drawShadowedText(nk_context *ctx, const char *text, float x, float y, float w, float h, @@ -92,6 +111,29 @@ static void drawShadowedText(nk_context *ctx, const char *text, nk_rgba(0, 0, 0, 0), color); } +static void drawShadowedTextRight(nk_context *ctx, const char *text, + float x, float y, float w, float h, + struct nk_color color) +{ + struct nk_command_buffer *canvas = nk_window_get_canvas(ctx); + if (canvas == nullptr) return; + + const struct nk_user_font *font = ctx->style.font; + if (font == nullptr) return; + + int len = (int)strlen(text); + float textW = font->width(font->userdata, font->height, text, len); + float textX = x + w - textW; + float textY = y + (h - font->height) * 0.5f; + + nk_draw_text(canvas, nk_rect(textX + SHADOW_OFF, textY + SHADOW_OFF, textW, font->height), + text, len, font, + nk_rgba(0, 0, 0, 0), nk_rgba(0x0F, 0x0F, 0x0F, 200)); + nk_draw_text(canvas, nk_rect(textX, textY, textW, font->height), + text, len, font, + nk_rgba(0, 0, 0, 0), color); +} + static void drawShadowedTitle(nk_context *ctx, const char *title, int winW, int winH) { struct nk_command_buffer *canvas = nk_window_get_canvas(ctx); @@ -152,6 +194,47 @@ static bool drawTabButton(nk_context *ctx, const char *label, return clicked; } +static void drawBoxPanel(nk_context *ctx, float x, float y, float w, float h) +{ + struct nk_command_buffer *canvas = nk_window_get_canvas(ctx); + if (canvas == nullptr) return; + + nk_fill_rect(canvas, nk_rect(x, y, w, h), 4.0f, nk_rgba(20, 20, 20, 180)); + nk_stroke_rect(canvas, nk_rect(x, y, w, h), 4.0f, 1.0f, nk_rgba(120, 120, 120, 180)); +} + +static bool drawLayoutButton(nk_context *ctx, const char *label, + float x, float y, float w, float h, + bool selected, BrowseMenuTextures &btex) +{ + struct nk_command_buffer *canvas = nk_window_get_canvas(ctx); + if (canvas == nullptr) return false; + + struct nk_rect r = nk_rect(x, y, w, h); + const struct nk_input *input = &ctx->input; + bool hovering = nk_input_is_mouse_hovering_rect(input, r) != 0; + bool highlighted = selected || hovering; + float scale = h / 40.0f; + + if (highlighted && btex.layoutBtnOutline.w > 0) { + struct nk_image outlineImg = slotToNkImage(btex.layoutBtnOutline); + nk_draw_image(canvas, + nk_rect(x - 2.0f * scale, y - 2.0f * scale, w + 4.0f * scale, h + 4.0f * scale), + &outlineImg, nk_rgba(255, 255, 255, selected ? 210 : 160)); + } + + if (btex.layoutBtnNorm.w > 0) { + const MenuTextureSlot &slot = (highlighted && btex.layoutBtnOver.w > 0) ? btex.layoutBtnOver : btex.layoutBtnNorm; + struct nk_image img = slotToNkImage(slot); + nk_draw_image(canvas, r, &img, nk_rgb(255, 255, 255)); + } else { + nk_fill_rect(canvas, r, 0, highlighted ? nk_rgb(92, 92, 140) : nk_rgb(80, 80, 80)); + } + + drawShadowedText(ctx, label, x, y, w, h, nk_rgb(255, 255, 255), true); + return hovering && nk_input_is_mouse_released(input, NK_BUTTON_LEFT) != 0; +} + static bool drawListRow(nk_context *ctx, const char *label, float x, float y, float w, float h, bool selected, bool hasTick, @@ -237,30 +320,203 @@ static bool drawCheckbox(nk_context *ctx, const char *label, return clicked; } +static int getControlsPad() +{ + int iPad = ProfileManager.GetPrimaryPad(); + return (iPad >= 0 && iPad < XUSER_MAX_COUNT) ? iPad : 0; +} + static const char *CTRL_SCHEME_LABELS[] = { "1", "2", "3" }; static const int CTRL_SCHEME_COUNT = 3; - -static const char *CTRL_SCHEME_NAMES[] = { - "Default", "Lefty", "Legacy" +static const int CTRL_SCHEME_TEXT_IDS[CTRL_SCHEME_COUNT] = { + IDS_CONTROLS_SCHEME0, + IDS_CONTROLS_SCHEME1, + IDS_CONTROLS_SCHEME2 }; -struct ControlBinding { - const char *label; - float x; - float y; +enum ControlsCalloutSlot { + kControlsCallout_Back = 0, + kControlsCallout_LT, + kControlsCallout_LB, + kControlsCallout_DPadLeft, + kControlsCallout_DPadRight, + kControlsCallout_DPadUp, + kControlsCallout_DPadDown, + kControlsCallout_LSButton, + kControlsCallout_LSStick, + kControlsCallout_Start, + kControlsCallout_RT, + kControlsCallout_RB, + kControlsCallout_Y, + kControlsCallout_B, + kControlsCallout_A, + kControlsCallout_X, + kControlsCallout_RSButton, + kControlsCallout_RSStick, + kControlsCallout_Count }; +struct ControlsCalloutLayout { + float anchorX; + float anchorY; + float railY; + float labelX; + bool alignRight; +}; + +struct ControlsCalloutState { + std::string text; +}; + +static const ControlsCalloutLayout CTRL_CALLOUT_LAYOUTS[kControlsCallout_Count] = { + {0.41f, 0.36f, 332.0f, 110.0f, true}, + {0.16f, 0.05f, 262.0f, 110.0f, true}, + {0.27f, 0.14f, 296.0f, 110.0f, true}, + {0.26f, 0.71f, 548.0f, 70.0f, true}, + {0.34f, 0.71f, 580.0f, 70.0f, true}, + {0.30f, 0.63f, 516.0f, 70.0f, true}, + {0.30f, 0.79f, 612.0f, 70.0f, true}, + {0.34f, 0.56f, 390.0f, 110.0f, true}, + {0.26f, 0.49f, 424.0f, 110.0f, true}, + {0.59f, 0.36f, 332.0f, 870.0f, false}, + {0.84f, 0.05f, 262.0f, 870.0f, false}, + {0.73f, 0.14f, 296.0f, 870.0f, false}, + {0.82f, 0.35f, 390.0f, 870.0f, false}, + {0.89f, 0.49f, 458.0f, 870.0f, false}, + {0.82f, 0.62f, 526.0f, 870.0f, false}, + {0.74f, 0.49f, 424.0f, 870.0f, false}, + {0.65f, 0.58f, 560.0f, 870.0f, false}, + {0.71f, 0.49f, 594.0f, 870.0f, false} +}; + +static void setControlCalloutText(ControlsCalloutState *states, ControlsCalloutSlot slot, int stringId) +{ + states[(int)slot].text = wideToUtf8(app.GetString(stringId)); +} + +static void addControlCallout(ControlsCalloutState *states, int layout, int stringId, unsigned char action) +{ + unsigned int input = InputManager.GetGameJoypadMaps((unsigned char)layout, action); + + if (input & _360_JOY_BUTTON_A) setControlCalloutText(states, kControlsCallout_A, stringId); + if (input & _360_JOY_BUTTON_B) setControlCalloutText(states, kControlsCallout_B, stringId); + if (input & _360_JOY_BUTTON_X) setControlCalloutText(states, kControlsCallout_X, stringId); + if (input & _360_JOY_BUTTON_Y) setControlCalloutText(states, kControlsCallout_Y, stringId); + if (input & _360_JOY_BUTTON_BACK) setControlCalloutText(states, kControlsCallout_Back, stringId); + if (input & _360_JOY_BUTTON_START) setControlCalloutText(states, kControlsCallout_Start, stringId); + if (input & _360_JOY_BUTTON_RB) setControlCalloutText(states, kControlsCallout_RB, stringId); + if (input & _360_JOY_BUTTON_LB) setControlCalloutText(states, kControlsCallout_LB, stringId); + if (input & _360_JOY_BUTTON_RTHUMB) setControlCalloutText(states, kControlsCallout_RSButton, stringId); + if (input & _360_JOY_BUTTON_LTHUMB) setControlCalloutText(states, kControlsCallout_LSButton, stringId); + if (input & _360_JOY_BUTTON_RSTICK_RIGHT) setControlCalloutText(states, kControlsCallout_RSStick, stringId); + if (input & _360_JOY_BUTTON_LSTICK_RIGHT) setControlCalloutText(states, kControlsCallout_LSStick, stringId); + if (input & _360_JOY_BUTTON_RT) setControlCalloutText(states, kControlsCallout_RT, stringId); + if (input & _360_JOY_BUTTON_LT) setControlCalloutText(states, kControlsCallout_LT, stringId); + if (input & _360_JOY_BUTTON_DPAD_RIGHT) setControlCalloutText(states, kControlsCallout_DPadRight, stringId); + if (input & _360_JOY_BUTTON_DPAD_LEFT) setControlCalloutText(states, kControlsCallout_DPadLeft, stringId); + if (input & _360_JOY_BUTTON_DPAD_UP) setControlCalloutText(states, kControlsCallout_DPadUp, stringId); + if (input & _360_JOY_BUTTON_DPAD_DOWN) setControlCalloutText(states, kControlsCallout_DPadDown, stringId); +} + +static void buildControlCallouts(ControlsCalloutState *states, int layout, bool creativeMode, bool southpaw) +{ + for (int i = 0; i < kControlsCallout_Count; ++i) { + states[i].text.clear(); + } + + addControlCallout(states, layout, creativeMode ? IDS_CONTROLS_JUMPFLY : IDS_CONTROLS_JUMP, MINECRAFT_ACTION_JUMP); + addControlCallout(states, layout, IDS_CONTROLS_INVENTORY, MINECRAFT_ACTION_INVENTORY); + addControlCallout(states, layout, IDS_CONTROLS_PAUSE, MINECRAFT_ACTION_PAUSEMENU); + addControlCallout(states, layout, creativeMode ? IDS_CONTROLS_SNEAKFLY : IDS_CONTROLS_SNEAK, MINECRAFT_ACTION_SNEAK_TOGGLE); + addControlCallout(states, layout, IDS_CONTROLS_USE, MINECRAFT_ACTION_USE); + addControlCallout(states, layout, IDS_CONTROLS_ACTION, MINECRAFT_ACTION_ACTION); + addControlCallout(states, layout, IDS_CONTROLS_HELDITEM, MINECRAFT_ACTION_RIGHT_SCROLL); + addControlCallout(states, layout, IDS_CONTROLS_HELDITEM, MINECRAFT_ACTION_LEFT_SCROLL); + addControlCallout(states, layout, IDS_CONTROLS_DROP, MINECRAFT_ACTION_DROP); + addControlCallout(states, layout, IDS_CONTROLS_CRAFTING, MINECRAFT_ACTION_CRAFTING); + addControlCallout(states, layout, IDS_CONTROLS_THIRDPERSON, MINECRAFT_ACTION_RENDER_THIRD_PERSON); + addControlCallout(states, layout, IDS_CONTROLS_PLAYERS, MINECRAFT_ACTION_GAME_INFO); + + if (southpaw) { + addControlCallout(states, layout, IDS_CONTROLS_LOOK, MINECRAFT_ACTION_RIGHT); + addControlCallout(states, layout, IDS_CONTROLS_MOVE, MINECRAFT_ACTION_LOOK_RIGHT); + } else { + addControlCallout(states, layout, IDS_CONTROLS_MOVE, MINECRAFT_ACTION_RIGHT); + addControlCallout(states, layout, IDS_CONTROLS_LOOK, MINECRAFT_ACTION_LOOK_RIGHT); + } + + if (creativeMode && layout == 0) { + addControlCallout(states, layout, IDS_CONTROLS_DPAD, MINECRAFT_ACTION_DPAD_LEFT); + } +} + +static void drawControlCallout(nk_context *ctx, struct nk_command_buffer *canvas, + const ControlsCalloutState &state, const ControlsCalloutLayout &layout, + float controllerX, float controllerY, float controllerW, float controllerH, + float scaleX, float scaleY) +{ + if (state.text.empty()) return; + + float railX = (layout.alignRight ? CTRL_LEFT_RAIL_X : CTRL_RIGHT_RAIL_X) * scaleX; + float railY = layout.railY * scaleY; + float anchorX = controllerX + layout.anchorX * controllerW; + float anchorY = controllerY + layout.anchorY * controllerH; + float labelX = layout.labelX * scaleX; + float labelY = (layout.railY - CTRL_LABEL_H * 0.5f) * scaleY; + float labelW = CTRL_LABEL_W * scaleX; + float labelH = CTRL_LABEL_H * scaleY; + float labelEdgeX = layout.alignRight ? (labelX + labelW - 6.0f * scaleX) : (labelX + 6.0f * scaleX); + float thickness = scaleY > 1.0f ? scaleY : 1.0f; + struct nk_color lineColor = nk_rgb(0xeb, 0xcc, 0x0f); + + nk_stroke_line(canvas, anchorX, anchorY, railX, railY, thickness, lineColor); + nk_stroke_line(canvas, railX, railY, labelEdgeX, railY, thickness, lineColor); + + if (layout.alignRight) { + drawShadowedTextRight(ctx, state.text.c_str(), labelX, labelY, labelW, labelH, nk_rgb(255, 255, 255)); + } else { + drawShadowedText(ctx, state.text.c_str(), labelX, labelY, labelW, labelH, nk_rgb(255, 255, 255), false); + } +} + void renderControlsMenu(nk_context *ctx, int winW, int winH, MenuTextures &tex, BrowseMenuTextures &btex) { - static int currentScheme = 0; - static bool invertLook = false; - static bool southpaw = false; + static ControlsCalloutState cachedCallouts[kControlsCallout_Count]; + static int cachedScheme = -1; + static bool cachedCreativeMode = false; + static bool cachedSouthpaw = false; float scaleX = (float)winW / BASE_W; float scaleY = (float)winH / BASE_H; + int iPad = getControlsPad(); + Minecraft *minecraft = Minecraft::GetInstance(); + bool notInGame = minecraft == nullptr || minecraft->level == nullptr; + bool creativeMode = !notInGame && minecraft->localplayers[iPad] != nullptr && + minecraft->localplayers[iPad]->abilities.mayfly; + + int currentScheme = app.GetGameSettings(iPad, eGameSetting_ControlScheme); + if (currentScheme < 0) currentScheme = 0; + if (currentScheme >= CTRL_SCHEME_COUNT) currentScheme = CTRL_SCHEME_COUNT - 1; + + bool invertLook = app.GetGameSettings(iPad, eGameSetting_ControlInvertLook) != 0; + bool southpaw = app.GetGameSettings(iPad, eGameSetting_ControlSouthPaw) != 0; + + if (cachedScheme != currentScheme || cachedCreativeMode != creativeMode || cachedSouthpaw != southpaw) { + buildControlCallouts(cachedCallouts, currentScheme, creativeMode, southpaw); + cachedScheme = currentScheme; + cachedCreativeMode = creativeMode; + cachedSouthpaw = southpaw; + } + + std::string title = wideToUtf8(app.GetString(IDS_CONTROLS)); + std::string currentLayoutLabel = wideToUtf8(app.GetString(IDS_CURRENT_LAYOUT)); + currentLayoutLabel += " : "; + currentLayoutLabel += wideToUtf8(app.GetString(CTRL_SCHEME_TEXT_IDS[currentScheme])); + std::string invertLookLabel = wideToUtf8(app.GetString(IDS_INVERT_LOOK)); + std::string southpawLabel = wideToUtf8(app.GetString(IDS_SOUTHPAW)); pushCleanStyle(ctx); @@ -268,84 +524,90 @@ void renderControlsMenu(nk_context *ctx, int winW, int winH, NK_WINDOW_NO_SCROLLBAR | NK_WINDOW_NO_INPUT | NK_WINDOW_BACKGROUND)) { drawPanoramaBg(ctx, winW, winH, tex); - drawShadowedTitle(ctx, "Controls", winW, winH); + drawShadowedTitle(ctx, title.c_str(), winW, winH); struct nk_command_buffer *canvas = nk_window_get_canvas(ctx); - const struct nk_input *input = &ctx->input; - - float layoutX = CTRL_LAYOUT_X * scaleX; - float layoutY = CTRL_LAYOUT_Y * scaleY; - float layoutW = CTRL_LAYOUT_W * scaleX; - float layoutH = CTRL_LAYOUT_H * scaleY; - - for (int i = 0; i < CTRL_SCHEME_COUNT; i++) { - float bx = layoutX + (float)i * (layoutW + CTRL_LAYOUT_STEP * scaleX); - bool selected = (currentScheme == i); - if (drawTabButton(ctx, CTRL_SCHEME_LABELS[i], bx, layoutY, layoutW, layoutH, selected, btex)) { - currentScheme = i; - } - } - - char currentLabel[128]; - snprintf(currentLabel, sizeof(currentLabel), "Current Layout : %s", CTRL_SCHEME_NAMES[currentScheme]); - float clY = layoutY + layoutH + 8.0f * scaleY; - drawShadowedText(ctx, currentLabel, 0, clY, (float)winW, 24.0f * scaleY, nk_rgb(255, 255, 200), true); - - float imgX = CTRL_IMAGE_X * scaleX; - float imgY = CTRL_IMAGE_Y * scaleY; - float imgW = CTRL_IMAGE_W * scaleX; - float imgH = CTRL_IMAGE_H * scaleY; - if (canvas != nullptr) { - nk_fill_rect(canvas, nk_rect(imgX, imgY, imgW, imgH), 0, nk_rgba(0, 0, 0, 100)); - } + float panelX = CTRL_SCHEME_PANEL_X * scaleX; + float panelY = CTRL_SCHEME_PANEL_Y * scaleY; + float panelW = CTRL_SCHEME_PANEL_W * scaleX; + float panelH = CTRL_SCHEME_PANEL_H * scaleY; + float layoutX = CTRL_LAYOUT_X * scaleX; + float layoutY = CTRL_LAYOUT_Y * scaleY; + float layoutW = CTRL_LAYOUT_W * scaleX; + float layoutH = CTRL_LAYOUT_H * scaleY; + float currentLayoutX = CTRL_CURRENT_LAYOUT_X * scaleX; + float currentLayoutY = CTRL_CURRENT_LAYOUT_Y * scaleY; + float currentLayoutW = CTRL_CURRENT_LAYOUT_W * scaleX; + float currentLayoutH = CTRL_CURRENT_LAYOUT_H * scaleY; + float controllerX = CTRL_IMAGE_X * scaleX; + float controllerY = CTRL_IMAGE_Y * scaleY; + float controllerW = CTRL_IMAGE_W * scaleX; + float controllerH = CTRL_IMAGE_H * scaleY; - ControlBinding bindings[] = { - { "Jump", 0.15f, 0.30f }, - { "Inventory", 0.15f, 0.45f }, - { "Sneak", 0.15f, 0.60f }, - { "Move", 0.15f, 0.75f }, - { "Use", 0.80f, 0.30f }, - { "Attack", 0.80f, 0.45f }, - { "Look", 0.80f, 0.60f }, - { "Held Item", 0.80f, 0.75f }, - }; - int bindingCount = 8; + drawBoxPanel(ctx, panelX, panelY, panelW, panelH); - if (southpaw) { - bindings[3].label = "Look"; - bindings[6].label = "Move"; - } + for (int i = 0; i < CTRL_SCHEME_COUNT; ++i) { + float buttonX = layoutX + (float)i * CTRL_LAYOUT_STEP * scaleX; + if (drawLayoutButton(ctx, CTRL_SCHEME_LABELS[i], buttonX, layoutY, layoutW, layoutH, + currentScheme == i, btex)) { + app.SetGameSettings(iPad, eGameSetting_ControlScheme, i); + currentScheme = i; + currentLayoutLabel = wideToUtf8(app.GetString(IDS_CURRENT_LAYOUT)); + currentLayoutLabel += " : "; + currentLayoutLabel += wideToUtf8(app.GetString(CTRL_SCHEME_TEXT_IDS[currentScheme])); + buildControlCallouts(cachedCallouts, currentScheme, creativeMode, southpaw); + cachedScheme = currentScheme; + } + } - const struct nk_user_font *font = ctx->style.font; - if (font != nullptr && canvas != nullptr) { - for (int i = 0; i < bindingCount; i++) { - float bx = imgX + bindings[i].x * imgW; - float by = imgY + bindings[i].y * imgH; - int len = (int)strlen(bindings[i].label); - float tw = font->width(font->userdata, font->height, bindings[i].label, len); - float tx = bx - tw * 0.5f; - nk_draw_text(canvas, nk_rect(tx + SHADOW_OFF, by + SHADOW_OFF, tw, font->height), - bindings[i].label, len, font, - nk_rgba(0, 0, 0, 0), nk_rgba(0x0F, 0x0F, 0x0F, 200)); - nk_draw_text(canvas, nk_rect(tx, by, tw, font->height), - bindings[i].label, len, font, - nk_rgba(0, 0, 0, 0), nk_rgb(255, 255, 255)); + drawShadowedText(ctx, currentLayoutLabel.c_str(), currentLayoutX, currentLayoutY, + currentLayoutW, currentLayoutH, nk_rgb(255, 255, 200), true); + + if (btex.controllerGraphic.w > 0) { + struct nk_image controllerImg = slotToNkImage(btex.controllerGraphic); + nk_draw_image(canvas, nk_rect(controllerX, controllerY, controllerW, controllerH), + &controllerImg, nk_rgb(255, 255, 255)); + } else { + drawBoxPanel(ctx, controllerX, controllerY, controllerW, controllerH); + } + + if (drawCheckbox(ctx, invertLookLabel.c_str(), + CTRL_INVERT_X * scaleX, CTRL_INVERT_Y * scaleY, + CTRL_INVERT_W * scaleX, CTRL_INVERT_H * scaleY, + invertLook, tex)) { + app.SetGameSettings(iPad, eGameSetting_ControlInvertLook, invertLook ? 0 : 1); + invertLook = !invertLook; + } + + if (drawCheckbox(ctx, southpawLabel.c_str(), + CTRL_SOUTHPAW_X * scaleX, CTRL_SOUTHPAW_Y * scaleY, + CTRL_SOUTHPAW_W * scaleX, CTRL_SOUTHPAW_H * scaleY, + southpaw, tex)) { + app.SetGameSettings(iPad, eGameSetting_ControlSouthPaw, southpaw ? 0 : 1); + southpaw = !southpaw; + buildControlCallouts(cachedCallouts, currentScheme, creativeMode, southpaw); + cachedSouthpaw = southpaw; + } + + float railW = scaleX > 1.0f ? scaleX : 1.0f; + nk_fill_rect(canvas, nk_rect(CTRL_LEFT_RAIL_X * scaleX, CTRL_RAIL_Y * scaleY, railW, CTRL_RAIL_H * scaleY), + 0, nk_rgba(15, 15, 15, 180)); + nk_fill_rect(canvas, nk_rect(CTRL_RIGHT_RAIL_X * scaleX, CTRL_RAIL_Y * scaleY, railW, CTRL_RAIL_H * scaleY), + 0, nk_rgba(15, 15, 15, 180)); + + for (int i = 0; i < kControlsCallout_Count; ++i) { + drawControlCallout(ctx, canvas, cachedCallouts[i], CTRL_CALLOUT_LAYOUTS[i], + controllerX, controllerY, controllerW, controllerH, scaleX, scaleY); + } + + if (notInGame) { + drawShadowedText(ctx, VER_PRODUCTVERSION_STR, + 93.0f * scaleX, 616.0f * scaleY, 238.0f * scaleX, 28.0f * scaleY, + nk_rgb(170, 170, 170), false); } } - float cbX = CTRL_CHECKBOX_X * scaleX; - float cbY = CTRL_CHECKBOX_Y * scaleY; - float cbW = CTRL_CHECKBOX_W * scaleX; - float cbH = CTRL_CHECKBOX_H * scaleY; - - if (drawCheckbox(ctx, "Invert Look", cbX, cbY, cbW, cbH, invertLook, tex)) - invertLook = !invertLook; - - float spY = cbY + cbH + 8.0f * scaleY; - if (drawCheckbox(ctx, "Southpaw", cbX, spY, cbW, cbH, southpaw, tex)) - southpaw = !southpaw; - drawControllerPrompts(ctx, winW, winH, tex); } nk_end(ctx); diff --git a/Minecraft.Client/CrossPlatform/PlatformStubs.cpp b/Minecraft.Client/CrossPlatform/PlatformStubs.cpp index 6397b60..c1e094e 100644 --- a/Minecraft.Client/CrossPlatform/PlatformStubs.cpp +++ b/Minecraft.Client/CrossPlatform/PlatformStubs.cpp @@ -10,20 +10,66 @@ extern "C" void AppleInput_HandleKey(int, int) {} C_4JInput InputManager; -void C_4JInput::Initialise(int iInputStateC, unsigned char ucMapC, unsigned char ucActionC, unsigned char ucMenuActionC) {} +static unsigned int g_stubJoypadMaps[8][256] = {}; +static unsigned char g_stubJoypadMapVals[XUSER_MAX_COUNT] = {}; +static unsigned int g_stubAxisMaps[XUSER_MAX_COUNT][4] = {}; +static unsigned int g_stubTriggerMaps[XUSER_MAX_COUNT][2] = {}; + +void C_4JInput::Initialise(int iInputStateC, unsigned char ucMapC, unsigned char ucActionC, unsigned char ucMenuActionC) +{ + for (int map = 0; map < 8; ++map) { + for (int action = 0; action < 256; ++action) { + g_stubJoypadMaps[map][action] = 0; + } + } + + for (int iPad = 0; iPad < XUSER_MAX_COUNT; ++iPad) { + g_stubJoypadMapVals[iPad] = 0; + g_stubAxisMaps[iPad][AXIS_MAP_LX] = AXIS_MAP_LX; + g_stubAxisMaps[iPad][AXIS_MAP_LY] = AXIS_MAP_LY; + g_stubAxisMaps[iPad][AXIS_MAP_RX] = AXIS_MAP_RX; + g_stubAxisMaps[iPad][AXIS_MAP_RY] = AXIS_MAP_RY; + g_stubTriggerMaps[iPad][TRIGGER_MAP_0] = TRIGGER_MAP_0; + g_stubTriggerMaps[iPad][TRIGGER_MAP_1] = TRIGGER_MAP_1; + } +} void C_4JInput::Tick(void) {} void C_4JInput::SetDeadzoneAndMovementRange(unsigned int uiDeadzone, unsigned int uiMovementRangeMax) {} -void C_4JInput::SetGameJoypadMaps(unsigned char ucMap, unsigned char ucAction, unsigned int uiActionVal) {} -unsigned int C_4JInput::GetGameJoypadMaps(unsigned char ucMap, unsigned char ucAction) { return 0; } -void C_4JInput::SetJoypadMapVal(int iPad, unsigned char ucMap) {} -unsigned char C_4JInput::GetJoypadMapVal(int iPad) { return 0; } +void C_4JInput::SetGameJoypadMaps(unsigned char ucMap, unsigned char ucAction, unsigned int uiActionVal) +{ + if (ucMap >= 8) return; + g_stubJoypadMaps[ucMap][ucAction] = uiActionVal; +} +unsigned int C_4JInput::GetGameJoypadMaps(unsigned char ucMap, unsigned char ucAction) +{ + if (ucMap >= 8) return 0; + return g_stubJoypadMaps[ucMap][ucAction]; +} +void C_4JInput::SetJoypadMapVal(int iPad, unsigned char ucMap) +{ + if (iPad < 0 || iPad >= XUSER_MAX_COUNT) return; + g_stubJoypadMapVals[iPad] = ucMap; +} +unsigned char C_4JInput::GetJoypadMapVal(int iPad) +{ + if (iPad < 0 || iPad >= XUSER_MAX_COUNT) return 0; + return g_stubJoypadMapVals[iPad]; +} void C_4JInput::SetJoypadSensitivity(int iPad, float fSensitivity) {} unsigned int C_4JInput::GetValue(int iPad, unsigned char ucAction, bool bRepeat) { return 0; } bool C_4JInput::ButtonPressed(int iPad, unsigned char ucAction) { return false; } bool C_4JInput::ButtonReleased(int iPad, unsigned char ucAction) { return false; } bool C_4JInput::ButtonDown(int iPad, unsigned char ucAction) { return false; } -void C_4JInput::SetJoypadStickAxisMap(int iPad, unsigned int uiFrom, unsigned int uiTo) {} -void C_4JInput::SetJoypadStickTriggerMap(int iPad, unsigned int uiFrom, unsigned int uiTo) {} +void C_4JInput::SetJoypadStickAxisMap(int iPad, unsigned int uiFrom, unsigned int uiTo) +{ + if (iPad < 0 || iPad >= XUSER_MAX_COUNT || uiFrom >= 4) return; + g_stubAxisMaps[iPad][uiFrom] = uiTo; +} +void C_4JInput::SetJoypadStickTriggerMap(int iPad, unsigned int uiFrom, unsigned int uiTo) +{ + if (iPad < 0 || iPad >= XUSER_MAX_COUNT || uiFrom >= 2) return; + g_stubTriggerMaps[iPad][uiFrom] = uiTo; +} void C_4JInput::SetKeyRepeatRate(float fRepeatDelaySecs, float fRepeatRateSecs) {} void C_4JInput::SetDebugSequence(const char *chSequenceA, int (*Func)(LPVOID), LPVOID lpParam) {} FLOAT C_4JInput::GetIdleSeconds(int iPad) { return 0.0f; }