diff --git a/src/Entity.c b/src/Entity.c index ca91dc200..74880cceb 100644 --- a/src/Entity.c +++ b/src/Entity.c @@ -781,15 +781,18 @@ void LocalPlayer_SetInterpPosition(float t) { static void LocalPlayer_HandleInput(float* xMoving, float* zMoving) { struct LocalPlayer* p = &LocalPlayer_Instance; struct HacksComp* hacks = &p->Hacks; + struct LocalPlayerInput* input; if (Gui_GetInputGrab()) { - p->Physics.Jumping = false; hacks->Speeding = false; + p->Physics.Jumping = false; hacks->Speeding = false; hacks->FlyingUp = false; hacks->FlyingDown = false; } else { - if (KeyBind_IsPressed(KEYBIND_FORWARD)) *zMoving -= 0.98f; - if (KeyBind_IsPressed(KEYBIND_BACK)) *zMoving += 0.98f; - if (KeyBind_IsPressed(KEYBIND_LEFT)) *xMoving -= 0.98f; - if (KeyBind_IsPressed(KEYBIND_RIGHT)) *xMoving += 0.98f; + /* keyboard input, touch, joystick, etc */ + for (input = &p->input; input; input = input->next) { + input->GetMovement(xMoving, zMoving); + } + *xMoving *= 0.98f; + *zMoving *= 0.98f; p->Physics.Jumping = KeyBind_IsPressed(KEYBIND_JUMP); hacks->Speeding = hacks->Enabled && KeyBind_IsPressed(KEYBIND_SPEED); @@ -802,7 +805,7 @@ static void LocalPlayer_HandleInput(float* xMoving, float* zMoving) { /* need a { } block because it's a macro */ Vec3_Set(p->Base.Velocity, 0,0,0); } - hacks->Noclip = KeyBind_IsPressed(KEYBIND_NOCLIP); + HacksComp_SetNoclip(hacks, KeyBind_IsPressed(KEYBIND_NOCLIP)); } } } @@ -870,6 +873,13 @@ static void LocalPlayer_CheckJumpVelocity(void* obj) { } } +static void LocalPlayer_GetMovement(float* xMoving, float* zMoving) { + if (KeyBind_IsPressed(KEYBIND_FORWARD)) *zMoving -= 1; + if (KeyBind_IsPressed(KEYBIND_BACK)) *zMoving += 1; + if (KeyBind_IsPressed(KEYBIND_LEFT)) *xMoving -= 1; + if (KeyBind_IsPressed(KEYBIND_RIGHT)) *xMoving += 1; +} + static const struct EntityVTABLE localPlayer_VTABLE = { LocalPlayer_Tick, Player_Despawn, LocalPlayer_SetLocation, Entity_GetCol, LocalPlayer_RenderModel, LocalPlayer_RenderName @@ -883,6 +893,7 @@ static void LocalPlayer_Init(void) { Entity_SetSkin(&p->Base, &Game_Username); Event_Register_(&UserEvents.HackPermissionsChanged, NULL, LocalPlayer_CheckJumpVelocity); + p->input.GetMovement = LocalPlayer_GetMovement; p->Collisions.Entity = &p->Base; HacksComp_Init(hacks); PhysicsComp_Init(&p->Physics, &p->Base); @@ -900,9 +911,9 @@ static void LocalPlayer_Init(void) { hacks->SpeedMultiplier = Options_GetFloat(OPT_SPEED_FACTOR, 0.1f, 50.0f, 10.0f); hacks->PushbackPlacing = Options_GetBool(OPT_PUSHBACK_PLACING, false); - hacks->NoclipSlide = Options_GetBool(OPT_NOCLIP_SLIDE, false); - hacks->WOMStyleHacks = Options_GetBool(OPT_WOM_STYLE_HACKS, false); - hacks->FullBlockStep = Options_GetBool(OPT_FULL_BLOCK_STEP, false); + hacks->NoclipSlide = Options_GetBool(OPT_NOCLIP_SLIDE, false); + hacks->WOMStyleHacks = Options_GetBool(OPT_WOM_STYLE_HACKS, false); + hacks->FullBlockStep = Options_GetBool(OPT_FULL_BLOCK_STEP, false); p->Physics.UserJumpVel = Options_GetFloat(OPT_JUMP_VELOCITY, 0.0f, 52.0f, 0.42f); p->Physics.JumpVel = p->Physics.UserJumpVel; hackPermMsgs = Options_GetBool(OPT_HACK_PERM_MSGS, true); @@ -1015,7 +1026,7 @@ static cc_bool LocalPlayer_HandleSetSpawn(void) { static cc_bool LocalPlayer_HandleFly(void) { struct LocalPlayer* p = &LocalPlayer_Instance; if (p->Hacks.CanFly && p->Hacks.Enabled) { - p->Hacks.Flying = !p->Hacks.Flying; + HacksComp_SetFlying(&p->Hacks, !p->Hacks.Flying); return true; } else if (!p->_warnedFly) { p->_warnedFly = true; @@ -1030,7 +1041,7 @@ static cc_bool LocalPlayer_HandleNoClip(void) { if (p->Hacks.WOMStyleHacks) return true; /* don't handle this here */ if (p->Hacks.Noclip) p->Base.Velocity.Y = 0; - p->Hacks.Noclip = !p->Hacks.Noclip; + HacksComp_SetNoclip(&p->Hacks, !p->Hacks.Noclip); return true; } else if (!p->_warnedNoclip) { p->_warnedNoclip = true; diff --git a/src/Entity.h b/src/Entity.h index 466546cd1..3cf2838fd 100644 --- a/src/Entity.h +++ b/src/Entity.h @@ -183,6 +183,12 @@ struct NetPlayer { CC_API void NetPlayer_Init(struct NetPlayer* player); extern struct NetPlayer NetPlayers_List[ENTITIES_SELF_ID]; +struct LocalPlayerInput; +struct LocalPlayerInput { + void (*GetMovement)(float* xMoving, float* zMoving); + struct LocalPlayerInput* next; +}; + /* Represents the user/player's own entity. */ struct LocalPlayer { struct Entity Base; @@ -194,6 +200,7 @@ struct LocalPlayer { struct CollisionsComp Collisions; struct PhysicsComp Physics; cc_bool _warnedRespawn, _warnedFly, _warnedNoclip, _warnedZoom; + struct LocalPlayerInput input; }; extern struct LocalPlayer LocalPlayer_Instance; diff --git a/src/EntityComponents.c b/src/EntityComponents.c index f5908bb20..5d1d557bc 100644 --- a/src/EntityComponents.c +++ b/src/EntityComponents.c @@ -243,10 +243,11 @@ void HacksComp_RecheckFlags(struct HacksComp* hacks) { void HacksComp_Update(struct HacksComp* hacks) { if (!hacks->CanFly || !hacks->Enabled) { - hacks->Flying = false; hacks->FlyingDown = false; hacks->FlyingUp = false; + HacksComp_SetFlying(hacks, false); + hacks->FlyingDown = false; hacks->FlyingUp = false; } if (!hacks->CanNoclip || !hacks->Enabled) { - hacks->Noclip = false; + HacksComp_SetNoclip(hacks, false); } if (!hacks->CanSpeed || !hacks->Enabled) { hacks->Speeding = false; hacks->HalfSpeeding = false; @@ -257,6 +258,18 @@ void HacksComp_Update(struct HacksComp* hacks) { Event_RaiseVoid(&UserEvents.HackPermissionsChanged); } +void HacksComp_SetFlying(struct HacksComp* hacks, cc_bool flying) { + if (hacks->Flying == flying) return; + hacks->Flying = flying; + Event_RaiseVoid(&UserEvents.HacksStateChanged); +} + +void HacksComp_SetNoclip(struct HacksComp* hacks, cc_bool noclip) { + if (hacks->Noclip == noclip) return; + hacks->Noclip = noclip; + Event_RaiseVoid(&UserEvents.HacksStateChanged); +} + /*########################################################################################################################* *--------------------------------------------------InterpolationComponent-------------------------------------------------* diff --git a/src/EntityComponents.h b/src/EntityComponents.h index aba81a161..868c0208c 100644 --- a/src/EntityComponents.h +++ b/src/EntityComponents.h @@ -72,6 +72,8 @@ void HacksComp_RecheckFlags(struct HacksComp* hacks); /* Updates state based on permissions (e.g. Flying set to false if CanFly is false) */ /* Raises UserEvents.HackPermissionsChanged */ void HacksComp_Update(struct HacksComp* hacks); +void HacksComp_SetFlying(struct HacksComp* hacks, cc_bool flying); +void HacksComp_SetNoclip(struct HacksComp* hacks, cc_bool noclip); /* Represents a position and orientation state */ struct InterpState { Vec3 Pos; float Pitch, Yaw, RotX, RotZ; }; diff --git a/src/Event.h b/src/Event.h index d42e33c36..e9a943e8a 100644 --- a/src/Event.h +++ b/src/Event.h @@ -135,6 +135,7 @@ CC_VAR extern struct _UserEventsList { struct Event_Block BlockChanged; /* User changes a block */ struct Event_Void HackPermissionsChanged; /* Hack permissions of the player changes */ struct Event_Void HeldBlockChanged; /* Held block in hotbar changes */ + struct Event_Void HacksStateChanged; /* Hack states changed (e.g. stops flying) */ } UserEvents; CC_VAR extern struct _BlockEventsList { diff --git a/src/ExtMath.c b/src/ExtMath.c index a4d3a60ec..894c48720 100644 --- a/src/ExtMath.c +++ b/src/ExtMath.c @@ -22,6 +22,7 @@ double Math_Exp(double x) { return exp(x); } float Math_SinF(float x) { return (float)Math_Sin(x); } float Math_CosF(float x) { return (float)Math_Cos(x); } +double Math_Atan2(double x, double y) { return atan2(y, x); } int Math_Floor(float value) { int valueI = (int)value; diff --git a/src/ExtMath.h b/src/ExtMath.h index d6afa7f5b..abc14c72c 100644 --- a/src/ExtMath.h +++ b/src/ExtMath.h @@ -32,6 +32,7 @@ CC_API double Math_Sin(double x); CC_API double Math_Cos(double x); float Math_SinF(float x); float Math_CosF(float x); +double Math_Atan2(double x, double y); /* Computes loge(x). Can also be used to approximate logy(x). */ /* e.g. for log3(x), use: Math_Log(x)/log(3) */ diff --git a/src/Gui.c b/src/Gui.c index 6429b36f6..7dddfd531 100644 --- a/src/Gui.c +++ b/src/Gui.c @@ -456,6 +456,8 @@ static void OnFileChanged(void* obj, struct Stream* stream, const cc_string* nam Game_UpdateTexture(&Gui.GuiClassicTex, stream, name, NULL); } else if (String_CaselessEqualsConst(name, "icons.png")) { Game_UpdateTexture(&Gui.IconsTex, stream, name, NULL); + } else if (String_CaselessEqualsConst(name, "touch.png")) { + Game_UpdateTexture(&Gui.TouchTex, stream, name, NULL); } } @@ -488,6 +490,7 @@ static void OnContextLost(void* obj) { Gfx_DeleteTexture(&Gui.GuiTex); Gfx_DeleteTexture(&Gui.GuiClassicTex); Gfx_DeleteTexture(&Gui.IconsTex); + Gfx_DeleteTexture(&Gui.TouchTex); } static void OnInit(void) { diff --git a/src/Gui.h b/src/Gui.h index fd6047a19..58903facb 100644 --- a/src/Gui.h +++ b/src/Gui.h @@ -41,7 +41,7 @@ CC_VAR extern struct _GuiData { /* Whether FPS counter (and other info) is shown in top left. */ cc_bool ShowFPS; float RawHotbarScale, RawChatScale, RawInventoryScale; - GfxResourceID GuiTex, GuiClassicTex, IconsTex; + GfxResourceID GuiTex, GuiClassicTex, IconsTex, TouchTex; } Gui; float Gui_Scale(float value); diff --git a/src/Screens.c b/src/Screens.c index 6f2ae4984..9885fcc4b 100644 --- a/src/Screens.c +++ b/src/Screens.c @@ -63,7 +63,7 @@ static struct HUDScreen { struct TextAtlas posAtlas; double accumulator; int frames, fps; - cc_bool speed, halfSpeed, noclip, fly, canSpeed; + cc_bool speed, halfSpeed, canSpeed, hacksChanged; int lastFov; struct HotbarWidget hotbar; } HUDScreen_Instance; @@ -121,10 +121,10 @@ static void HUDScreen_DrawPosition(struct HUDScreen* s) { Gfx_UpdateDynamicVb_IndexedTris(Models.Vb, vertices, count); } -static cc_bool HUDScreen_HacksChanged(struct HUDScreen* s) { +static cc_bool HUDScreen_HasHacksChanged(struct HUDScreen* s) { struct HacksComp* hacks = &LocalPlayer_Instance.Hacks; - return hacks->Speeding != s->speed || hacks->HalfSpeeding != s->halfSpeed || hacks->Flying != s->fly - || hacks->Noclip != s->noclip || Game_Fov != s->lastFov || hacks->CanSpeed != s->canSpeed; + return hacks->Speeding != s->speed || hacks->HalfSpeeding != s->halfSpeed + || Game_Fov != s->lastFov || hacks->CanSpeed != s->canSpeed || s->hacksChanged; } static void HUDScreen_UpdateHackState(struct HUDScreen* s) { @@ -133,8 +133,9 @@ static void HUDScreen_UpdateHackState(struct HUDScreen* s) { cc_bool speeding; hacks = &LocalPlayer_Instance.Hacks; - s->speed = hacks->Speeding; s->halfSpeed = hacks->HalfSpeeding; s->fly = hacks->Flying; - s->noclip = hacks->Noclip; s->lastFov = Game_Fov; s->canSpeed = hacks->CanSpeed; + s->speed = hacks->Speeding; s->halfSpeed = hacks->HalfSpeeding; + s->lastFov = Game_Fov; s->canSpeed = hacks->CanSpeed; + s->hacksChanged = false; String_InitArray(status, statusBuffer); if (Game_Fov != Game_DefaultFov) { @@ -246,11 +247,16 @@ static int HUDscreen_PointerDown(void* screen, int id, int x, int y) { return false; } +static void HUDScreen_HacksChanged(void* obj) { + ((struct HUDScreen*)obj)->hacksChanged = true; +} + static void HUDScreen_Init(void* screen) { struct HUDScreen* s = (struct HUDScreen*)screen; HotbarWidget_Create(&s->hotbar); TextWidget_Init(&s->line1); TextWidget_Init(&s->line2); + Event_Register_(&UserEvents.HacksStateChanged, screen, HUDScreen_HacksChanged); } static void HUDScreen_Render(void* screen, double delta) { @@ -264,7 +270,7 @@ static void HUDScreen_Render(void* screen, double delta) { if (Game_ClassicMode) { Elem_Render(&s->line2, delta); } else if (IsOnlyChatActive() && Gui.ShowFPS) { - if (HUDScreen_HacksChanged(s)) { HUDScreen_UpdateHackState(s); } + if (HUDScreen_HasHacksChanged(s)) HUDScreen_UpdateHackState(s); HUDScreen_DrawPosition(s); Elem_Render(&s->line2, delta); } @@ -273,8 +279,12 @@ static void HUDScreen_Render(void* screen, double delta) { Gfx_SetTexturing(false); } +static void HUDScreen_Free(void* screen) { + Event_Unregister_(&UserEvents.HacksStateChanged, screen, HUDScreen_HacksChanged); +} + static const struct ScreenVTABLE HUDScreen_VTABLE = { - HUDScreen_Init, HUDScreen_Update, Screen_NullFunc, + HUDScreen_Init, HUDScreen_Update, HUDScreen_Free, HUDScreen_Render, HUDScreen_BuildMesh, HUDScreen_KeyDown, HUDScreen_KeyUp, Screen_FKeyPress, Screen_FText, HUDscreen_PointerDown, Screen_FPointer, Screen_FPointer, Screen_FMouseScroll, @@ -1876,35 +1886,78 @@ void DisconnectScreen_Show(const cc_string* title, const cc_string* message) { *--------------------------------------------------------TouchScreen------------------------------------------------------* *#########################################################################################################################*/ #ifdef CC_BUILD_TOUCH -static struct TouchScreen { - Screen_Body - cc_uint8 binds[7]; - struct FontDesc font; - struct ButtonWidget btns[7]; -} TouchScreen; - -static struct Widget* touch_widgets[7] = { - (struct Widget*)&TouchScreen.btns[0], (struct Widget*)&TouchScreen.btns[1], - (struct Widget*)&TouchScreen.btns[2], (struct Widget*)&TouchScreen.btns[3], - (struct Widget*)&TouchScreen.btns[4], (struct Widget*)&TouchScreen.btns[5], - (struct Widget*)&TouchScreen.btns[6], -}; -#define TOUCH_MAX_VERTICES (7 * BUTTONWIDGET_MAX) - -static const struct TouchBindDesc { +#define TOUCH_MAX_BTNS 4 +struct TouchBindDesc { const char* text; cc_uint8 bind, width; cc_int16 x, y; -} touchDescs[7] = { - { "<", KEYBIND_LEFT, 40, 10, 50 }, - { ">", KEYBIND_RIGHT, 40, 150, 50 }, - { "^", KEYBIND_FORWARD, 40, 80, 90 }, - { "\\/", KEYBIND_BACK, 40, 80, 10 }, - { "Jump", KEYBIND_JUMP, 100, 50, 90 }, - { "", KEYBIND_COUNT, 100, 50, 50 }, - { "More", KEYBIND_COUNT, 100, 50, 10 }, + Widget_LeftClick OnClick; }; +static struct TouchScreen { + Screen_Body + const struct TouchBindDesc* descs; + int numDescs; + struct FontDesc font; + struct ThumbstickWidget thumbstick; + struct ButtonWidget btns[TOUCH_MAX_BTNS]; +} TouchScreen; + +static struct Widget* touch_widgets[1 + TOUCH_MAX_BTNS] = { + (struct Widget*)&TouchScreen.thumbstick, (struct Widget*)&TouchScreen.btns[0], + (struct Widget*)&TouchScreen.btns[1], (struct Widget*)&TouchScreen.btns[2], + (struct Widget*)&TouchScreen.btns[3] +}; +#define TOUCH_MAX_VERTICES (THUMBSTICKWIDGET_MAX + TOUCH_MAX_BTNS * BUTTONWIDGET_MAX) + +static void TouchScreen_UpdateModeText(void* screen); +static void TouchScreen_ModeClick(void* s, void* w) { + Input_Placing = !Input_Placing; + TouchScreen_UpdateModeText(s); +} +static void TouchScreen_MoreClick(void* s, void* w) { TouchMoreScreen_Show(); } + +static const struct TouchBindDesc normDescs[3] = { + { "Jump", KEYBIND_JUMP, 100, 50, 90, NULL }, + { "", KEYBIND_COUNT, 100, 50, 50, TouchScreen_ModeClick }, + { "More", KEYBIND_COUNT, 100, 50, 10, TouchScreen_MoreClick }, +}; +static const struct TouchBindDesc hackDescs[4] = { + { "Up", KEYBIND_FLY_UP, 100, 50, 130, NULL }, + { "Down", KEYBIND_FLY_DOWN, 100, 50, 90, NULL }, + { "", KEYBIND_COUNT, 100, 50, 50, TouchScreen_ModeClick }, + { "More", KEYBIND_COUNT, 100, 50, 10, TouchScreen_MoreClick }, +}; + +static void TouchScreen_InitButtons(struct TouchScreen* s) { + struct HacksComp* hacks = &LocalPlayer_Instance.Hacks; + const struct TouchBindDesc* desc; + int i; + + if (hacks->Flying || hacks->Noclip) { + s->descs = hackDescs; + s->numDescs = Array_Elems(hackDescs); + } else { + s->descs = normDescs; + s->numDescs = Array_Elems(normDescs); + } + s->numWidgets = 1 + s->numDescs; + + for (i = 0; i < s->numDescs; i++) { + desc = &s->descs[i]; + ButtonWidget_Init(&s->btns[i], desc->width, desc->OnClick); + } +} + +static void TouchScreen_HacksChanged(void* screen) { + struct TouchScreen* s = (struct TouchScreen*)screen; + /* InitButtons changes number of widgets, hence */ + /* must destroy graphics resources BEFORE that */ + Screen_ContextLost(s); + TouchScreen_InitButtons(s); + Gui_Refresh((struct Screen*)s); +} + static void TouchScreen_ContextLost(void* screen) { struct TouchScreen* s = (struct TouchScreen*)screen; Font_Free(&s->font); @@ -1913,15 +1966,10 @@ static void TouchScreen_ContextLost(void* screen) { static void TouchScreen_UpdateModeText(void* screen) { struct TouchScreen* s = (struct TouchScreen*)screen; - ButtonWidget_SetConst(&s->btns[5], Input_Placing ? "Place" : "Delete", &s->font); + ButtonWidget_SetConst(&s->btns[s->numDescs - 2], + Input_Placing ? "Place" : "Delete", &s->font); } -static void TouchScreen_ModeClick(void* s, void* w) { - Input_Placing = !Input_Placing; - TouchScreen_UpdateModeText(s); -} -static void TouchScreen_MoreClick(void* s, void* w) { TouchMoreScreen_Show(); } - static void TouchScreen_ContextRecreated(void* screen) { struct TouchScreen* s = (struct TouchScreen*)screen; const struct TouchBindDesc* desc; @@ -1929,8 +1977,8 @@ static void TouchScreen_ContextRecreated(void* screen) { Screen_CreateVb(screen); Drawer2D_MakeFont(&s->font, 16, FONT_FLAGS_BOLD); - for (i = 0; i < s->numWidgets; i++) { - desc = &touchDescs[i]; + for (i = 0; i < s->numDescs; i++) { + desc = &s->descs[i]; ButtonWidget_SetConst(&s->btns[i], desc->text, &s->font); } TouchScreen_UpdateModeText(s); @@ -1951,11 +1999,15 @@ static int TouchScreen_PointerDown(void* screen, int id, int x, int y) { //Chat_Add1("POINTER DOWN: %i", &id); if (Gui_GetInputGrab()) return false; - for (i = 0; i < s->numWidgets; i++) { + if (Widget_Contains(&s->thumbstick, x, y)) { + s->thumbstick.active |= id; return true; + } + + for (i = 0; i < s->numDescs; i++) { if (!Widget_Contains(&s->btns[i], x, y)) continue; - if (s->binds[i] < KEYBIND_COUNT) { - Input_SetPressed(KeyBinds[s->binds[i]], true); + if (s->descs[i].bind < KEYBIND_COUNT) { + Input_SetPressed(KeyBinds[s->descs[i].bind], true); } else { s->btns[i].MenuClick(screen, &s->btns[i]); } @@ -1969,12 +2021,13 @@ static int TouchScreen_PointerUp(void* screen, int id, int x, int y) { struct TouchScreen* s = (struct TouchScreen*)screen; int i; //Chat_Add1("POINTER UP: %i", &id); + s->thumbstick.active &= ~id; - for (i = 0; i < s->numWidgets; i++) { + for (i = 0; i < s->numDescs; i++) { if (!(s->btns[i].active & id)) continue; - if (s->binds[i] < KEYBIND_COUNT) { - Input_SetPressed(KeyBinds[s->binds[i]], false); + if (s->descs[i].bind < KEYBIND_COUNT) { + Input_SetPressed(KeyBinds[s->descs[i].bind], false); } s->btns[i].active &= ~id; return true; @@ -1982,41 +2035,48 @@ static int TouchScreen_PointerUp(void* screen, int id, int x, int y) { return false; } +static void TouchScreen_GetMovement(float* xMoving, float* zMoving) { + ThumbstickWidget_GetMovement(&TouchScreen.thumbstick, xMoving, zMoving); +} + +struct LocalPlayerInput touchInput; static void TouchScreen_Init(void* screen) { struct TouchScreen* s = (struct TouchScreen*)screen; - int i; s->widgets = touch_widgets; - s->numWidgets = Array_Elems(touch_widgets); s->maxVertices = TOUCH_MAX_VERTICES; + Event_Register_(&UserEvents.HacksStateChanged, screen, TouchScreen_HacksChanged); - for (i = 0; i < s->numWidgets; i++) { - ButtonWidget_Init(&s->btns[i], touchDescs[i].width, NULL); - s->binds[i] = touchDescs[i].bind; - } - - s->btns[5].MenuClick = TouchScreen_ModeClick; - s->btns[6].MenuClick = TouchScreen_MoreClick; + TouchScreen_InitButtons(s); + ThumbstickWidget_Init(&s->thumbstick); + touchInput.GetMovement = TouchScreen_GetMovement; + LocalPlayer_Instance.input.next = &touchInput; } static void TouchScreen_Layout(void* screen) { - struct TouchScreen* s; + struct TouchScreen* s = (struct TouchScreen*)screen; + const struct TouchBindDesc* desc; int i, height; - s = (struct TouchScreen*)screen; HUDScreen_Layout(Gui_HUD); height = Gui_HUD->hotbar.height; - for (i = 0; i < s->numWidgets; i++) { - Widget_SetLocation(&s->btns[i], i < 4 ? ANCHOR_MIN : ANCHOR_MAX, - ANCHOR_MAX, touchDescs[i].x, touchDescs[i].y); + for (i = 0; i < s->numDescs; i++) { + desc = &s->descs[i]; + Widget_SetLocation(&s->btns[i], ANCHOR_MAX, ANCHOR_MAX, desc->x, desc->y); s->btns[i].yOffset += height; Widget_Layout(&s->btns[i]); } + + Widget_SetLocation(&s->thumbstick, ANCHOR_MIN, ANCHOR_MAX, 30, 50); +} + +static void TouchScreen_Free(void* s) { + Event_Unregister_(&UserEvents.HacksStateChanged, s, TouchScreen_HacksChanged); } static const struct ScreenVTABLE TouchScreen_VTABLE = { - TouchScreen_Init, Screen_NullUpdate, Screen_NullFunc, + TouchScreen_Init, Screen_NullUpdate, TouchScreen_Free, TouchScreen_Render, Screen_BuildMesh, Screen_FInput, Screen_FInput, Screen_FKeyPress, Screen_FText, TouchScreen_PointerDown, TouchScreen_PointerUp, Screen_FPointer, Screen_FMouseScroll, diff --git a/src/Widgets.c b/src/Widgets.c index d0523bfe2..4b92ea946 100644 --- a/src/Widgets.c +++ b/src/Widgets.c @@ -2500,3 +2500,116 @@ void SpecialInputWidget_Create(struct SpecialInputWidget* w, struct FontDesc* fo w->target = target; SpecialInputWidget_InitTabs(w); } + + +/*########################################################################################################################* +*----------------------------------------------------ThumbstickWidget-----------------------------------------------------* +*#########################################################################################################################*/ +#ifdef CC_BUILD_TOUCH +#define DIR_YMAX (1 << 0) +#define DIR_YMIN (1 << 1) +#define DIR_XMAX (1 << 2) +#define DIR_XMIN (1 << 3) + +static void ThumbstickWidget_Rotate(void* widget, struct VertexTextured** vertices, int offset) { + struct ThumbstickWidget* w = (struct ThumbstickWidget*)widget; + struct VertexTextured* ptr; + int i, x, y; + + ptr = *vertices - 4; + for (i = 0; i < 4; i++) { + int x = ptr[i].X - w->x; + int y = ptr[i].Y - w->y; + ptr[i].X = -y + w->x + offset; + ptr[i].Y = x + w->y; + } +} + +static void ThumbstickWidget_BuildGroup(void* widget, struct Texture* tex, struct VertexTextured** vertices) { + struct ThumbstickWidget* w = (struct ThumbstickWidget*)widget; + float tmp; + tex->Y = w->y + w->height / 2; + Gfx_Make2DQuad(tex, PACKEDCOL_WHITE, vertices); + + tex->Y = w->y; + tmp = tex->uv.V1; tex->uv.V1 = tex->uv.V2; tex->uv.V2 = tmp; + Gfx_Make2DQuad(tex, PACKEDCOL_WHITE, vertices); + + /* TODO: The two X sides */ + Gfx_Make2DQuad(tex, PACKEDCOL_WHITE, vertices); + ThumbstickWidget_Rotate(widget, vertices, w->width); + + tmp = tex->uv.V1; tex->uv.V1 = tex->uv.V2; tex->uv.V2 = tmp; + Gfx_Make2DQuad(tex, PACKEDCOL_WHITE, vertices); + ThumbstickWidget_Rotate(widget, vertices, w->width / 2); +} + +static void ThumbstickWidget_BuildMesh(void* widget, struct VertexTextured** vertices) { + struct ThumbstickWidget* w = (struct ThumbstickWidget*)widget; + struct Texture tex; + + tex.X = w->x; + tex.Width = w->width; tex.Height = w->height / 2; + tex.uv.U1 = 0.0f; tex.uv.U2 = 1.0f; + + tex.uv.V1 = 0.0f; tex.uv.V2 = 0.5f; + ThumbstickWidget_BuildGroup(widget, &tex, vertices); + tex.uv.V1 = 0.5f; tex.uv.V2 = 1.0f; + ThumbstickWidget_BuildGroup(widget, &tex, vertices); +} + +static int ThumbstickWidget_CalcDirs(struct ThumbstickWidget* w) { + int i, dx, dy, dirs = 0; + double angle; + + for (i = 0; i < INPUT_MAX_POINTERS; i++) { + if (!(w->active & (1 << i))) continue; + + dx = Pointers[i].x - (w->x + w->width / 2); + dy = Pointers[i].y - (w->y + w->height / 2); + angle = Math_Atan2(dx, dy) * MATH_RAD2DEG; + + /* 4 quadrants diagonally, but slightly expanded for overlap*/ + if (angle >= 30 && angle <= 150) dirs |= DIR_YMAX; + if (angle >= -60 && angle <= 60) dirs |= DIR_XMAX; + if (angle >= -150 && angle <= -30) dirs |= DIR_YMIN; + if (angle < -120 || angle > 120) dirs |= DIR_XMIN; + } + return dirs; +} + +static int ThumbstickWidget_Render2(void* widget, int offset) { + struct ThumbstickWidget* w = (struct ThumbstickWidget*)widget; + int i, base, flags = ThumbstickWidget_CalcDirs(w); + + if (Gui.TouchTex) { + Gfx_BindTexture(Gui.TouchTex); + for (i = 0; i < 4; i++) { + base = (flags & (1 << i)) ? 0 : THUMBSTICKWIDGET_PER; + Gfx_DrawVb_IndexedTris_Range(4, offset + base + (i * 4)); + } + } + return offset + THUMBSTICKWIDGET_MAX; +} + +static const struct WidgetVTABLE ThumbstickWidget_VTABLE = { + NULL, Screen_NullFunc, Widget_CalcPosition, + Widget_Key, Widget_Key, Widget_MouseScroll, + Widget_Pointer, Widget_Pointer, Widget_PointerMove, + ThumbstickWidget_BuildMesh, ThumbstickWidget_Render2 +}; +void ThumbstickWidget_Init(struct ThumbstickWidget* w) { + Widget_Reset(w); + w->VTABLE = &ThumbstickWidget_VTABLE; + w->width = Display_ScaleX(128); + w->height = Display_ScaleY(128); +} + +void ThumbstickWidget_GetMovement(struct ThumbstickWidget* w, float* xMoving, float* zMoving) { + int dirs = ThumbstickWidget_CalcDirs(w); + if (dirs & DIR_XMIN) *xMoving -= 1; + if (dirs & DIR_XMAX) *xMoving += 1; + if (dirs & DIR_YMIN) *zMoving -= 1; + if (dirs & DIR_YMAX) *zMoving += 1; +} +#endif diff --git a/src/Widgets.h b/src/Widgets.h index 23e997626..2ddc0921a 100644 --- a/src/Widgets.h +++ b/src/Widgets.h @@ -281,4 +281,13 @@ CC_NOINLINE void SpecialInputWidget_Create(struct SpecialInputWidget* w, struct CC_NOINLINE void SpecialInputWidget_Redraw(struct SpecialInputWidget* w); CC_NOINLINE void SpecialInputWidget_UpdateCols(struct SpecialInputWidget* w); CC_NOINLINE void SpecialInputWidget_SetActive(struct SpecialInputWidget* w, cc_bool active); + +#ifdef CC_BUILD_TOUCH +struct ThumbstickWidget { Widget_Body }; +#define THUMBSTICKWIDGET_PER (4 * 4) +#define THUMBSTICKWIDGET_MAX (THUMBSTICKWIDGET_PER * 2) + +void ThumbstickWidget_Init(struct ThumbstickWidget* w); +void ThumbstickWidget_GetMovement(struct ThumbstickWidget* w, float* xMoving, float* zMoving); +#endif #endif