diff --git a/ios/CCIOS.xcodeproj/project.pbxproj b/ios/CCIOS.xcodeproj/project.pbxproj index 54a93c4..aac987c 100644 --- a/ios/CCIOS.xcodeproj/project.pbxproj +++ b/ios/CCIOS.xcodeproj/project.pbxproj @@ -7,6 +7,7 @@ objects = { /* Begin PBXBuildFile section */ + 9A4D0C642BDD168800E1695D /* TouchUI.c in Sources */ = {isa = PBXBuildFile; fileRef = 9A4D0C632BDD168800E1695D /* TouchUI.c */; }; 9A57ECEE2BCD1408006A89F0 /* AudioBackend.c in Sources */ = {isa = PBXBuildFile; fileRef = 9A57ECED2BCD1408006A89F0 /* AudioBackend.c */; }; 9A57ECF02BCD1413006A89F0 /* main.c in Sources */ = {isa = PBXBuildFile; fileRef = 9A57ECEF2BCD1412006A89F0 /* main.c */; }; 9A62ADF5286D906F00E5E3DE /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 9A62ADF4286D906F00E5E3DE /* Assets.xcassets */; }; @@ -92,6 +93,7 @@ /* End PBXBuildFile section */ /* Begin PBXFileReference section */ + 9A4D0C632BDD168800E1695D /* TouchUI.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = TouchUI.c; sourceTree = ""; }; 9A57ECED2BCD1408006A89F0 /* AudioBackend.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = AudioBackend.c; sourceTree = ""; }; 9A57ECEF2BCD1412006A89F0 /* main.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = main.c; sourceTree = ""; }; 9A62ADF4286D906F00E5E3DE /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Assets.xcassets; path = ClassiCube/Assets.xcassets; sourceTree = ""; }; @@ -210,6 +212,7 @@ 9A89D37727F802F500FF3F80 /* src */ = { isa = PBXGroup; children = ( + 9A4D0C632BDD168800E1695D /* TouchUI.c */, 9A57ECEF2BCD1412006A89F0 /* main.c */, 9A57ECED2BCD1408006A89F0 /* AudioBackend.c */, 9A7401DA2B7384060040E575 /* SSL.c */, @@ -429,6 +432,7 @@ 9A89D56227F802F600FF3F80 /* _ftbase.c in Sources */, 9A89D56B27F802F600FF3F80 /* Server.c in Sources */, 9A89D50027F802F600FF3F80 /* _truetype.c in Sources */, + 9A4D0C642BDD168800E1695D /* TouchUI.c in Sources */, 9AC5433E2AE2649F0086C85F /* SystemFonts.c in Sources */, 9A89D57F27F802F600FF3F80 /* LWeb.c in Sources */, 9A89D56627F802F600FF3F80 /* Drawer2D.c in Sources */, diff --git a/src/AudioBackend.c b/src/AudioBackend.c index 975ad6c..fafe33c 100644 --- a/src/AudioBackend.c +++ b/src/AudioBackend.c @@ -624,7 +624,7 @@ void Audio_Close(struct AudioContext* ctx) { ctx->sampleRate = 0; } -static float Log10(float volume) { return Math_Log(volume) / Math_Log(10); } +static float Log10(float volume) { return Math_Log2(volume) / Math_Log2(10); } static void UpdateVolume(struct AudioContext* ctx) { /* Object doesn't exist until Audio_SetFormat is called */ @@ -1305,6 +1305,7 @@ void Audio_FreeChunks(void** chunks, int numChunks) { *#########################################################################################################################*/ #include /* TODO needs way more testing, especially with sounds */ +static cc_bool valid_handles[SND_STREAM_MAX]; struct AudioBuffer { int available; @@ -1325,8 +1326,10 @@ cc_bool AudioBackend_Init(void) { void AudioBackend_Tick(void) { // TODO is this really threadsafe with music? should this be done in Audio_Poll instead? - for (int i = 0; i < SND_STREAM_MAX; i++) - snd_stream_poll(i); + for (int i = 0; i < SND_STREAM_MAX; i++) + { + if (valid_handles[i]) snd_stream_poll(i); + } } void AudioBackend_Free(void) { @@ -1367,6 +1370,7 @@ cc_result Audio_Init(struct AudioContext* ctx, int buffers) { ctx->count = buffers; ctx->bufHead = 0; + valid_handles[ctx->hnd] = true; return 0; } @@ -1374,6 +1378,7 @@ void Audio_Close(struct AudioContext* ctx) { if (ctx->count) { snd_stream_stop(ctx->hnd); snd_stream_destroy(ctx->hnd); + valid_handles[ctx->hnd] = false; } ctx->hnd = SND_STREAM_INVALID; diff --git a/src/AxisLinesRenderer.c b/src/AxisLinesRenderer.c index e128002..59d5b76 100644 --- a/src/AxisLinesRenderer.c +++ b/src/AxisLinesRenderer.c @@ -30,21 +30,23 @@ void AxisLinesRenderer_Render(void) { Vec3 coords[5], pos, dirVector; int i, count; float axisLengthScale, axisThicknessScale; + struct Entity* e; if (!AxisLinesRenderer_Enabled) return; /* Don't do it in a ContextRecreated handler, because we only want VB recreated if ShowAxisLines in on. */ if (!axisLines_vb) { axisLines_vb = Gfx_CreateDynamicVb(VERTEX_FORMAT_COLOURED, AXISLINES_NUM_VERTICES); } + e = &Entities.CurPlayer->Base; if (Camera.Active->isThirdPerson) { - pos = LocalPlayer_Instance.Base.Position; + pos = e->Position; axisLengthScale = 1; axisThicknessScale = 1; pos.y += 0.05f; } else { pos = Camera.CurrentPos; - dirVector = Vec3_GetDirVector(LocalPlayer_Instance.Base.Yaw * MATH_DEG2RAD, LocalPlayer_Instance.Base.Pitch * MATH_DEG2RAD); + dirVector = Vec3_GetDirVector(e->Yaw * MATH_DEG2RAD, e->Pitch * MATH_DEG2RAD); Vec3_Mul1(&dirVector, &dirVector, 0.5f); Vec3_Add(&pos, &dirVector, &pos); axisLengthScale = 1.0f / 32.0f; diff --git a/src/Bitmap.c b/src/Bitmap.c index 04b0dc1..af8c0d9 100644 --- a/src/Bitmap.c +++ b/src/Bitmap.c @@ -163,8 +163,8 @@ static void Png_Reconstruct(cc_uint8 type, cc_uint8 bytesPerPixel, cc_uint8* lin /* 7.2 Scanlines */ #define PNG_Do_Grayscale(dstI, src, scale) rgb = (src) * scale; Bitmap_Set(dst[dstI], rgb, rgb, rgb, 255); -#define PNG_Do_Grayscale_8() rgb = src[0]; Bitmap_Set(*dst, rgb, rgb, rgb, 255); dst--; src -= 2; -#define PNG_Do_Grayscale_A__8() rgb = src[0]; Bitmap_Set(*dst, rgb, rgb, rgb, src[1]); dst--; src -= 1; +#define PNG_Do_Grayscale_8() rgb = src[0]; Bitmap_Set(*dst, rgb, rgb, rgb, 255); dst--; src -= 1; +#define PNG_Do_Grayscale_A__8() rgb = src[0]; Bitmap_Set(*dst, rgb, rgb, rgb, src[1]); dst--; src -= 2; #define PNG_Do_RGB__8() Bitmap_Set(*dst, src[0], src[1], src[2], 255); dst--; src -= 3; #define PNG_Do_RGB_A__8() Bitmap_Set(*dst, src[0], src[1], src[2], src[3]); dst++; src += 4; #define PNG_Do_Palette__8() *dst-- = palette[*src--]; @@ -334,7 +334,7 @@ cc_result Png_Decode(struct Bitmap* bmp, struct Stream* stream) { cc_uint32 i; /* idat state */ - cc_uint32 begY, rowY = 0, endY; + cc_uint32 available = 0, rowY = 0; cc_uint8 buffer[PNG_PALETTE * 3]; cc_uint32 read, bufferIdx = 0; cc_uint32 left, bufferLen = 0; @@ -461,19 +461,18 @@ cc_result Png_Decode(struct Bitmap* bmp, struct Stream* stream) { if (!bmp->scan0) return PNG_ERR_NO_DATA; if (rowY >= bmp->height) break; - - begY = bufferIdx / scanlineBytes; left = bufferLen - bufferIdx; - res = compStream.Read(&compStream, &data[bufferIdx], left, &read); + res = compStream.Read(&compStream, &data[bufferIdx], left, &read); if (res) return res; if (!read) break; + available += read; bufferIdx += read; - endY = bufferIdx / scanlineBytes; + /* Process all of the scanline(s) that have been fully decompressed */ /* NOTE: Need to check height too, in case IDAT is corrupted and has extra data */ - for (rowY = begY; rowY < endY && rowY < bmp->height; rowY++) { + for (; available >= scanlineBytes && rowY < bmp->height; rowY++, available -= scanlineBytes) { cc_uint8* scanline = &data[rowY * scanlineBytes]; if (scanline[0] > PNG_FILTER_PAETH) return PNG_ERR_INVALID_SCANLINE; @@ -489,12 +488,14 @@ cc_result Png_Decode(struct Bitmap* bmp, struct Stream* stream) { /* immediately into the destination colour format */ if (colorspace == PNG_COLOR_RGB_A) { /* Prior line is no longer needed and can be overwritten now */ - rowExpander(bmp->width, palette, &prior[1], Bitmap_GetRow(bmp, rowY - 1)); - /* Current line is also no longer needed and can be overwritten now */ - if (rowY == bmp->height - 1) - rowExpander(bmp->width, palette, &scanline[1], Bitmap_GetRow(bmp, rowY)); + rowExpander(bmp->width, palette, &prior[1], Bitmap_GetRow(bmp, rowY - 1)); } } + + /* Current line is also no longer needed and can be overwritten now */ + if (colorspace == PNG_COLOR_RGB_A && rowY == bmp->height - 1) { + rowExpander(bmp->width, palette, &scanline[1], Bitmap_GetRow(bmp, rowY)); + } } /* Check if image fully decoded or not */ diff --git a/src/Block.c b/src/Block.c index fd2551e..9a974f0 100644 --- a/src/Block.c +++ b/src/Block.c @@ -512,7 +512,8 @@ int Block_FindID(const cc_string* name) { cc_string blockName; int block; - for (block = BLOCK_AIR; block < BLOCK_COUNT; block++) { + for (block = BLOCK_AIR; block < BLOCK_COUNT; block++) + { blockName = Block_UNSAFE_GetName(block); if (String_CaselessEquals(&blockName, name)) return block; } @@ -604,7 +605,7 @@ static int RotateVertical(cc_string* name, int offset) { static int RotateFence(cc_string* name, int offset) { /* Fence type blocks */ - float yaw = Math_ClampAngle(LocalPlayer_Instance.Base.Yaw); + float yaw = Math_ClampAngle(Entities.CurPlayer->Base.Yaw); if (yaw < 45.0f || (yaw >= 135.0f && yaw < 225.0f) || yaw > 315.0f) { AutoRotate_Insert(name, offset, "-WE"); @@ -629,7 +630,7 @@ static int RotatePillar(cc_string* name, int offset) { } static int RotateDirection(cc_string* name, int offset) { - float yaw = Math_ClampAngle(LocalPlayer_Instance.Base.Yaw); + float yaw = Math_ClampAngle(Entities.CurPlayer->Base.Yaw); if (yaw >= 45.0f && yaw < 135.0f) { AutoRotate_Insert(name, offset, "-E"); diff --git a/src/Camera.c b/src/Camera.c index 1d085b2..2133ab9 100644 --- a/src/Camera.c +++ b/src/Camera.c @@ -22,7 +22,7 @@ static void Camera_OnRawMovement(float deltaX, float deltaY) { cam_deltaX += deltaX; cam_deltaY += deltaY; } -void Camera_KeyLookUpdate(double delta) { +void Camera_KeyLookUpdate(float delta) { if (Gui.InputGrab) return; /* divide by 25 to have reasonable sensitivity for default mouse sens */ float amount = (Camera.Sensitivity / 25.0f) * (1000 * delta); @@ -42,24 +42,23 @@ static void PerspectiveCamera_GetProjection(struct Matrix* proj) { Gfx_CalcPerspectiveMatrix(proj, fovy, aspectRatio, (float)Game_ViewDistance); } -static void PerspectiveCamera_GetView(struct Matrix* mat) { +static void PerspectiveCamera_GetView(struct LocalPlayer* p, struct Matrix* mat) { Vec3 pos = Camera.CurrentPos; - Vec2 rot = Camera.Active->GetOrientation(); + Vec2 rot = Camera.Active->GetOrientation(p); Matrix_LookRot(mat, pos, rot); Matrix_MulBy(mat, &Camera.TiltM); } -static void PerspectiveCamera_GetPickedBlock(struct RayTracer* t) { - struct Entity* p = &LocalPlayer_Instance.Base; - Vec3 dir = Vec3_GetDirVector(p->Yaw * MATH_DEG2RAD, p->Pitch * MATH_DEG2RAD + Camera.TiltPitch); - Vec3 eyePos = Entity_GetEyePosition(p); - float reach = LocalPlayer_Instance.ReachDistance; - Picking_CalcPickedBlock(&eyePos, &dir, reach, t); +static void PerspectiveCamera_GetPickedBlock(struct LocalPlayer* p, struct RayTracer* t) { + struct Entity* e = &p->Base; + Vec3 dir = Vec3_GetDirVector(e->Yaw * MATH_DEG2RAD, e->Pitch * MATH_DEG2RAD + Camera.TiltPitch); + Vec3 eyePos = Entity_GetEyePosition(e); + Picking_CalcPickedBlock(&eyePos, &dir, p->ReachDistance, t); } #define CAMERA_SENSI_FACTOR (0.0002f / 3.0f * MATH_RAD2DEG) -static Vec2 PerspectiveCamera_GetMouseDelta(double delta) { +static Vec2 PerspectiveCamera_GetMouseDelta(float delta) { float sensitivity = CAMERA_SENSI_FACTOR * Camera.Sensitivity; static float speedX, speedY, newSpeedX, newSpeedY, accelX, accelY; Vec2 v; @@ -67,8 +66,8 @@ static Vec2 PerspectiveCamera_GetMouseDelta(double delta) { if (Camera.Smooth) { accelX = (cam_deltaX - speedX) * 35 / Camera.Mass; accelY = (cam_deltaY - speedY) * 35 / Camera.Mass; - newSpeedX = accelX * (float)delta + speedX; - newSpeedY = accelY * (float)delta + speedY; + newSpeedX = accelX * delta + speedX; + newSpeedY = accelY * delta + speedY; /* High acceleration means velocity overshoots the correct position on low FPS, */ /* causing wiggling. If newSpeed has opposite sign of speed, set speed to 0 */ @@ -86,8 +85,8 @@ static Vec2 PerspectiveCamera_GetMouseDelta(double delta) { return v; } -static void PerspectiveCamera_UpdateMouseRotation(double delta) { - struct Entity* e = &LocalPlayer_Instance.Base; +static void PerspectiveCamera_UpdateMouseRotation(struct LocalPlayer* p, float delta) { + struct Entity* e = &p->Base; struct LocationUpdate update; Vec2 rot = PerspectiveCamera_GetMouseDelta(delta); @@ -108,15 +107,14 @@ static void PerspectiveCamera_UpdateMouseRotation(double delta) { e->VTABLE->SetLocation(e, &update); } -static void PerspectiveCamera_UpdateMouse(double delta) { +static void PerspectiveCamera_UpdateMouse(struct LocalPlayer* p, float delta) { if (!Gui.InputGrab && Window_Main.Focused) Window_UpdateRawMouse(); - PerspectiveCamera_UpdateMouseRotation(delta); + PerspectiveCamera_UpdateMouseRotation(p, delta); cam_deltaX = 0; cam_deltaY = 0; } -static void PerspectiveCamera_CalcViewBobbing(float t, float velTiltScale) { - struct LocalPlayer* p = &LocalPlayer_Instance; +static void PerspectiveCamera_CalcViewBobbing(struct LocalPlayer* p, float t, float velTiltScale) { struct Entity* e = &p->Base; struct Matrix tiltY, velX; @@ -148,23 +146,23 @@ static void PerspectiveCamera_CalcViewBobbing(float t, float velTiltScale) { /*########################################################################################################################* *---------------------------------------------------First person camera---------------------------------------------------* *#########################################################################################################################*/ -static Vec2 FirstPersonCamera_GetOrientation(void) { - struct Entity* p = &LocalPlayer_Instance.Base; +static Vec2 FirstPersonCamera_GetOrientation(struct LocalPlayer* p) { + struct Entity* e = &p->Base; Vec2 v; - v.x = p->Yaw * MATH_DEG2RAD; - v.y = p->Pitch * MATH_DEG2RAD; + v.x = e->Yaw * MATH_DEG2RAD; + v.y = e->Pitch * MATH_DEG2RAD; return v; } -static Vec3 FirstPersonCamera_GetPosition(float t) { - struct Entity* p = &LocalPlayer_Instance.Base; - Vec3 camPos = Entity_GetEyePosition(p); - float yaw = p->Yaw * MATH_DEG2RAD; - PerspectiveCamera_CalcViewBobbing(t, 1); +static Vec3 FirstPersonCamera_GetPosition(struct LocalPlayer* p, float t) { + struct Entity* e = &p->Base; + Vec3 camPos = Entity_GetEyePosition(e); + float yaw = e->Yaw * MATH_DEG2RAD; + PerspectiveCamera_CalcViewBobbing(p, t, 1); camPos.y += Camera.BobbingVer; - camPos.x += Camera.BobbingHor * (float)Math_Cos(yaw); - camPos.z += Camera.BobbingHor * (float)Math_Sin(yaw); + camPos.x += Camera.BobbingHor * Math_CosF(yaw); + camPos.z += Camera.BobbingHor * Math_SinF(yaw); return camPos; } @@ -185,11 +183,11 @@ static struct Camera cam_FirstPerson = { #define DEF_ZOOM 3.0f static float dist_third = DEF_ZOOM, dist_forward = DEF_ZOOM; -static Vec2 ThirdPersonCamera_GetOrientation(void) { - struct Entity* p = &LocalPlayer_Instance.Base; +static Vec2 ThirdPersonCamera_GetOrientation(struct LocalPlayer* p) { + struct Entity* e = &p->Base; Vec2 v; - v.x = p->Yaw * MATH_DEG2RAD; - v.y = p->Pitch * MATH_DEG2RAD; + v.x = e->Yaw * MATH_DEG2RAD; + v.y = e->Pitch * MATH_DEG2RAD; if (cam_isForwardThird) { v.x += MATH_PI; v.y = -v.y; } v.x += cam_rotOffset.x * MATH_DEG2RAD; @@ -197,24 +195,24 @@ static Vec2 ThirdPersonCamera_GetOrientation(void) { return v; } -static float ThirdPersonCamera_GetZoom(void) { +static float ThirdPersonCamera_GetZoom(struct LocalPlayer* p) { float dist = cam_isForwardThird ? dist_forward : dist_third; /* Don't allow zooming out when -fly */ - if (dist > DEF_ZOOM && !LocalPlayer_CheckCanZoom()) dist = DEF_ZOOM; + if (dist > DEF_ZOOM && !LocalPlayer_CheckCanZoom(p)) dist = DEF_ZOOM; return dist; } -static Vec3 ThirdPersonCamera_GetPosition(float t) { - struct Entity* p = &LocalPlayer_Instance.Base; - float dist = ThirdPersonCamera_GetZoom(); +static Vec3 ThirdPersonCamera_GetPosition(struct LocalPlayer* p, float t) { + struct Entity* e = &p->Base; + float dist = ThirdPersonCamera_GetZoom(p); Vec3 target, dir; Vec2 rot; - PerspectiveCamera_CalcViewBobbing(t, dist); - target = Entity_GetEyePosition(p); + PerspectiveCamera_CalcViewBobbing(p, t, dist); + target = Entity_GetEyePosition(e); target.y += Camera.BobbingVer; - rot = Camera.Active->GetOrientation(); + rot = Camera.Active->GetOrientation(p); dir = Vec3_GetDirVector(rot.x, rot.y); Vec3_Negate(&dir, &dir); @@ -255,7 +253,7 @@ static void OnRawMovement(void* obj, float deltaX, float deltaY) { Camera.Active->OnRawMovement(deltaX, deltaY); } -static void OnAxisUpdate(void* obj, int axis, float x, float y) { +static void OnAxisUpdate(void* obj, int port, int axis, float x, float y) { if (!Input.RawMode) return; if (Gamepad_AxisBehaviour[axis] != AXIS_BEHAVIOUR_CAMERA) return; @@ -263,13 +261,13 @@ static void OnAxisUpdate(void* obj, int axis, float x, float y) { } static void OnHacksChanged(void* obj) { - struct HacksComp* h = &LocalPlayer_Instance.Hacks; + struct HacksComp* h = &Entities.CurPlayer->Hacks; /* Leave third person if not allowed anymore */ if (!h->CanUseThirdPerson || !h->Enabled) Camera_CycleActive(); } void Camera_CycleActive(void) { - struct LocalPlayer* p = &LocalPlayer_Instance; + struct LocalPlayer* p = &LocalPlayer_Instances[0]; if (Game_ClassicMode) return; Camera.Active = Camera.Active->next; diff --git a/src/Camera.h b/src/Camera.h index 2358b82..8d8f513 100644 --- a/src/Camera.h +++ b/src/Camera.h @@ -8,6 +8,7 @@ Copyright 2014-2023 ClassiCube | Licensed under BSD-3 struct RayTracer; struct Camera; struct IGameComponent; +struct LocalPlayer; extern struct IGameComponent Camera_Component; /* Shared data for cameras. */ @@ -45,16 +46,16 @@ struct Camera { /* Calculates the current projection matrix of this camera. */ void (*GetProjection)(struct Matrix* proj); /* Calculates the current modelview matrix of this camera. */ - void (*GetView)(struct Matrix* view); + void (*GetView)(struct LocalPlayer* p, struct Matrix* view); /* Returns the current orientation of the camera. */ - Vec2 (*GetOrientation)(void); + Vec2 (*GetOrientation)(struct LocalPlayer* p); /* Returns the current interpolated position of the camera. */ - Vec3 (*GetPosition)(float t); + Vec3 (*GetPosition)(struct LocalPlayer* p, float t); /* Called to update the camera's state. */ /* Typically, this is used to adjust yaw/pitch based on accumulated mouse movement. */ - void (*UpdateMouse)(double delta); + void (*UpdateMouse)(struct LocalPlayer* p, float delta); /* Called when mouse/pointer has moved. */ void (*OnRawMovement)(float deltaX, float deltaY); /* Called when user closes all menus, and is interacting with camera again. */ @@ -63,7 +64,7 @@ struct Camera { void (*LoseFocus)(void); /* Calculates selected block in the world, based on camera's current state */ - void (*GetPickedBlock)(struct RayTracer* t); + void (*GetPickedBlock)(struct LocalPlayer* p, struct RayTracer* t); /* Zooms the camera in or out when scrolling mouse wheel. */ cc_bool (*Zoom)(float amount); @@ -80,5 +81,5 @@ CC_API void Camera_Register(struct Camera* camera); void Camera_CheckFocus(void); void Camera_UpdateProjection(void); void Camera_SetFov(int fov); -void Camera_KeyLookUpdate(double delta); +void Camera_KeyLookUpdate(float delta); #endif diff --git a/src/Chat.h b/src/Chat.h index a97d463..c4366bf 100644 --- a/src/Chat.h +++ b/src/Chat.h @@ -67,8 +67,8 @@ typedef void (*FP_Chat_AddOf)(const cc_string* text, int msgType); /* Shorthand for Chat_AddOf(String_FromReadonly(raw), MSG_TYPE_NORMAL) */ void Chat_AddRaw(const char* raw); -void Chat_Add1(const char* format, const void* a1); -void Chat_Add2(const char* format, const void* a1, const void* a2); -void Chat_Add3(const char* format, const void* a1, const void* a2, const void* a3); -void Chat_Add4(const char* format, const void* a1, const void* a2, const void* a3, const void* a4); +CC_API void Chat_Add1(const char* format, const void* a1); +CC_API void Chat_Add2(const char* format, const void* a1, const void* a2); +CC_API void Chat_Add3(const char* format, const void* a1, const void* a2, const void* a3); +CC_API void Chat_Add4(const char* format, const void* a1, const void* a2, const void* a3, const void* a4); #endif diff --git a/src/Commands.c b/src/Commands.c index 1a994cf..b64e84f 100644 --- a/src/Commands.c +++ b/src/Commands.c @@ -237,7 +237,7 @@ static struct ChatCommand ResolutionCommand = { static void ModelCommand_Execute(const cc_string* args, int argsCount) { if (argsCount) { - Entity_SetModel(&LocalPlayer_Instance.Base, args); + Entity_SetModel(&Entities.CurPlayer->Base, args); } else { Chat_AddRaw("&e/client model: &cYou didn't specify a model name."); } @@ -267,6 +267,23 @@ static struct ChatCommand ClearDeniedCommand = { } }; +static void MotdCommand_Execute(const cc_string* args, int argsCount) { + if (Server.IsSinglePlayer) { + Chat_AddRaw("&eThis command can only be used in multiplayer."); + return; + } + Chat_Add1("&eName: &f%s", &Server.Name); + Chat_Add1("&eMOTD: &f%s", &Server.MOTD); +} + +static struct ChatCommand MotdCommand = { + "Motd", MotdCommand_Execute, + COMMAND_FLAG_UNSPLIT_ARGS, + { + "&a/client motd", + "&eDisplays the server's name and MOTD." + } +}; /*########################################################################################################################* *-------------------------------------------------------DrawOpCommand-----------------------------------------------------* @@ -482,7 +499,7 @@ static struct ChatCommand ReplaceCommand = { *------------------------------------------------------TeleportCommand----------------------------------------------------* *#########################################################################################################################*/ static void TeleportCommand_Execute(const cc_string* args, int argsCount) { - struct Entity* e = &LocalPlayer_Instance.Base; + struct Entity* e = &Entities.CurPlayer->Base; struct LocationUpdate update; Vec3 v; @@ -709,6 +726,7 @@ static void OnInit(void) { Commands_Register(&ModelCommand); Commands_Register(&TeleportCommand); Commands_Register(&ClearDeniedCommand); + Commands_Register(&MotdCommand); Commands_Register(&BlockEditCommand); Commands_Register(&CuboidCommand); Commands_Register(&ReplaceCommand); diff --git a/src/Constants.h b/src/Constants.h index b5db721..5a96863 100644 --- a/src/Constants.h +++ b/src/Constants.h @@ -67,9 +67,8 @@ enum SKIN_TYPE { SKIN_64x32, SKIN_64x64, SKIN_64x64_SLIM, SKIN_INVALID = 0xF0 }; #define Int32_MinValue ((cc_int32)-2147483647L - (cc_int32)1L) #define Int32_MaxValue ((cc_int32)2147483647L) -/* Skins were moved to use Amazon S3, so link directly to avoid a pointless redirect */ #define SKINS_SERVER "http://cdn.classicube.net/skin" -#define UPDATES_SERVER "http://cs.classicube.net/client" +#define UPDATES_SERVER "http://cdn.classicube.net/client" #define SERVICES_SERVER "https://www.classicube.net/api" #define RESOURCE_SERVER "http://static.classicube.net" /* Webpage where users can register for a new account */ diff --git a/src/Core.h b/src/Core.h index 1d63082..aff7c29 100644 --- a/src/Core.h +++ b/src/Core.h @@ -119,7 +119,7 @@ typedef cc_uint8 cc_bool; #define CC_BUILD_NETWORKING -#undef CC_BUILD_FREETYPE +//#define CC_BUILD_FREETYPE #define CC_BUILD_RESOURCES #define CC_BUILD_PLUGINS #define CC_BUILD_ANIMATIONS @@ -136,6 +136,7 @@ typedef cc_uint8 cc_bool; #define CC_BUILD_NOSOUNDS #define CC_BUILD_HTTPCLIENT #define CC_BUILD_BEARSSL + #define CC_BUILD_SPLITSCREEN #elif defined XENON /* libxenon also defines __linux__ (yes, really) */ #define CC_BUILD_XBOX360 @@ -292,6 +293,7 @@ typedef cc_uint8 cc_bool; #define CC_BUILD_COOPTHREADED #define CC_BUILD_HTTPCLIENT #define CC_BUILD_BEARSSL + #define CC_BUILD_SPLITSCREEN #elif defined __vita__ #define CC_BUILD_PSVITA #define CC_BUILD_CONSOLE @@ -306,6 +308,7 @@ typedef cc_uint8 cc_bool; #define CC_BUILD_LOWMEM #define CC_BUILD_HTTPCLIENT #define CC_BUILD_BEARSSL + #define CC_BUILD_SPLITSCREEN #undef CC_BUILD_RESOURCES #elif defined PLAT_PS3 #define CC_BUILD_PS3 @@ -314,13 +317,15 @@ typedef cc_uint8 cc_bool; #define CC_BUILD_OPENAL #define CC_BUILD_HTTPCLIENT #define CC_BUILD_BEARSSL + #define CC_BUILD_SPLITSCREEN #elif defined N64 #define CC_BIG_ENDIAN #define CC_BUILD_N64 #define CC_BUILD_CONSOLE #define CC_BUILD_LOWMEM #define CC_BUILD_COOPTHREADED - #define CC_BUILD_OPENAL + #define CC_BUILD_NOMUSIC + #define CC_BUILD_NOSOUNDS #undef CC_BUILD_RESOURCES #undef CC_BUILD_NETWORKING #undef CC_BUILD_FILESYSTEM @@ -349,6 +354,7 @@ typedef cc_uint8 cc_bool; #define CC_BUILD_OPENAL #define CC_BUILD_HTTPCLIENT #define CC_BUILD_BEARSSL + #define CC_BUILD_SPLITSCREEN #define CC_BUILD_TOUCH #elif defined __SWITCH__ #define CC_BUILD_SWITCH diff --git a/src/Drawer2D.c b/src/Drawer2D.c index 312279c..589ca0b 100644 --- a/src/Drawer2D.c +++ b/src/Drawer2D.c @@ -187,7 +187,7 @@ void Gradient_Noise(struct Context2D* ctx, BitmapCol color, int variation, cc_uint32 alpha; if (!Drawer2D_Clamp(ctx, &x, &y, &width, &height)) return; - alpha = BitmapColor_A_Bits(color); + alpha = color & BITMAPCOLOR_A_MASK; for (yy = 0; yy < height; yy++) { dst = Bitmap_GetRow(bmp, y + yy) + x; @@ -539,6 +539,12 @@ static void DrawBitmappedTextCore(struct Bitmap* bmp, struct DrawTextArgs* args, static void DrawBitmappedText(struct Bitmap* bmp, struct DrawTextArgs* args, int x, int y) { int offset = Drawer2D_ShadowOffset(args->font->size); + if (!fontBitmap.scan0) { + if (args->useShadow) FallbackFont_DrawText(args, bmp, x, y, true); + FallbackFont_DrawText(args, bmp, x, y, false); + return; + } + if (args->useShadow) { DrawBitmappedTextCore(bmp, args, x + offset, y + offset, true); } @@ -550,6 +556,8 @@ static int MeasureBitmappedWidth(const struct DrawTextArgs* args) { int xPadding, width; cc_string text; + if (!fontBitmap.scan0) return FallbackFont_TextWidth(args); + /* adjust coords to make drawn text match GDI fonts */ xPadding = Drawer2D_XPadding(point); width = 0; diff --git a/src/Entity.c b/src/Entity.c index c730626..40ebb81 100644 --- a/src/Entity.c +++ b/src/Entity.c @@ -367,7 +367,7 @@ static void Entity_CheckSkin(struct Entity* e) { if (!e->SkinFetchState) { first = Entity_FirstOtherWithSameSkinAndFetchedSkin(e); - flags = e == &LocalPlayer_Instance.Base ? HTTP_FLAG_NOCACHE : 0; + flags = e == &LocalPlayer_Instances[0].Base ? HTTP_FLAG_NOCACHE : 0; if (!first) { e->_skinReqID = Http_AsyncGetSkin(&skin, flags); @@ -452,7 +452,7 @@ void Entities_Tick(struct ScheduledTask* task) { } } -void Entities_RenderModels(double delta, float t) { +void Entities_RenderModels(float delta, float t) { int i; Gfx_SetAlphaTest(true); @@ -497,24 +497,24 @@ void Entities_Remove(EntityID id) { } } -EntityID Entities_GetClosest(struct Entity* src) { +int Entities_GetClosest(struct Entity* src) { Vec3 eyePos = Entity_GetEyePosition(src); Vec3 dir = Vec3_GetDirVector(src->Yaw * MATH_DEG2RAD, src->Pitch * MATH_DEG2RAD); float closestDist = -200; /* NOTE: was previously positive infinity */ - EntityID targetID = ENTITIES_SELF_ID; + int targetID = -1; float t0, t1; int i; - for (i = 0; i < ENTITIES_SELF_ID; i++) /* because we don't want to pick against local player */ + for (i = 0; i < ENTITIES_MAX_COUNT; i++) /* because we don't want to pick against local player */ { - struct Entity* entity = Entities.List[i]; - if (!entity) continue; - if (!Intersection_RayIntersectsRotatedBox(eyePos, dir, entity, &t0, &t1)) continue; + struct Entity* e = Entities.List[i]; + if (!e || e == &Entities.CurPlayer->Base) continue; + if (!Intersection_RayIntersectsRotatedBox(eyePos, dir, e, &t0, &t1)) continue; - if (targetID == ENTITIES_SELF_ID || t0 < closestDist) { + if (targetID == -1 || t0 < closestDist) { closestDist = t0; - targetID = (EntityID)i; + targetID = i; } } return targetID; @@ -613,23 +613,27 @@ struct IGameComponent TabList_Component = { /*########################################################################################################################* *------------------------------------------------------LocalPlayer--------------------------------------------------------* *#########################################################################################################################*/ -struct LocalPlayer LocalPlayer_Instance; +struct LocalPlayer LocalPlayer_Instances[MAX_LOCAL_PLAYERS]; static cc_bool hackPermMsgs; -float LocalPlayer_JumpHeight(void) { - struct LocalPlayer* p = &LocalPlayer_Instance; +static struct LocalPlayerInput* sources_head; +static struct LocalPlayerInput* sources_tail; + +void LocalPlayerInput_Add(struct LocalPlayerInput* source) { + LinkedList_Append(source, sources_head, sources_tail); +} + +float LocalPlayer_JumpHeight(struct LocalPlayer* p) { return (float)PhysicsComp_CalcMaxHeight(p->Physics.JumpVel); } -void LocalPlayer_SetInterpPosition(float t) { - struct LocalPlayer* p = &LocalPlayer_Instance; +void LocalPlayer_SetInterpPosition(struct LocalPlayer* p, float t) { if (!(p->Hacks.WOMStyleHacks && p->Hacks.Noclip)) { Vec3_Lerp(&p->Base.Position, &p->Base.prev.pos, &p->Base.next.pos, t); } Entity_LerpAngles(&p->Base, t); } -static void LocalPlayer_HandleInput(float* xMoving, float* zMoving) { - struct LocalPlayer* p = &LocalPlayer_Instance; +static void LocalPlayer_HandleInput(struct LocalPlayer* p, float* xMoving, float* zMoving) { struct HacksComp* hacks = &p->Hacks; struct LocalPlayerInput* input; @@ -640,8 +644,8 @@ static void LocalPlayer_HandleInput(float* xMoving, float* zMoving) { } /* keyboard input, touch, joystick, etc */ - for (input = &p->input; input; input = input->next) { - input->GetMovement(xMoving, zMoving); + for (input = sources_head; input; input = input->next) { + input->GetMovement(p, xMoving, zMoving); } *xMoving *= 0.98f; *zMoving *= 0.98f; @@ -660,7 +664,7 @@ static void LocalPlayer_HandleInput(float* xMoving, float* zMoving) { } static void LocalPlayer_InputSet(int key, cc_bool pressed) { - struct HacksComp* hacks = &LocalPlayer_Instance.Hacks; + struct HacksComp* hacks = &LocalPlayer_Instances[0].Hacks; if (pressed && !hacks->Enabled) return; if (KeyBind_Claims(KEYBIND_SPEED, key)) hacks->Speeding = pressed; @@ -678,10 +682,10 @@ static void LocalPlayer_InputUp(void* obj, int key) { static void LocalPlayer_SetLocation(struct Entity* e, struct LocationUpdate* update) { struct LocalPlayer* p = (struct LocalPlayer*)e; - LocalInterpComp_SetLocation(&p->Interp, update); + LocalInterpComp_SetLocation(&p->Interp, update, e); } -static void LocalPlayer_Tick(struct Entity* e, double delta) { +static void LocalPlayer_Tick(struct Entity* e, float delta) { struct LocalPlayer* p = (struct LocalPlayer*)e; struct HacksComp* hacks = &p->Hacks; float xMoving = 0, zMoving = 0; @@ -694,7 +698,7 @@ static void LocalPlayer_Tick(struct Entity* e, double delta) { wasOnGround = e->OnGround; LocalInterpComp_AdvanceState(&p->Interp, e); - LocalPlayer_HandleInput(&xMoving, &zMoving); + LocalPlayer_HandleInput(p, &xMoving, &zMoving); hacks->Floating = hacks->Noclip || hacks->Flying; if (!hacks->Floating && hacks->CanBePushed) PhysicsComp_DoEntityPush(e); @@ -712,18 +716,18 @@ static void LocalPlayer_Tick(struct Entity* e, double delta) { e->next.pos = e->Position; e->Position = e->prev.pos; AnimatedComp_Update(e, e->prev.pos, e->next.pos, delta); - TiltComp_Update(&p->Tilt, delta); + TiltComp_Update(p, &p->Tilt, delta); Entity_CheckSkin(&p->Base); - SoundComp_Tick(wasOnGround); + SoundComp_Tick(p, wasOnGround); } -static void LocalPlayer_RenderModel(struct Entity* e, double deltaTime, float t) { +static void LocalPlayer_RenderModel(struct Entity* e, float delta, float t) { struct LocalPlayer* p = (struct LocalPlayer*)e; AnimatedComp_GetCurrent(e, t); - TiltComp_GetCurrent(&p->Tilt, t); + TiltComp_GetCurrent(p, &p->Tilt, t); - if (!Camera.Active->isThirdPerson) return; + if (!Camera.Active->isThirdPerson && p == Entities.CurPlayer) return; Model_Render(e->Model, e); } @@ -732,38 +736,24 @@ static cc_bool LocalPlayer_ShouldRenderName(struct Entity* e) { } static void LocalPlayer_CheckJumpVelocity(void* obj) { - struct LocalPlayer* p = &LocalPlayer_Instance; + struct LocalPlayer* p = (struct LocalPlayer*)obj; if (!HacksComp_CanJumpHigher(&p->Hacks)) { p->Physics.JumpVel = p->Physics.ServerJumpVel; } } -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; - - /* TODO: Move to separate LocalPlayerInputSource */ - if (!Input.JoystickMovement) return; - *xMoving = Math_CosF(Input.JoystickAngle); - *zMoving = Math_SinF(Input.JoystickAngle); -} - static const struct EntityVTABLE localPlayer_VTABLE = { LocalPlayer_Tick, Player_Despawn, LocalPlayer_SetLocation, Entity_GetColor, LocalPlayer_RenderModel, LocalPlayer_ShouldRenderName }; -static void LocalPlayer_Init(void) { - struct LocalPlayer* p = &LocalPlayer_Instance; +static void LocalPlayer_Init(struct LocalPlayer* p, int index) { struct HacksComp* hacks = &p->Hacks; Entity_Init(&p->Base); Entity_SetName(&p->Base, &Game_Username); Entity_SetSkin(&p->Base, &Game_Username); - Event_Register_(&UserEvents.HackPermsChanged, NULL, LocalPlayer_CheckJumpVelocity); + Event_Register_(&UserEvents.HackPermsChanged, p, LocalPlayer_CheckJumpVelocity); - p->input.GetMovement = LocalPlayer_GetMovement; p->Collisions.Entity = &p->Base; HacksComp_Init(hacks); PhysicsComp_Init(&p->Physics, &p->Base); @@ -774,12 +764,13 @@ static void LocalPlayer_Init(void) { p->Physics.Hacks = &p->Hacks; p->Physics.Collisions = &p->Collisions; p->Base.VTABLE = &localPlayer_VTABLE; + p->index = index; hacks->Enabled = !Game_PureClassic && Options_GetBool(OPT_HACKS_ENABLED, true); /* p->Base.Health = 20; TODO: survival mode stuff */ if (Game_ClassicMode) return; - hacks->SpeedMultiplier = Options_GetFloat(OPT_SPEED_FACTOR, 0.1f, 50.0f, 10.0f); + 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); @@ -789,23 +780,28 @@ static void LocalPlayer_Init(void) { hackPermMsgs = Options_GetBool(OPT_HACK_PERM_MSGS, true); } -void LocalPlayer_ResetJumpVelocity(void) { - struct LocalPlayer* p = &LocalPlayer_Instance; +void LocalPlayer_ResetJumpVelocity(struct LocalPlayer* p) { cc_bool higher = HacksComp_CanJumpHigher(&p->Hacks); p->Physics.JumpVel = higher ? p->Physics.UserJumpVel : 0.42f; p->Physics.ServerJumpVel = p->Physics.JumpVel; } -static void LocalPlayer_Reset(void) { - struct LocalPlayer* p = &LocalPlayer_Instance; +static void LocalPlayer_Reset(struct LocalPlayer* p) { p->ReachDistance = 5.0f; Vec3_Set(p->Base.Velocity, 0,0,0); - LocalPlayer_ResetJumpVelocity(); + LocalPlayer_ResetJumpVelocity(p); } -static void LocalPlayer_OnNewMap(void) { - struct LocalPlayer* p = &LocalPlayer_Instance; +static void LocalPlayers_Reset(void) { + int i; + for (i = 0; i < Game_NumLocalPlayers; i++) + { + LocalPlayer_Reset(&LocalPlayer_Instances[i]); + } +} + +static void LocalPlayer_OnNewMap(struct LocalPlayer* p) { Vec3_Set(p->Base.Velocity, 0,0,0); Vec3_Set(p->OldVelocity, 0,0,0); @@ -815,9 +811,16 @@ static void LocalPlayer_OnNewMap(void) { p->_warnedZoom = false; } +static void LocalPlayers_OnNewMap(void) { + int i; + for (i = 0; i < Game_NumLocalPlayers; i++) + { + LocalPlayer_OnNewMap(&LocalPlayer_Instances[i]); + } +} + static cc_bool LocalPlayer_IsSolidCollide(BlockID b) { return Blocks.Collide[b] == COLLIDE_SOLID; } -static void LocalPlayer_DoRespawn(void) { - struct LocalPlayer* p = &LocalPlayer_Instance; +static void LocalPlayer_DoRespawn(struct LocalPlayer* p) { struct LocationUpdate update; struct AABB bb; Vec3 spawn = p->Spawn; @@ -863,10 +866,9 @@ static void LocalPlayer_DoRespawn(void) { p->Base.OnGround = Entity_TouchesAny(&bb, LocalPlayer_IsSolidCollide); } -cc_bool LocalPlayer_HandleRespawn(void) { - struct LocalPlayer* p = &LocalPlayer_Instance; +cc_bool LocalPlayer_HandleRespawn(struct LocalPlayer* p) { if (p->Hacks.CanRespawn) { - LocalPlayer_DoRespawn(); + LocalPlayer_DoRespawn(p); return true; } else if (!p->_warnedRespawn) { p->_warnedRespawn = true; @@ -875,8 +877,7 @@ cc_bool LocalPlayer_HandleRespawn(void) { return false; } -cc_bool LocalPlayer_HandleSetSpawn(void) { - struct LocalPlayer* p = &LocalPlayer_Instance; +cc_bool LocalPlayer_HandleSetSpawn(struct LocalPlayer* p) { if (p->Hacks.CanRespawn) { if (!p->Hacks.CanNoclip && !p->Base.OnGround) { @@ -896,11 +897,10 @@ cc_bool LocalPlayer_HandleSetSpawn(void) { p->SpawnYaw = p->Base.Yaw; p->SpawnPitch = p->Base.Pitch; } - return LocalPlayer_HandleRespawn(); + return LocalPlayer_HandleRespawn(p); } -cc_bool LocalPlayer_HandleFly(void) { - struct LocalPlayer* p = &LocalPlayer_Instance; +cc_bool LocalPlayer_HandleFly(struct LocalPlayer* p) { if (p->Hacks.CanFly && p->Hacks.Enabled) { HacksComp_SetFlying(&p->Hacks, !p->Hacks.Flying); return true; @@ -911,8 +911,7 @@ cc_bool LocalPlayer_HandleFly(void) { return false; } -cc_bool LocalPlayer_HandleNoclip(void) { - struct LocalPlayer* p = &LocalPlayer_Instance; +cc_bool LocalPlayer_HandleNoclip(struct LocalPlayer* p) { if (p->Hacks.CanNoclip && p->Hacks.Enabled) { if (p->Hacks.WOMStyleHacks) return true; /* don't handle this here */ if (p->Hacks.Noclip) p->Base.Velocity.y = 0; @@ -926,8 +925,7 @@ cc_bool LocalPlayer_HandleNoclip(void) { return false; } -cc_bool LocalPlayer_HandleJump(void) { - struct LocalPlayer* p = &LocalPlayer_Instance; +cc_bool LocalPlayer_HandleJump(struct LocalPlayer* p) { struct HacksComp* hacks = &p->Hacks; struct PhysicsComp* physics = &p->Physics; int maxJumps; @@ -945,8 +943,7 @@ cc_bool LocalPlayer_HandleJump(void) { return false; } -cc_bool LocalPlayer_CheckCanZoom(void) { - struct LocalPlayer* p = &LocalPlayer_Instance; +cc_bool LocalPlayer_CheckCanZoom(struct LocalPlayer* p) { if (p->Hacks.CanFly) return true; if (!p->_warnedZoom) { @@ -956,42 +953,46 @@ cc_bool LocalPlayer_CheckCanZoom(void) { return false; } -void LocalPlayer_MoveToSpawn(void) { - struct LocalPlayer* p = &LocalPlayer_Instance; - struct LocationUpdate update; - - update.flags = LU_HAS_POS | LU_HAS_YAW | LU_HAS_PITCH; - update.pos = p->Spawn; - update.yaw = p->SpawnYaw; - update.pitch = p->SpawnPitch; - - p->Base.VTABLE->SetLocation(&p->Base, &update); +void LocalPlayers_MoveToSpawn(struct LocationUpdate* update) { + struct LocalPlayer* p; + int i; + + for (i = 0; i < Game_NumLocalPlayers; i++) + { + p = &LocalPlayer_Instances[i]; + p->Base.VTABLE->SetLocation(&p->Base, update); + + if (update->flags & LU_HAS_POS) p->Spawn = update->pos; + if (update->flags & LU_HAS_YAW) p->SpawnYaw = update->yaw; + if (update->flags & LU_HAS_PITCH) p->SpawnPitch = update->pitch; + } + /* TODO: This needs to be before new map... */ - Camera.CurrentPos = Camera.Active->GetPosition(0.0f); + Camera.CurrentPos = Camera.Active->GetPosition(Entities.CurPlayer, 0.0f); } -void LocalPlayer_CalcDefaultSpawn(void) { - struct LocalPlayer* p = &LocalPlayer_Instance; +void LocalPlayer_CalcDefaultSpawn(struct LocalPlayer* p, struct LocationUpdate* update) { float x = (World.Width / 2) + 0.5f; float z = (World.Length / 2) + 0.5f; - p->Spawn = Respawn_FindSpawnPosition(x, z, p->Base.Size); - p->SpawnYaw = 0.0f; - p->SpawnPitch = 0.0f; + update->flags = LU_HAS_POS | LU_HAS_YAW | LU_HAS_PITCH; + update->pos = Respawn_FindSpawnPosition(x, z, p->Base.Size); + update->yaw = 0.0f; + update->pitch = 0.0f; } /*########################################################################################################################* *-------------------------------------------------------NetPlayer---------------------------------------------------------* *#########################################################################################################################*/ -struct NetPlayer NetPlayers_List[ENTITIES_SELF_ID]; +struct NetPlayer NetPlayers_List[MAX_NET_PLAYERS]; static void NetPlayer_SetLocation(struct Entity* e, struct LocationUpdate* update) { struct NetPlayer* p = (struct NetPlayer*)e; NetInterpComp_SetLocation(&p->Interp, update, e); } -static void NetPlayer_Tick(struct Entity* e, double delta) { +static void NetPlayer_Tick(struct Entity* e, float delta) { struct NetPlayer* p = (struct NetPlayer*)e; NetInterpComp_AdvanceState(&p->Interp, e); @@ -999,7 +1000,7 @@ static void NetPlayer_Tick(struct Entity* e, double delta) { AnimatedComp_Update(e, e->prev.pos, e->next.pos, delta); } -static void NetPlayer_RenderModel(struct Entity* e, double deltaTime, float t) { +static void NetPlayer_RenderModel(struct Entity* e, float delta, float t) { Vec3_Lerp(&e->Position, &e->prev.pos, &e->next.pos, t); Entity_LerpAngles(e, t); @@ -1034,6 +1035,7 @@ void NetPlayer_Init(struct NetPlayer* p) { *---------------------------------------------------Entities component----------------------------------------------------* *#########################################################################################################################*/ static void Entities_Init(void) { + int i; Event_Register_(&GfxEvents.ContextLost, NULL, Entities_ContextLost); Event_Register_(&InputEvents.Down, NULL, LocalPlayer_InputDown); Event_Register_(&InputEvents.Up, NULL, LocalPlayer_InputUp); @@ -1046,8 +1048,12 @@ static void Entities_Init(void) { ShadowMode_Names, Array_Elems(ShadowMode_Names)); if (Game_ClassicMode) Entities.ShadowsMode = SHADOW_MODE_NONE; - Entities.List[ENTITIES_SELF_ID] = &LocalPlayer_Instance.Base; - LocalPlayer_Init(); + for (i = 0; i < Game_NumLocalPlayers; i++) + { + LocalPlayer_Init(&LocalPlayer_Instances[i], i); + Entities.List[MAX_NET_PLAYERS + i] = &LocalPlayer_Instances[i].Base; + } + Entities.CurPlayer = &LocalPlayer_Instances[0]; } static void Entities_Free(void) { @@ -1061,6 +1067,6 @@ static void Entities_Free(void) { struct IGameComponent Entities_Component = { Entities_Init, /* Init */ Entities_Free, /* Free */ - LocalPlayer_Reset, /* Reset */ - LocalPlayer_OnNewMap, /* OnNewMap */ + LocalPlayers_Reset, /* Reset */ + LocalPlayers_OnNewMap, /* OnNewMap */ }; diff --git a/src/Entity.h b/src/Entity.h index 18fcbd2..295d168 100644 --- a/src/Entity.h +++ b/src/Entity.h @@ -11,12 +11,21 @@ struct Model; struct IGameComponent; struct ScheduledTask; +struct LocalPlayer; + extern struct IGameComponent TabList_Component; extern struct IGameComponent Entities_Component; +#ifdef CC_BUILD_SPLITSCREEN +#define MAX_LOCAL_PLAYERS 4 +#else +#define MAX_LOCAL_PLAYERS 1 +#endif +#define MAX_NET_PLAYERS 255 + /* Offset used to avoid floating point roundoff errors. */ #define ENTITY_ADJUSTMENT 0.001f -#define ENTITIES_MAX_COUNT 256 +#define ENTITIES_MAX_COUNT (MAX_NET_PLAYERS + MAX_LOCAL_PLAYERS) #define ENTITIES_SELF_ID 255 enum NameMode { @@ -66,11 +75,11 @@ struct EntityLocation { Vec3 pos; float pitch, yaw, rotX, rotY, rotZ; }; struct Entity; struct EntityVTABLE { - void (*Tick)(struct Entity* e, double delta); + void (*Tick)(struct Entity* e, float delta); void (*Despawn)(struct Entity* e); void (*SetLocation)(struct Entity* e, struct LocationUpdate* update); PackedCol (*GetCol)(struct Entity* e); - void (*RenderModel)(struct Entity* e, double deltaTime, float t); + void (*RenderModel)(struct Entity* e, float delta, float t); cc_bool (*ShouldRenderName)(struct Entity* e); }; @@ -162,16 +171,18 @@ void Entity_LerpAngles(struct Entity* e, float t); CC_VAR extern struct _EntitiesData { struct Entity* List[ENTITIES_MAX_COUNT]; cc_uint8 NamesMode, ShadowsMode; + struct LocalPlayer* CurPlayer; } Entities; /* Ticks all entities */ void Entities_Tick(struct ScheduledTask* task); /* Renders all entities */ -void Entities_RenderModels(double delta, float t); +void Entities_RenderModels(float delta, float t); /* Removes the given entity, raising EntityEvents.Removed event */ void Entities_Remove(EntityID id); /* Gets the ID of the closest entity to the given entity */ -EntityID Entities_GetClosest(struct Entity* src); +/* Returns -1 if there is no other entity nearby */ +int Entities_GetClosest(struct Entity* src); #define TABLIST_MAX_NAMES 256 /* Data for all entries in tab list */ @@ -212,13 +223,14 @@ struct NetPlayer { struct NetInterpComp Interp; }; CC_API void NetPlayer_Init(struct NetPlayer* player); -extern struct NetPlayer NetPlayers_List[ENTITIES_SELF_ID]; +extern struct NetPlayer NetPlayers_List[MAX_NET_PLAYERS]; struct LocalPlayerInput; struct LocalPlayerInput { - void (*GetMovement)(float* xMoving, float* zMoving); + void (*GetMovement)(struct LocalPlayer* p, float* xMoving, float* zMoving); struct LocalPlayerInput* next; }; +void LocalPlayerInput_Add(struct LocalPlayerInput* source); /* Represents the user/player's own entity. */ struct LocalPlayer { @@ -231,23 +243,23 @@ struct LocalPlayer { struct CollisionsComp Collisions; struct PhysicsComp Physics; cc_bool _warnedRespawn, _warnedFly, _warnedNoclip, _warnedZoom; - struct LocalPlayerInput input; + cc_uint8 index; }; -extern struct LocalPlayer LocalPlayer_Instance; +extern struct LocalPlayer LocalPlayer_Instances[MAX_LOCAL_PLAYERS]; /* Returns how high (in blocks) the player can jump. */ -float LocalPlayer_JumpHeight(void); +float LocalPlayer_JumpHeight(struct LocalPlayer* p); /* Interpolates current position and orientation between Interp.Prev and Interp.Next */ -void LocalPlayer_SetInterpPosition(float t); -void LocalPlayer_ResetJumpVelocity(void); -cc_bool LocalPlayer_CheckCanZoom(void); +void LocalPlayer_SetInterpPosition(struct LocalPlayer* p, float t); +void LocalPlayer_ResetJumpVelocity(struct LocalPlayer* p); +cc_bool LocalPlayer_CheckCanZoom(struct LocalPlayer* p); /* Moves local player back to spawn point. */ -void LocalPlayer_MoveToSpawn(void); -void LocalPlayer_CalcDefaultSpawn(void); - -cc_bool LocalPlayer_HandleRespawn(void); -cc_bool LocalPlayer_HandleSetSpawn(void); -cc_bool LocalPlayer_HandleFly(void); -cc_bool LocalPlayer_HandleNoclip(void); -cc_bool LocalPlayer_HandleJump(void); +void LocalPlayers_MoveToSpawn(struct LocationUpdate* update); +void LocalPlayer_CalcDefaultSpawn(struct LocalPlayer* p, struct LocationUpdate* update); + +cc_bool LocalPlayer_HandleRespawn(struct LocalPlayer* p); +cc_bool LocalPlayer_HandleSetSpawn(struct LocalPlayer* p); +cc_bool LocalPlayer_HandleFly(struct LocalPlayer* p); +cc_bool LocalPlayer_HandleNoclip(struct LocalPlayer* p); +cc_bool LocalPlayer_HandleJump(struct LocalPlayer* p); #endif diff --git a/src/EntityComponents.c b/src/EntityComponents.c index 4d222ff..9627133 100644 --- a/src/EntityComponents.c +++ b/src/EntityComponents.c @@ -57,7 +57,7 @@ void AnimatedComp_Init(struct AnimatedComp* anim) { anim->BobStrength = 1.0f; anim->BobStrengthO = 1.0f; anim->BobStrengthN = 1.0f; } -void AnimatedComp_Update(struct Entity* e, Vec3 oldPos, Vec3 newPos, double delta) { +void AnimatedComp_Update(struct Entity* e, Vec3 oldPos, Vec3 newPos, float delta) { struct AnimatedComp* anim = &e->Anim; float dx = newPos.x - oldPos.x; float dz = newPos.z - oldPos.z; @@ -71,9 +71,9 @@ void AnimatedComp_Update(struct Entity* e, Vec3 oldPos, Vec3 newPos, double delt if (distance > 0.05f) { walkDelta = distance * 2 * (float)(20 * delta); anim->WalkTimeN += walkDelta; - anim->SwingN += (float)delta * 3; + anim->SwingN += delta * 3; } else { - anim->SwingN -= (float)delta * 3; + anim->SwingN -= delta * 3; } Math_Clamp(anim->SwingN, 0.0f, 1.0f); @@ -120,8 +120,7 @@ void TiltComp_Init(struct TiltComp* anim) { anim->VelTiltStrengthO = 1.0f; anim->VelTiltStrengthN = 1.0f; } -void TiltComp_Update(struct TiltComp* anim, double delta) { - struct LocalPlayer* p = &LocalPlayer_Instance; +void TiltComp_Update(struct LocalPlayer* p, struct TiltComp* anim, float delta) { int i; anim->VelTiltStrengthO = anim->VelTiltStrengthN; @@ -131,8 +130,7 @@ void TiltComp_Update(struct TiltComp* anim, double delta) { } } -void TiltComp_GetCurrent(struct TiltComp* anim, float t) { - struct LocalPlayer* p = &LocalPlayer_Instance; +void TiltComp_GetCurrent(struct LocalPlayer* p, struct TiltComp* anim, float t) { struct AnimatedComp* pAnim = &p->Base.Anim; anim->VelTiltStrength = Math_Lerp(anim->VelTiltStrengthO, anim->VelTiltStrengthN, t); @@ -427,8 +425,7 @@ void NetInterpComp_AdvanceState(struct NetInterpComp* interp, struct Entity* e) /*########################################################################################################################* *-----------------------------------------------LocalInterpolationComponent-----------------------------------------------* *#########################################################################################################################*/ -static void LocalInterpComp_SetPosition(struct LocationUpdate* update, int mode) { - struct Entity* e = &LocalPlayer_Instance.Base; +static void LocalInterpComp_SetPosition(struct Entity* e, struct LocationUpdate* update, int mode) { float yOffset; if (mode == LU_POS_ABSOLUTE_INSTANT || mode == LU_POS_ABSOLUTE_SMOOTH) { @@ -455,15 +452,14 @@ static void LocalInterpComp_Angle(float* prev, float* next, float value, cc_bool if (!interpolate) *prev = value; } -void LocalInterpComp_SetLocation(struct InterpComp* interp, struct LocationUpdate* update) { - struct Entity* e = &LocalPlayer_Instance.Base; +void LocalInterpComp_SetLocation(struct InterpComp* interp, struct LocationUpdate* update, struct Entity* e) { struct EntityLocation* prev = &e->prev; struct EntityLocation* next = &e->next; cc_uint8 flags = update->flags; cc_bool interpolate = flags & LU_ORI_INTERPOLATE; if (flags & LU_HAS_POS) { - LocalInterpComp_SetPosition(update, flags & LU_POS_MODEMASK); + LocalInterpComp_SetPosition(e, update, flags & LU_POS_MODEMASK); } if (flags & LU_HAS_PITCH) { LocalInterpComp_Angle(&prev->pitch, &next->pitch, update->pitch, interpolate); @@ -1013,7 +1009,7 @@ static double PhysicsComp_YPosAt(int t, float u) { double PhysicsComp_CalcMaxHeight(float u) { /* equation below comes from solving diff(x(t, u))= 0 */ /* We only work in discrete timesteps, so test both rounded up and down */ - double t = 49.49831645 * Math_Log(0.247483075 * u + 0.9899323); + double t = 34.30961849 * Math_Log2(0.247483075 * u + 0.9899323); double value_floor = PhysicsComp_YPosAt((int)t, u); double value_ceil = PhysicsComp_YPosAt((int)t + 1, u); return max(value_floor, value_ceil); @@ -1134,18 +1130,17 @@ static cc_bool SoundComp_ShouldPlay(struct LocalPlayer* p, Vec3 soundPos) { /* have our legs just crossed over the '0' point? */ if (Camera.Active->isThirdPerson) { - oldLegRot = (float)Math_Cos(p->Base.Anim.WalkTimeO); - newLegRot = (float)Math_Cos(p->Base.Anim.WalkTimeN); + oldLegRot = Math_CosF(p->Base.Anim.WalkTimeO); + newLegRot = Math_CosF(p->Base.Anim.WalkTimeN); } else { - oldLegRot = (float)Math_Sin(p->Base.Anim.WalkTimeO); - newLegRot = (float)Math_Sin(p->Base.Anim.WalkTimeN); + oldLegRot = Math_SinF(p->Base.Anim.WalkTimeO); + newLegRot = Math_SinF(p->Base.Anim.WalkTimeN); } return Math_Sign(oldLegRot) != Math_Sign(newLegRot); } -void SoundComp_Tick(cc_bool wasOnGround) { - struct LocalPlayer* p = &LocalPlayer_Instance; - Vec3 soundPos = p->Base.next.pos; +void SoundComp_Tick(struct LocalPlayer* p, cc_bool wasOnGround) { + Vec3 soundPos = p->Base.next.pos; SoundComp_GetSound(p); if (!sounds_anyNonAir) soundPos = Vec3_BigPos(); diff --git a/src/EntityComponents.h b/src/EntityComponents.h index f4cb711..1fd394c 100644 --- a/src/EntityComponents.h +++ b/src/EntityComponents.h @@ -8,6 +8,7 @@ struct Entity; struct LocationUpdate; +struct LocalPlayer; /* Entity component that performs model animation depending on movement speed and time */ struct AnimatedComp { @@ -20,7 +21,7 @@ struct AnimatedComp { }; void AnimatedComp_Init(struct AnimatedComp* anim); -void AnimatedComp_Update(struct Entity* entity, Vec3 oldPos, Vec3 newPos, double delta); +void AnimatedComp_Update(struct Entity* entity, Vec3 oldPos, Vec3 newPos, float delta); void AnimatedComp_GetCurrent(struct Entity* entity, float t); /* Entity component that performs tilt animation depending on movement speed and time */ @@ -30,8 +31,8 @@ struct TiltComp { }; void TiltComp_Init(struct TiltComp* anim); -void TiltComp_Update(struct TiltComp* anim, double delta); -void TiltComp_GetCurrent(struct TiltComp* anim, float t); +void TiltComp_Update(struct LocalPlayer* p, struct TiltComp* anim, float delta); +void TiltComp_GetCurrent(struct LocalPlayer* p, struct TiltComp* anim, float t); /* Entity component that performs management of hack states */ struct HacksComp { @@ -81,7 +82,7 @@ float HacksComp_CalcSpeedFactor(struct HacksComp* hacks, cc_bool canSpeed); /* Base entity component that performs interpolation of position and orientation */ struct InterpComp { InterpComp_Layout }; -void LocalInterpComp_SetLocation(struct InterpComp* interp, struct LocationUpdate* update); +void LocalInterpComp_SetLocation(struct InterpComp* interp, struct LocationUpdate* update, struct Entity* e); void LocalInterpComp_AdvanceState(struct InterpComp* interp, struct Entity* e); /* Represents a network orientation state */ @@ -130,5 +131,5 @@ double PhysicsComp_CalcMaxHeight(float u); void PhysicsComp_DoEntityPush(struct Entity* entity); /* Entity component that plays block step sounds */ -void SoundComp_Tick(cc_bool wasOnGround); +void SoundComp_Tick(struct LocalPlayer* p, cc_bool wasOnGround); #endif diff --git a/src/EntityRenderers.c b/src/EntityRenderers.c index 8af83a1..f673a89 100644 --- a/src/EntityRenderers.c +++ b/src/EntityRenderers.c @@ -19,7 +19,7 @@ static cc_bool shadows_boundTex; static GfxResourceID shadows_VB; static GfxResourceID shadows_tex; static float shadow_radius, shadow_uvScale; -struct ShadowData { float y; BlockID Block; cc_uint8 A; }; +struct ShadowData { float y; BlockID block; cc_uint8 alpha; }; /* Circle shadows extend at most 4 blocks vertically */ #define SHADOW_MAX_RANGE 4 @@ -54,7 +54,7 @@ static void EntityShadow_DrawCoords(struct VertexTextured** vertices, struct Ent z2 = min(z2, cen.z + shadow_radius); v2 = v2 <= 1.0f ? v2 : 1.0f; v = *vertices; - col = PackedCol_Make(255, 255, 255, data->A); + col = PackedCol_Make(255, 255, 255, data->alpha); v->x = x1; v->y = data->y; v->z = z1; v->Col = col; v->U = u1; v->V = v1; v++; v->x = x2; v->y = data->y; v->z = z1; v->Col = col; v->U = u2; v->V = v1; v++; @@ -83,13 +83,13 @@ static void EntityShadow_DrawCircle(struct VertexTextured** vertices, struct Ent Vec3 min, max, nMin, nMax; int i; x = (float)Math_Floor(x); z = (float)Math_Floor(z); - min = Blocks.MinBB[data[0].Block]; max = Blocks.MaxBB[data[0].Block]; + min = Blocks.MinBB[data[0].block]; max = Blocks.MaxBB[data[0].block]; EntityShadow_DrawCoords(vertices, e, &data[0], x + min.x, z + min.z, x + max.x, z + max.z); for (i = 1; i < 4; i++) { - if (data[i].Block == BLOCK_AIR) return; - nMin = Blocks.MinBB[data[i].Block]; nMax = Blocks.MaxBB[data[i].Block]; + if (data[i].block == BLOCK_AIR) return; + nMin = Blocks.MinBB[data[i].block]; nMax = Blocks.MaxBB[data[i].block]; EntityShadow_DrawCoords(vertices, e, &data[i], x + min.x, z + nMin.z, x + max.x, z + min.z); EntityShadow_DrawCoords(vertices, e, &data[i], x + min.x, z + max.z, x + max.x, z + nMax.z); @@ -103,11 +103,12 @@ static void EntityShadow_DrawCircle(struct VertexTextured** vertices, struct Ent static void EntityShadow_CalcAlpha(float playerY, struct ShadowData* data) { float height = playerY - data->y; if (height <= 6.0f) { - data->A = (cc_uint8)(160 - 160 * height / 6.0f); - data->y += 1.0f / 64.0f; return; + data->alpha = (cc_uint8)(160 - 160 * height / 6.0f); + data->y += 1.0f / 64.0f; + return; } - data->A = 0; + data->alpha = 0; if (height <= 16.0f) data->y += 1.0f / 64.0f; else if (height <= 32.0f) data->y += 1.0f / 16.0f; else if (height <= 96.0f) data->y += 1.0f / 8.0f; @@ -144,7 +145,7 @@ static cc_bool EntityShadow_GetBlocks(struct Entity* e, int x, int y, int z, str topY = y + Blocks.MaxBB[block].y; if (topY >= posY + 0.01f) continue; - cur->Block = block; cur->y = topY; + cur->block = block; cur->y = topY; EntityShadow_CalcAlpha(posY, cur); i++; cur++; @@ -154,7 +155,7 @@ static cc_bool EntityShadow_GetBlocks(struct Entity* e, int x, int y, int z, str } if (i < 4) { - cur->Block = Env.EdgeBlock; cur->y = 0.0f; + cur->block = Env.EdgeBlock; cur->y = 0.0f; EntityShadow_CalcAlpha(posY, cur); i++; cur++; } @@ -188,16 +189,16 @@ static void EntityShadow_Draw(struct Entity* e) { x1 = Math_Floor(pos.x - shadow_radius); z1 = Math_Floor(pos.z - shadow_radius); x2 = Math_Floor(pos.x + shadow_radius); z2 = Math_Floor(pos.z + shadow_radius); - if (EntityShadow_GetBlocks(e, x1, y, z1, data) && data[0].A > 0) { + if (EntityShadow_GetBlocks(e, x1, y, z1, data) && data[0].alpha > 0) { EntityShadow_DrawCircle(&ptr, e, data, (float)x1, (float)z1); } - if (x1 != x2 && EntityShadow_GetBlocks(e, x2, y, z1, data) && data[0].A > 0) { + if (x1 != x2 && EntityShadow_GetBlocks(e, x2, y, z1, data) && data[0].alpha > 0) { EntityShadow_DrawCircle(&ptr, e, data, (float)x2, (float)z1); } - if (z1 != z2 && EntityShadow_GetBlocks(e, x1, y, z2, data) && data[0].A > 0) { + if (z1 != z2 && EntityShadow_GetBlocks(e, x1, y, z2, data) && data[0].alpha > 0) { EntityShadow_DrawCircle(&ptr, e, data, (float)x1, (float)z2); } - if (x1 != x2 && z1 != z2 && EntityShadow_GetBlocks(e, x2, y, z2, data) && data[0].A > 0) { + if (x1 != x2 && z1 != z2 && EntityShadow_GetBlocks(e, x2, y, z2, data) && data[0].alpha > 0) { EntityShadow_DrawCircle(&ptr, e, data, (float)x2, (float)z2); } } @@ -242,6 +243,7 @@ static void EntityShadows_MakeTexture(void) { } void EntityShadows_Render(void) { + struct Entity* e; int i; if (Entities.ShadowsMode == SHADOW_MODE_NONE) return; @@ -256,13 +258,14 @@ void EntityShadows_Render(void) { Gfx_SetAlphaBlending(true); Gfx_SetVertexFormat(VERTEX_FORMAT_TEXTURED); - EntityShadow_Draw(Entities.List[ENTITIES_SELF_ID]); + EntityShadow_Draw(&Entities.CurPlayer->Base); if (Entities.ShadowsMode == SHADOW_MODE_CIRCLE_ALL) { - for (i = 0; i < ENTITIES_SELF_ID; i++) + for (i = 0; i < ENTITIES_MAX_COUNT; i++) { - if (!Entities.List[i] || !Entities.List[i]->ShouldRender) continue; - EntityShadow_Draw(Entities.List[i]); + e = Entities.List[i]; + if (!e || !e->ShouldRender || e == &Entities.CurPlayer->Base) continue; + EntityShadow_Draw(e); } } @@ -348,7 +351,7 @@ static void DrawName(struct Entity* e) { scale = scale > 1.0f ? (1.0f/70.0f) : (scale/70.0f); size.x = e->NameTex.width * scale; size.y = e->NameTex.height * scale; - if (Entities.NamesMode == NAME_MODE_ALL_UNSCALED && LocalPlayer_Instance.Hacks.CanSeeAllNames) { + if (Entities.NamesMode == NAME_MODE_ALL_UNSCALED && Entities.CurPlayer->Hacks.CanSeeAllNames) { Matrix_Mul(&mat, &Gfx.View, &Gfx.Projection); /* TODO: This mul is slow, avoid it */ /* Get W component of transformed position */ scale = pos.x * mat.row1.w + pos.y * mat.row2.w + pos.z * mat.row3.w + mat.row4.w; @@ -373,10 +376,10 @@ void EntityNames_Delete(struct Entity* e) { /*########################################################################################################################* *-----------------------------------------------------Names rendering-----------------------------------------------------* *#########################################################################################################################*/ -static EntityID closestEntityId; +static int closestEntityId; void EntityNames_Render(void) { - struct LocalPlayer* p = &LocalPlayer_Instance; + struct LocalPlayer* p = Entities.CurPlayer; cc_bool hadFog; int i; @@ -391,9 +394,7 @@ void EntityNames_Render(void) { for (i = 0; i < ENTITIES_MAX_COUNT; i++) { if (!Entities.List[i]) continue; - if (i != closestEntityId || i == ENTITIES_SELF_ID) { - DrawName(Entities.List[i]); - } + if (i != closestEntityId) DrawName(Entities.List[i]); } Gfx_SetAlphaTest(false); @@ -401,7 +402,7 @@ void EntityNames_Render(void) { } void EntityNames_RenderHovered(void) { - struct LocalPlayer* p = &LocalPlayer_Instance; + struct LocalPlayer* p = Entities.CurPlayer; cc_bool allNames, hadFog; int i; @@ -417,7 +418,7 @@ void EntityNames_RenderHovered(void) { for (i = 0; i < ENTITIES_MAX_COUNT; i++) { if (!Entities.List[i]) continue; - if ((i == closestEntityId || allNames) && i != ENTITIES_SELF_ID) { + if ((i == closestEntityId || allNames) && Entities.List[i] != &p->Base) { DrawName(Entities.List[i]); } } diff --git a/src/EnvRenderer.c b/src/EnvRenderer.c index 5493503..74b0f13 100644 --- a/src/EnvRenderer.c +++ b/src/EnvRenderer.c @@ -18,15 +18,15 @@ #include "Camera.h" #include "Particle.h" #include "Options.h" +#include "Entity.h" cc_bool EnvRenderer_Legacy, EnvRenderer_Minimal; static float CalcBlendFactor(float x) { - /* return -0.05 + 0.22 * (Math_Log(x) * 0.25f); */ - double blend = -0.13 + 0.28 * (Math_Log(x) * 0.25); - if (blend < 0.0) blend = 0.0; - if (blend > 1.0) blend = 1.0; - return (float)blend; + float blend = -0.13f + 0.28f * ((float)Math_Log2(x) * 0.17329f); + if (blend < 0.0f) blend = 0.0f; + if (blend > 1.0f) blend = 1.0f; + return blend; } #define EnvRenderer_AxisSize() (EnvRenderer_Legacy ? 128 : 2048) @@ -40,21 +40,25 @@ static int CalcNumVertices(int axis1Len, int axis2Len) { /*########################################################################################################################* *------------------------------------------------------------Fog----------------------------------------------------------* *#########################################################################################################################*/ -static void CalcFog(float* density, PackedCol* color) { +static cc_bool CameraInsideBlock(BlockID block, IVec3* coords) { + struct AABB blockBB; Vec3 pos; + IVec3_ToVec3(&pos, coords); /* pos = coords; */ + + Vec3_Add(&blockBB.Min, &pos, &Blocks.MinBB[block]); + Vec3_Add(&blockBB.Max, &pos, &Blocks.MaxBB[block]); + return AABB_ContainsPoint(&blockBB, &Camera.CurrentPos); +} + +static void CalcFog(float* density, PackedCol* color) { IVec3 coords; BlockID block; - struct AABB blockBB; float blend; IVec3_Floor(&coords, &Camera.CurrentPos); /* coords = floor(camera_pos); */ - IVec3_ToVec3(&pos, &coords); /* pos = coords; */ - block = World_SafeGetBlock(coords.x, coords.y, coords.z); - Vec3_Add(&blockBB.Min, &pos, &Blocks.MinBB[block]); - Vec3_Add(&blockBB.Max, &pos, &Blocks.MaxBB[block]); - if (AABB_ContainsPoint(&blockBB, &Camera.CurrentPos) && Blocks.FogDensity[block]) { + if (Blocks.FogDensity[block] && CameraInsideBlock(block, &coords)) { *density = Blocks.FogDensity[block]; *color = Blocks.FogCol[block]; } else { @@ -322,7 +326,8 @@ void EnvRenderer_RenderSkybox(void) { /* Rotate around camera */ pos = Camera.CurrentPos; Vec3_Set(Camera.CurrentPos, 0,0,0); - Camera.Active->GetView(&view); Matrix_MulBy(&m, &view); + Camera.Active->GetView(Entities.CurPlayer, &view); + Matrix_MulBy(&m, &view); Camera.CurrentPos = pos; Gfx_LoadMatrix(MATRIX_VIEW, &m); @@ -338,7 +343,7 @@ void EnvRenderer_RenderSkybox(void) { *#########################################################################################################################*/ cc_int16* Weather_Heightmap; static GfxResourceID rain_tex, snow_tex, weather_vb; -static double weather_accumulator; +static float weather_accumulator; static IVec3 lastPos; #define WEATHER_EXTENT 4 @@ -429,7 +434,7 @@ static float CalcRainAlphaAt(float x) { struct RainCoord { int dx, dz; float y; }; static RNGState snowDirRng; -void EnvRenderer_RenderWeather(double deltaTime) { +void EnvRenderer_RenderWeather(float delta) { struct RainCoord coords[WEATHER_RANGE * WEATHER_RANGE]; int i, weather, numCoords = 0; struct VertexTextured* v; @@ -460,8 +465,8 @@ void EnvRenderer_RenderWeather(double deltaTime) { pos.y += 64; pos.y = max(World.Height, pos.y); - weather_accumulator += deltaTime; - particles = weather == WEATHER_RAINY && (weather_accumulator >= 0.25 || moved); + weather_accumulator += delta; + particles = weather == WEATHER_RAINY && (weather_accumulator >= 0.25f || moved); for (dx = -WEATHER_EXTENT; dx <= WEATHER_EXTENT; dx++) { for (dz = -WEATHER_EXTENT; dz <= WEATHER_EXTENT; dz++) { diff --git a/src/EnvRenderer.h b/src/EnvRenderer.h index 4be6366..b273441 100644 --- a/src/EnvRenderer.h +++ b/src/EnvRenderer.h @@ -31,7 +31,7 @@ extern cc_int16* Weather_Heightmap; /* Called when a block is changed to update internal weather state. */ void EnvRenderer_OnBlockChanged(int x, int y, int z, BlockID oldBlock, BlockID newBlock); /* Renders rainfall/snowfall weather. */ -void EnvRenderer_RenderWeather(double deltaTime); +void EnvRenderer_RenderWeather(float delta); /* Whether large quads are broken down into smaller quads. */ /* This makes them have less rendering issues when using vertex fog. */ diff --git a/src/Event.c b/src/Event.c index ab8480a..91cca9c 100644 --- a/src/Event.c +++ b/src/Event.c @@ -178,10 +178,10 @@ void Event_RaiseRawMove(struct Event_RawMove* handlers, float xDelta, float yDel } } -void Event_RaisePadAxis(struct Event_PadAxis* handlers, int axis, float x, float y) { +void Event_RaisePadAxis(struct Event_PadAxis* handlers, int port, int axis, float x, float y) { int i; for (i = 0; i < handlers->Count; i++) { - handlers->Handlers[i](handlers->Objs[i], axis, x, y); + handlers->Handlers[i](handlers->Objs[i], port, axis, x, y); } } diff --git a/src/Event.h b/src/Event.h index ed7dcb0..398a6df 100644 --- a/src/Event.h +++ b/src/Event.h @@ -63,7 +63,7 @@ struct Event_RawMove { void* Objs[EVENT_MAX_CALLBACKS]; int Count; }; -typedef void (*Event_PadAxis_Callback)(void* obj, int axis, float x, float y); +typedef void (*Event_PadAxis_Callback)(void* obj, int port, int axis, float x, float y); struct Event_PadAxis { Event_PadAxis_Callback Handlers[EVENT_MAX_CALLBACKS]; void* Objs[EVENT_MAX_CALLBACKS]; int Count; @@ -108,7 +108,7 @@ void Event_RaiseString(struct Event_String* handlers, const cc_string* str); /* Calls all registered callbacks for an event which has raw pointer movement arguments. */ void Event_RaiseRawMove(struct Event_RawMove* handlers, float xDelta, float yDelta); /* Calls all registered callbacks for an event which has pad axis arguments. */ -void Event_RaisePadAxis(struct Event_PadAxis* handlers, int axis, float x, float y); +void Event_RaisePadAxis(struct Event_PadAxis* handlers, int port, int axis, float x, float y); /* Calls all registered callbacks for an event which has a channel and a 64 byte data argument. */ void Event_RaisePluginMessage(struct Event_PluginMessage* handlers, cc_uint8 channel, cc_uint8* data); diff --git a/src/ExtMath.c b/src/ExtMath.c index c97a881..6baa884 100644 --- a/src/ExtMath.c +++ b/src/ExtMath.c @@ -148,7 +148,6 @@ float Random_Float(RNGState* seed) { *--------------------------------------------------Transcendental functions-----------------------------------------------* *#########################################################################################################################*/ static const double SQRT2 = 1.4142135623730950488016887242096980785696718753769; -static const double LOGE2 = 0.6931471805599453094172321214581765680755001343602; #ifdef CC_BUILD_DREAMCAST #include @@ -162,7 +161,7 @@ double Math_Cos(double x) { return cos(x); } double Math_Exp2(double x) { return exp2(x); } double Math_Log2(double x) { return log2(x); } -double Math_Atan2(double x, double y) { return atan2(y, x); } +float Math_Atan2f(float x, float y) { return atan2f(y, x); } #else /***** Caleb's Math functions *****/ @@ -297,149 +296,6 @@ double Math_Cos(double x) { return SinStage3(x_div_pi_shifted - Floord(x_div_pi_shifted)); } -/************** - * Math_Atan2 * - **************/ - -/* Calculates the 5th degree polynomial ARCTN 4903 listed in the book's - * appendix. - * - * Associated math function: arctan(x) - * Allowed input range: [0, tan(pi/32)] - * Precision: 16.52 - */ -static double AtanStage1(double x) { - const double A[] = { - .99999999999969557, - -.3333333333318, - .1999999997276, - -.14285702288, - .11108719478, - -.8870580341e-1, - }; - - double P = A[5]; - double x_2 = x * x; - int i; - - for (i = 4; i >= 0; i--) { - P *= x_2; - P += A[i]; - } - P *= x; - return P; -} - -/* This function finds out in which partition the non-negative real number x - * resides out of 8 partitions, which are precomputed. It then uses the - * following law: - * - * t = x_i^{-1} - (x_i^{-2} + 1)/(x_i^{-1} + x) - * arctan(x) = arctan(x_i) + arctan(t) - * - * where x_i = tan((2i - 2)*pi/32) and i is the partition number. The value of t - * is guaranteed to be between [-tan(pi/32), tan(pi/32)]. - * - * Associated math function: arctan(x) - * Allowed input range: [0, infinity] - */ -static double AtanStage2(double x) { - const double X_i[] = { - 0.0, - 0.0984914033571642477671304050090839155018329620361328125, - 0.3033466836073424044428747947677038609981536865234375, - 0.53451113595079158269385288804187439382076263427734375, - 0.82067879082866024287312711749109439551830291748046875, - 1.218503525587976366040265929768793284893035888671875, - 1.8708684117893887854933154812897555530071258544921875, - 3.29655820893832096629694206058047711849212646484375, - (float)(1e+300 * 1e+300) /* Infinity */ - }; - - const double div_x_i[] = { - 0, - 0, - 5.02733949212584807497705696732737123966217041015625, - 2.41421356237309492343001693370752036571502685546875, - 1.496605762665489169904731170390732586383819580078125, - 1.0000000000000002220446049250313080847263336181640625, - 0.66817863791929898997778991542872972786426544189453125, - 0.414213562373095089963470627481001429259777069091796875, - 0.1989123673796580893391450217677629552781581878662109375, - }; - - const double div_x_i_2_plus_1[] = { - 0, - 0, - 26.2741423690881816810360760428011417388916015625, - 6.8284271247461898468600338674150407314300537109375, - 3.23982880884355051165357508580200374126434326171875, - 2.000000000000000444089209850062616169452667236328125, - 1.446462692171689656817079594475217163562774658203125, - 1.1715728752538099310953612075536511838436126708984375, - 1.0395661298965801488947136022034101188182830810546875, - }; - - int L = 0; - int R = 8; - double t; - - while (R - L > 1) { - int m = (L + R) / 2; - if (X_i[m] <= x) - L = m; - else if (X_i[m] > x) - R = m; - } - - if (R <= 1) - return AtanStage1(x); - - t = div_x_i[R] - div_x_i_2_plus_1[R] / (div_x_i[R] + x); - if (t >= 0) - return (2 * R - 2) * PI / 32.0 + AtanStage1(t); - - return (2 * R - 2) * PI / 32.0 - AtanStage1(-t); -} - -/* Uses the property arctan(x) = -arctan(-x). - * - * Associated math function: arctan(x) - * Allowed input range: anything - */ -static double Atan(double x) { - if (x == DBL_NAN) - return DBL_NAN; - if (x == NEG_INF) - return -PI / 2.0; - if (x == POS_INF) - return PI / 2.0; - if (x >= 0) - return AtanStage2(x); - return -AtanStage2(-x); -} - -/* Implements the function atan2 using Atan. - * - * Associated math function: atan2(y, x) - * Allowed input range: anything - */ -double Math_Atan2(double x, double y) { - if (x > 0) - return Atan(y / x); - if (x < 0) { - if (y >= 0) - return Atan(y / x) + PI; - return Atan(y / x) - PI; - } - - /* x = 0 case */ - if (y > 0) return PI / 2.0; - if (y < 0) return -PI / 2.0; - - return DBL_NAN; -} - /************ * Math_Exp * ************/ @@ -590,14 +446,26 @@ double Math_Log2(double x) { return exponent + Log2Stage1(doi.d); } -#endif -/* Uses the property that - * log_e(x) = log_2(x) * log_e(2). - * - * Associated math function: log_e(x) - * Allowed input range: anything - */ -double Math_Log(double x) { - return Math_Log2(x) * LOGE2; +// Approximation of atan2f using the Remez algorithm +// https://math.stackexchange.com/a/1105038 +float Math_Atan2f(float x, float y) { + if (x == 0) { + if (y > 0) return PI / 2.0f; + if (y < 0) return -PI / 2.0f; + return 0; /* Should probably be NaN */ + } + + float ax = Math_AbsF(x); + float ay = Math_AbsF(y); + + float a = (ax < ay) ? (ax / ay) : (ay / ax); + float s = a * a; + float r = ((-0.0464964749f * s + 0.15931422f) * s - 0.327622764f) * s * a + a; + + if (ay > ax) r = 1.57079637f - r; + if (x < 0) r = 3.14159274f - r; + if (y < 0) r = -r; + return r; } +#endif \ No newline at end of file diff --git a/src/ExtMath.h b/src/ExtMath.h index 4907a41..a4a689c 100644 --- a/src/ExtMath.h +++ b/src/ExtMath.h @@ -31,16 +31,15 @@ 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 atan2(y, x), intended primarily for angle calculation*/ +/* Note that accuracy is only up to around 4 decimal places */ +float Math_Atan2f(float x, float y); -/* Computes loge(x). Can also be used to approximate logy(x). */ -/* e.g. for log3(x), use: Math_Log(x)/log(3) */ -double Math_Log(double x); -/* Computes log2(x). Can also be used to approximate log2(x). */ -/* e.g. for log3(x), use: Math_Log2(x)/log2(3) */ +/* Computes log2(x). Can also be used to approximate log_y(x). */ +/* e.g. for log3(x), use: log2(x)/log2(3) */ double Math_Log2(double x); /* Computes 2^x. Can also be used to approximate y^x. */ -/* e.g. for 3^x, use: Math_Exp2(log2(3)*x) */ +/* e.g. for 3^x, use: exp2(log2(3)*x) */ double Math_Exp2(double x); int Math_Floor(float value); diff --git a/src/Formats.c b/src/Formats.c index 97d1ef6..6b948e3 100644 --- a/src/Formats.c +++ b/src/Formats.c @@ -18,7 +18,7 @@ #include "Utils.h" #ifdef CC_BUILD_FILESYSTEM -static cc_bool calcDefaultSpawn; +static struct LocationUpdate* spawn_point; static struct MapImporter* imp_head; static struct MapImporter* imp_tail; @@ -63,12 +63,13 @@ struct MapImporter* MapImporter_Find(const cc_string* path) { cc_result Map_LoadFrom(const cc_string* path) { cc_string relPath, fileName, fileExt; + struct LocationUpdate update = { 0 }; struct MapImporter* imp; struct Stream stream; cc_result res; Game_Reset(); - calcDefaultSpawn = false; + spawn_point = &update; res = Stream_OpenFile(&stream, path); if (res) { Logger_SysWarn2(res, "opening", path); return res; } @@ -84,8 +85,8 @@ cc_result Map_LoadFrom(const cc_string* path) { if (res) Logger_SysWarn2(res, "decoding", path); World_SetNewMap(World.Blocks, World.Width, World.Height, World.Length); - if (calcDefaultSpawn) LocalPlayer_CalcDefaultSpawn(); - LocalPlayer_MoveToSpawn(); + if (!spawn_point) LocalPlayer_CalcDefaultSpawn(Entities.CurPlayer, &update); + LocalPlayers_MoveToSpawn(&update); relPath = *path; Utils_UNSAFE_GetFilename(&relPath); @@ -184,7 +185,6 @@ static cc_result Lvl_Load(struct Stream* stream) { cc_result res; int i; - struct LocalPlayer* p = &LocalPlayer_Instance; struct Stream compStream; struct InflateState state; Inflate_MakeStream2(&compStream, &state, stream); @@ -197,11 +197,12 @@ static cc_result Lvl_Load(struct Stream* stream) { World.Length = Stream_GetU16_LE(&header[4]); World.Height = Stream_GetU16_LE(&header[6]); - p->Spawn.x = Stream_GetU16_LE(&header[8]); - p->Spawn.z = Stream_GetU16_LE(&header[10]); - p->Spawn.y = Stream_GetU16_LE(&header[12]); - p->SpawnYaw = Math_Packed2Deg(header[14]); - p->SpawnPitch = Math_Packed2Deg(header[15]); + spawn_point->flags = LU_HAS_POS | LU_HAS_YAW | LU_HAS_PITCH; + spawn_point->pos.x = Stream_GetU16_LE(&header[8]); + spawn_point->pos.z = Stream_GetU16_LE(&header[10]); + spawn_point->pos.y = Stream_GetU16_LE(&header[12]); + spawn_point->yaw = Math_Packed2Deg(header[14]); + spawn_point->pitch = Math_Packed2Deg(header[15]); /* (2) pervisit, perbuild permissions */ if ((res = Map_ReadBlocks(&compStream))) return res; @@ -271,7 +272,6 @@ static cc_result Fcm_Load(struct Stream* stream) { cc_result res; int i, count; - struct LocalPlayer* p = &LocalPlayer_Instance; struct Stream compStream; struct InflateState state; Inflate_MakeStream2(&compStream, &state, stream); @@ -284,11 +284,12 @@ static cc_result Fcm_Load(struct Stream* stream) { World.Height = Stream_GetU16_LE(&header[7]); World.Length = Stream_GetU16_LE(&header[9]); - p->Spawn.x = ((int)Stream_GetU32_LE(&header[11])) / 32.0f; - p->Spawn.y = ((int)Stream_GetU32_LE(&header[15])) / 32.0f; - p->Spawn.z = ((int)Stream_GetU32_LE(&header[19])) / 32.0f; - p->SpawnYaw = Math_Packed2Deg(header[23]); - p->SpawnPitch = Math_Packed2Deg(header[24]); + spawn_point->flags = LU_HAS_POS | LU_HAS_YAW | LU_HAS_PITCH; + spawn_point->pos.x = ((int)Stream_GetU32_LE(&header[11])) / 32.0f; + spawn_point->pos.y = ((int)Stream_GetU32_LE(&header[15])) / 32.0f; + spawn_point->pos.z = ((int)Stream_GetU32_LE(&header[19])) / 32.0f; + spawn_point->yaw = Math_Packed2Deg(header[23]); + spawn_point->pitch = Math_Packed2Deg(header[24]); /* header[25] (4) date modified */ /* header[29] (4) date created */ @@ -677,19 +678,18 @@ static void Cw_Callback_1(struct NbtTag* tag) { } static void Cw_Callback_2(struct NbtTag* tag) { - struct LocalPlayer* p = &LocalPlayer_Instance; - if (IsTag(tag->parent, "MapGenerator")) { if (IsTag(tag, "Seed")) { World.Seed = NbtTag_I32(tag); return; } return; } if (!IsTag(tag->parent, "Spawn")) return; + spawn_point->flags = LU_HAS_POS | LU_HAS_YAW | LU_HAS_PITCH; - if (IsTag(tag, "X")) { p->Spawn.x = NbtTag_I16(tag); return; } - if (IsTag(tag, "Y")) { p->Spawn.y = NbtTag_I16(tag); return; } - if (IsTag(tag, "Z")) { p->Spawn.z = NbtTag_I16(tag); return; } - if (IsTag(tag, "H")) { p->SpawnYaw = Math_Packed2Deg(NbtTag_U8(tag)); return; } - if (IsTag(tag, "P")) { p->SpawnPitch = Math_Packed2Deg(NbtTag_U8(tag)); return; } + if (IsTag(tag, "X")) { spawn_point->pos.x = NbtTag_I16(tag); return; } + if (IsTag(tag, "Y")) { spawn_point->pos.y = NbtTag_I16(tag); return; } + if (IsTag(tag, "Z")) { spawn_point->pos.z = NbtTag_I16(tag); return; } + if (IsTag(tag, "H")) { spawn_point->yaw = Math_Packed2Deg(NbtTag_U8(tag)); return; } + if (IsTag(tag, "P")) { spawn_point->pitch = Math_Packed2Deg(NbtTag_U8(tag)); return; } } static BlockID cw_curID; @@ -702,7 +702,7 @@ static PackedCol Cw_ParseColor(PackedCol defValue) { static void Cw_Callback_4(struct NbtTag* tag) { BlockID id = cw_curID; - struct LocalPlayer* p = &LocalPlayer_Instance; + struct LocalPlayer* p = &LocalPlayer_Instances[0]; if (!IsTag(tag->parent->parent, "CPE")) return; if (!IsTag(tag->parent->parent->parent, "Metadata")) return; @@ -1238,7 +1238,7 @@ Classic 0.15 to Classic 0.30: static void Dat_Format0And1(void) { /* Formats 0 and 1 don't store spawn position, so use default of map centre */ - calcDefaultSpawn = true; + spawn_point = NULL; /* Similiar env to how it appears in preclassic - 0.13 classic client */ Env.CloudsHeight = -30000; @@ -1286,7 +1286,6 @@ static cc_result Dat_LoadFormat1(struct Stream* stream) { } static cc_result Dat_LoadFormat2(struct Stream* stream) { - struct LocalPlayer* p = &LocalPlayer_Instance; struct JClassDesc classes[CLASS_CAPACITY]; cc_uint8 header[2 + 2]; struct JUnion obj; @@ -1326,11 +1325,14 @@ static cc_result Dat_LoadFormat2(struct Stream* stream) { World.Blocks = field->Value.Array.Ptr; World.Volume = field->Value.Array.Size; } else if (String_CaselessEqualsConst(&fieldName, "xSpawn")) { - p->Spawn.x = (float)Java_I32(field); + spawn_point->pos.x = (float)Java_I32(field); + spawn_point->flags = LU_HAS_POS; } else if (String_CaselessEqualsConst(&fieldName, "ySpawn")) { - p->Spawn.y = (float)Java_I32(field); + spawn_point->pos.y = (float)Java_I32(field); + spawn_point->flags = LU_HAS_POS; } else if (String_CaselessEqualsConst(&fieldName, "zSpawn")) { - p->Spawn.z = (float)Java_I32(field); + spawn_point->pos.z = (float)Java_I32(field); + spawn_point->flags = LU_HAS_POS; } } return 0; @@ -1447,11 +1449,12 @@ static void MCLevel_Callback_3(struct NbtTag* tag) { struct NbtTag* field = tag->parent; if (IsTag(group, "Map") && IsTag(field, "spawn")) { - cc_int16 value = NbtTag_I16(tag); + cc_int16 value = NbtTag_I16(tag); + spawn_point->flags = LU_HAS_POS; - if (tag->listIndex == 0) LocalPlayer_Instance.Spawn.x = value; - if (tag->listIndex == 1) LocalPlayer_Instance.Spawn.y = value - 1.0f; - if (tag->listIndex == 2) LocalPlayer_Instance.Spawn.z = value; + if (tag->listIndex == 0) spawn_point->pos.x = value; + if (tag->listIndex == 1) spawn_point->pos.y = value - 1.0f; + if (tag->listIndex == 2) spawn_point->pos.z = value; } } @@ -1568,9 +1571,9 @@ static cc_result Cw_WriteBockDef(struct Stream* stream, int b) { } cc_result Cw_Save(struct Stream* stream) { + struct LocalPlayer* p = Entities.CurPlayer; cc_uint8 buffer[2048]; cc_uint8* cur; - struct LocalPlayer* p = &LocalPlayer_Instance; cc_result res; int b; @@ -1618,7 +1621,7 @@ cc_result Cw_Save(struct Stream* stream) { { cur = Nbt_WriteDict(cur, "ClickDistance"); { - cur = Nbt_WriteUInt16(cur, "Distance", (cc_uint16)(LocalPlayer_Instance.ReachDistance * 32)); + cur = Nbt_WriteUInt16(cur, "Distance", (cc_uint16)(p->ReachDistance * 32)); } *cur++ = NBT_END; cur = Nbt_WriteDict(cur, "EnvWeatherType"); @@ -1735,9 +1738,9 @@ static const struct JField { { JFIELD_I32, false, "width", &World.Width }, { JFIELD_I32, false, "depth", &World.Height }, { JFIELD_I32, false, "height", &World.Length }, - { JFIELD_I32, true, "xSpawn", &LocalPlayer_Instance.Base.Position.x }, - { JFIELD_I32, true, "ySpawn", &LocalPlayer_Instance.Base.Position.y }, - { JFIELD_I32, true, "zSpawn", &LocalPlayer_Instance.Base.Position.z }, + { JFIELD_I32, true, "xSpawn", &LocalPlayer_Instances[0].Base.Position.x }, + { JFIELD_I32, true, "ySpawn", &LocalPlayer_Instances[0].Base.Position.y }, + { JFIELD_I32, true, "zSpawn", &LocalPlayer_Instances[0].Base.Position.z }, { JFIELD_ARRAY,0, "blocks" } /* TODO classic only blocks */ }; diff --git a/src/Game.c b/src/Game.c index c02e6c0..3f7d161 100644 --- a/src/Game.c +++ b/src/Game.c @@ -65,8 +65,11 @@ struct GameVersion Game_Version; static char usernameBuffer[STRING_SIZE]; static char mppassBuffer[STRING_SIZE]; -cc_string Game_Username = String_FromArray(usernameBuffer); -cc_string Game_Mppass = String_FromArray(mppassBuffer); +cc_string Game_Username = String_FromArray(usernameBuffer); +cc_string Game_Mppass = String_FromArray(mppassBuffer); +#ifdef CC_BUILD_SPLITSCREEN +int Game_NumLocalPlayers = 1; +#endif const char* const FpsLimit_Names[FPS_LIMIT_COUNT] = { "LimitVSync", "Limit30FPS", "Limit60FPS", "Limit120FPS", "Limit144FPS", "LimitNone", @@ -402,6 +405,7 @@ static void Game_Load(void) { Game_UpdateDimensions(); Game_SetFpsLimit(Options_GetEnum(OPT_FPS_LIMIT, 0, FpsLimit_Names, FPS_LIMIT_COUNT)); Gfx_Create(); + Logger_WarnFunc = Game_WarnFunc; LoadOptions(); GameVersion_Load(); @@ -479,11 +483,11 @@ void Game_SetFpsLimit(int method) { } static void UpdateViewMatrix(void) { - Camera.Active->GetView(&Gfx.View); + Camera.Active->GetView(Entities.CurPlayer, &Gfx.View); FrustumCulling_CalcFrustumEquations(&Gfx.Projection, &Gfx.View); } -static void Render3DFrame(double delta, float t) { +static void Render3DFrame(float delta, float t) { Vec3 pos; Gfx_LoadMatrix(MATRIX_PROJECTION, &Gfx.Projection); Gfx_LoadMatrix(MATRIX_VIEW, &Gfx.View); @@ -527,7 +531,7 @@ static void Render3DFrame(double delta, float t) { if (!Game_HideGui) HeldBlockRenderer_Render(delta); } -static void Render3D_Anaglyph(double delta, float t) { +static void Render3D_Anaglyph(float delta, float t) { struct Matrix proj = Gfx.Projection; struct Matrix view = Gfx.View; @@ -599,7 +603,50 @@ void Game_TakeScreenshot(void) { #endif } -static void Game_RenderFrame(double delta) { +static CC_INLINE void Game_DrawFrame(float delta, float t) { + UpdateViewMatrix(); + + if (!Gui_GetBlocksWorld()) { + Camera.Active->GetPickedBlock(Entities.CurPlayer, &Game_SelectedPos); /* TODO: only pick when necessary */ + Camera_KeyLookUpdate(delta); + InputHandler_Tick(); + + if (Game_Anaglyph3D) { + Render3D_Anaglyph(delta, t); + } else { + Render3DFrame(delta, t); + } + } else { + RayTracer_SetInvalid(&Game_SelectedPos); + } + + Gfx_Begin2D(Game.Width, Game.Height); + Gui_RenderGui(delta); + OnscreenKeyboard_Draw3D(); +/* TODO find a better solution than this */ +#ifdef CC_BUILD_3DS + if (Game_Anaglyph3D) { + extern void Gfx_SetTopRight(void); + Gfx_SetTopRight(); + Gui_RenderGui(delta); + } +#endif + Gfx_End2D(); +} + +#ifdef CC_BUILD_SPLITSCREEN +static void DrawSplitscreen(float delta, float t, int i, int x, int y, int w, int h) { + Gfx_SetViewport(x, y, w, h); + + Entities.CurPlayer = &LocalPlayer_Instances[i]; + LocalPlayer_SetInterpPosition(Entities.CurPlayer, t); + Camera.CurrentPos = Camera.Active->GetPosition(Entities.CurPlayer, t); + + Game_DrawFrame(delta, t); +} +#endif + +static CC_INLINE void Game_RenderFrame(double delta) { struct ScheduledTask entTask; float t; @@ -624,7 +671,7 @@ static void Game_RenderFrame(double delta) { Game_Vertices = 0; if (Input.Sources & INPUT_SOURCE_GAMEPAD) Gamepad_Tick(delta); - Camera.Active->UpdateMouse(delta); + Camera.Active->UpdateMouse(Entities.CurPlayer, delta); if (!Window_Main.Focused && !Gui.InputGrab) Gui_ShowPauseMenu(); @@ -635,44 +682,40 @@ static void Game_RenderFrame(double delta) { PerformScheduledTasks(delta); entTask = tasks[entTaskI]; t = (float)(entTask.accumulator / entTask.interval); - LocalPlayer_SetInterpPosition(t); + LocalPlayer_SetInterpPosition(Entities.CurPlayer, t); - Camera.CurrentPos = Camera.Active->GetPosition(t); + Camera.CurrentPos = Camera.Active->GetPosition(Entities.CurPlayer, t); /* NOTE: EnvRenderer_UpdateFog also also sets clear color */ EnvRenderer_UpdateFog(); - UpdateViewMatrix(); AudioBackend_Tick(); /* TODO: Not calling Gfx_EndFrame doesn't work with Direct3D9 */ if (Window_Main.Inactive) return; Gfx_ClearBuffers(GFX_BUFFER_COLOR | GFX_BUFFER_DEPTH); - - if (!Gui_GetBlocksWorld()) { - Camera.Active->GetPickedBlock(&Game_SelectedPos); /* TODO: only pick when necessary */ - Camera_KeyLookUpdate(delta); - InputHandler_Tick(); - - if (Game_Anaglyph3D) { - Render3D_Anaglyph(delta, t); - } else { - Render3DFrame(delta, t); - } - } else { - RayTracer_SetInvalid(&Game_SelectedPos); - } - - Gfx_Begin2D(Game.Width, Game.Height); - Gui_RenderGui(delta); - OnscreenKeyboard_Draw3D(); -/* TODO find a better solution than this */ -#ifdef CC_BUILD_3DS - if (Game_Anaglyph3D) { - extern void Gfx_SetTopRight(void); - Gfx_SetTopRight(); - Gui_RenderGui(delta); + +#ifdef CC_BUILD_SPLITSCREEN + switch (Game_NumLocalPlayers) { + case 1: + Game_DrawFrame(delta, t); break; + case 2: + DrawSplitscreen(delta, t, 0, 0, 0, Game.Width, Game.Height / 2); + DrawSplitscreen(delta, t, 1, 0, Game.Height / 2, Game.Width, Game.Height / 2); + break; + case 3: + DrawSplitscreen(delta, t, 0, 0, 0, Game.Width , Game.Height / 2); + DrawSplitscreen(delta, t, 1, 0, Game.Height / 2, Game.Width / 2, Game.Height / 2); + DrawSplitscreen(delta, t, 2, Game.Width / 2, Game.Height / 2, Game.Width / 2, Game.Height / 2); + break; + case 4: + DrawSplitscreen(delta, t, 0, 0, 0, Game.Width / 2, Game.Height / 2); + DrawSplitscreen(delta, t, 1, Game.Width / 2, 0, Game.Width / 2, Game.Height / 2); + DrawSplitscreen(delta, t, 2, 0, Game.Height / 2, Game.Width / 2, Game.Height / 2); + DrawSplitscreen(delta, t, 3, Game.Width / 2, Game.Height / 2, Game.Width / 2, Game.Height / 2); + break; } +#else + Game_DrawFrame(delta, t); #endif - Gfx_End2D(); if (Game_ScreenshotRequested) Game_TakeScreenshot(); Gfx_EndFrame(); diff --git a/src/Game.h b/src/Game.h index e796dae..ffefd1e 100644 --- a/src/Game.h +++ b/src/Game.h @@ -24,6 +24,12 @@ extern cc_bool Game_UseCPEBlocks; extern cc_string Game_Username; extern cc_string Game_Mppass; +#ifdef CC_BUILD_SPLITSCREEN +extern int Game_NumLocalPlayers; +#else +#define Game_NumLocalPlayers 1 +#endif + #if defined CC_BUILD_N64 #define DEFAULT_VIEWDIST 20 #elif defined CC_BUILD_NDS || defined CC_BUILD_PS1 diff --git a/src/Generator.c b/src/Generator.c index 7ad9649..94b0029 100644 --- a/src/Generator.c +++ b/src/Generator.c @@ -671,7 +671,7 @@ static void NotchyGen_PlantTrees(void) { treeX += Random_Next(&rnd, 6) - Random_Next(&rnd, 6); treeZ += Random_Next(&rnd, 6) - Random_Next(&rnd, 6); - if (!World_ContainsXZ(treeX, treeZ) || Random_Float(&rnd) >= 0.25) continue; + if (!World_ContainsXZ(treeX, treeZ) || Random_Float(&rnd) >= 0.25f) continue; treeY = heightmap[treeZ * World.Width + treeX] + 1; if (treeY >= World.Height) continue; treeHeight = 5 + Random_Next(&rnd, 3); diff --git a/src/Graphics.h b/src/Graphics.h index fd9b93c..29b5487 100644 --- a/src/Graphics.h +++ b/src/Graphics.h @@ -245,14 +245,16 @@ void Gfx_EndFrame(void); /* Sets whether to synchronise with monitor refresh to avoid tearing, and maximum frame rate */ /* NOTE: VSync setting may be unsupported or just ignored */ void Gfx_SetFpsLimit(cc_bool vsync, float minFrameMillis); -/* Updates state when the window's dimensions have changed */ -/* NOTE: This may require recreating the context depending on the backend */ -void Gfx_OnWindowResize(void); /* Gets information about the user's GPU and current backend state */ /* Backend state may include depth buffer bits, free memory, etc */ /* NOTE: Each line is separated by \n */ void Gfx_GetApiInfo(cc_string* info); +/* Updates state when the window's dimensions have changed */ +/* NOTE: This may require recreating the context depending on the backend */ +void Gfx_OnWindowResize(void); +void Gfx_SetViewport(int x, int y, int w, int h); + enum Screen3DS { TOP_SCREEN, BOTTOM_SCREEN }; #ifdef CC_BUILD_DUALSCREEN /* Selects which screen on the 3DS to render to */ diff --git a/src/Graphics_3DS.c b/src/Graphics_3DS.c index ad95bf6..36c8d53 100644 --- a/src/Graphics_3DS.c +++ b/src/Graphics_3DS.c @@ -575,6 +575,8 @@ void Gfx_EndFrame(void) { void Gfx_OnWindowResize(void) { } +void Gfx_SetViewport(int x, int y, int w, int h) { } + /*########################################################################################################################* *----------------------------------------------------------Buffers--------------------------------------------------------* diff --git a/src/Graphics_D3D11.c b/src/Graphics_D3D11.c index d49bd0a..19f57f6 100644 --- a/src/Graphics_D3D11.c +++ b/src/Graphics_D3D11.c @@ -440,7 +440,7 @@ void Gfx_CalcOrthoMatrix(struct Matrix* matrix, float width, float height, float matrix->row4.z = zNear / (zNear - zFar); } -static double Cotangent(double x) { return Math_Cos(x) / Math_Sin(x); } +static float Cotangent(float x) { return Math_CosF(x) / Math_SinF(x); } void Gfx_CalcPerspectiveMatrix(struct Matrix* matrix, float fov, float aspect, float zFar) { // Deliberately swap zNear/zFar in projection matrix calculation to produce // a projection matrix that results in a reversed depth buffer @@ -450,7 +450,7 @@ void Gfx_CalcPerspectiveMatrix(struct Matrix* matrix, float fov, float aspect, f // Source https://learn.microsoft.com/en-us/windows/win32/direct3d9/d3dxmatrixperspectivefovrh // NOTE: This calculation is shared with Direct3D 9 backend - float c = (float)Cotangent(0.5f * fov); + float c = Cotangent(0.5f * fov); *matrix = Matrix_Identity; matrix->row1.x = c / aspect; @@ -646,12 +646,12 @@ static void RS_CreateRasterState(void) { ID3D11Device_CreateRasterizerState(device, &desc, &rs_states[1]); } -static void RS_UpdateViewport(void) { +void Gfx_SetViewport(int x, int y, int w, int h) { D3D11_VIEWPORT viewport; - viewport.TopLeftX = 0; - viewport.TopLeftY = 0; - viewport.Width = Window_Main.Width; - viewport.Height = Window_Main.Height; + viewport.TopLeftX = x; + viewport.TopLeftY = y; + viewport.Width = w; + viewport.Height = h; viewport.MinDepth = 0.0f; viewport.MaxDepth = 1.0f; ID3D11DeviceContext_RSSetViewports(context, 1, &viewport); @@ -670,7 +670,7 @@ static void RS_FreeRasterStates(void) { static void RS_Init(void) { RS_CreateRasterState(); - RS_UpdateViewport(); + Gfx_SetViewport(0, 0, Game.Width, Game.Height); RS_UpdateRasterState(); } @@ -1173,7 +1173,7 @@ void Gfx_OnWindowResize(void) { if (hr) Logger_Abort2(hr, "Failed to resize swapchain"); OM_InitTargets(); - RS_UpdateViewport(); + Gfx_SetViewport(0, 0, Game.Width, Game.Height); } static void InitPipeline(void) { diff --git a/src/Graphics_D3D9.c b/src/Graphics_D3D9.c index 073b804..8cf140a 100644 --- a/src/Graphics_D3D9.c +++ b/src/Graphics_D3D9.c @@ -760,7 +760,7 @@ void Gfx_CalcOrthoMatrix(struct Matrix* matrix, float width, float height, float matrix->row4.z = zNear / (zNear - zFar); } -static double Cotangent(double x) { return Math_Cos(x) / Math_Sin(x); } +static float Cotangent(float x) { return Math_CosF(x) / Math_SinF(x); } void Gfx_CalcPerspectiveMatrix(struct Matrix* matrix, float fov, float aspect, float zFar) { /* Deliberately swap zNear/zFar in projection matrix calculation to produce */ /* a projection matrix that results in a reversed depth buffer */ @@ -770,7 +770,7 @@ void Gfx_CalcPerspectiveMatrix(struct Matrix* matrix, float fov, float aspect, f /* Source https://learn.microsoft.com/en-us/windows/win32/direct3d9/d3dxmatrixperspectivefovrh */ /* NOTE: This calculation is shared with Direct3D 11 backend */ - float c = (float)Cotangent(0.5f * fov); + float c = Cotangent(0.5f * fov); *matrix = Matrix_Identity; matrix->row1.x = c / aspect; @@ -886,4 +886,6 @@ void Gfx_OnWindowResize(void) { /* Only resize when necessary */ UpdateSwapchain(" (resizing window)"); } + +void Gfx_SetViewport(int x, int y, int w, int h) { } #endif diff --git a/src/Graphics_Dreamcast.c b/src/Graphics_Dreamcast.c index 9c54288..baaa9f0 100644 --- a/src/Graphics_Dreamcast.c +++ b/src/Graphics_Dreamcast.c @@ -4,7 +4,8 @@ #include "Errors.h" #include "Logger.h" #include "Window.h" -#include "../third_party/gldc/include/gldc.h" +#include "../third_party/gldc/gldc.h" +#include "../third_party/gldc/src/draw.c" #include #include #include @@ -30,7 +31,7 @@ static void InitGLState(void) { void Gfx_Create(void) { if (!Gfx.Created) glKosInit(); - glViewport(0, 0, vid_mode->width, vid_mode->height); + Gfx_SetViewport(0, 0, Game.Width, Game.Height); InitGLState(); Gfx.MinTexWidth = 8; @@ -104,10 +105,10 @@ void Gfx_CalcOrthoMatrix(struct Matrix* matrix, float width, float height, float matrix->row4.z = -(zFar + zNear) / (zFar - zNear); } -static double Cotangent(double x) { return Math_Cos(x) / Math_Sin(x); } +static float Cotangent(float x) { return Math_CosF(x) / Math_SinF(x); } void Gfx_CalcPerspectiveMatrix(struct Matrix* matrix, float fov, float aspect, float zFar) { float zNear = 0.1f; - float c = (float)Cotangent(0.5f * fov); + float c = Cotangent(0.5f * fov); /* Transposed, source https://learn.microsoft.com/en-us/windows/win32/opengl/glfrustum */ /* For a FOV based perspective matrix, left/right/top/bottom are calculated as: */ @@ -465,6 +466,22 @@ cc_bool Gfx_WarnIfNecessary(void) { *----------------------------------------------------------Drawing--------------------------------------------------------* *#########################################################################################################################*/ #define VB_PTR gfx_vertices +static const void* VERTEX_PTR; + +extern void DrawColouredQuads(const void* src, Vertex* dst, int numQuads); +extern void DrawTexturedQuads(const void* src, Vertex* dst, int numQuads); + +void DrawQuads(int count) { + if (!count) return; + Vertex* start = submitVertices(count); + + if (TEXTURES_ENABLED) { + DrawTexturedQuads(VERTEX_PTR, start, count >> 2); + } else { + DrawColouredQuads(VERTEX_PTR, start, count >> 2); + } +} + static void SetupVertices(int startVertex) { if (gfx_format == VERTEX_FORMAT_TEXTURED) { @@ -489,29 +506,33 @@ void Gfx_SetVertexFormat(VertexFormat fmt) { } void Gfx_DrawVb_Lines(int verticesCount) { - SetupVertices(0); + //SetupVertices(0); //glDrawArrays(GL_LINES, 0, verticesCount); } void Gfx_DrawVb_IndexedTris_Range(int verticesCount, int startVertex) { - SetupVertices(startVertex); - glDrawArrays(GL_QUADS, 0, verticesCount); + if (gfx_format == VERTEX_FORMAT_TEXTURED) { + VERTEX_PTR = gfx_vertices + startVertex * SIZEOF_VERTEX_TEXTURED; + } else { + VERTEX_PTR = gfx_vertices + startVertex * SIZEOF_VERTEX_COLOURED; + } + + DrawQuads(verticesCount); } void Gfx_DrawVb_IndexedTris(int verticesCount) { - SetupVertices(0); - + VERTEX_PTR = gfx_vertices; + if (textureOffset) ShiftTextureCoords(verticesCount); - glDrawArrays(GL_QUADS, 0, verticesCount); + DrawQuads(verticesCount); if (textureOffset) UnshiftTextureCoords(verticesCount); } void Gfx_DrawIndexedTris_T2fC4b(int verticesCount, int startVertex) { if (renderingDisabled) return; - cc_uint32 offset = startVertex * SIZEOF_VERTEX_TEXTURED; - gldcVertexPointer(SIZEOF_VERTEX_TEXTURED, (void*)(VB_PTR + offset)); - glDrawArrays(GL_QUADS, 0, verticesCount); + VERTEX_PTR = gfx_vertices + startVertex * SIZEOF_VERTEX_TEXTURED; + DrawQuads(verticesCount); } @@ -555,6 +576,17 @@ void Gfx_EndFrame(void) { } void Gfx_OnWindowResize(void) { - glViewport(0, 0, Game.Width, Game.Height); + Gfx_SetViewport(0, 0, Game.Width, Game.Height); +} + +void Gfx_SetViewport(int x, int y, int w, int h) { + if (x == 0 && y == 0 && w == Game.Width && h == Game.Height) { + glDisable(GL_SCISSOR_TEST); + } else { + glEnable(GL_SCISSOR_TEST); + } + + glViewport(x, y, w, h); + glScissor (x, y, w, h); } #endif diff --git a/src/Graphics_GCWii.c b/src/Graphics_GCWii.c index 8e0fa7f..923b0cf 100644 --- a/src/Graphics_GCWii.c +++ b/src/Graphics_GCWii.c @@ -27,9 +27,8 @@ static void InitGX(void) { memset(fifo_buffer, 0, FIFO_SIZE); GX_Init(fifo_buffer, FIFO_SIZE); - GX_SetViewport(0, 0, mode->fbWidth, mode->efbHeight, 0, 1); + Gfx_SetViewport(0, 0, mode->fbWidth, mode->efbHeight); GX_SetDispCopyYScale((f32)mode->xfbHeight / (f32)mode->efbHeight); - GX_SetScissor(0, 0, mode->fbWidth, mode->efbHeight); GX_SetDispCopySrc(0, 0, mode->fbWidth, mode->efbHeight); GX_SetDispCopyDst(mode->fbWidth, mode->xfbHeight); GX_SetCopyFilter(mode->aa, mode->sample_pattern, @@ -312,6 +311,11 @@ void Gfx_EndFrame(void) { void Gfx_OnWindowResize(void) { } +void Gfx_SetViewport(int x, int y, int w, int h) { + GX_SetViewport(x, y, w, h, 0, 1); + GX_SetScissor(x, y, w, h); +} + cc_bool Gfx_WarnIfNecessary(void) { return false; } @@ -442,10 +446,10 @@ void Gfx_CalcOrthoMatrix(struct Matrix* matrix, float width, float height, float matrix->row4.z = -zFar / (zFar - zNear); } -static double Cotangent(double x) { return Math_Cos(x) / Math_Sin(x); } +static float Cotangent(float x) { return Math_CosF(x) / Math_SinF(x); } void Gfx_CalcPerspectiveMatrix(struct Matrix* matrix, float fov, float aspect, float zFar) { float zNear = 0.1f; - float c = (float)Cotangent(0.5f * fov); + float c = Cotangent(0.5f * fov); // Transposed, source guPersepctive https://github.com/devkitPro/libogc/blob/master/libogc/gu.c *matrix = Matrix_Identity; @@ -593,4 +597,4 @@ void Gfx_DrawVb_IndexedTris(int verticesCount) { void Gfx_DrawIndexedTris_T2fC4b(int verticesCount, int startVertex) { Draw_TexturedTriangles(verticesCount, startVertex); } -#endif \ No newline at end of file +#endif diff --git a/src/Graphics_N64.c b/src/Graphics_N64.c index 4bc24d5..1b26f04 100644 --- a/src/Graphics_N64.c +++ b/src/Graphics_N64.c @@ -79,6 +79,8 @@ void Gfx_SetFpsLimit(cc_bool vsync, float minFrameMs) { void Gfx_OnWindowResize(void) { } +void Gfx_SetViewport(int x, int y, int w, int h) { } + void Gfx_BeginFrame(void) { surface_t* disp = display_get(); @@ -279,10 +281,10 @@ void Gfx_CalcOrthoMatrix(struct Matrix* matrix, float width, float height, float matrix->row4.z = -(zFar + zNear) / (zFar - zNear); } -static double Cotangent(double x) { return Math_Cos(x) / Math_Sin(x); } +static float Cotangent(float x) { return Math_CosF(x) / Math_SinF(x); } void Gfx_CalcPerspectiveMatrix(struct Matrix* matrix, float fov, float aspect, float zFar) { float zNear = 0.1f; - float c = (float)Cotangent(0.5f * fov); + float c = Cotangent(0.5f * fov); /* Transposed, source https://learn.microsoft.com/en-us/windows/win32/opengl/glfrustum */ /* For a FOV based perspective matrix, left/right/top/bottom are calculated as: */ diff --git a/src/Graphics_NDS.c b/src/Graphics_NDS.c index 50dae9a..ba081ea 100644 --- a/src/Graphics_NDS.c +++ b/src/Graphics_NDS.c @@ -12,7 +12,9 @@ void Gfx_Create(void) { Gfx_RestoreState(); - Gfx.MaxTexWidth = 256; + Gfx.MinTexWidth = 8; + Gfx.MinTexHeight = 8; + Gfx.MaxTexWidth = 256; Gfx.MaxTexHeight = 256; //Gfx.MaxTexSize = 256 * 256; Gfx.Created = true; @@ -22,7 +24,7 @@ void Gfx_Create(void) { glClearPolyID(63); glAlphaFunc(7); - glClearDepth(0x7FFF); + glClearDepth(GL_MAX_DEPTH); glViewport(0, 0, 255, 191); vramSetBankA(VRAM_A_TEXTURE); @@ -66,6 +68,8 @@ void Gfx_SetFpsLimit(cc_bool vsync, float minFrameMs) { void Gfx_OnWindowResize(void) { } +void Gfx_SetViewport(int x, int y, int w, int h) { } + void Gfx_BeginFrame(void) { } @@ -168,8 +172,18 @@ void Gfx_DisableMipmaps(void) { } /*########################################################################################################################* *-----------------------------------------------------State management----------------------------------------------------* *#########################################################################################################################*/ -void Gfx_SetFaceCulling(cc_bool enabled) { } -void Gfx_SetAlphaBlending(cc_bool enabled) { } +void Gfx_SetFaceCulling(cc_bool enabled) { + glPolyFmt(POLY_ALPHA(31) | (enabled ? POLY_CULL_BACK : POLY_CULL_NONE)); +} + +void Gfx_SetAlphaBlending(cc_bool enabled) { + /*if (enabled) { + glEnable(GL_BLEND); + } else { + glDisable(GL_BLEND); + }*/ +} + void Gfx_SetAlphaArgBlend(cc_bool enabled) { } static void SetColorWrite(cc_bool r, cc_bool g, cc_bool b, cc_bool a) { @@ -206,10 +220,10 @@ void Gfx_CalcOrthoMatrix(struct Matrix* matrix, float width, float height, float matrix->row4.z = -(zFar + zNear) / (zFar - zNear); } -static double Cotangent(double x) { return Math_Cos(x) / Math_Sin(x); } +static float Cotangent(float x) { return Math_CosF(x) / Math_SinF(x); } void Gfx_CalcPerspectiveMatrix(struct Matrix* matrix, float fov, float aspect, float zFar) { float zNear = 0.1f; - float c = (float)Cotangent(0.5f * fov); + float c = Cotangent(0.5f * fov); /* Transposed, source https://learn.microsoft.com/en-us/windows/win32/opengl/glfrustum */ /* For a FOV based perspective matrix, left/right/top/bottom are calculated as: */ @@ -454,19 +468,28 @@ static void Draw_ColouredTriangles(int verticesCount, int startVertex) { static void Draw_TexturedTriangles(int verticesCount, int startVertex) { glBegin(GL_QUADS); - int width = 0, height = 0; - glGetInt(GL_GET_TEXTURE_WIDTH, &width); width = inttof32(width); - glGetInt(GL_GET_TEXTURE_HEIGHT, &height); height = inttof32(height); - + int width = 0, height = 0; + glGetInt(GL_GET_TEXTURE_WIDTH, &width); + glGetInt(GL_GET_TEXTURE_HEIGHT, &height); + + // Original code used was + // U = mulf32(v->u, inttof32(width)) + // which behind the scenes expands to + // W = width << 12 + // U = ((int64)v->u * W) >> 12; + // and in this case, the bit shifts can be cancelled out + // to avoid calling __aeabi_lmul to perform the 64 bit multiplication + // therefore the code can be simplified to + // U = v->u * width for (int i = 0; i < verticesCount; i++) { struct DSTexturedVertex* v = (struct DSTexturedVertex*)gfx_vertices + startVertex + i; - GFX_COLOR = v->rgb; - glTexCoord2t16(f32tot16(mulf32(v->u, width)), f32tot16(mulf32(v->v, height))); - GFX_VERTEX16 = v->xy; - GFX_VERTEX16 = v->z; + GFX_COLOR = v->rgb; + GFX_TEX_COORD = TEXTURE_PACK(f32tot16(v->u * width), f32tot16(v->v * height)); + GFX_VERTEX16 = v->xy; + GFX_VERTEX16 = v->z; } glEnd(); } diff --git a/src/Graphics_PS1.c b/src/Graphics_PS1.c index 1f936df..ce21f15 100644 --- a/src/Graphics_PS1.c +++ b/src/Graphics_PS1.c @@ -489,7 +489,7 @@ void Gfx_CalcOrthoMatrix(struct Matrix* matrix, float width, float height, float matrix->row4.z = zNear / (zNear - zFar); } -static double Cotangent(double x) { return Math_Cos(x) / Math_Sin(x); } +static float Cotangent(float x) { return Math_CosF(x) / Math_SinF(x); } void Gfx_CalcPerspectiveMatrix(struct Matrix* matrix, float fov, float aspect, float zFar) { float zNear = 0.01f; /* Source https://learn.microsoft.com/en-us/windows/win32/direct3d9/d3dxmatrixperspectivefovrh */ @@ -727,6 +727,8 @@ void Gfx_OnWindowResize(void) { // TODO } +void Gfx_SetViewport(int x, int y, int w, int h) { } + void Gfx_GetApiInfo(cc_string* info) { String_AppendConst(info, "-- Using PS1 --\n"); PrintMaxTextureInfo(info); diff --git a/src/Graphics_PS2.c b/src/Graphics_PS2.c index 451cf04..383bd86 100644 --- a/src/Graphics_PS2.c +++ b/src/Graphics_PS2.c @@ -412,11 +412,11 @@ void Gfx_CalcOrthoMatrix(struct Matrix* matrix, float width, float height, float matrix->row4.z = -(zFar + zNear) / (zFar - zNear); } -static double Cotangent(double x) { return Math_Cos(x) / Math_Sin(x); } +static float Cotangent(float x) { return Math_CosF(x) / Math_SinF(x); } void Gfx_CalcPerspectiveMatrix(struct Matrix* matrix, float fov, float aspect, float zFar) { float zNear_ = zFar; float zFar_ = 0.1f; - float c = (float)Cotangent(0.5f * fov); + float c = Cotangent(0.5f * fov); /* Transposed, source https://learn.microsoft.com/en-us/windows/win32/opengl/glfrustum */ /* For pos FOV based perspective matrix, left/right/top/bottom are calculated as: */ @@ -671,6 +671,8 @@ void Gfx_OnWindowResize(void) { // TODO } +void Gfx_SetViewport(int x, int y, int w, int h) { } + void Gfx_GetApiInfo(cc_string* info) { String_AppendConst(info, "-- Using PS2 --\n"); PrintMaxTextureInfo(info); diff --git a/src/Graphics_PS3.c b/src/Graphics_PS3.c index f1e5e38..3283ba3 100644 --- a/src/Graphics_PS3.c +++ b/src/Graphics_PS3.c @@ -354,10 +354,10 @@ void Gfx_CalcOrthoMatrix(struct Matrix* matrix, float width, float height, float matrix->row4.z = zNear / (zNear - zFar); } -static double Cotangent(double x) { return Math_Cos(x) / Math_Sin(x); } +static float Cotangent(float x) { return Math_CosF(x) / Math_SinF(x); } void Gfx_CalcPerspectiveMatrix(struct Matrix* matrix, float fov, float aspect, float zFar) { float zNear = 0.1f; - float c = (float)Cotangent(0.5f * fov); + float c = Cotangent(0.5f * fov); // Same as Direct3D9 // TODO: should it be like OpenGL? ??? @@ -414,7 +414,7 @@ static void ResetFrameState(void) { GCM_USER_CLIP_PLANE_DISABLE); // NOTE: Must be called each frame, otherwise renders upside down at 4x zoom - Gfx_OnWindowResize(); + Gfx_SetViewport(0, 0, Game.Width, Game.Height); } // https://github.com/ps3dev/PSL1GHT/blob/master/ppu/include/rsx/rsx.h#L30 @@ -450,24 +450,26 @@ void Gfx_EndFrame(void) { } void Gfx_OnWindowResize(void) { + Gfx_SetViewport(0, 0, Game.Width, Game.Height); +} + +void Gfx_SetViewport(int x, int y, int w, int h) { f32 scale[4], offset[4]; - - u16 w = DisplayInfo.Width; - u16 h = DisplayInfo.Height; f32 zmin = 0.0f; f32 zmax = 1.0f; + y = Game.Height - y - h; scale[0] = w * 0.5f; scale[1] = h * -0.5f; scale[2] = (zmax - zmin) * 0.5f; scale[3] = 0.0f; - offset[0] = w * 0.5f; - offset[1] = h * 0.5f; + offset[0] = x + w * 0.5f; + offset[1] = x + h * 0.5f; offset[2] = (zmax + zmin) * 0.5f; offset[3] = 0.0f; - rsxSetViewport(context, 0, 0, w, h, zmin, zmax, scale, offset); - rsxSetScissor(context, 0, 0, w, h); + rsxSetViewport(context, x, y, w, h, zmin, zmax, scale, offset); + rsxSetScissor(context, x, y, w, h); // TODO: even needed? for (int i = 0; i < 8; i++) diff --git a/src/Graphics_PSP.c b/src/Graphics_PSP.c index 48c25ba..82b53a9 100644 --- a/src/Graphics_PSP.c +++ b/src/Graphics_PSP.c @@ -205,10 +205,10 @@ void Gfx_CalcOrthoMatrix(struct Matrix* matrix, float width, float height, float matrix->row4.z = -(zFar + zNear) / (zFar - zNear); } -static double Cotangent(double x) { return Math_Cos(x) / Math_Sin(x); } +static float Cotangent(float x) { return Math_CosF(x) / Math_SinF(x); } void Gfx_CalcPerspectiveMatrix(struct Matrix* matrix, float fov, float aspect, float zFar) { float zNear = 0.1f; - float c = (float)Cotangent(0.5f * fov); + float c = Cotangent(0.5f * fov); // Transposed, source https://learn.microsoft.com/en-us/windows/win32/opengl/glfrustum // For a FOV based perspective matrix, left/right/top/bottom are calculated as: @@ -283,6 +283,8 @@ void Gfx_EndFrame(void) { void Gfx_OnWindowResize(void) { } +void Gfx_SetViewport(int x, int y, int w, int h) { } + static cc_uint8* gfx_vertices; static int gfx_fields; diff --git a/src/Graphics_PSVita.c b/src/Graphics_PSVita.c index 629cc64..c96a799 100644 --- a/src/Graphics_PSVita.c +++ b/src/Graphics_PSVita.c @@ -728,10 +728,10 @@ void Gfx_CalcOrthoMatrix(struct Matrix* matrix, float width, float height, float matrix->row4.z = -(zFar + zNear) / (zFar - zNear); } -static double Cotangent(double x) { return Math_Cos(x) / Math_Sin(x); } +static float Cotangent(float x) { return Math_CosF(x) / Math_SinF(x); } void Gfx_CalcPerspectiveMatrix(struct Matrix* matrix, float fov, float aspect, float zFar) { float zNear = 0.1f; - float c = (float)Cotangent(0.5f * fov); + float c = Cotangent(0.5f * fov); // Transposed, source https://learn.microsoft.com/en-us/windows/win32/opengl/glfrustum // For a FOV based perspective matrix, left/right/top/bottom are calculated as: @@ -811,6 +811,8 @@ void Gfx_EndFrame(void) { void Gfx_OnWindowResize(void) { } +void Gfx_SetViewport(int x, int y, int w, int h) { } + /*########################################################################################################################* *--------------------------------------------------------GPU Buffers------------------------------------------------------* diff --git a/src/Graphics_Saturn.c b/src/Graphics_Saturn.c index b9015e0..0949fde 100644 --- a/src/Graphics_Saturn.c +++ b/src/Graphics_Saturn.c @@ -272,11 +272,11 @@ void Gfx_CalcOrthoMatrix(struct Matrix* matrix, float width, float height, float matrix->row4.z = zNear / (zNear - zFar); } -static double Cotangent(double x) { return Math_Cos(x) / Math_Sin(x); } +static float Cotangent(float x) { return Math_CosF(x) / Math_SinF(x); } void Gfx_CalcPerspectiveMatrix(struct Matrix* matrix, float fov, float aspect, float zFar) { float zNear = 0.01f; /* Source https://learn.microsoft.com/en-us/windows/win32/direct3d9/d3dxmatrixperspectivefovrh */ - float c = (float)Cotangent(0.5f * fov); + float c = Cotangent(0.5f * fov); *matrix = Matrix_Identity; matrix->row1.x = c / aspect; @@ -435,6 +435,8 @@ void Gfx_OnWindowResize(void) { // TODO } +void Gfx_SetViewport(int x, int y, int w, int h) { } + void Gfx_GetApiInfo(cc_string* info) { String_AppendConst(info, "-- Using Saturn --\n"); PrintMaxTextureInfo(info); diff --git a/src/Graphics_SoftGPU.c b/src/Graphics_SoftGPU.c index 2e32e7f..5b19f26 100644 --- a/src/Graphics_SoftGPU.c +++ b/src/Graphics_SoftGPU.c @@ -255,10 +255,10 @@ void Gfx_CalcOrthoMatrix(struct Matrix* matrix, float width, float height, float matrix->row4.z = -(zFar + zNear) / (zFar - zNear); } -static double Cotangent(double x) { return Math_Cos(x) / Math_Sin(x); } +static float Cotangent(float x) { return Math_CosF(x) / Math_SinF(x); } void Gfx_CalcPerspectiveMatrix(struct Matrix* matrix, float fov, float aspect, float zFar) { float zNear = 0.1f; - float c = (float)Cotangent(0.5f * fov); + float c = Cotangent(0.5f * fov); /* Transposed, source https://learn.microsoft.com/en-us/windows/win32/opengl/glfrustum */ /* For pos FOV based perspective matrix, left/right/top/bottom are calculated as: */ @@ -491,6 +491,8 @@ void Gfx_OnWindowResize(void) { colorBuffer = fb_bmp.scan0; } +void Gfx_SetViewport(int x, int y, int w, int h) { } + void Gfx_GetApiInfo(cc_string* info) { int pointerSize = sizeof(void*) * 8; String_Format1(info, "-- Using software (%i bit) --\n", &pointerSize); diff --git a/src/Graphics_WiiU.c b/src/Graphics_WiiU.c index 870bb72..7cc5991 100644 --- a/src/Graphics_WiiU.c +++ b/src/Graphics_WiiU.c @@ -31,7 +31,6 @@ static GfxResourceID white_square; static WHBGfxShaderGroup* group; static void InitGfx(void) { - WHBGfxInit(); GX2InitSampler(&sampler, GX2_TEX_CLAMP_MODE_WRAP, GX2_TEX_XY_FILTER_MODE_POINT); WHBGfxLoadGFDShaderGroup(&colorShader, 0, coloured_gsh); @@ -86,7 +85,9 @@ static void Gfx_RestoreState(void) { static GX2Texture* pendingTex; static GfxResourceID Gfx_AllocTexture(struct Bitmap* bmp, int rowWidth, cc_uint8 flags, cc_bool mipmaps) { - GX2Texture* tex = Mem_AllocCleared(1, sizeof(GX2Texture), "GX2 texture"); + GX2Texture* tex = Mem_TryAllocCleared(1, sizeof(GX2Texture)); + if (!tex) return NULL; + // TODO handle out of memory better int width = bmp->width, height = bmp->height; tex->surface.width = width; @@ -99,8 +100,9 @@ static GfxResourceID Gfx_AllocTexture(struct Bitmap* bmp, int rowWidth, cc_uint8 tex->compMap = GX2_COMP_MAP(GX2_SQ_SEL_R, GX2_SQ_SEL_G, GX2_SQ_SEL_B, GX2_SQ_SEL_A); GX2CalcSurfaceSizeAndAlignment(&tex->surface); GX2InitTextureRegs(tex); + tex->surface.image = MEMAllocFromDefaultHeapEx(tex->surface.imageSize, tex->surface.alignment); - // TODO check result + if (!tex->surface.image) { Mem_Free(tex); return NULL; } CopyTextureData(tex->surface.image, tex->surface.pitch << 2, bmp, rowWidth << 2); GX2Invalidate(GX2_INVALIDATE_MODE_CPU_TEXTURE, tex->surface.image, tex->surface.imageSize); @@ -374,11 +376,11 @@ void Gfx_CalcOrthoMatrix(struct Matrix* matrix, float width, float height, float matrix->row4.z = zNear / (zNear - zFar); } -static double Cotangent(double x) { return Math_Cos(x) / Math_Sin(x); } +static float Cotangent(float x) { return Math_CosF(x) / Math_SinF(x); } void Gfx_CalcPerspectiveMatrix(struct Matrix* matrix, float fov, float aspect, float zFar) { // TODO verify this float zNear = 0.1f; - float c = (float)Cotangent(0.5f * fov); + float c = Cotangent(0.5f * fov); *matrix = Matrix_Identity; matrix->row1.x = c / aspect; @@ -431,12 +433,18 @@ void Gfx_ClearBuffers(GfxBuffers buffers) { } } +static int drc_ticks; void Gfx_EndFrame(void) { GX2ColorBuffer* buf; buf = WHBGfxGetTVColourBuffer(); GX2CopyColorBufferToScanBuffer(buf, GX2_SCAN_TARGET_TV); + + GX2ContextState* state = WHBGfxGetDRCContextState(); + GX2SetContextState(state); + drc_ticks = (drc_ticks + 1) % 200; buf = WHBGfxGetDRCColourBuffer(); + GX2ClearColor(buf, drc_ticks / 200.0f, drc_ticks / 200.0f, drc_ticks / 200.0f, 1.0f); GX2CopyColorBufferToScanBuffer(buf, GX2_SCAN_TARGET_DRC); GX2SwapScanBuffers(); @@ -458,10 +466,16 @@ void Gfx_GetApiInfo(cc_string* info) { void Gfx_OnWindowResize(void) { } + +void Gfx_SetViewport(int x, int y, int w, int h) { + GX2SetViewport(x, y, w, h, 0.0f, 1.0f); + GX2SetScissor( x, y, w, h); +} + void Gfx_3DS_SetRenderScreen1(enum Screen3DS screen) { GX2ContextState* tv_state = WHBGfxGetTVContextState(); GX2ContextState* drc_state = WHBGfxGetDRCContextState(); // TODO GX2SetContextState(screen == TOP_SCREEN ? tv_state : drc_state); } -#endif \ No newline at end of file +#endif diff --git a/src/Graphics_Xbox.c b/src/Graphics_Xbox.c index 9a87233..e4c0d93 100644 --- a/src/Graphics_Xbox.c +++ b/src/Graphics_Xbox.c @@ -106,6 +106,7 @@ static void ResetState(void) { } static GfxResourceID white_square; + void Gfx_Create(void) { Gfx.MaxTexWidth = 512; Gfx.MaxTexHeight = 512; // TODO: 1024? @@ -507,12 +508,12 @@ void Gfx_CalcOrthoMatrix(struct Matrix* matrix, float width, float height, float } // https://github.com/XboxDev/nxdk/blob/master/samples/mesh/math3d.c#L292 -static double Cotangent(double x) { return Math_Cos(x) / Math_Sin(x); } +static float Cotangent(float x) { return Math_CosF(x) / Math_SinF(x); } void Gfx_CalcPerspectiveMatrix(struct Matrix* matrix, float fov, float aspect, float zFar) { float zNear = 0.1f; /* Source https://learn.microsoft.com/en-us/windows/win32/direct3d9/d3dxmatrixperspectivefovrh */ /* NOTE: This calculation is shared with Direct3D 11 backend */ - float c = (float)Cotangent(0.5f * fov); + float c = Cotangent(0.5f * fov); *matrix = Matrix_Identity; matrix->row1.x = c / aspect; @@ -535,15 +536,11 @@ void Gfx_CalcPerspectiveMatrix(struct Matrix* matrix, float fov, float aspect, f void Gfx_OnWindowResize(void) { } +static struct Vec4 vp_scale = { 320, -240, 8388608, 1 }; +static struct Vec4 vp_offset = { 320, 240, 8388608, 1 }; static struct Matrix _view, _proj, _mvp; -void Gfx_LoadMatrix(MatrixType type, const struct Matrix* matrix) { - struct Matrix* dst = type == MATRIX_PROJECTION ? &_proj : &_view; - *dst = *matrix; - - struct Matrix combined; - Matrix_Mul(&combined, &_view, &_proj); - +static void UpdateVSConstants(void) { uint32_t* p; p = pb_begin(); @@ -554,11 +551,11 @@ void Gfx_LoadMatrix(MatrixType type, const struct Matrix* matrix) { p = pb_push1(p, NV097_SET_TRANSFORM_CONSTANT_LOAD, 96); // upload transformation matrix - pb_push(p++, NV097_SET_TRANSFORM_CONSTANT, 4*4 + 4); - Mem_Copy(p, &combined, 16 * 4); p += 16; + pb_push(p++, NV097_SET_TRANSFORM_CONSTANT, 4*4 + 4 + 4); + Mem_Copy(p, &_mvp, 16 * 4); p += 16; // Upload viewport too - struct Vec4 viewport = { 320, 240, 8388608, 1 }; - Mem_Copy(p, &viewport, 4 * 4); p += 4; + Mem_Copy(p, &vp_scale, 4 * 4); p += 4; + Mem_Copy(p, &vp_offset, 4 * 4); p += 4; // Upload constants too //struct Vec4 v = { 1, 1, 1, 1 }; //Mem_Copy(p, &v, 4 * 4); p += 4; @@ -567,6 +564,14 @@ void Gfx_LoadMatrix(MatrixType type, const struct Matrix* matrix) { pb_end(p); } +void Gfx_LoadMatrix(MatrixType type, const struct Matrix* matrix) { + struct Matrix* dst = type == MATRIX_PROJECTION ? &_proj : &_view; + *dst = *matrix; + + Matrix_Mul(&_mvp, &_view, &_proj); + UpdateVSConstants(); +} + void Gfx_LoadIdentityMatrix(MatrixType type) { Gfx_LoadMatrix(type, &Matrix_Identity); } @@ -577,6 +582,20 @@ void Gfx_EnableTextureOffset(float x, float y) { void Gfx_DisableTextureOffset(void) { } +void Gfx_SetViewport(int x, int y, int w, int h) { + vp_scale.x = w * 0.5f; + vp_scale.y = h * -0.5f; + vp_offset.x = x + w * 0.5f; + vp_offset.y = y + h * 0.5f; + + uint32_t* p; + p = pb_begin(); + // NV097_SET_SURFACE_CLIP_HORIZONTAL followed by NV097_SET_SURFACE_CLIP_VERTICAL + p = pb_push2(p, NV097_SET_SURFACE_CLIP_HORIZONTAL, x | (w << 16), y | (h << 16)); + pb_end(p); +} + + /*########################################################################################################################* diff --git a/src/Graphics_Xbox360.c b/src/Graphics_Xbox360.c index 1e5af82..745729c 100644 --- a/src/Graphics_Xbox360.c +++ b/src/Graphics_Xbox360.c @@ -349,11 +349,11 @@ void Gfx_CalcOrthoMatrix(struct Matrix* matrix, float width, float height, float matrix->row4.z = zNear / (zNear - zFar); } -static double Cotangent(double x) { return Math_Cos(x) / Math_Sin(x); } +static float Cotangent(float x) { return Math_CosF(x) / Math_SinF(x); } void Gfx_CalcPerspectiveMatrix(struct Matrix* matrix, float fov, float aspect, float zFar) { // TODO verify this float zNear = 0.1f; - float c = (float)Cotangent(0.5f * fov); + float c = Cotangent(0.5f * fov); *matrix = Matrix_Identity; matrix->row1.x = c / aspect; @@ -402,4 +402,6 @@ void Gfx_GetApiInfo(cc_string* info) { void Gfx_OnWindowResize(void) { } + +void Gfx_SetViewport(int x, int y, int w, int h) { } #endif diff --git a/src/Gui.c b/src/Gui.c index 0238572..e6f7bd7 100644 --- a/src/Gui.c +++ b/src/Gui.c @@ -248,13 +248,11 @@ void Gui_Remove(struct Screen* s) { } void Gui_Add(struct Screen* s, int priority) { - int i; + struct Screen* existing; 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]); - } + + existing = Gui_GetScreen(priority); + if (existing) Gui_RemoveCore(existing); Gui_AddCore(s, priority); Gui_OnScreensChanged(); @@ -287,6 +285,15 @@ struct Screen* Gui_GetClosable(void) { return NULL; } +struct Screen* Gui_GetScreen(int priority) { + int i; + for (i = 0; i < Gui.ScreensCount; i++) + { + if (priorities[i] == priority) return Gui_Screens[i]; + } + return NULL; +} + void Gui_UpdateInputGrab(void) { Gui.InputGrab = Gui_GetInputGrab(); Camera_CheckFocus(); @@ -300,7 +307,7 @@ void Gui_ShowPauseMenu(void) { } } -void Gui_RenderGui(double delta) { +void Gui_RenderGui(float delta) { struct Screen* s; int i; @@ -406,7 +413,7 @@ void Widget_SetLocation(void* widget, cc_uint8 horAnchor, cc_uint8 verAnchor, in w->horAnchor = horAnchor; w->verAnchor = verAnchor; w->xOffset = Display_ScaleX(xOffset); w->yOffset = Display_ScaleY(yOffset); - Widget_Layout(w); + if (w->VTABLE) Widget_Layout(w); } void Widget_CalcPosition(void* widget) { @@ -457,7 +464,7 @@ void Widget_SetDisabled(void* widget, int disabled) { /*########################################################################################################################* *-------------------------------------------------------Screen base-------------------------------------------------------* *#########################################################################################################################*/ -void Screen_Render2Widgets(void* screen, double delta) { +void Screen_Render2Widgets(void* screen, float delta) { struct Screen* s = (struct Screen*)screen; struct Widget** widgets = s->widgets; int i, offset = 0; @@ -592,7 +599,7 @@ static void OnPointerMove(void* obj, int idx) { } } -static void OnAxisUpdate(void* obj, int axis, float x, float y) { +static void OnAxisUpdate(void* obj, int port, int axis, float x, float y) { struct Screen* s; int i; @@ -606,7 +613,6 @@ static void OnAxisUpdate(void* obj, int axis, float x, float y) { } - /*########################################################################################################################* *------------------------------------------------------Gui component------------------------------------------------------* *#########################################################################################################################*/ @@ -701,13 +707,6 @@ static void OnInit(void) { Event_Register_(&WindowEvents.Resized, NULL, OnResize); Event_Register_(&InputEvents.TextChanged, NULL, OnTextChanged); -#ifdef CC_BUILD_TOUCH - #define DEFAULT_SP_ONSCREEN (ONSCREEN_BTN_FLY | ONSCREEN_BTN_SPEED) - #define DEFAULT_MP_ONSCREEN (ONSCREEN_BTN_FLY | ONSCREEN_BTN_SPEED | ONSCREEN_BTN_CHAT) - Gui._onscreenButtons = Options_GetInt(OPT_TOUCH_BUTTONS, 0, Int32_MaxValue, - Server.IsSinglePlayer ? DEFAULT_SP_ONSCREEN : DEFAULT_MP_ONSCREEN); -#endif - LoadOptions(); Gui_ShowDefault(); } diff --git a/src/Gui.h b/src/Gui.h index 360a165..cf2fcb3 100644 --- a/src/Gui.h +++ b/src/Gui.h @@ -45,8 +45,7 @@ CC_VAR extern struct _GuiData { float RawHotbarScale, RawChatScale, RawInventoryScale, RawCrosshairScale; GfxResourceID GuiTex, GuiClassicTex, IconsTex, TouchTex; int DefaultLines; - /* (internal) Bitmask of on-screen buttons, see Input.h */ - int _onscreenButtons; + int _unused; float RawTouchScale; /* The highest priority screen that has grabbed input. */ struct Screen* InputGrab; @@ -70,11 +69,11 @@ struct ScreenVTABLE { /* Initialises persistent state. */ void (*Init)(void* elem); /* Updates this screen, called every frame just before Render(). */ - void (*Update)(void* elem, double delta); + void (*Update)(void* elem, float delta); /* Frees/releases persistent state. */ void (*Free)(void* elem); /* Draws this screen and its widgets on screen. */ - void (*Render)(void* elem, double delta); + void (*Render)(void* elem, float delta); /* Builds the vertex mesh for all the widgets in the screen. */ void (*BuildMesh)(void* elem); /* Returns non-zero if an input press is handled. */ @@ -114,7 +113,7 @@ struct ScreenVTABLE { /* Represents a container of widgets and other 2D elements. May cover entire window. */ struct Screen { Screen_Body }; /* Calls Widget_Render2 on each widget in the screen. */ -void Screen_Render2Widgets(void* screen, double delta); +void Screen_Render2Widgets(void* screen, float delta); void Screen_UpdateVb(void* screen); struct VertexTextured* Screen_LockVb(void* screen); int Screen_DoPointerDown(void* screen, int id, int x, int y); @@ -145,7 +144,7 @@ union WidgetMeta { int val; void* ptr; }; struct WidgetVTABLE { /* Draws this widget on-screen. */ - void (*Render)(void* elem, double delta); + void (*Render)(void* elem, float delta); /* Destroys allocated graphics resources. */ void (*Free)(void* elem); /* Positions this widget on-screen. */ @@ -259,13 +258,15 @@ CC_API struct Screen* Gui_GetInputGrab(void); struct Screen* Gui_GetBlocksWorld(void); /* Returns highest priority screen that is closable. */ struct Screen* Gui_GetClosable(void); +/* Returns screen with the given priority */ +CC_API struct Screen* Gui_GetScreen(int priority); void Gui_UpdateInputGrab(void); void Gui_ShowPauseMenu(void); void Gui_LayoutAll(void); void Gui_RefreshAll(void); void Gui_Refresh(struct Screen* s); -void Gui_RenderGui(double delta); +void Gui_RenderGui(float delta); #define TEXTATLAS_MAX_WIDTHS 16 struct TextAtlas { diff --git a/src/HeldBlockRenderer.c b/src/HeldBlockRenderer.c index 0d54bd2..b0b603a 100644 --- a/src/HeldBlockRenderer.c +++ b/src/HeldBlockRenderer.c @@ -17,7 +17,7 @@ static struct Matrix held_blockProj; static cc_bool held_animating, held_breaking, held_swinging; static float held_swingY; -static double held_time, held_period = 0.25; +static float held_time, held_period = 0.25f; static BlockID held_lastBlock; /* Since not using Entity_SetModel, which normally automatically does this */ @@ -39,7 +39,7 @@ static void HeldBlockRenderer_RenderModel(void) { /* TODO: Need to properly reallocate per model VB here */ if (Blocks.Draw[held_block] == DRAW_GAS) { - model = LocalPlayer_Instance.Base.Model; + model = Entities.CurPlayer->Base.Model; SetHeldModel(model); Vec3_Set(held_entity.ModelScale, 1.0f,1.0f,1.0f); @@ -61,7 +61,7 @@ static void HeldBlockRenderer_RenderModel(void) { } static void SetMatrix(void) { - struct Entity* p = &LocalPlayer_Instance.Base; + struct Entity* p = &Entities.CurPlayer->Base; struct Matrix lookAt; Vec3 eye = { 0,0,0 }; eye.y = Entity_GetEyeHeight(p); @@ -71,7 +71,7 @@ static void SetMatrix(void) { static void ResetHeldState(void) { /* Based off details from http://pastebin.com/KFV0HkmD (Thanks goodlyay!) */ - struct Entity* p = &LocalPlayer_Instance.Base; + struct Entity* p = &Entities.CurPlayer->Base; Vec3 eye = { 0,0,0 }; eye.y = Entity_GetEyeHeight(p); held_entity.Position = eye; @@ -118,24 +118,24 @@ static void OnProjectionChanged(void* obj) { https://github.com/UnknownShadow200/ClassicalSharp/wiki/Dig-animation-details */ static void HeldBlockRenderer_DigAnimation(void) { - double sinHalfCircle, sinHalfCircleWeird; + float sinHalfCircle, sinHalfCircleWeird; float t, sqrtLerpPI; t = held_time / held_period; - sinHalfCircle = Math_Sin(t * MATH_PI); + sinHalfCircle = Math_SinF(t * MATH_PI); sqrtLerpPI = Math_SqrtF(t) * MATH_PI; - held_entity.Position.x -= (float)Math_Sin(sqrtLerpPI) * 0.4f; - held_entity.Position.y += (float)Math_Sin(sqrtLerpPI * 2) * 0.2f; - held_entity.Position.z -= (float)sinHalfCircle * 0.2f; + held_entity.Position.x -= Math_SinF(sqrtLerpPI) * 0.4f; + held_entity.Position.y += Math_SinF(sqrtLerpPI * 2) * 0.2f; + held_entity.Position.z -= sinHalfCircle * 0.2f; - sinHalfCircleWeird = Math_Sin(t * t * MATH_PI); - held_entity.RotY -= (float)Math_Sin(sqrtLerpPI) * 80.0f; - held_entity.Yaw -= (float)Math_Sin(sqrtLerpPI) * 80.0f; - held_entity.RotX += (float)sinHalfCircleWeird * 20.0f; + sinHalfCircleWeird = Math_SinF(t * t * MATH_PI); + held_entity.RotY -= Math_SinF(sqrtLerpPI) * 80.0f; + held_entity.Yaw -= Math_SinF(sqrtLerpPI) * 80.0f; + held_entity.RotX += sinHalfCircleWeird * 20.0f; } -static void HeldBlockRenderer_ResetAnim(cc_bool setLastHeld, double period) { +static void HeldBlockRenderer_ResetAnim(cc_bool setLastHeld, float period) { held_time = 0.0f; held_swingY = 0.0f; held_animating = false; held_swinging = false; held_period = period; @@ -147,7 +147,7 @@ static PackedCol HeldBlockRenderer_GetCol(struct Entity* entity) { PackedCol col; float adjPitch, t, scale; - player = &LocalPlayer_Instance.Base; + player = &Entities.CurPlayer->Base; col = player->VTABLE->GetCol(player); /* Adjust pitch so angle when looking straight down is 0. */ @@ -190,13 +190,13 @@ static void OnBlockChanged(void* obj, IVec3 coords, BlockID old, BlockID now) { HeldBlockRenderer_ClickAnim(false); } -static void DoAnimation(double delta, float lastSwingY) { - double t; +static void DoAnimation(float delta, float lastSwingY) { + float t; if (!held_animating) return; if (held_swinging || !held_breaking) { t = held_time / held_period; - held_swingY = -0.4f * (float)Math_Sin(t * MATH_PI); + held_swingY = -0.4f * Math_SinF(t * MATH_PI); held_entity.Position.y += held_swingY; if (held_swinging) { @@ -212,11 +212,11 @@ static void DoAnimation(double delta, float lastSwingY) { held_time += delta; if (held_time > held_period) { - HeldBlockRenderer_ResetAnim(true, 0.25); + HeldBlockRenderer_ResetAnim(true, 0.25f); } } -void HeldBlockRenderer_Render(double delta) { +void HeldBlockRenderer_Render(float delta) { float lastSwingY; struct Matrix view; if (!HeldBlockRenderer_Show) return; diff --git a/src/HeldBlockRenderer.h b/src/HeldBlockRenderer.h index d10edba..8fa7a80 100644 --- a/src/HeldBlockRenderer.h +++ b/src/HeldBlockRenderer.h @@ -11,5 +11,5 @@ extern struct IGameComponent HeldBlockRenderer_Component; extern cc_bool HeldBlockRenderer_Show; void HeldBlockRenderer_ClickAnim(cc_bool digging); -void HeldBlockRenderer_Render(double delta); +void HeldBlockRenderer_Render(float delta); #endif diff --git a/src/Http_Worker.c b/src/Http_Worker.c index b7c0a62..5bf5470 100644 --- a/src/Http_Worker.c +++ b/src/Http_Worker.c @@ -496,13 +496,15 @@ static cc_result HttpConnection_Open(struct HttpConnection* conn, const struct H static cc_result HttpConnection_Read(struct HttpConnection* conn, cc_uint8* data, cc_uint32 count, cc_uint32* read) { if (conn->sslCtx) return SSL_Read(conn->sslCtx, data, count, read); + return Socket_Read(conn->socket, data, count, read); } -static cc_result HttpConnection_Write(struct HttpConnection* conn, const cc_uint8* data, cc_uint32 count, cc_uint32* wrote) { +static cc_result HttpConnection_Write(struct HttpConnection* conn, const cc_uint8* data, cc_uint32 count) { if (conn->sslCtx) - return SSL_Write(conn->sslCtx, data, count, wrote); - return Socket_Write(conn->socket, data, count, wrote); + return SSL_WriteAll(conn->sslCtx, data, count); + + return Socket_WriteAll(conn->socket, data, count); } @@ -621,15 +623,13 @@ static void HttpClient_Serialise(struct HttpClientState* state) { static cc_result HttpClient_SendRequest(struct HttpClientState* state) { char inputBuffer[16384]; cc_string inputMsg; - cc_uint32 wrote; String_InitArray(inputMsg, inputBuffer); state->req->meta = &inputMsg; state->req->progress = HTTP_PROGRESS_FETCHING_DATA; HttpClient_Serialise(state); - /* TODO check that wrote is >= inputMsg.length */ - return HttpConnection_Write(state->conn, (cc_uint8*)inputBuffer, inputMsg.length, &wrote); + return HttpConnection_Write(state->conn, (cc_uint8*)inputBuffer, inputMsg.length); } @@ -833,9 +833,12 @@ static cc_result HttpClient_ParseResponse(struct HttpClientState* state) { { dst = state->dataLeft > INPUT_BUFFER_LEN ? (req->data + req->size) : buffer; res = HttpConnection_Read(state->conn, dst, INPUT_BUFFER_LEN, &total); + if (res) return res; - if (res) return res; - if (total == 0) return ERR_END_OF_STREAM; + if (total == 0) { + Platform_LogConst("Http read unexpectedly returned 0"); + return ERR_END_OF_STREAM; + } if (dst != buffer) { /* When there is more than INPUT_BUFFER_LEN bytes of unread data/content, */ @@ -1278,7 +1281,7 @@ static void PerformRequest(struct HttpRequest* req, cc_string* url) { end = Stopwatch_Measure(); elapsed = Stopwatch_ElapsedMS(beg, end); - Platform_Log4("HTTP: result %i (http %i) in %i ms (%i bytes)", + Platform_Log4("HTTP: result %e (http %i) in %i ms (%i bytes)", &req->result, &req->statusCode, &elapsed, &req->size); Http_FinishRequest(req); diff --git a/src/Input.c b/src/Input.c index a24b689..cc4235a 100644 --- a/src/Input.c +++ b/src/Input.c @@ -291,6 +291,15 @@ void Input_Clear(void) { ClearTouches(); } +int Input_CalcDelta(int key, int horDelta, int verDelta) { + if (Input_IsLeftButton(key) || key == CCKEY_KP4) return -horDelta; + if (Input_IsRightButton(key) || key == CCKEY_KP6) return +horDelta; + if (Input_IsUpButton(key) || key == CCKEY_KP8) return -verDelta; + if (Input_IsDownButton(key) || key == CCKEY_KP2) return +verDelta; + + return 0; +} + /*########################################################################################################################* *----------------------------------------------------------Mouse----------------------------------------------------------* @@ -418,48 +427,97 @@ static void KeyBind_Init(void) { *---------------------------------------------------------Gamepad---------------------------------------------------------* *#########################################################################################################################*/ #define GAMEPAD_BEG_BTN CCPAD_A -static float pad_holdtime[INPUT_COUNT - GAMEPAD_BEG_BTN]; +#define GAMEPAD_BTN_COUNT (INPUT_COUNT - GAMEPAD_BEG_BTN) int Gamepad_AxisBehaviour[2] = { AXIS_BEHAVIOUR_MOVEMENT, AXIS_BEHAVIOUR_CAMERA }; int Gamepad_AxisSensitivity[2] = { AXIS_SENSI_NORMAL, AXIS_SENSI_NORMAL }; static const float axis_sensiFactor[] = { 0.25f, 0.5f, 1.0f, 2.0f, 4.0f }; -void Gamepad_SetButton(int btn, int pressed) { +struct GamepadState { + float axisX[2], axisY[2]; + cc_bool pressed[GAMEPAD_BTN_COUNT]; + float holdtime[GAMEPAD_BTN_COUNT]; +}; +static struct GamepadState gamepads[INPUT_MAX_GAMEPADS]; + +static void Gamepad_Update(struct GamepadState* pad, float delta) { + int btn; + for (btn = 0; btn < GAMEPAD_BTN_COUNT; btn++) + { + if (!pad->pressed[btn]) continue; + pad->holdtime[btn] += delta; + if (pad->holdtime[btn] < 1.0f) continue; + + /* Held for over a second, trigger a fake press */ + pad->holdtime[btn] = 0; + Input_SetPressed(btn + GAMEPAD_BEG_BTN); + } +} + + +void Gamepad_SetButton(int port, int btn, int pressed) { + struct GamepadState* pad = &gamepads[port]; + int i; + btn -= GAMEPAD_BEG_BTN; + /* Reset hold tracking time */ - if (pressed && !Input.Pressed[btn]) pad_holdtime[btn - GAMEPAD_BEG_BTN] = 0; + if (pressed && !pad->pressed[btn]) pad->holdtime[btn] = 0; + pad->pressed[btn] = pressed != 0;; + + /* Set pressed if button pressed on any gamepad, to avoid constant flip flopping */ + /* between pressed and non-pressed when multiple controllers are plugged in */ + for (i = 0; i < INPUT_MAX_GAMEPADS; i++) + pressed |= gamepads[i].pressed[btn]; - Input_SetNonRepeatable(btn, pressed); + Input_SetNonRepeatable(btn + GAMEPAD_BEG_BTN, pressed); } -void Gamepad_SetAxis(int axis, float x, float y, double delta) { +void Gamepad_SetAxis(int port, int axis, float x, float y, float delta) { + gamepads[port].axisX[axis] = x; + gamepads[port].axisY[axis] = y; if (x == 0 && y == 0) return; int sensi = Gamepad_AxisSensitivity[axis]; - float scale = delta * 60.0 * axis_sensiFactor[sensi]; - Event_RaisePadAxis(&ControllerEvents.AxisUpdate, axis, x * scale, y * scale); - - if (Gamepad_AxisBehaviour[axis] == AXIS_BEHAVIOUR_MOVEMENT) { - if (!Input.RawMode) return; + float scale = delta * 60.0f * axis_sensiFactor[sensi]; + Event_RaisePadAxis(&ControllerEvents.AxisUpdate, port, axis, x * scale, y * scale); +} - Input.JoystickMovement = true; - Input.JoystickAngle = Math_Atan2(x, y); +void Gamepad_Tick(float delta) { + int port; + Window_ProcessGamepads(delta); + + for (port = 0; port < INPUT_MAX_GAMEPADS; port++) + { + Gamepad_Update(&gamepads[port], delta); } } -void Gamepad_Tick(double delta) { - int btn; +static void PlayerInputPad(int port, int axis, struct LocalPlayer* p, float* xMoving, float* zMoving) { + float x, y, angle; + if (Gamepad_AxisBehaviour[axis] != AXIS_BEHAVIOUR_MOVEMENT) return; + + x = gamepads[port].axisX[axis]; + y = gamepads[port].axisY[axis]; + + if (x != 0 || y != 0) { + angle = Math_Atan2f(x, y); + *xMoving = Math_CosF(angle); + *zMoving = Math_SinF(angle); + } +} - for (btn = GAMEPAD_BEG_BTN; btn < INPUT_COUNT; btn++) +static void PlayerInputGamepad(struct LocalPlayer* p, float* xMoving, float* zMoving) { + int port; + for (port = 0; port < INPUT_MAX_GAMEPADS; port++) { - if (!Input.Pressed[btn]) continue; - pad_holdtime[btn - GAMEPAD_BEG_BTN] += delta; - if (pad_holdtime[btn - GAMEPAD_BEG_BTN] < 1.0) continue; - - /* Held for over a second, trigger a fake press */ - pad_holdtime[btn - GAMEPAD_BEG_BTN] = 0; - Input_SetPressed(btn); + /* In splitscreen mode, tie a controller to a specific player*/ + if (Game_NumLocalPlayers > 1 && p->index != port) continue; + + PlayerInputPad(port, PAD_AXIS_LEFT, p, xMoving, zMoving); + PlayerInputPad(port, PAD_AXIS_RIGHT, p, xMoving, zMoving); } } +static struct LocalPlayerInput gamepadInput = { PlayerInputGamepad }; /*########################################################################################################################* @@ -653,8 +711,11 @@ static void MouseStateUpdate(int button, cc_bool pressed) { struct Entity* p; /* defer getting the targeted entity, as it's a costly operation */ if (input_pickingId == -1) { - p = &LocalPlayer_Instance.Base; + p = &Entities.CurPlayer->Base; input_pickingId = Entities_GetClosest(p); + + if (input_pickingId == -1) + input_pickingId = ENTITIES_SELF_ID; } input_buttonsDown[button] = pressed; @@ -698,8 +759,8 @@ void InputHandler_OnScreensChanged(void) { static cc_bool TouchesSolid(BlockID b) { return Blocks.Collide[b] == COLLIDE_SOLID; } static cc_bool PushbackPlace(struct AABB* blockBB) { - struct Entity* p = &LocalPlayer_Instance.Base; - struct HacksComp* hacks = &LocalPlayer_Instance.Hacks; + struct Entity* p = &Entities.CurPlayer->Base; + struct HacksComp* hacks = &Entities.CurPlayer->Hacks; Face closestFace; cc_bool insideMap; @@ -750,9 +811,10 @@ static cc_bool IntersectsOthers(Vec3 pos, BlockID block) { Vec3_Add(&blockBB.Min, &pos, &Blocks.MinBB[block]); Vec3_Add(&blockBB.Max, &pos, &Blocks.MaxBB[block]); - for (id = 0; id < ENTITIES_SELF_ID; id++) { + for (id = 0; id < ENTITIES_MAX_COUNT; id++) + { e = Entities.List[id]; - if (!e) continue; + if (!e || e == &Entities.CurPlayer->Base) continue; Entity_GetBounds(e, &entityBB); entityBB.Min.y += 1.0f / 32.0f; /* when player is exactly standing on top of ground */ @@ -762,8 +824,8 @@ static cc_bool IntersectsOthers(Vec3 pos, BlockID block) { } static cc_bool CheckIsFree(BlockID block) { - struct Entity* p = &LocalPlayer_Instance.Base; - struct HacksComp* hacks = &LocalPlayer_Instance.Hacks; + struct Entity* p = &Entities.CurPlayer->Base; + struct HacksComp* hacks = &Entities.CurPlayer->Hacks; Vec3 pos, nextPos; struct AABB blockBB, playerBB; @@ -775,7 +837,7 @@ static cc_bool CheckIsFree(BlockID block) { IVec3_ToVec3(&pos, &Game_SelectedPos.translatedPos); if (IntersectsOthers(pos, block)) return false; - nextPos = LocalPlayer_Instance.Base.next.pos; + nextPos = p->next.pos; Vec3_Add(&blockBB.Min, &pos, &Blocks.MinBB[block]); Vec3_Add(&blockBB.Max, &pos, &Blocks.MaxBB[block]); @@ -919,7 +981,7 @@ static void InputHandler_Toggle(int key, cc_bool* target, const char* enableMsg, } cc_bool InputHandler_SetFOV(int fov) { - struct HacksComp* h = &LocalPlayer_Instance.Hacks; + struct HacksComp* h = &Entities.CurPlayer->Hacks; if (!h->Enabled || !h->CanUseThirdPerson) return false; Camera.ZoomFov = fov; @@ -935,7 +997,7 @@ cc_bool Input_HandleMouseWheel(float delta) { if (!hotbar && Camera.Active->Zoom(delta)) return true; if (!KeyBind_IsPressed(KEYBIND_ZOOM_SCROLL)) return false; - h = &LocalPlayer_Instance.Hacks; + h = &Entities.CurPlayer->Hacks; if (!h->Enabled || !h->CanUseThirdPerson) return false; if (input_fovIndex == -1.0f) input_fovIndex = (float)Camera.ZoomFov; @@ -946,7 +1008,7 @@ cc_bool Input_HandleMouseWheel(float delta) { } static void InputHandler_CheckZoomFov(void* obj) { - struct HacksComp* h = &LocalPlayer_Instance.Hacks; + struct HacksComp* h = &Entities.CurPlayer->Hacks; if (!h->Enabled || !h->CanUseThirdPerson) Camera_SetFov(Camera.DefaultFov); } @@ -1038,16 +1100,18 @@ static void HandleHotkeyDown(int key) { } static cc_bool HandleLocalPlayerKey(int key) { + struct LocalPlayer* p = Entities.CurPlayer; + if (KeyBind_Claims(KEYBIND_RESPAWN, key)) { - return LocalPlayer_HandleRespawn(); + return LocalPlayer_HandleRespawn(p); } else if (KeyBind_Claims(KEYBIND_SET_SPAWN, key)) { - return LocalPlayer_HandleSetSpawn(); + return LocalPlayer_HandleSetSpawn(p); } else if (KeyBind_Claims(KEYBIND_FLY, key)) { - return LocalPlayer_HandleFly(); + return LocalPlayer_HandleFly(p); } else if (KeyBind_Claims(KEYBIND_NOCLIP, key)) { - return LocalPlayer_HandleNoclip(); + return LocalPlayer_HandleNoclip(p); } else if (KeyBind_Claims(KEYBIND_JUMP, key)) { - return LocalPlayer_HandleJump(); + return LocalPlayer_HandleJump(p); } return false; } @@ -1177,7 +1241,19 @@ static void OnInputUp(void* obj, int key) { } static void OnFocusChanged(void* obj) { if (!Window_Main.Focused) Input_Clear(); } + +static void PlayerInputNormal(struct LocalPlayer* p, 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 struct LocalPlayerInput normalInput = { PlayerInputNormal }; + static void OnInit(void) { + LocalPlayerInput_Add(&normalInput); + LocalPlayerInput_Add(&gamepadInput); + Event_Register_(&PointerEvents.Down, NULL, OnPointerDown); Event_Register_(&PointerEvents.Up, NULL, OnPointerUp); Event_Register_(&InputEvents.Down, NULL, OnInputDown); diff --git a/src/Input.h b/src/Input.h index 38d5ad3..35fff1e 100644 --- a/src/Input.h +++ b/src/Input.h @@ -67,10 +67,6 @@ extern struct _InputState { cc_bool RawMode; /* Sources available for input (Mouse/Keyboard, Gamepad) */ cc_uint8 Sources; - /* Whether a gamepad joystick is being used to control player movement */ - cc_bool JoystickMovement; - /* Angle of the gamepad joystick being used to control player movement */ - float JoystickAngle; } Input; #define INPUT_SOURCE_NORMAL (1 << 0) @@ -110,6 +106,7 @@ void Input_Clear(void); #else #define Input_IsActionPressed() Input_IsCtrlPressed() #endif +int Input_CalcDelta(int btn, int horDelta, int verDelta); #ifdef CC_BUILD_TOUCH @@ -196,10 +193,11 @@ extern int Gamepad_AxisBehaviour[2]; extern int Gamepad_AxisSensitivity[2]; /* Sets value of the given gamepad button */ -void Gamepad_SetButton(int btn, int pressed); +void Gamepad_SetButton(int port, int btn, int pressed); /* Sets value of the given axis */ -void Gamepad_SetAxis(int axis, float x, float y, double delta); -void Gamepad_Tick(double delta); +void Gamepad_SetAxis(int port, int axis, float x, float y, float delta); +void Gamepad_Tick(float delta); +#define INPUT_MAX_GAMEPADS 4 /* whether to leave text input open for user to enter further input */ @@ -245,20 +243,4 @@ void InputHandler_OnScreensChanged(void); void InputHandler_DeleteBlock(void); void InputHandler_PlaceBlock(void); void InputHandler_PickBlock(void); - -/* Enumeration of on-screen buttons for touch GUI */ -#define ONSCREEN_BTN_CHAT (1 << 0) -#define ONSCREEN_BTN_LIST (1 << 1) -#define ONSCREEN_BTN_SPAWN (1 << 2) -#define ONSCREEN_BTN_SETSPAWN (1 << 3) -#define ONSCREEN_BTN_FLY (1 << 4) -#define ONSCREEN_BTN_NOCLIP (1 << 5) -#define ONSCREEN_BTN_SPEED (1 << 6) -#define ONSCREEN_BTN_HALFSPEED (1 << 7) -#define ONSCREEN_BTN_CAMERA (1 << 8) -#define ONSCREEN_BTN_DELETE (1 << 9) -#define ONSCREEN_BTN_PICK (1 << 10) -#define ONSCREEN_BTN_PLACE (1 << 11) -#define ONSCREEN_BTN_SWITCH (1 << 12) -#define ONSCREEN_MAX_BTNS 13 #endif diff --git a/src/LBackend.c b/src/LBackend.c index 5338e27..5d18efd 100644 --- a/src/LBackend.c +++ b/src/LBackend.c @@ -24,6 +24,9 @@ #include "Input.h" #include "Utils.h" #include "Event.h" +#include "Stream.h" +#include "Logger.h" +#include "Errors.h" struct FontDesc titleFont, textFont, hintFont, logoFont, rowFont; /* Contains the pixels that are drawn to the window */ @@ -102,6 +105,36 @@ void LBackend_DrawTitle(struct Context2D* ctx, const char* title) { Launcher_DrawTitle(&logoFont, title, ctx); } +/* Scales up flag bitmap if necessary */ +static void LBackend_ScaleFlag(struct Bitmap* bmp) { + struct Bitmap scaled; + int width = Display_ScaleX(bmp->width); + int height = Display_ScaleY(bmp->height); + /* at default DPI don't need to rescale it */ + if (width == bmp->width && height == bmp->height) return; + + Bitmap_TryAllocate(&scaled, width, height); + if (!scaled.scan0) { + Logger_SysWarn(ERR_OUT_OF_MEMORY, "resizing flags bitmap"); return; + } + + Bitmap_Scale(&scaled, bmp, 0, 0, bmp->width, bmp->height); + Mem_Free(bmp->scan0); + *bmp = scaled; +} + +void LBackend_DecodeFlag(struct Flag* flag, cc_uint8* data, cc_uint32 len) { + struct Stream s; + cc_result res; + + Stream_ReadonlyMemory(&s, data, len); + res = Png_Decode(&flag->bmp, &s); + if (res) Logger_SysWarn(res, "decoding flag"); + flag->meta = NULL; + + LBackend_ScaleFlag(&flag->bmp); +} + static void OnPointerMove(void* obj, int idx); void LBackend_SetScreen(struct LScreen* s) { int i; @@ -299,6 +332,7 @@ static void OnPointerDown(void* obj, int idx) { struct LScreen* s = Launcher_Active; struct LWidget* over; struct LWidget* prev; + if (Window_Main.SoftKeyboardFocus) return; if (!s) return; over = GetWidgetAt(s, idx); @@ -312,6 +346,7 @@ static void OnPointerUp(void* obj, int idx) { struct LScreen* s = Launcher_Active; struct LWidget* over; struct LWidget* prev; + if (Window_Main.SoftKeyboardFocus) return; if (!s) return; over = GetWidgetAt(s, idx); @@ -332,6 +367,7 @@ static void OnPointerMove(void* obj, int idx) { struct LWidget* over; struct LWidget* prev; cc_bool overSame; + if (Window_Main.SoftKeyboardFocus) return; if (!s) return; over = GetWidgetAt(s, idx); @@ -899,8 +935,9 @@ static void LTable_DrawHeaderBackground(struct LTable* w) { static BitmapCol LBackend_TableRowColor(struct LTable* w, int row) { struct ServerInfo* entry = row < w->rowsCount ? LTable_Get(row) : NULL; cc_bool selected = entry && String_Equals(&entry->hash, w->selectedHash); + cc_bool featured = entry && entry->featured; - return LTable_RowColor(entry, row, selected); + return LTable_RowColor(row, selected, featured); } /* Draws background behind each row in the table */ diff --git a/src/LBackend.h b/src/LBackend.h index 3162b9d..2ebb8ab 100644 --- a/src/LBackend.h +++ b/src/LBackend.h @@ -15,6 +15,7 @@ struct LLabel; struct LLine; struct LSlider; struct LTable; +struct Flag; void LBackend_Init(void); void LBackend_Free(void); @@ -24,6 +25,8 @@ void LBackend_CloseScreen(struct LScreen* s); void LBackend_UpdateTitleFont(void); void LBackend_DrawTitle(struct Context2D* ctx, const char* title); +void LBackend_DecodeFlag(struct Flag* flag, cc_uint8* data, cc_uint32 len); + /* Resets pixels to default, then draws widgets of current screen over it */ void LBackend_Redraw(void); void LBackend_ThemeChanged(void); @@ -65,7 +68,6 @@ void LBackend_TableInit(struct LTable* w); void LBackend_TableUpdate(struct LTable* w); /* Adjusts Y position of rows and number of visible rows */ void LBackend_TableReposition(struct LTable* w); -void LBackend_TableFlagAdded(struct LTable* w); void LBackend_TableDraw(struct LTable* w); void LBackend_TableMouseDown(struct LTable* w, int idx); diff --git a/src/LBackend_Android.c b/src/LBackend_Android.c new file mode 100644 index 0000000..5fd15e5 --- /dev/null +++ b/src/LBackend_Android.c @@ -0,0 +1,614 @@ +#include "LBackend.h" +#if defined CC_BUILD_ANDROID11111111111 +#include "Launcher.h" +#include "Drawer2D.h" +#include "Window.h" +#include "LWidgets.h" +#include "String.h" +#include "Gui.h" +#include "Drawer2D.h" +#include "Launcher.h" +#include "ExtMath.h" +#include "Window.h" +#include "Funcs.h" +#include "LWeb.h" +#include "Platform.h" +#include "LScreens.h" +#include "Input.h" +#include "Utils.h" +#include "Event.h" +#include +#include +#include +#include + +struct FontDesc logoFont; + +static void HookEvents(void); +static void LBackend_InitHooks(void); +void LBackend_Init(void) { + HookEvents(); + LBackend_InitHooks(); +} + +void LBackend_Free(void) { + Font_Free(&logoFont); +} + +void LBackend_UpdateLogoFont(void) { + Font_Free(&logoFont); + Launcher_MakeLogoFont(&logoFont); +} +void LBackend_DrawLogo(struct Context2D* ctx, const char* title) { + Launcher_DrawLogo(&logoFont, title, ctx); +} + +static void LBackend_LayoutDimensions(struct LWidget* w) { + const struct LLayout* l = w->layouts + 2; + while (l->type) + { + switch (l->type) + { + case LLAYOUT_WIDTH: + w->width = WindowInfo.Width - w->x - Display_ScaleX(l->offset); + w->width = max(1, w->width); + break; + case LLAYOUT_HEIGHT: + w->height = WindowInfo.Height - w->y - Display_ScaleY(l->offset); + w->height = max(1, w->height); + break; + } + l++; + } +} + +static void LBackend_GetLayoutArgs(void* widget, jvalue* args) { + struct LWidget* w = (struct LWidget*)widget; + const struct LLayout* l = w->layouts; + + args[0].i = l[0].type & 0xFF; + args[1].i = Display_ScaleX(l[0].offset); + args[2].i = l[1].type & 0xFF; + args[3].i = Display_ScaleY(l[1].offset); +} + +void LBackend_LayoutWidget(struct LWidget* w) { + const struct LLayout* l = w->layouts; + // TODO remove this? once Table is done + + /* e.g. Table widget needs adjusts width/height based on window */ + if (l[1].type & LLAYOUT_EXTRA) + LBackend_LayoutDimensions(w); +} + +void LBackend_MarkDirty(void* widget) { } +void LBackend_InitFramebuffer(void) { } +void LBackend_FreeFramebuffer(void) { } + +static void JNICALL java_drawBackground(JNIEnv* env, jobject o, jobject bmp) { + Platform_LogConst("---$$$--"); + AndroidBitmapInfo info; + void* addr = NULL; + + AndroidBitmap_getInfo(env, bmp, &info); + AndroidBitmap_lockPixels(env, bmp, &addr); + + // TODO refactor this + struct Context2D ctx; + struct Bitmap pixels; + pixels.scan0 = addr; + pixels.width = info.width; + pixels.height = info.height; + Context2D_Wrap(&ctx, &pixels); + + struct LScreen* s = Launcher_Active; + if (s) s->DrawBackground(s, &ctx); + + AndroidBitmap_unlockPixels(env, bmp); +} + +void LBackend_Redraw(void) { + JNIEnv* env; + JavaGetCurrentEnv(env); + JavaCallVoid(env, "redrawBackground", "()V", NULL); +} + +static void LBackend_ButtonUpdateBackground(struct LButton* btn); +void LBackend_ThemeChanged(void) { + struct LScreen* s = Launcher_Active; + LBackend_Redraw(); + + for (int i = 0; i < s->numWidgets; i++) + { + struct LWidget* w = s->widgets[i]; + if (w->type != LWIDGET_BUTTON) continue; + LBackend_ButtonUpdateBackground((struct LButton*)w); + } +} + +void LBackend_Tick(void) { } + +static struct LWidget* FindWidgetForView(int id) { + struct LScreen* s = Launcher_Active; + for (int i = 0; i < s->numWidgets; i++) + { + void* meta = s->widgets[i]->meta; + if (meta != id) continue; + + return s->widgets[i]; + } + return NULL; +} + +static int ToAndroidColor(BitmapCol color) { + int R = BitmapCol_R(color); + int G = BitmapCol_G(color); + int B = BitmapCol_B(color); + int A = BitmapCol_A(color); + return (A << 24) | (R << 16) | (G << 8) | B; +} + + +static jstring JNICALL java_nextTextPart(JNIEnv* env, jobject o, jstring total, jintArray state) { + char buffer[NATIVE_STR_LEN]; + cc_string text = JavaGetString(env, total, buffer); + + jint* state_ = (*env)->GetIntArrayElements(env, state, NULL); + text.buffer += state_[0]; + text.length -= state_[0]; + + cc_string left = text, part; + char colorCode = 'f'; + + Drawer2D_UNSAFE_NextPart(&text, &part, &colorCode); + BitmapCol color = Drawer2D_GetColor(colorCode); + + state_[0] += left.length - text.length; + state_[1] = ToAndroidColor(color); + + (*env)->ReleaseIntArrayElements(env, state, state_, 0); + return JavaMakeString(env, &part); +} + + +/*########################################################################################################################* +*-----------------------------------------------------Event handling------------------------------------------------------* +*#########################################################################################################################*/ +static void RequestRedraw(void* obj) { LBackend_Redraw(); } + +static void OnPointerUp(void* obj, int idx) { + Launcher_Active->MouseUp(Launcher_Active, idx); +} + +static void OnWindowCreated(void* obj) { + // e.g. after pause and resume + // TODO should pause/resume not trigger launcher screen recreation? + if (Launcher_Active) Launcher_SetScreen(Launcher_Active); +} + +static void HookEvents(void) { + Event_Register_(&WindowEvents.RedrawNeeded, NULL, RequestRedraw); + Event_Register_(&PointerEvents.Up, NULL, OnPointerUp); + Event_Register_(&WindowEvents.Created, NULL, OnWindowCreated); +} + + +/*########################################################################################################################* +*------------------------------------------------------ButtonWidget-------------------------------------------------------* +*#########################################################################################################################*/ +void LBackend_ButtonInit(struct LButton* w, int width, int height) { + w->_textWidth = Display_ScaleX(width); + w->_textHeight = Display_ScaleY(height); +} + +static void LBackend_ButtonShow(struct LButton* w) { + JNIEnv* env; JavaGetCurrentEnv(env); + jvalue args[6]; + + LBackend_GetLayoutArgs(w, args); + args[4].i = w->_textWidth; + args[5].i = w->_textHeight; + + jmethodID method = JavaGetIMethod(env, "buttonAdd", "(IIIIII)I"); + w->meta = (void*)JavaICall_Int(env, method, args); +} + +void LBackend_ButtonUpdate(struct LButton* w) { + JNIEnv* env; JavaGetCurrentEnv(env); + jvalue args[2]; + if (!w->meta) return; + + args[0].i = (int)w->meta; + args[1].l = JavaMakeString(env, &w->text); + + // TODO share logic with LabelUpdate/ButtonUpdate + jmethodID method = JavaGetIMethod(env, "buttonUpdate", "(ILjava/lang/String;)V"); + JavaICall_Void(env, method, args); + (*env)->DeleteLocalRef(env, args[1].l); +} +void LBackend_ButtonDraw(struct LButton* w) { } + +static void JNICALL java_makeButtonActive(JNIEnv* env, jobject o, jobject bmp) { + Platform_LogConst("---&&&--"); + AndroidBitmapInfo info; + void* addr = NULL; + + // TODO share code with drawBackground + AndroidBitmap_getInfo(env, bmp, &info); + AndroidBitmap_lockPixels(env, bmp, &addr); + + // TODO refactor this + struct Context2D ctx; + struct Bitmap pixels; + pixels.scan0 = addr; + pixels.width = info.width; + pixels.height = info.height; + Context2D_Wrap(&ctx, &pixels); + + LButton_DrawBackground(&ctx, 0, 0, info.width, info.height, true); + AndroidBitmap_unlockPixels(env, bmp); +} + +static void JNICALL java_makeButtonDefault(JNIEnv* env, jobject o, jobject bmp) { + Platform_LogConst("---####--"); + AndroidBitmapInfo info; + void* addr = NULL; + + // TODO share code with drawBackground + AndroidBitmap_getInfo(env, bmp, &info); + AndroidBitmap_lockPixels(env, bmp, &addr); + + // TODO refactor this + struct Context2D ctx; + struct Bitmap pixels; + pixels.scan0 = addr; + pixels.width = info.width; + pixels.height = info.height; + Context2D_Wrap(&ctx, &pixels); + + LButton_DrawBackground(&ctx, 0, 0, info.width, info.height, false); + AndroidBitmap_unlockPixels(env, bmp); +} + +static void LBackend_ButtonUpdateBackground(struct LButton* w) { + JNIEnv* env; JavaGetCurrentEnv(env); + jvalue args[1]; + if (!w->meta) return; + + args[0].i = (int)w->meta; + jmethodID method = JavaGetIMethod(env, "buttonUpdateBackground", "(I)V"); + JavaICall_Void(env, method, args); +} + + +/*########################################################################################################################* +*-----------------------------------------------------CheckboxWidget------------------------------------------------------* +*#########################################################################################################################*/ +void LBackend_CheckboxInit(struct LCheckbox* w) { } + +static void LBackend_CheckboxShow(struct LCheckbox* w) { + JNIEnv* env; JavaGetCurrentEnv(env); + jvalue args[6]; + + LBackend_GetLayoutArgs(w, args); + args[4].l = JavaMakeString(env, &w->text); + args[5].z = w->value; + + jmethodID method = JavaGetIMethod(env, "checkboxAdd", "(IIIILjava/lang/String;Z)I"); + w->meta = (void*)JavaICall_Int(env, method, args); + (*env)->DeleteLocalRef(env, args[4].l); +} +void LBackend_CheckboxDraw(struct LCheckbox* w) { } + +void LBackend_CheckboxUpdate(struct LCheckbox* w) { + JNIEnv* env; JavaGetCurrentEnv(env); + jvalue args[2]; + if (!w->meta) return; + + args[0].i = (int)w->meta; + args[1].z = w->value; + + // TODO share logic with LabelUpdate/ButtonUpdate + jmethodID method = JavaGetIMethod(env, "checkboxUpdate", "(IZ)V"); + JavaICall_Void(env, method, args); +} + + +/*########################################################################################################################* +*------------------------------------------------------InputWidget--------------------------------------------------------* +*#########################################################################################################################*/ +void LBackend_InputInit(struct LInput* w, int width) { + w->_textHeight = Display_ScaleX(width); +} + +static void LBackend_InputShow(struct LInput* w) { + JNIEnv* env; JavaGetCurrentEnv(env); + jvalue args[8]; + + LBackend_GetLayoutArgs(w, args); + args[4].i = w->_textHeight; + args[5].i = Display_ScaleY(LINPUT_HEIGHT); + args[6].i = w->inputType; + args[7].l = JavaMakeConst(env, w->hintText); + + jmethodID method = JavaGetIMethod(env, "inputAdd", "(IIIIIIILjava/lang/String;)I"); + w->meta = (void*)JavaICall_Int(env, method, args); + (*env)->DeleteLocalRef(env, args[7].l); +} + +void LBackend_InputUpdate(struct LInput* w) { + JNIEnv* env; JavaGetCurrentEnv(env); + jvalue args[2]; + if (!w->meta) return; + + args[0].i = (int)w->meta; + args[1].l = JavaMakeString(env, &w->text); + + // TODO share logic with LabelUpdate/ButtonUpdate + jmethodID method = JavaGetIMethod(env, "inputUpdate", "(ILjava/lang/String;)V"); + JavaICall_Void(env, method, args); + (*env)->DeleteLocalRef(env, args[1].l); +} + +void LBackend_InputTick(struct LInput* w) { } +void LBackend_InputSelect(struct LInput* w, int idx, cc_bool wasSelected) { } +void LBackend_InputUnselect(struct LInput* w) { } +void LBackend_InputDraw(struct LInput* w) { } + + +/*########################################################################################################################* +*------------------------------------------------------LabelWidget--------------------------------------------------------* +*#########################################################################################################################*/ +void LBackend_LabelInit(struct LLabel* w) { } + +static void LBackend_LabelShow(struct LLabel* w) { + JNIEnv* env; JavaGetCurrentEnv(env); + jvalue args[4]; + LBackend_GetLayoutArgs(w, args); + + jmethodID method = JavaGetIMethod(env, "labelAdd", "(IIII)I"); + w->meta = (void*)JavaICall_Int(env, method, args); +} + +void LBackend_LabelUpdate(struct LLabel* w) { + JNIEnv* env; JavaGetCurrentEnv(env); + jvalue args[2]; + if (!w->meta) return; + + args[0].i = (int)w->meta; + args[1].l = JavaMakeString(env, &w->text); + + // TODO share logic with LabelUpdate/ButtonUpdate + jmethodID method = JavaGetIMethod(env, "labelUpdate", "(ILjava/lang/String;)V"); + JavaICall_Void(env, method, args); + (*env)->DeleteLocalRef(env, args[1].l); +} +void LBackend_LabelDraw(struct LLabel* w) { } + + +/*########################################################################################################################* +*-------------------------------------------------------LineWidget--------------------------------------------------------* +*#########################################################################################################################*/ +void LBackend_LineInit(struct LLine* w, int width) { + w->_width = Display_ScaleX(width); +} + +static void LBackend_LineShow(struct LLine* w) { + JNIEnv* env; JavaGetCurrentEnv(env); + jvalue args[7]; + + LBackend_GetLayoutArgs(w, args); + args[4].i = w->_width; + args[5].i = Display_ScaleY(LLINE_HEIGHT); + args[6].i = ToAndroidColor(LLine_GetColor()); + + jmethodID method = JavaGetIMethod(env, "lineAdd", "(IIIIIII)I"); + w->meta = (void*)JavaICall_Int(env, method, args); +} +void LBackend_LineDraw(struct LLine* w) { } + + +/*########################################################################################################################* +*------------------------------------------------------SliderWidget-------------------------------------------------------* +*#########################################################################################################################*/ +void LBackend_SliderInit(struct LSlider* w, int width, int height) { + w->_width = Display_ScaleX(width); + w->_height = Display_ScaleY(height); +} + +static void LBackend_SliderShow(struct LSlider* w) { + JNIEnv* env; JavaGetCurrentEnv(env); + jvalue args[7]; + + LBackend_GetLayoutArgs(w, args); + args[4].i = w->_width; + args[5].i = w->_height; + args[6].i = ToAndroidColor(w->color); + + jmethodID method = JavaGetIMethod(env, "sliderAdd", "(IIIIIII)I"); + w->meta = (void*)JavaICall_Int(env, method, args); +} + +void LBackend_SliderUpdate(struct LSlider* w) { + JNIEnv* env; JavaGetCurrentEnv(env); + jvalue args[2]; + if (!w->meta) return; + + args[0].i = (int)w->meta; + args[1].i = w->value; + + jmethodID method = JavaGetIMethod(env, "sliderUpdate", "(II)V"); + JavaICall_Void(env, method, args); +} +void LBackend_SliderDraw(struct LSlider* w) {} + + +/*########################################################################################################################* +*-------------------------------------------------------TableWidget-------------------------------------------------------* +*#########################################################################################################################*/ +void LBackend_TableInit(struct LTable* w) { + +} + +static void LBackend_TableShow(struct LTable* w) { + JNIEnv* env; JavaGetCurrentEnv(env); + jvalue args[5]; + + LBackend_GetLayoutArgs(w, args); + args[4].i = ToAndroidColor(LTable_RowColor(1, false, false)); + + jmethodID method = JavaGetIMethod(env, "tableAdd", "(IIIII)I"); + w->meta = (void*)JavaICall_Int(env, method, args); + LBackend_TableUpdate(w); +} + +static jstring GetTableDetails(JNIEnv* env, struct ServerInfo* server) { + char buffer[NATIVE_STR_LEN]; + cc_string text = String_FromArray(buffer); + + String_Format2(&text, "%i/%i players, up for ", &server->players, &server->maxPlayers); + LTable_FormatUptime(&text, server->uptime); + if (server->software.length) String_Format1(&text, " | %s", &server->software); + + return JavaMakeString(env, &text); +} + +void LBackend_TableUpdate(struct LTable* w) { + JNIEnv* env; JavaGetCurrentEnv(env); + jvalue args[3]; + jmethodID method; + + method = JavaGetIMethod(env, "tableStartUpdate", "()V"); + JavaICall_Void(env, method, args); + method = JavaGetIMethod(env, "tableAddEntry", "(Ljava/lang/String;Ljava/lang/String;Z)V"); + + for (int i = 0; i < w->rowsCount; i++) + { + struct ServerInfo* info = LTable_Get(i); + args[0].l = JavaMakeString(env, &info->name); + args[1].l = GetTableDetails(env, info); + args[2].z = info->featured; + JavaICall_Void(env, method, args); + + (*env)->DeleteLocalRef(env, args[0].l); + (*env)->DeleteLocalRef(env, args[1].l); + } + + method = JavaGetIMethod(env, "tableFinishUpdate", "(I)V"); + args[0].i = (int)w->meta; + JavaICall_Void(env, method, args); +} + +void LBackend_TableReposition(struct LTable* w) { + +} + +void LBackend_TableFlagAdded(struct LTable* w) { +} + +void LBackend_TableDraw(struct LTable* w) { } +void LBackend_TableMouseDown(struct LTable* w, int idx) { } +void LBackend_TableMouseMove(struct LTable* w, int idx) { } +void LBackend_TableMouseUp(struct LTable* w, int idx) { } + +static jint JNICALL java_tableGetColor(JNIEnv* env, jobject o, jint row, jboolean selected, jboolean featured) { + return ToAndroidColor(LTable_RowColor(row, selected, featured)); +} + + +/*########################################################################################################################* +*--------------------------------------------------------UIBackend--------------------------------------------------------* +*#########################################################################################################################*/ +#define UI_EVENT_CLICKED 1 +#define UI_EVENT_CHANGED 2 + +static void JNICALL java_UIClicked(JNIEnv* env, jobject o, jint id) { + struct LWidget* w = FindWidgetForView(id); + if (!w) return; + + if (w->OnClick) w->OnClick(w); +} + +static void JNICALL java_UIChanged(JNIEnv* env, jobject o, jint id, jint val) { + struct LCheckbox* cb = (struct LCheckbox*)FindWidgetForView(id); + if (!cb) return; + + cb->value = val; + if (cb->ValueChanged) cb->ValueChanged(cb); +} + +static void JNICALL java_UIString(JNIEnv* env, jobject o, jint id, jstring str) { + struct LInput* ipt = (struct LInput*)FindWidgetForView(id); + if (!ipt) return; + + char buffer[NATIVE_STR_LEN]; + cc_string text = JavaGetString(env, str, buffer); + String_Copy(&ipt->text, &text); + if (ipt->TextChanged) ipt->TextChanged(ipt); +} + +static void ShowWidget(struct LWidget* w) { + switch (w->type) { + case LWIDGET_BUTTON: + LBackend_ButtonShow((struct LButton*)w); + LBackend_ButtonUpdate((struct LButton*)w); + break; + case LWIDGET_CHECKBOX: + LBackend_CheckboxShow((struct LCheckbox*)w); + break; + case LWIDGET_INPUT: + LBackend_InputShow((struct LInput*)w); + LBackend_InputUpdate((struct LInput*)w); + break; + case LWIDGET_LABEL: + LBackend_LabelShow((struct LLabel*)w); + LBackend_LabelUpdate((struct LLabel*)w); + break; + case LWIDGET_LINE: + LBackend_LineShow((struct LLine*)w); + break; + case LWIDGET_SLIDER: + LBackend_SliderShow((struct LSlider*)w); + break; + case LWIDGET_TABLE: + LBackend_TableShow((struct LTable*)w); + break; + } +} + +void LBackend_SetScreen(struct LScreen* s) { + for (int i = 0; i < s->numWidgets; i++) + { + ShowWidget(s->widgets[i]); + } +} + +void LBackend_CloseScreen(struct LScreen* s) { + // stop referencing widgets + for (int i = 0; i < s->numWidgets; i++) + { + s->widgets[i]->meta = NULL; + } + + JNIEnv* env; JavaGetCurrentEnv(env); + jmethodID method = JavaGetIMethod(env, "clearWidgetsAsync", "()V"); + JavaICall_Void(env, method, NULL); +} + +static const JNINativeMethod methods[] = { + { "nextTextPart", "(Ljava/lang/String;[I)Ljava/lang/String;", java_nextTextPart }, + { "drawBackground", "(Landroid/graphics/Bitmap;)V", java_drawBackground }, + { "makeButtonActive", "(Landroid/graphics/Bitmap;)V", java_makeButtonActive }, + { "makeButtonDefault", "(Landroid/graphics/Bitmap;)V", java_makeButtonDefault }, + { "processOnUIClicked", "(I)V", java_UIClicked }, + { "processOnUIChanged", "(II)V", java_UIChanged }, + { "processOnUIString", "(ILjava/lang/String;)V", java_UIString }, + { "tableGetColor", "(IZZ)I", java_tableGetColor }, +}; + +static void LBackend_InitHooks(void) { + JNIEnv* env; + JavaGetCurrentEnv(env); + JavaRegisterNatives(env, methods); +} +#endif \ No newline at end of file diff --git a/src/LScreens.c b/src/LScreens.c index 6c8d781..4d8df2b 100644 --- a/src/LScreens.c +++ b/src/LScreens.c @@ -18,6 +18,7 @@ #include "Utils.h" #include "LBackend.h" #include "Http.h" +#include "Game.h" #define LAYOUTS static const struct LLayout #define IsEnterButton(btn) (btn == CCKEY_ENTER || btn == CCPAD_START || btn == CCPAD_A || btn == CCKEY_KP_ENTER) @@ -379,14 +380,9 @@ static void ColoursScreen_MouseWheel(struct LScreen* s_, float delta) { } static void ColoursScreen_KeyDown(struct LScreen* s, int key, cc_bool was) { - if (Input_IsLeftButton(key)) { - ColoursScreen_AdjustSelected(s, -1); - } else if (Input_IsRightButton(key)) { - ColoursScreen_AdjustSelected(s, +1); - } else if (Input_IsUpButton(key)) { - ColoursScreen_AdjustSelected(s, +10); - } else if (Input_IsDownButton(key)) { - ColoursScreen_AdjustSelected(s, -10); + int delta = Input_CalcDelta(key, 1, 10); + if (delta) { + ColoursScreen_AdjustSelected(s, delta); } else { LScreen_KeyDown(s, key, was); } @@ -652,18 +648,79 @@ void MFAScreen_SetActive(void) { } +/*########################################################################################################################* +*----------------------------------------------------------SplitScreen----------------------------------------------------* +*#########################################################################################################################*/ +#ifdef CC_BUILD_SPLITSCREEN +static struct SplitScreen { + LScreen_Layout + struct LButton btnPlayers[3], btnBack; + cc_bool signingIn; +} SplitScreen; + +#define SPLITSCREEN_MAX_WIDGETS 4 +static struct LWidget* split_widgets[SPLITSCREEN_MAX_WIDGETS]; + +LAYOUTS sps_btnPlayers2[] = { { ANCHOR_CENTRE, 0 }, { ANCHOR_CENTRE, -120 } }; +LAYOUTS sps_btnPlayers3[] = { { ANCHOR_CENTRE, 0 }, { ANCHOR_CENTRE, -70 } }; +LAYOUTS sps_btnPlayers4[] = { { ANCHOR_CENTRE, 0 }, { ANCHOR_CENTRE, -20 } }; +LAYOUTS sps_btnBack[] = { { ANCHOR_CENTRE, 0 }, { ANCHOR_CENTRE, 170 } }; + +static void SplitScreen_Start(int players) { + static const cc_string user = String_FromConst(DEFAULT_USERNAME); + Game_NumLocalPlayers = players; + + Launcher_StartGame(&user, &String_Empty, &String_Empty, &String_Empty, &String_Empty); +} + +static void SplitScreen_Players2(void* w) { SplitScreen_Start(2); } +static void SplitScreen_Players3(void* w) { SplitScreen_Start(3); } +static void SplitScreen_Players4(void* w) { SplitScreen_Start(4); } + +static void SplitScreen_Activated(struct LScreen* s_) { + struct SplitScreen* s = (struct SplitScreen*)s_; + + LButton_Add(s, &s->btnPlayers[0], 300, 35, "2 player splitscreen", + SplitScreen_Players2, sps_btnPlayers2); + LButton_Add(s, &s->btnPlayers[1], 300, 35, "3 player splitscreen", + SplitScreen_Players3, sps_btnPlayers3); + LButton_Add(s, &s->btnPlayers[2], 300, 35, "4 player splitscreen", + SplitScreen_Players4, sps_btnPlayers4); + + LButton_Add(s, &s->btnBack, 100, 35, "Back", + SwitchToMain, sps_btnBack); +} + +void SplitScreen_SetActive(void) { + struct SplitScreen* s = &SplitScreen; + LScreen_Reset((struct LScreen*)s); + + s->widgets = split_widgets; + s->maxWidgets = Array_Elems(split_widgets); + + s->Activated = SplitScreen_Activated; + s->title = "Splitscreen mode"; + + Launcher_SetScreen((struct LScreen*)s); +} + +static void SwitchToSplitScreen(void* w) { SplitScreen_SetActive(); } +#endif + + /*########################################################################################################################* *----------------------------------------------------------MainScreen-----------------------------------------------------* *#########################################################################################################################*/ static struct MainScreen { LScreen_Layout - struct LButton btnLogin, btnResume, btnDirect, btnSPlayer, btnRegister, btnOptions, btnUpdates; + struct LButton btnLogin, btnResume, btnDirect, btnSPlayer, btnSplit; + struct LButton btnRegister, btnOptions, btnUpdates; struct LInput iptUsername, iptPassword; struct LLabel lblStatus, lblUpdate; cc_bool signingIn; } MainScreen; -#define MAINSCREEN_MAX_WIDGETS 11 +#define MAINSCREEN_MAX_WIDGETS 12 static struct LWidget* main_widgets[MAINSCREEN_MAX_WIDGETS]; LAYOUTS main_iptUsername[] = { { ANCHOR_CENTRE_MIN, -140 }, { ANCHOR_CENTRE, -120 } }; @@ -675,6 +732,7 @@ LAYOUTS main_lblStatus[] = { { ANCHOR_CENTRE, 0 }, { ANCHOR_CENTRE, 20 } }; LAYOUTS main_btnResume[] = { { ANCHOR_CENTRE, 90 }, { ANCHOR_CENTRE, -25 } }; LAYOUTS main_btnDirect[] = { { ANCHOR_CENTRE, 0 }, { ANCHOR_CENTRE, 60 } }; LAYOUTS main_btnSPlayer[] = { { ANCHOR_CENTRE, 0 }, { ANCHOR_CENTRE, 110 } }; +LAYOUTS main_btnSplit[] = { { ANCHOR_CENTRE, 0 }, { ANCHOR_CENTRE, 160 } }; LAYOUTS main_btnRegister[] = { { ANCHOR_MIN, 6 }, { ANCHOR_MAX, 6 } }; LAYOUTS main_btnOptions[] = { { ANCHOR_CENTRE, 0 }, { ANCHOR_MAX, 6 } }; @@ -823,6 +881,12 @@ static void MainScreen_ApplyUpdateLabel(struct MainScreen* s) { } } +#ifdef CC_BUILD_CONSOLE +static void MainScreen_ExitApp(void* w) { + Window_Main.Exists = false; +} +#endif + static void MainScreen_Activated(struct LScreen* s_) { struct MainScreen* s = (struct MainScreen*)s_; @@ -839,11 +903,13 @@ static void MainScreen_Activated(struct LScreen* s_) { LLabel_Add(s, &s->lblStatus, "", main_lblStatus); LButton_Add(s, &s->btnDirect, 200, 35, "Direct connect", SwitchToDirectConnect, main_btnDirect); - LButton_Add(s, &s->btnSPlayer, 200, 35, "Singleplayer", + LButton_Add(s, &s->btnSPlayer, 200, 35, "Singleplayer", MainScreen_Singleplayer, main_btnSPlayer); +#ifdef CC_BUILD_SPLITSCREEN + LButton_Add(s, &s->btnSplit, 200, 35, "Splitscreen (WIP)", + SwitchToSplitScreen, main_btnSplit); +#endif - LLabel_Add(s, &s->lblUpdate, "&eChecking..", - Updater_Supported ? main_lblUpdate_N : main_lblUpdate_H); if (Process_OpenSupported) { LButton_Add(s, &s->btnRegister, 100, 35, "Register", MainScreen_Register, main_btnRegister); @@ -851,10 +917,19 @@ static void MainScreen_Activated(struct LScreen* s_) { LButton_Add(s, &s->btnOptions, 100, 35, "Options", SwitchToSettings, main_btnOptions); + +#ifdef CC_BUILD_CONSOLE + LLabel_Add(s, &s->lblUpdate, "&eChecking..", main_lblUpdate_N); + LButton_Add(s, &s->btnUpdates, 100, 35, "Exit", + MainScreen_ExitApp, main_btnUpdates); +#else + LLabel_Add(s, &s->lblUpdate, "&eChecking..", + Updater_Supported ? main_lblUpdate_N : main_lblUpdate_H); if (Updater_Supported) { LButton_Add(s, &s->btnUpdates, 100, 35, "Updates", SwitchToUpdates, main_btnUpdates); } +#endif s->btnResume.OnHover = MainScreen_ResumeHover; s->btnResume.OnUnhover = MainScreen_ResumeUnhover; @@ -1300,12 +1375,8 @@ static void ServersScreen_Activated(struct LScreen* s_) { static void ServersScreen_Tick(struct LScreen* s_) { struct ServersScreen* s = (struct ServersScreen*)s_; - int count; LScreen_Tick(s_); - - count = FetchFlagsTask.count; LWebTask_Tick(&FetchFlagsTask.Base, NULL); - if (count != FetchFlagsTask.count) LBackend_TableFlagAdded(&s->table); if (!FetchServersTask.Base.working) return; LWebTask_Tick(&FetchServersTask.Base, NULL); diff --git a/src/LWeb.c b/src/LWeb.c index d623abe..95bd05d 100644 --- a/src/LWeb.c +++ b/src/LWeb.c @@ -11,6 +11,7 @@ #include "Errors.h" #include "Utils.h" #include "Http.h" +#include "LBackend.h" /*########################################################################################################################* *----------------------------------------------------------JSON-----------------------------------------------------------* @@ -580,39 +581,13 @@ void FetchUpdateTask_Run(cc_bool release, int buildIndex) { *#########################################################################################################################*/ struct FetchFlagsData FetchFlagsTask; static int flagsCount, flagsCapacity; - static struct Flag* flags; -/* Scales up flag bitmap if necessary */ -static void FetchFlagsTask_Scale(struct Bitmap* bmp) { - struct Bitmap scaled; - int width = Display_ScaleX(bmp->width); - int height = Display_ScaleY(bmp->height); - /* at default DPI don't need to rescale it */ - if (width == bmp->width && height == bmp->height) return; - - Bitmap_TryAllocate(&scaled, width, height); - if (!scaled.scan0) { - Logger_SysWarn(ERR_OUT_OF_MEMORY, "resizing flags bitmap"); return; - } - - Bitmap_Scale(&scaled, bmp, 0, 0, bmp->width, bmp->height); - Mem_Free(bmp->scan0); - *bmp = scaled; -} - static void FetchFlagsTask_DownloadNext(void); static void FetchFlagsTask_Handle(cc_uint8* data, cc_uint32 len) { struct Flag* flag = &flags[FetchFlagsTask.count]; - struct Stream s; - cc_result res; - - Stream_ReadonlyMemory(&s, data, len); - res = Png_Decode(&flag->bmp, &s); - if (res) Logger_SysWarn(res, "decoding flag"); - flag->meta = NULL; - - FetchFlagsTask_Scale(&flag->bmp); + LBackend_DecodeFlag(flag, data, len); + FetchFlagsTask.count++; FetchFlagsTask_DownloadNext(); } @@ -645,7 +620,8 @@ static void FetchFlagsTask_Ensure(void) { void FetchFlagsTask_Add(const struct ServerInfo* server) { int i; - for (i = 0; i < flagsCount; i++) { + for (i = 0; i < flagsCount; i++) + { if (flags[i].country[0] != server->country[0]) continue; if (flags[i].country[1] != server->country[1]) continue; /* flag is already or will be downloaded */ @@ -656,6 +632,7 @@ void FetchFlagsTask_Add(const struct ServerInfo* server) { Bitmap_Init(flags[flagsCount].bmp, 0, 0, NULL); flags[flagsCount].country[0] = server->country[0]; flags[flagsCount].country[1] = server->country[1]; + flags[flagsCount].meta = NULL; flagsCount++; FetchFlagsTask_DownloadNext(); @@ -663,7 +640,8 @@ void FetchFlagsTask_Add(const struct ServerInfo* server) { struct Flag* Flags_Get(const struct ServerInfo* server) { int i; - for (i = 0; i < FetchFlagsTask.count; i++) { + for (i = 0; i < FetchFlagsTask.count; i++) + { if (flags[i].country[0] != server->country[0]) continue; if (flags[i].country[1] != server->country[1]) continue; return &flags[i]; diff --git a/src/LWidgets.c b/src/LWidgets.c index 454b0be..53c8039 100644 --- a/src/LWidgets.c +++ b/src/LWidgets.c @@ -32,8 +32,8 @@ void LWidget_CalcOffsets(void) { flagYOffset = Display_ScaleY(6); } -void LWidget_DrawBorder(struct Context2D* ctx, BitmapCol color, int insetX, int insetY, - int x, int y, int width, int height) { +static void LWidget_DrawInsetBorder(struct Context2D* ctx, BitmapCol color, int insetX, int insetY, + int x, int y, int width, int height) { Context2D_Clear(ctx, color, x + insetX, y, width - 2 * insetX, insetY); @@ -48,6 +48,22 @@ void LWidget_DrawBorder(struct Context2D* ctx, BitmapCol color, int insetX, int insetX, height - 2 * insetY); } +void LWidget_DrawBorder(struct Context2D* ctx, BitmapCol color, int borderX, int borderY, + int x, int y, int width, int height) { + Context2D_Clear(ctx, color, + x, y, + width, borderY); + Context2D_Clear(ctx, color, + x, y + height - borderY, + width, borderY); + Context2D_Clear(ctx, color, + x, y, + borderX, height); + Context2D_Clear(ctx, color, + x + width - borderX, y, + borderX, height); +} + /*########################################################################################################################* *------------------------------------------------------ButtonWidget-------------------------------------------------------* @@ -70,11 +86,10 @@ static void LButton_DrawBase(struct Context2D* ctx, int x, int y, int width, int static void LButton_DrawBorder(struct Context2D* ctx, int x, int y, int width, int height) { BitmapCol backColor = Launcher_Theme.ButtonBorderColor; #ifdef CC_BUILD_IOS - int xoff = 0; /* TODO temp hack */ + LWidget_DrawBorder(ctx, backColor, oneX, oneY, x, y, width, height); #else - int xoff = oneX; + LWidget_DrawInsetBorder(ctx, backColor, oneX, oneY, x, y, width, height); #endif - LWidget_DrawBorder(ctx, backColor, xoff, oneY, x, y, width, height); } static void LButton_DrawHighlight(struct Context2D* ctx, int x, int y, int width, int height, cc_bool active) { @@ -758,14 +773,14 @@ void LTable_ShowSelected(struct LTable* w) { LTable_ClampTopRow(w); } -BitmapCol LTable_RowColor(struct ServerInfo* entry, int row, cc_bool selected) { +BitmapCol LTable_RowColor(int row, cc_bool selected, cc_bool featured) { BitmapCol featSelColor = BitmapColor_RGB( 50, 53, 0); BitmapCol featuredColor = BitmapColor_RGB(101, 107, 0); BitmapCol selectedColor = BitmapColor_RGB( 40, 40, 40); - if (entry && entry->featured) { + if (featured) { return selected ? featSelColor : featuredColor; - } else if (entry && selected) { + } else if (selected) { return selectedColor; } diff --git a/src/LWidgets.h b/src/LWidgets.h index 29adae4..64be2e1 100644 --- a/src/LWidgets.h +++ b/src/LWidgets.h @@ -247,5 +247,5 @@ int LTable_GetSelectedIndex(struct LTable* w); void LTable_SetSelectedTo(struct LTable* w, int index); void LTable_RowClick(struct LTable* w, int row); /* Works out the background color of the given row */ -BitmapCol LTable_RowColor(struct ServerInfo* entry, int row, cc_bool selected); +BitmapCol LTable_RowColor(int row, cc_bool selected, cc_bool featured); #endif diff --git a/src/Launcher.c b/src/Launcher.c index 5bb7a4d..4b1e7f4 100644 --- a/src/Launcher.c +++ b/src/Launcher.c @@ -65,8 +65,7 @@ void Launcher_DisplayHttpError(struct HttpRequest* req, const char* action, cc_s if (res) { /* Non HTTP error - this is not good */ Http_LogError(action, req); - String_Format2(dst, res >= 0x80000000 ? "&cError %h when %c" : "&cError %i when %c", - &res, action); + String_Format2(dst, "&cError %e when %c", &res, action); } else if (status != 200) { String_Format2(dst, "&c%i error when %c", &status, action); } else { @@ -272,7 +271,9 @@ void Launcher_Run(void) { #endif for (;;) { - Window_ProcessEvents(10 / 1000.0); + Window_ProcessEvents(10 / 1000.0f); + Window_ProcessGamepads(10 / 1000.0f); + Gamepad_Tick(10 / 1000.0f); if (!Window_Main.Exists || Launcher_ShouldExit) break; Launcher_Active->Tick(Launcher_Active); @@ -579,4 +580,4 @@ void Launcher_MakeTitleFont(struct FontDesc* font) { Font_Make(font, 32, FONT_FLAGS_NONE); Drawer2D.BitmappedText = false; } -#endif \ No newline at end of file +#endif diff --git a/src/Logger.c b/src/Logger.c index f4732be..f1797da 100644 --- a/src/Logger.c +++ b/src/Logger.c @@ -126,14 +126,12 @@ static void AppendErrorDesc(cc_string* msg, cc_result res, Logger_DescribeError } void Logger_FormatWarn(cc_string* msg, cc_result res, const char* action, Logger_DescribeError describeErr) { - String_Format2(msg, res < 20000 ? "Error %i when %c" : "Error %h when %c", - &res, action); + String_Format2(msg, "Error %e when %c", &res, action); AppendErrorDesc(msg, res, describeErr); } void Logger_FormatWarn2(cc_string* msg, cc_result res, const char* action, const cc_string* path, Logger_DescribeError describeErr) { - String_Format3(msg, res < 20000 ? "Error %i when %c '%s'" : "Error %h when %c '%s'", - &res, action, path); + String_Format3(msg, "Error %e when %c '%s'", &res, action, path); AppendErrorDesc(msg, res, describeErr); } diff --git a/src/MapRenderer.c b/src/MapRenderer.c index 77d4eec..9a02904 100644 --- a/src/MapRenderer.c +++ b/src/MapRenderer.c @@ -78,7 +78,7 @@ CC_NOINLINE static int MapRenderer_UsedAtlases(void) { /*########################################################################################################################* *-------------------------------------------------------Map rendering-----------------------------------------------------* *#########################################################################################################################*/ -static void CheckWeather(double delta) { +static void CheckWeather(float delta) { IVec3 pos; BlockID block; cc_bool outside; @@ -183,7 +183,7 @@ static void RenderNormalBatch(int batch) { } } -void MapRenderer_RenderNormal(double delta) { +void MapRenderer_RenderNormal(float delta) { int batch; if (!mapChunks) return; @@ -256,7 +256,7 @@ static void RenderTranslucentBatch(int batch) { } } -void MapRenderer_RenderTranslucent(double delta) { +void MapRenderer_RenderTranslucent(float delta) { int vertices, batch; if (!mapChunks) return; @@ -510,7 +510,7 @@ static void RefreshBorderChunks(int maxHeight) { /*########################################################################################################################* *--------------------------------------------------Chunks updating/sorting------------------------------------------------* *#########################################################################################################################*/ -#define CHUNK_TARGET_TIME ((1.0/30) + 0.01) +#define CHUNK_TARGET_TIME ((1.0f/30) + 0.01f) static int chunksTarget = 12; static Vec3 lastCamPos; static float lastYaw, lastPitch; @@ -601,7 +601,7 @@ static int UpdateChunksStill(int* chunkUpdates) { return j; } -static void UpdateChunks(double delta) { +static void UpdateChunks(float delta) { struct LocalPlayer* p; cc_bool samePos; int chunkUpdates = 0; @@ -610,7 +610,7 @@ static void UpdateChunks(double delta) { chunksTarget += delta < CHUNK_TARGET_TIME ? 1 : -1; Math_Clamp(chunksTarget, 4, maxChunkUpdates); - p = &LocalPlayer_Instance; + p = Entities.CurPlayer; samePos = Vec3_Equals(&Camera.CurrentPos, &lastCamPos) && p->Base.Pitch == lastPitch && p->Base.Yaw == lastYaw; @@ -684,7 +684,7 @@ static void UpdateSortOrder(void) { /*SimpleOcclusionCulling();*/ } -void MapRenderer_Update(double delta) { +void MapRenderer_Update(float delta) { if (!mapChunks) return; UpdateSortOrder(); UpdateChunks(delta); diff --git a/src/MapRenderer.h b/src/MapRenderer.h index 97a8aba..f378656 100644 --- a/src/MapRenderer.h +++ b/src/MapRenderer.h @@ -59,13 +59,13 @@ struct ChunkInfo { }; /* Renders the meshes of non-translucent blocks in visible chunks. */ -void MapRenderer_RenderNormal(double delta); +void MapRenderer_RenderNormal(float delta); /* Renders the meshes of translucent blocks in visible chunks. */ -void MapRenderer_RenderTranslucent(double delta); +void MapRenderer_RenderTranslucent(float delta); /* Potentially updates sort order of rendered chunks. */ /* Potentially builds meshes for several nearby chunks. */ /* NOTE: This should be called once per frame. */ -void MapRenderer_Update(double delta); +void MapRenderer_Update(float delta); /* Marks the given chunk as needing to be rebuilt/redrawn. */ /* NOTE: Coordinates outside the map are simply ignored. */ diff --git a/src/Menus.c b/src/Menus.c index aba842e..774a31f 100644 --- a/src/Menus.c +++ b/src/Menus.c @@ -41,34 +41,33 @@ struct MenuOptionDesc { Widget_LeftClick OnClick; Button_Get GetValue; Button_Set SetValue; }; -struct SimpleButtonDesc { short x, y; const char* title; Widget_LeftClick onClick; }; /*########################################################################################################################* *--------------------------------------------------------Menu base--------------------------------------------------------* *#########################################################################################################################*/ -static void Menu_InitButtons(struct ButtonWidget* btns, int width, const struct SimpleButtonDesc* descs, int count) { +void Menu_AddButtons(void* screen, struct ButtonWidget* btns, int width, const struct SimpleButtonDesc* descs, int count) { int i; for (i = 0; i < count; i++) { - ButtonWidget_Init(&btns[i], width, descs[i].onClick); + ButtonWidget_Add(screen, &btns[i], width, descs[i].onClick); } } -static void Menu_LayoutButtons(struct ButtonWidget* btns, const struct SimpleButtonDesc* descs, int count) { +void Menu_LayoutButtons(struct ButtonWidget* btns, const struct SimpleButtonDesc* descs, int count) { int i; for (i = 0; i < count; i++) { Widget_SetLocation(&btns[i], ANCHOR_CENTRE, ANCHOR_CENTRE, descs[i].x, descs[i].y); } } -static void Menu_SetButtons(struct ButtonWidget* btns, struct FontDesc* font, const struct SimpleButtonDesc* descs, int count) { +void Menu_SetButtons(struct ButtonWidget* btns, struct FontDesc* font, const struct SimpleButtonDesc* descs, int count) { int i; for (i = 0; i < count; i++) { ButtonWidget_SetConst(&btns[i], descs[i].title, font); } } -static void Menu_LayoutBack(struct ButtonWidget* btn) { +void Menu_LayoutBack(struct ButtonWidget* btn) { Widget_SetLocation(btn, ANCHOR_CENTRE, ANCHOR_MAX, 0, 25); } static void Menu_CloseKeyboard(void* s) { OnscreenKeyboard_Close(); } @@ -264,7 +263,7 @@ static void ListScreen_Layout(void* screen) { ANCHOR_CENTRE, ANCHOR_CENTRE, 0, (i - 2) * 50); } - if (s->ActionClick && Input_TouchMode) { + if (Input_TouchMode) { Widget_SetLocation(&s->done, ANCHOR_CENTRE_MIN, ANCHOR_MAX, -150, 25); Widget_SetLocation(&s->action, ANCHOR_CENTRE_MAX, ANCHOR_MAX, -150, 25); } else { @@ -403,24 +402,19 @@ static void ListScreen_Init(void* screen) { ButtonWidget_Add(s, &s->btns[i], 300, s->EntryClick); s->btns[i].meta.val = i; } - width = s->ActionClick && Input_TouchMode ? 140 : 400; - - if (s->ActionClick) { - ButtonWidget_Add(s, &s->action, width, s->ActionClick); - } else { - ButtonWidget_Init( &s->action, width, s->ActionClick); - } + width = Input_TouchMode ? 140 : 400; + ButtonWidget_Add(s, &s->action, width, s->ActionClick); ButtonWidget_Add(s, &s->left, 40, ListScreen_MoveBackwards); ButtonWidget_Add(s, &s->right, 40, ListScreen_MoveForwards); - TextWidget_Add(s, &s->title); + TextWidget_Add(s, &s->title); ButtonWidget_Add(s, &s->done, width, s->DoneClick); s->maxVertices = Screen_CalcDefaultMaxVertices(screen); s->LoadEntries(s); } -static void ListScreen_Render(void* screen, double delta) { +static void ListScreen_Render(void* screen, float delta) { Menu_RenderBounds(); Screen_Render2Widgets(screen, delta); } @@ -447,7 +441,6 @@ static void ListScreen_ContextRecreated(void* screen) { ButtonWidget_SetConst(&s->done, "Done", &s->font); ListScreen_UpdatePage(s); - if (!s->ActionClick) return; ButtonWidget_SetConst(&s->action, s->actionText, &s->font); } @@ -476,7 +469,7 @@ void ListScreen_Show(void) { /*########################################################################################################################* *--------------------------------------------------------MenuScreen-------------------------------------------------------* *#########################################################################################################################*/ -static void MenuScreen_Render2(void* screen, double delta) { +void MenuScreen_Render2(void* screen, float delta) { Menu_RenderBounds(); Screen_Render2Widgets(screen, delta); } @@ -505,32 +498,24 @@ static void PauseScreenBase_ContextRecreated(struct PauseScreen* s, struct FontD TextWidget_SetConst(&s->title, "Game menu", titleFont); } -static void PauseScreenBase_Init(struct PauseScreen* s, int width) { - Menu_InitButtons(s->btns, width, s->descs, s->descsCount); - ButtonWidget_Init(&s->back, 400, PauseScreenBase_Game); - TextWidget_Init(&s->title); - - s->maxVertices = Screen_CalcDefaultMaxVertices(s); +static void PauseScreenBase_AddWidgets(struct PauseScreen* s, int width) { + TextWidget_Add(s, &s->title); + Menu_AddButtons(s, s->btns, width, s->descs, s->descsCount); + ButtonWidget_Add(s, &s->back, 400, PauseScreenBase_Game); } /*########################################################################################################################* *-------------------------------------------------------PauseScreen-------------------------------------------------------* *#########################################################################################################################*/ -static struct Widget* pause_widgets[] = { - (struct Widget*)&PauseScreen.title, - (struct Widget*)&PauseScreen.btns[0], (struct Widget*)&PauseScreen.btns[1], - (struct Widget*)&PauseScreen.btns[2], (struct Widget*)&PauseScreen.btns[3], - (struct Widget*)&PauseScreen.btns[4], (struct Widget*)&PauseScreen.btns[5], - (struct Widget*)&PauseScreen.back, (struct Widget*)&PauseScreen.quit -}; +static struct Widget* pause_widgets[1 + 6 + 2]; static void PauseScreen_CheckHacksAllowed(void* screen) { struct PauseScreen* s = (struct PauseScreen*)screen; if (Gui.ClassicMenu) return; Widget_SetDisabled(&s->btns[4], - !LocalPlayer_Instance.Hacks.CanAnyHacks); /* select texture pack */ + !Entities.CurPlayer->Hacks.CanAnyHacks); /* select texture pack */ s->dirty = true; } @@ -563,13 +548,15 @@ static void PauseScreen_Init(void* screen) { { -160, 50, "Hotkeys...", Menu_SwitchHotkeys } }; s->widgets = pause_widgets; - s->numWidgets = Array_Elems(pause_widgets); + s->numWidgets = 0; + s->maxWidgets = Array_Elems(pause_widgets); Event_Register_(&UserEvents.HackPermsChanged, s, PauseScreen_CheckHacksAllowed); s->descs = descs; s->descsCount = Array_Elems(descs); - ButtonWidget_Init(&s->quit, 120, PauseScreenBase_Quit); - PauseScreenBase_Init(s, 300); + PauseScreenBase_AddWidgets(s, 300); + ButtonWidget_Add(s, &s->quit, 120, PauseScreenBase_Quit); + s->maxVertices = Screen_CalcDefaultMaxVertices(s); if (Server.IsSinglePlayer) return; s->btns[1].flags = WIDGET_FLAG_DISABLED; @@ -599,12 +586,7 @@ void PauseScreen_Show(void) { /*########################################################################################################################* *----------------------------------------------------ClassicPauseScreen---------------------------------------------------* *#########################################################################################################################*/ -static struct Widget* classicPause_widgets[] = { - (struct Widget*)&PauseScreen.title, - (struct Widget*)&PauseScreen.btns[0], (struct Widget*)&PauseScreen.btns[1], - (struct Widget*)&PauseScreen.btns[2], (struct Widget*)&PauseScreen.btns[3], - (struct Widget*)&PauseScreen.btns[4], (struct Widget*)&PauseScreen.back -}; +static struct Widget* classicPause_widgets[1 + 5 + 1]; static void ClassicPauseScreen_ContextRecreated(void* screen) { struct PauseScreen* s = (struct PauseScreen*)screen; @@ -630,13 +612,14 @@ static void ClassicPauseScreen_Init(void* screen) { { 0, 100, "Nostalgia options...", Menu_SwitchNostalgia } }; s->widgets = classicPause_widgets; - s->numWidgets = Array_Elems(classicPause_widgets); + s->numWidgets = 0; + s->maxWidgets = Array_Elems(classicPause_widgets); s->descs = descs; /* Don't show nostalgia options in classic mode */ - s->descsCount = Game_ClassicMode ? 4 : 5; - s->widgets[5] = Game_ClassicMode ? NULL : (struct Widget*)&s->btns[4]; - PauseScreenBase_Init(s, 400); + s->descsCount = Game_ClassicMode ? 4 : 5; + PauseScreenBase_AddWidgets(s, 400); + s->maxVertices = Screen_CalcDefaultMaxVertices(s); if (Server.IsSinglePlayer) return; s->btns[1].flags = WIDGET_FLAG_DISABLED; @@ -666,17 +649,11 @@ static struct OptionsGroupScreen { Screen_Body struct FontDesc textFont; struct ButtonWidget btns[8]; - struct TextWidget desc; - struct ButtonWidget done; + struct TextWidget desc; + struct ButtonWidget done; } OptionsGroupScreen; -static struct Widget* optGroups_widgets[] = { - (struct Widget*)&OptionsGroupScreen.btns[0], (struct Widget*)&OptionsGroupScreen.btns[1], - (struct Widget*)&OptionsGroupScreen.btns[2], (struct Widget*)&OptionsGroupScreen.btns[3], - (struct Widget*)&OptionsGroupScreen.btns[4], (struct Widget*)&OptionsGroupScreen.btns[5], - (struct Widget*)&OptionsGroupScreen.btns[6], (struct Widget*)&OptionsGroupScreen.btns[7], - (struct Widget*)&OptionsGroupScreen.desc, (struct Widget*)&OptionsGroupScreen.done -}; +static struct Widget* optGroups_widgets[8 + 2]; static const char* const optsGroup_descs[8] = { "&eMusic/Sound, view bobbing, and more", @@ -702,7 +679,7 @@ static const struct SimpleButtonDesc optsGroup_btns[8] = { static void OptionsGroupScreen_CheckHacksAllowed(void* screen) { struct OptionsGroupScreen* s = (struct OptionsGroupScreen*)screen; Widget_SetDisabled(&s->btns[6], - !LocalPlayer_Instance.Hacks.CanAnyHacks); /* env settings */ + !Entities.CurPlayer->Hacks.CanAnyHacks); /* env settings */ s->dirty = true; } @@ -744,12 +721,13 @@ static void OptionsGroupScreen_Init(void* screen) { Event_Register_(&UserEvents.HackPermsChanged, s, OptionsGroupScreen_CheckHacksAllowed); s->widgets = optGroups_widgets; - s->numWidgets = Array_Elems(optGroups_widgets); + s->numWidgets = 0; + s->maxWidgets = Array_Elems(optGroups_widgets); s->selectedI = -1; - Menu_InitButtons(s->btns, 300, optsGroup_btns, 8); - TextWidget_Init(&s->desc); - ButtonWidget_Init(&s->done, 400, Menu_SwitchPause); + Menu_AddButtons(s, s->btns, 300, optsGroup_btns, 8); + TextWidget_Add(s, &s->desc); + ButtonWidget_Add(s, &s->done, 400, Menu_SwitchPause); s->maxVertices = Screen_CalcDefaultMaxVertices(s); } @@ -903,7 +881,7 @@ static void EditHotkeyScreen_RemoveHotkey(void* screen, void* b) { HotkeyListScreen_Show(); } -static void EditHotkeyScreen_Render(void* screen, double delta) { +static void EditHotkeyScreen_Render(void* screen, float delta) { struct EditHotkeyScreen* s = (struct EditHotkeyScreen*)screen; PackedCol grey = PackedCol_Make(150, 150, 150, 255); @@ -975,7 +953,7 @@ static void EditHotkeyScreen_ContextRecreated(void* screen) { ButtonWidget_SetConst(&s->cancel, "Cancel", &s->titleFont); } -static void EditHotkeyScreen_Update(void* screen, double delta) { +static void EditHotkeyScreen_Update(void* screen, float delta) { struct EditHotkeyScreen* s = (struct EditHotkeyScreen*)screen; s->input.base.caretAccumulator += delta; } @@ -1059,14 +1037,7 @@ static struct GenLevelScreen { } GenLevelScreen; #define GENLEVEL_NUM_INPUTS 4 -static struct Widget* gen_widgets[] = { - (struct Widget*)&GenLevelScreen.inputs[0], (struct Widget*)&GenLevelScreen.inputs[1], - (struct Widget*)&GenLevelScreen.inputs[2], (struct Widget*)&GenLevelScreen.inputs[3], - (struct Widget*)&GenLevelScreen.labels[0], (struct Widget*)&GenLevelScreen.labels[1], - (struct Widget*)&GenLevelScreen.labels[2], (struct Widget*)&GenLevelScreen.labels[3], - (struct Widget*)&GenLevelScreen.title, (struct Widget*)&GenLevelScreen.flatgrass, - (struct Widget*)&GenLevelScreen.vanilla, (struct Widget*)&GenLevelScreen.cancel -}; +static struct Widget* gen_widgets[2 * GENLEVEL_NUM_INPUTS + 4]; CC_NOINLINE static int GenLevelScreen_GetInt(struct GenLevelScreen* s, int index) { struct TextInputWidget* input = &s->inputs[index]; @@ -1126,17 +1097,21 @@ static void GenLevelScreen_Make(struct GenLevelScreen* s, int i, int def) { String_InitArray(tmp, tmpBuffer); desc.VTABLE->GetDefault(&desc, &tmp); - TextInputWidget_Create(&s->inputs[i], 200, &tmp, &desc); - s->inputs[i].base.showCaret = false; - TextWidget_Init(&s->labels[i]); + TextWidget_Add(s, &s->labels[i]); s->labels[i].color = PackedCol_Make(224, 224, 224, 255); + /* TODO placeholder */ + TextInputWidget_Add(s, &s->inputs[i], 200, &tmp, &desc); + s->inputs[i].base.showCaret = false; s->inputs[i].onscreenType = KEYBOARD_TYPE_INTEGER; + s->inputs[i].base.meta.val = 10000; } +#define GenLevelScreen_IsInput(w) (w)->meta.val == 10000 static struct TextInputWidget* GenLevelScreen_SelectedInput(struct GenLevelScreen* s) { - if (s->selectedI >= 0 && s->selectedI < GENLEVEL_NUM_INPUTS) - return &s->inputs[s->selectedI]; + if (s->selectedI >= 0 && GenLevelScreen_IsInput(s->widgets[s->selectedI])) { + return (struct TextInputWidget*)s->widgets[s->selectedI]; + } return NULL; } @@ -1210,15 +1185,15 @@ static void GenLevelScreen_ContextRecreated(void* screen) { Font_Free(&titleFont); } -static void GenLevelScreen_Update(void* screen, double delta) { +static void GenLevelScreen_Update(void* screen, float delta) { struct GenLevelScreen* s = (struct GenLevelScreen*)screen; struct TextInputWidget* selected = GenLevelScreen_SelectedInput(s); int i; + for (i = 0; i < GENLEVEL_NUM_INPUTS; i++) { - s->inputs[i].base.showCaret = i == s->selectedI; + s->inputs[i].base.showCaret = &s->inputs[i] == selected; } - if (selected) selected->base.caretAccumulator += delta; } @@ -1239,19 +1214,20 @@ static void GenLevelScreen_Layout(void* screen) { static void GenLevelScreen_Init(void* screen) { struct GenLevelScreen* s = (struct GenLevelScreen*)screen; - s->widgets = gen_widgets; - s->numWidgets = Array_Elems(gen_widgets); - s->selectedI = -1; + s->widgets = gen_widgets; + s->numWidgets = 0; + s->maxWidgets = Array_Elems(gen_widgets); + s->selectedI = -1; GenLevelScreen_Make(s, 0, World.Width); GenLevelScreen_Make(s, 1, World.Height); GenLevelScreen_Make(s, 2, World.Length); GenLevelScreen_Make(s, 3, 0); - TextWidget_Init(&s->title); - ButtonWidget_Init(&s->flatgrass, 200, GenLevelScreen_Flatgrass); - ButtonWidget_Init(&s->vanilla, 200, GenLevelScreen_Notchy); - ButtonWidget_Init(&s->cancel, 400, Menu_SwitchPause); + TextWidget_Add(s, &s->title); + ButtonWidget_Add(s, &s->flatgrass, 200, GenLevelScreen_Flatgrass); + ButtonWidget_Add(s, &s->vanilla, 200, GenLevelScreen_Notchy); + ButtonWidget_Add(s, &s->cancel, 400, Menu_SwitchPause); s->maxVertices = Screen_CalcDefaultMaxVertices(s); } @@ -1516,7 +1492,7 @@ static void SaveLevelScreen_ContextRecreated(void* screen) { #endif } -static void SaveLevelScreen_Update(void* screen, double delta) { +static void SaveLevelScreen_Update(void* screen, float delta) { struct SaveLevelScreen* s = (struct SaveLevelScreen*)screen; s->input.base.caretAccumulator += delta; } @@ -1679,8 +1655,18 @@ static void FontListScreen_LoadEntries(struct ListScreen* s) { ListScreen_Select(s, SysFonts_UNSAFE_GetDefault()); } +static void FontListScreen_RegisterCallback(const cc_string* path) { + Chat_Add1("Loaded font from %s", path); +} + static void FontListScreen_UploadCallback(const cc_string* path) { - SysFonts_Register(path); + cc_result res = SysFonts_Register(path, FontListScreen_RegisterCallback); + + if (res) { + Logger_SimpleWarn2(res, "loading font from", path); + } else { + SysFonts_SaveCache(); + } } static void FontListScreen_ActionFunc(void* s, void* w) { @@ -1960,12 +1946,7 @@ static struct KeyBindsScreen { struct ButtonWidget buttons[KEYBINDS_MAX_BTNS]; } KeyBindsScreen; -static struct Widget* key_widgets[KEYBINDS_MAX_BTNS + 5] = { - NULL,NULL,NULL,NULL,NULL,NULL, NULL,NULL,NULL,NULL,NULL,NULL, - (struct Widget*)&KeyBindsScreen.title, (struct Widget*)&KeyBindsScreen.msg, - (struct Widget*)&KeyBindsScreen.back, (struct Widget*)&KeyBindsScreen.left, - (struct Widget*)&KeyBindsScreen.right -}; +static struct Widget* key_widgets[KEYBINDS_MAX_BTNS + 5]; static void KeyBindsScreen_Update(struct KeyBindsScreen* s, int i) { cc_string text; char textBuffer[STRING_SIZE]; @@ -2068,27 +2049,27 @@ static void KeyBindsScreen_Init(void* screen) { struct KeyBindsScreen* s = (struct KeyBindsScreen*)screen; int i; s->widgets = key_widgets; - s->numWidgets = KEYBINDS_MAX_BTNS + 3; + s->numWidgets = 0; + s->maxWidgets = Array_Elems(key_widgets); s->curI = -1; - for (i = 0; i < s->bindsCount; i++) { - ButtonWidget_Init(&s->buttons[i], s->btnWidth, KeyBindsScreen_OnBindingClick); + for (i = 0; i < s->bindsCount; i++) + { + ButtonWidget_Add(s, &s->buttons[i], s->btnWidth, KeyBindsScreen_OnBindingClick); s->widgets[i] = (struct Widget*)&s->buttons[i]; s->buttons[i].meta.val = i; } - for (; i < KEYBINDS_MAX_BTNS; i++) { s->widgets[i] = NULL; } - TextWidget_Init(&s->title); - TextWidget_Init(&s->msg); - ButtonWidget_Init(&s->back, 400, Gui.ClassicMenu ? Menu_SwitchClassicOptions : Menu_SwitchOptions); - - ButtonWidget_Init(&s->left, 40, s->leftPage); - ButtonWidget_Init(&s->right, 40, s->rightPage); - Widget_SetDisabled(&s->left, !s->leftPage); - Widget_SetDisabled(&s->right, !s->rightPage); + TextWidget_Add(s, &s->title); + TextWidget_Add(s, &s->msg); + ButtonWidget_Add(s, &s->back, 400, Gui.ClassicMenu ? Menu_SwitchClassicOptions : Menu_SwitchOptions); - if (s->leftPage || s->rightPage) - s->numWidgets += 2; + if (s->leftPage || s->rightPage) { + ButtonWidget_Add(s, &s->left, 40, s->leftPage); + ButtonWidget_Add(s, &s->right, 40, s->rightPage); + Widget_SetDisabled(&s->left, !s->leftPage); + Widget_SetDisabled(&s->right, !s->rightPage); + } s->maxVertices = Screen_CalcDefaultMaxVertices(s); } @@ -2232,7 +2213,6 @@ void HotbarBindingsScreen_Show(void) { /*########################################################################################################################* *--------------------------------------------------MenuInputOverlay-------------------------------------------------------* *#########################################################################################################################*/ -typedef void (*MenuInputDone)(const cc_string* value, cc_bool valid); static struct MenuInputOverlay { Screen_Body cc_bool screenMode; @@ -2321,12 +2301,12 @@ static void MenuInputOverlay_Init(void* screen) { s->maxVertices = Screen_CalcDefaultMaxVertices(s); } -static void MenuInputOverlay_Update(void* screen, double delta) { +static void MenuInputOverlay_Update(void* screen, float delta) { struct MenuInputOverlay* s = (struct MenuInputOverlay*)screen; s->input.base.caretAccumulator += delta; } -static void MenuInputOverlay_Render(void* screen, double delta) { +static void MenuInputOverlay_Render(void* screen, float delta) { struct MenuInputOverlay* s = (struct MenuInputOverlay*)screen; if (s->screenMode) Menu_RenderBounds(); @@ -2334,10 +2314,6 @@ static void MenuInputOverlay_Render(void* screen, double delta) { } static void MenuInputOverlay_Free(void* screen) { - struct MenuInputOverlay* s = (struct MenuInputOverlay*)screen; - Elem_Free(&s->input.base); - Elem_Free(&s->ok); - Elem_Free(&s->Default); OnscreenKeyboard_Close(); } @@ -2412,7 +2388,7 @@ static struct MenuOptionsScreen { const char* descriptions[MENUOPTS_MAX_OPTS + 1]; struct ButtonWidget* activeBtn; InitMenuOptions DoInit, DoRecreateExtra, OnHacksChanged; - int numButtons, numCore; + int numButtons; struct FontDesc titleFont, textFont; struct TextGroupWidget extHelp; struct Texture extHelpTextures[5]; /* max lines is 5 */ @@ -2421,11 +2397,7 @@ static struct MenuOptionsScreen { } MenuOptionsScreen_Instance; static struct MenuInputDesc menuOpts_descs[MENUOPTS_MAX_OPTS]; -static struct Widget* menuOpts_widgets[MENUOPTS_MAX_OPTS + 1] = { - NULL,NULL,NULL,NULL,NULL, NULL,NULL,NULL,NULL,NULL, - NULL, - (struct Widget*)&MenuOptionsScreen_Instance.done -}; +static struct Widget* menuOpts_widgets[MENUOPTS_MAX_OPTS + 1]; static void Menu_GetBool(cc_string* raw, cc_bool v) { String_AppendConst(raw, v ? "ON" : "OFF"); @@ -2528,14 +2500,14 @@ static int MenuOptionsScreen_PointerMove(void* screen, int id, int x, int y) { return true; } -static void MenuOptionsScreen_InitButtons(struct MenuOptionsScreen* s, const struct MenuOptionDesc* btns, int count, Widget_LeftClick backClick) { +static void MenuOptionsScreen_AddButtons(struct MenuOptionsScreen* s, const struct MenuOptionDesc* btns, int count, Widget_LeftClick backClick) { struct ButtonWidget* btn; int i; for (i = 0; i < count; i++) { btn = &s->buttons[i]; - ButtonWidget_Make(btn, 300, btns[i].OnClick, - ANCHOR_CENTRE, ANCHOR_CENTRE, btns[i].dir * 160, btns[i].y); + ButtonWidget_Add(s, btn, 300, btns[i].OnClick); + Widget_SetLocation(btn, ANCHOR_CENTRE, ANCHOR_CENTRE, btns[i].dir * 160, btns[i].y); btn->optName = btns[i].name; btn->GetValue = btns[i].GetValue; @@ -2544,7 +2516,7 @@ static void MenuOptionsScreen_InitButtons(struct MenuOptionsScreen* s, const str s->widgets[i] = (struct Widget*)btn; } s->numButtons = count; - ButtonWidget_Init(&s->done, 400, backClick); + ButtonWidget_Add(s, &s->done, 400, backClick); } static void MenuOptionsScreen_Bool(void* screen, void* widget) { @@ -2615,9 +2587,9 @@ static void MenuOptionsScreen_Init(void* screen) { struct MenuOptionsScreen* s = (struct MenuOptionsScreen*)screen; int i; - s->widgets = menuOpts_widgets; - s->numWidgets = MENUOPTS_MAX_OPTS + 1; /* always have back button */ - s->maxVertices = BUTTONWIDGET_MAX; + s->widgets = menuOpts_widgets; + s->numWidgets = 0; + s->maxWidgets = MENUOPTS_MAX_OPTS + 1; /* always have back button */ /* The various menu options screens might have different number of widgets */ for (i = 0; i < MENUOPTS_MAX_OPTS; i++) { @@ -2632,10 +2604,12 @@ static void MenuOptionsScreen_Init(void* screen) { TextGroupWidget_Create(&s->extHelp, 5, s->extHelpTextures, MenuOptionsScreen_GetDesc); s->extHelp.lines = 0; Event_Register_(&UserEvents.HackPermsChanged, screen, MenuOptionsScreen_OnHacksChanged); + + s->maxVertices = Screen_CalcDefaultMaxVertices(s); } #define EXTHELP_PAD 5 /* padding around extended help box */ -static void MenuOptionsScreen_Render(void* screen, double delta) { +static void MenuOptionsScreen_Render(void* screen, float delta) { struct MenuOptionsScreen* s = (struct MenuOptionsScreen*)screen; struct TextGroupWidget* w; PackedCol tableColor = PackedCol_Make(20, 20, 20, 200); @@ -2758,10 +2732,10 @@ static void ClassicOptionsScreen_SetShowFPS(const cc_string* v) { Gui.ShowFPS = static void ClassicOptionsScreen_GetViewBob(cc_string* v) { Menu_GetBool(v, Game_ViewBobbing); } static void ClassicOptionsScreen_SetViewBob(const cc_string* v) { Game_ViewBobbing = Menu_SetBool(v, OPT_VIEW_BOBBING); } -static void ClassicOptionsScreen_GetHacks(cc_string* v) { Menu_GetBool(v, LocalPlayer_Instance.Hacks.Enabled); } +static void ClassicOptionsScreen_GetHacks(cc_string* v) { Menu_GetBool(v, Entities.CurPlayer->Hacks.Enabled); } static void ClassicOptionsScreen_SetHacks(const cc_string* v) { - LocalPlayer_Instance.Hacks.Enabled = Menu_SetBool(v, OPT_HACKS_ENABLED); - HacksComp_Update(&LocalPlayer_Instance.Hacks); + Entities.CurPlayer->Hacks.Enabled = Menu_SetBool(v, OPT_HACKS_ENABLED); + HacksComp_Update(&Entities.CurPlayer->Hacks); } static void ClassicOptionsScreen_RecreateExtra(struct MenuOptionsScreen* s) { @@ -2790,14 +2764,11 @@ static void ClassicOptionsScreen_InitWidgets(struct MenuOptionsScreen* s) { { 0, 60, "Hacks enabled", MenuOptionsScreen_Bool, ClassicOptionsScreen_GetHacks, ClassicOptionsScreen_SetHacks } }; - s->numCore = 9 + 1; - s->maxVertices += 9 * BUTTONWIDGET_MAX + BUTTONWIDGET_MAX; s->DoRecreateExtra = ClassicOptionsScreen_RecreateExtra; - MenuOptionsScreen_InitButtons(s, buttons, Array_Elems(buttons), Menu_SwitchPause); - ButtonWidget_Make(&s->buttons[9], 400, Menu_SwitchBindsClassic, - ANCHOR_CENTRE, ANCHOR_MAX, 0, 95); - s->widgets[9] = (struct Widget*)&s->buttons[9]; + MenuOptionsScreen_AddButtons(s, buttons, Array_Elems(buttons), Menu_SwitchPause); + ButtonWidget_Add(s, &s->buttons[9], 400, Menu_SwitchBindsClassic); + Widget_SetLocation(&s->buttons[9], ANCHOR_CENTRE, ANCHOR_MAX, 0, 95); /* Disable certain options */ if (!Server.IsSinglePlayer) Menu_Remove(s, 3); @@ -2872,10 +2843,7 @@ static void EnvSettingsScreen_InitWidgets(struct MenuOptionsScreen* s) { { 1, 50, "Water level", MenuOptionsScreen_Input, EnvSettingsScreen_GetEdgeHeight, EnvSettingsScreen_SetEdgeHeight } }; - - s->numCore = 10; - s->maxVertices += 10 * BUTTONWIDGET_MAX; - MenuOptionsScreen_InitButtons(s, buttons, Array_Elems(buttons), Menu_SwitchOptions); + MenuOptionsScreen_AddButtons(s, buttons, Array_Elems(buttons), Menu_SwitchOptions); } void EnvSettingsScreen_Show(void) { @@ -2962,10 +2930,7 @@ static void GraphicsOptionsScreen_InitWidgets(struct MenuOptionsScreen* s) { { 1, 50, "Anaglyph 3D", MenuOptionsScreen_Bool, ClassicOptionsScreen_GetAnaglyph, ClassicOptionsScreen_SetAnaglyph } }; - - s->numCore = 9; - s->maxVertices += 9 * BUTTONWIDGET_MAX; - MenuOptionsScreen_InitButtons(s, buttons, Array_Elems(buttons), Menu_SwitchOptions); + MenuOptionsScreen_AddButtons(s, buttons, Array_Elems(buttons), Menu_SwitchOptions); s->descriptions[0] = "&eChange the smoothness of the smooth camera."; s->descriptions[1] = \ @@ -3047,10 +3012,7 @@ static void ChatOptionsScreen_InitWidgets(struct MenuOptionsScreen* s) { { -1,-50, "Scale with window", MenuOptionsScreen_Bool, ChatOptionsScreen_GetAutoScaleChat, ChatOptionsScreen_SetAutoScaleChat } }; - - s->numCore = 5; - s->maxVertices += 5 * BUTTONWIDGET_MAX; - MenuOptionsScreen_InitButtons(s, buttons, Array_Elems(buttons), Menu_SwitchOptions); + MenuOptionsScreen_AddButtons(s, buttons, Array_Elems(buttons), Menu_SwitchOptions); } void ChatOptionsScreen_Show(void) { @@ -3112,10 +3074,7 @@ static void GuiOptionsScreen_InitWidgets(struct MenuOptionsScreen* s) { { 1, 50, "Select system font", Menu_SwitchFont, NULL, NULL } }; - - s->numCore = 8; - s->maxVertices += 8 * BUTTONWIDGET_MAX; - MenuOptionsScreen_InitButtons(s, buttons, Array_Elems(buttons), Menu_SwitchOptions); + MenuOptionsScreen_AddButtons(s, buttons, Array_Elems(buttons), Menu_SwitchOptions); } void GuiOptionsScreen_Show(void) { @@ -3130,15 +3089,15 @@ void GuiOptionsScreen_Show(void) { /*########################################################################################################################* *---------------------------------------------------HacksSettingsScreen---------------------------------------------------* *#########################################################################################################################*/ -static void HacksSettingsScreen_GetHacks(cc_string* v) { Menu_GetBool(v, LocalPlayer_Instance.Hacks.Enabled); } +static void HacksSettingsScreen_GetHacks(cc_string* v) { Menu_GetBool(v, Entities.CurPlayer->Hacks.Enabled); } static void HacksSettingsScreen_SetHacks(const cc_string* v) { - LocalPlayer_Instance.Hacks.Enabled = Menu_SetBool(v,OPT_HACKS_ENABLED); - HacksComp_Update(&LocalPlayer_Instance.Hacks); + Entities.CurPlayer->Hacks.Enabled = Menu_SetBool(v,OPT_HACKS_ENABLED); + HacksComp_Update(&Entities.CurPlayer->Hacks); } -static void HacksSettingsScreen_GetSpeed(cc_string* v) { String_AppendFloat(v, LocalPlayer_Instance.Hacks.SpeedMultiplier, 2); } +static void HacksSettingsScreen_GetSpeed(cc_string* v) { String_AppendFloat(v, Entities.CurPlayer->Hacks.SpeedMultiplier, 2); } static void HacksSettingsScreen_SetSpeed(const cc_string* v) { - LocalPlayer_Instance.Hacks.SpeedMultiplier = Menu_Float(v); + Entities.CurPlayer->Hacks.SpeedMultiplier = Menu_Float(v); Options_Set(OPT_SPEED_FACTOR, v); } @@ -3147,12 +3106,15 @@ static void HacksSettingsScreen_SetClipping(const cc_string* v) { Camera.Clipping = Menu_SetBool(v, OPT_CAMERA_CLIPPING); } -static void HacksSettingsScreen_GetJump(cc_string* v) { String_AppendFloat(v, LocalPlayer_JumpHeight(), 3); } +static void HacksSettingsScreen_GetJump(cc_string* v) { + String_AppendFloat(v, LocalPlayer_JumpHeight(Entities.CurPlayer), 3); +} + static void HacksSettingsScreen_SetJump(const cc_string* v) { cc_string str; char strBuffer[STRING_SIZE]; struct PhysicsComp* physics; - physics = &LocalPlayer_Instance.Physics; + physics = &Entities.CurPlayer->Physics; physics->JumpVel = PhysicsComp_CalcJumpVelocity(Menu_Float(v)); physics->UserJumpVel = physics->JumpVel; @@ -3161,19 +3123,19 @@ static void HacksSettingsScreen_SetJump(const cc_string* v) { Options_Set(OPT_JUMP_VELOCITY, &str); } -static void HacksSettingsScreen_GetWOMHacks(cc_string* v) { Menu_GetBool(v, LocalPlayer_Instance.Hacks.WOMStyleHacks); } +static void HacksSettingsScreen_GetWOMHacks(cc_string* v) { Menu_GetBool(v, Entities.CurPlayer->Hacks.WOMStyleHacks); } static void HacksSettingsScreen_SetWOMHacks(const cc_string* v) { - LocalPlayer_Instance.Hacks.WOMStyleHacks = Menu_SetBool(v, OPT_WOM_STYLE_HACKS); + Entities.CurPlayer->Hacks.WOMStyleHacks = Menu_SetBool(v, OPT_WOM_STYLE_HACKS); } -static void HacksSettingsScreen_GetFullStep(cc_string* v) { Menu_GetBool(v, LocalPlayer_Instance.Hacks.FullBlockStep); } +static void HacksSettingsScreen_GetFullStep(cc_string* v) { Menu_GetBool(v, Entities.CurPlayer->Hacks.FullBlockStep); } static void HacksSettingsScreen_SetFullStep(const cc_string* v) { - LocalPlayer_Instance.Hacks.FullBlockStep = Menu_SetBool(v, OPT_FULL_BLOCK_STEP); + Entities.CurPlayer->Hacks.FullBlockStep = Menu_SetBool(v, OPT_FULL_BLOCK_STEP); } -static void HacksSettingsScreen_GetPushback(cc_string* v) { Menu_GetBool(v, LocalPlayer_Instance.Hacks.PushbackPlacing); } +static void HacksSettingsScreen_GetPushback(cc_string* v) { Menu_GetBool(v, Entities.CurPlayer->Hacks.PushbackPlacing); } static void HacksSettingsScreen_SetPushback(const cc_string* v) { - LocalPlayer_Instance.Hacks.PushbackPlacing = Menu_SetBool(v, OPT_PUSHBACK_PLACING); + Entities.CurPlayer->Hacks.PushbackPlacing = Menu_SetBool(v, OPT_PUSHBACK_PLACING); } static void HacksSettingsScreen_GetLiquids(cc_string* v) { Menu_GetBool(v, Game_BreakableLiquids); } @@ -3181,9 +3143,9 @@ static void HacksSettingsScreen_SetLiquids(const cc_string* v) { Game_BreakableLiquids = Menu_SetBool(v, OPT_MODIFIABLE_LIQUIDS); } -static void HacksSettingsScreen_GetSlide(cc_string* v) { Menu_GetBool(v, LocalPlayer_Instance.Hacks.NoclipSlide); } +static void HacksSettingsScreen_GetSlide(cc_string* v) { Menu_GetBool(v, Entities.CurPlayer->Hacks.NoclipSlide); } static void HacksSettingsScreen_SetSlide(const cc_string* v) { - LocalPlayer_Instance.Hacks.NoclipSlide = Menu_SetBool(v, OPT_NOCLIP_SLIDE); + Entities.CurPlayer->Hacks.NoclipSlide = Menu_SetBool(v, OPT_NOCLIP_SLIDE); } static void HacksSettingsScreen_GetFOV(cc_string* v) { String_AppendInt(v, Camera.Fov); } @@ -3198,7 +3160,7 @@ static void HacksSettingsScreen_SetFOV(const cc_string* v) { static void HacksSettingsScreen_CheckHacksAllowed(struct MenuOptionsScreen* s) { struct Widget** widgets = s->widgets; - struct LocalPlayer* p = &LocalPlayer_Instance; + struct LocalPlayer* p = Entities.CurPlayer; cc_bool disabled = !p->Hacks.Enabled; Widget_SetDisabled(widgets[3], disabled || !p->Hacks.CanSpeed); @@ -3232,11 +3194,9 @@ static void HacksSettingsScreen_InitWidgets(struct MenuOptionsScreen* s) { { 1, 50, "Field of view", MenuOptionsScreen_Input, HacksSettingsScreen_GetFOV, HacksSettingsScreen_SetFOV }, }; - s->numCore = 10; - s->maxVertices += 10 * BUTTONWIDGET_MAX; s->OnHacksChanged = HacksSettingsScreen_CheckHacksAllowed; - MenuOptionsScreen_InitButtons(s, buttons, Array_Elems(buttons), Menu_SwitchOptions); + MenuOptionsScreen_AddButtons(s, buttons, Array_Elems(buttons), Menu_SwitchOptions); HacksSettingsScreen_CheckHacksAllowed(s); s->descriptions[2] = "&eIf &fON&e, then the third person cameras will limit\nðeir zoom distance if they hit a solid block."; @@ -3260,8 +3220,8 @@ void HacksSettingsScreen_Show(void) { /*########################################################################################################################* *----------------------------------------------------MiscOptionsScreen----------------------------------------------------* *#########################################################################################################################*/ -static void MiscOptionsScreen_GetReach(cc_string* v) { String_AppendFloat(v, LocalPlayer_Instance.ReachDistance, 2); } -static void MiscOptionsScreen_SetReach(const cc_string* v) { LocalPlayer_Instance.ReachDistance = Menu_Float(v); } +static void MiscOptionsScreen_GetReach(cc_string* v) { String_AppendFloat(v, Entities.CurPlayer->ReachDistance, 2); } +static void MiscOptionsScreen_SetReach(const cc_string* v) { Entities.CurPlayer->ReachDistance = Menu_Float(v); } static void MiscOptionsScreen_GetMusic(cc_string* v) { String_AppendInt(v, Audio_MusicVolume); } static void MiscOptionsScreen_SetMusic(const cc_string* v) { @@ -3310,9 +3270,7 @@ static void MiscSettingsScreen_InitWidgets(struct MenuOptionsScreen* s) { { 1, 50, "Mouse sensitivity", MenuOptionsScreen_Input, MiscOptionsScreen_GetSensitivity, MiscOptionsScreen_SetSensitivity } }; - s->numCore = 7; - s->maxVertices += 7 * BUTTONWIDGET_MAX; - MenuOptionsScreen_InitButtons(s, buttons, Array_Elems(buttons), Menu_SwitchOptions); + MenuOptionsScreen_AddButtons(s, buttons, Array_Elems(buttons), Menu_SwitchOptions); /* Disable certain options */ if (!Server.IsSinglePlayer) Menu_Remove(s, 0); @@ -3342,10 +3300,7 @@ static struct NostalgiaMenuScreen { struct TextWidget title; } NostalgiaMenuScreen; -static struct Widget* nostalgiaMenu_widgets[] = { - (struct Widget*)&NostalgiaMenuScreen.btnA, (struct Widget*)&NostalgiaMenuScreen.btnF, - (struct Widget*)&NostalgiaMenuScreen.done, (struct Widget*)&NostalgiaMenuScreen.title -}; +static struct Widget* nostalgiaMenu_widgets[4]; static void NostalgiaMenuScreen_Appearance(void* a, void* b) { NostalgiaAppearanceScreen_Show(); } static void NostalgiaMenuScreen_Functionality(void* a, void* b) { NostalgiaFunctionalityScreen_Show(); } @@ -3451,10 +3406,8 @@ static void NostalgiaAppearanceScreen_InitWidgets(struct MenuOptionsScreen* s) { { 1, 50, "Classic options", MenuOptionsScreen_Bool, NostalgiaScreen_GetOpts, NostalgiaScreen_SetOpts }, }; - s->numCore = Array_Elems(buttons); - s->maxVertices += Array_Elems(buttons) * BUTTONWIDGET_MAX; - MenuOptionsScreen_InitButtons(s, buttons, Array_Elems(buttons), Menu_SwitchNostalgia); + MenuOptionsScreen_AddButtons(s, buttons, Array_Elems(buttons), Menu_SwitchNostalgia); } void NostalgiaAppearanceScreen_Show(void) { @@ -3513,14 +3466,11 @@ static void NostalgiaFunctionalityScreen_InitWidgets(struct MenuOptionsScreen* s { 1, 0, "Game version", NostalgiaScreen_Version, NostalgiaScreen_GetVersion, NostalgiaScreen_SetVersion } }; - s->numCore = Array_Elems(buttons) + 1; - s->maxVertices += Array_Elems(buttons) * BUTTONWIDGET_MAX + TEXTWIDGET_MAX; s->DoRecreateExtra = NostalgiaScreen_RecreateExtra; - MenuOptionsScreen_InitButtons(s, buttons, Array_Elems(buttons), Menu_SwitchNostalgia); - TextWidget_Init(&nostalgia_desc); + MenuOptionsScreen_AddButtons(s, buttons, Array_Elems(buttons), Menu_SwitchNostalgia); + TextWidget_Add(s, &nostalgia_desc); Widget_SetLocation(&nostalgia_desc, ANCHOR_CENTRE, ANCHOR_CENTRE, 0, 100); - s->widgets[4] = (struct Widget*)&nostalgia_desc; NostalgiaScreen_UpdateVersionDisabled(); s->descriptions[3] = \ @@ -3537,11 +3487,12 @@ void NostalgiaFunctionalityScreen_Show(void) { /*########################################################################################################################* *---------------------------------------------------------Overlay---------------------------------------------------------* *#########################################################################################################################*/ -static void Overlay_InitLabels(struct TextWidget* labels) { +static void Overlay_AddLabels(void* screen, struct TextWidget* labels) { int i; - TextWidget_Init(&labels[0]); - for (i = 1; i < 4; i++) { - TextWidget_Init(&labels[i]); + TextWidget_Add(screen, &labels[0]); + for (i = 1; i < 4; i++) + { + TextWidget_Add(screen, &labels[i]); labels[i].color = PackedCol_Make(224, 224, 224, 255); } } @@ -3569,7 +3520,7 @@ static struct TexIdsOverlay { struct TextAtlas idAtlas; struct TextWidget title; } TexIdsOverlay; -static struct Widget* texids_widgets[1] = { (struct Widget*)&TexIdsOverlay.title }; +static struct Widget* texids_widgets[1]; #define TEXIDS_MAX_ROWS_PER_PAGE 16 #define TEXIDS_MAX_PER_PAGE (TEXIDS_MAX_ROWS_PER_PAGE * ATLAS2D_TILES_PER_ROW) @@ -3708,10 +3659,11 @@ static void TexIdsOverlay_OnAtlasChanged(void* screen) { static void TexIdsOverlay_Init(void* screen) { struct TexIdsOverlay* s = (struct TexIdsOverlay*)screen; s->widgets = texids_widgets; - s->numWidgets = Array_Elems(texids_widgets); + s->numWidgets = 0; + s->maxWidgets = Array_Elems(texids_widgets); s->maxVertices = TEXIDS_MAX_VERTICES; - TextWidget_Init(&s->title); + TextWidget_Add(s, &s->title); Event_Register_(&TextureEvents.AtlasChanged, s, TexIdsOverlay_OnAtlasChanged); } @@ -3720,7 +3672,7 @@ static void TexIdsOverlay_Free(void* screen) { Event_Unregister_(&TextureEvents.AtlasChanged, s, TexIdsOverlay_OnAtlasChanged); } -static void TexIdsOverlay_Render(void* screen, double delta) { +static void TexIdsOverlay_Render(void* screen, float delta) { struct TexIdsOverlay* s = (struct TexIdsOverlay*)screen; int offset = 0; Menu_RenderBounds(); @@ -3768,11 +3720,7 @@ static struct UrlWarningOverlay { char _urlBuffer[STRING_SIZE * 4]; } UrlWarningOverlay; -static struct Widget* urlwarning_widgets[] = { - (struct Widget*)&UrlWarningOverlay.lbls[0], (struct Widget*)&UrlWarningOverlay.lbls[1], - (struct Widget*)&UrlWarningOverlay.lbls[2], (struct Widget*)&UrlWarningOverlay.lbls[3], - (struct Widget*)&UrlWarningOverlay.btns[0], (struct Widget*)&UrlWarningOverlay.btns[1] -}; +static struct Widget* urlwarning_widgets[4 + 2]; static void UrlWarningOverlay_OpenUrl(void* screen, void* b) { struct UrlWarningOverlay* s = (struct UrlWarningOverlay*)screen; @@ -3815,11 +3763,12 @@ static void UrlWarningOverlay_Layout(void* screen) { static void UrlWarningOverlay_Init(void* screen) { struct UrlWarningOverlay* s = (struct UrlWarningOverlay*)screen; s->widgets = urlwarning_widgets; - s->numWidgets = Array_Elems(urlwarning_widgets); + s->numWidgets = 0; + s->maxWidgets = Array_Elems(urlwarning_widgets); - Overlay_InitLabels(s->lbls); - ButtonWidget_Init(&s->btns[0], 160, UrlWarningOverlay_OpenUrl); - ButtonWidget_Init(&s->btns[1], 160, UrlWarningOverlay_AppendUrl); + Overlay_AddLabels(s, s->lbls); + ButtonWidget_Add(s, &s->btns[0], 160, UrlWarningOverlay_OpenUrl); + ButtonWidget_Add(s, &s->btns[1], 160, UrlWarningOverlay_AppendUrl); s->maxVertices = Screen_CalcDefaultMaxVertices(s); } @@ -3858,12 +3807,7 @@ static struct TexPackOverlay { char _urlBuffer[URL_MAX_SIZE]; } TexPackOverlay; -static struct Widget* texpack_widgets[] = { - (struct Widget*)&TexPackOverlay.lbls[0], (struct Widget*)&TexPackOverlay.lbls[1], - (struct Widget*)&TexPackOverlay.lbls[2], (struct Widget*)&TexPackOverlay.lbls[3], - (struct Widget*)&TexPackOverlay.btns[0], (struct Widget*)&TexPackOverlay.btns[1], - (struct Widget*)&TexPackOverlay.btns[2], (struct Widget*)&TexPackOverlay.btns[3] -}; +static struct Widget* texpack_widgets[4 + 4]; static cc_bool TexPackOverlay_IsAlways(void* screen, void* w) { struct ButtonWidget* btn = (struct ButtonWidget*)w; @@ -3931,7 +3875,7 @@ static void TexPackOverlay_UpdateLine3(struct TexPackOverlay* s) { } } -static void TexPackOverlay_Update(void* screen, double delta) { +static void TexPackOverlay_Update(void* screen, float delta) { struct TexPackOverlay* s = (struct TexPackOverlay*)screen; struct HttpRequest item; if (!Http_GetResult(s->reqID, &item)) return; @@ -3994,17 +3938,18 @@ static void TexPackOverlay_Layout(void* screen) { static void TexPackOverlay_Init(void* screen) { struct TexPackOverlay* s = (struct TexPackOverlay*)screen; s->widgets = texpack_widgets; - s->numWidgets = Array_Elems(texpack_widgets); + s->numWidgets = 0; + s->maxWidgets = Array_Elems(texpack_widgets); s->contentLength = 0; s->gotContent = false; - s->deny = false; - Overlay_InitLabels(s->lbls); + s->deny = false; + Overlay_AddLabels(s, s->lbls); - ButtonWidget_Init(&s->btns[0], 160, NULL); - ButtonWidget_Init(&s->btns[1], 160, NULL); - ButtonWidget_Init(&s->btns[2], 160, NULL); - ButtonWidget_Init(&s->btns[3], 160, NULL); + ButtonWidget_Add(s, &s->btns[0], 160, NULL); + ButtonWidget_Add(s, &s->btns[1], 160, NULL); + ButtonWidget_Add(s, &s->btns[2], 160, NULL); + ButtonWidget_Add(s, &s->btns[3], 160, NULL); s->maxVertices = Screen_CalcDefaultMaxVertices(s); } @@ -4029,418 +3974,3 @@ void TexPackOverlay_Show(const cc_string* url) { s->reqID = Http_AsyncGetHeaders(url, HTTP_FLAG_PRIORITY); Gui_Add((struct Screen*)s, GUI_PRIORITY_TEXPACK); } - - -#ifdef CC_BUILD_TOUCH -/*########################################################################################################################* -*---------------------------------------------------TouchControlsScreen---------------------------------------------------* -*#########################################################################################################################*/ -#define ONSCREEN_PAGE_BTNS 8 -static struct TouchOnscreenScreen { - Screen_Body - struct ButtonWidget back, left, right; - struct ButtonWidget btns[ONSCREEN_PAGE_BTNS]; - const struct SimpleButtonDesc* btnDescs; - struct FontDesc font; -} TouchOnscreenScreen; - -static struct Widget* touchOnscreen_widgets[3 + ONSCREEN_PAGE_BTNS] = { - (struct Widget*)&TouchOnscreenScreen.back, (struct Widget*)&TouchOnscreenScreen.left, - (struct Widget*)&TouchOnscreenScreen.right, (struct Widget*)&TouchOnscreenScreen.btns[0], - (struct Widget*)&TouchOnscreenScreen.btns[1], (struct Widget*)&TouchOnscreenScreen.btns[2], - (struct Widget*)&TouchOnscreenScreen.btns[3], (struct Widget*)&TouchOnscreenScreen.btns[4], - (struct Widget*)&TouchOnscreenScreen.btns[5], (struct Widget*)&TouchOnscreenScreen.btns[6], - (struct Widget*)&TouchOnscreenScreen.btns[7] -}; - -static void TouchOnscreen_UpdateColors(struct TouchOnscreenScreen* s) { - PackedCol grey = PackedCol_Make(0x7F, 0x7F, 0x7F, 0xFF); - int i, bit; - - for (i = 0; i < ONSCREEN_PAGE_BTNS; i++) - { - bit = s->btns[i].meta.val; - s->btns[i].color = (Gui._onscreenButtons & bit) ? PACKEDCOL_WHITE : grey; - } -} - -static void TouchOnscreen_Any(void* screen, void* w) { - struct TouchOnscreenScreen* s = (struct TouchOnscreenScreen*)screen; - struct ButtonWidget* btn = (struct ButtonWidget*)w; - int bit = btn->meta.val; - - if (Gui._onscreenButtons & bit) { - Gui._onscreenButtons &= ~bit; - } else { - Gui._onscreenButtons |= bit; - } - - Options_SetInt(OPT_TOUCH_BUTTONS, Gui._onscreenButtons); - TouchOnscreen_UpdateColors(s); - TouchScreen_Refresh(); -} -static void TouchOnscreen_More(void* s, void* w) { TouchCtrlsScreen_Show(); } - -static const struct SimpleButtonDesc touchOnscreen_page1[ONSCREEN_PAGE_BTNS] = { - { -120, -50, "Chat", TouchOnscreen_Any }, { 120, -50, "Tablist", TouchOnscreen_Any }, - { -120, 0, "Spawn", TouchOnscreen_Any }, { 120, 0, "Set spawn", TouchOnscreen_Any }, - { -120, 50, "Fly", TouchOnscreen_Any }, { 120, 50, "Noclip", TouchOnscreen_Any }, - { -120, 100, "Speed", TouchOnscreen_Any }, { 120, 100, "Half speed", TouchOnscreen_Any } -}; -static const struct SimpleButtonDesc touchOnscreen_page2[ONSCREEN_PAGE_BTNS] = { - { -120, -50, "Third person", TouchOnscreen_Any }, { 120, -50, "Delete", TouchOnscreen_Any }, - { -120, 0, "Pick", TouchOnscreen_Any }, { 120, 0, "Place", TouchOnscreen_Any }, - { -120, 50, "Switch hotbar", TouchOnscreen_Any }, { 120, 50, "---", TouchOnscreen_Any }, - { -120, 100, "---", TouchOnscreen_Any }, { 120, 100, "---", TouchOnscreen_Any } -}; - -static void TouchOnscreen_SetPage(struct TouchOnscreenScreen* s, cc_bool page1) { - int i; - int offset = page1 ? 0 : ONSCREEN_PAGE_BTNS; - s->btnDescs = page1 ? touchOnscreen_page1 : touchOnscreen_page2; - Menu_InitButtons(s->btns, 200, s->btnDescs, ONSCREEN_PAGE_BTNS); - - Widget_SetDisabled(&s->left, page1); - Widget_SetDisabled(&s->right, !page1); - - for (i = 0; i < ONSCREEN_PAGE_BTNS; i++) - { - s->btns[i].meta.val = 1 << (i + offset); - } -} - -static void TouchOnscreen_Left(void* screen, void* b) { - struct TouchOnscreenScreen* s = (struct TouchOnscreenScreen*)screen; - TouchOnscreen_SetPage(s, true); - Gui_Refresh((struct Screen*)s); - TouchOnscreen_UpdateColors(s); -} - -static void TouchOnscreen_Right(void* screen, void* b) { - struct TouchOnscreenScreen* s = (struct TouchOnscreenScreen*)screen; - TouchOnscreen_SetPage(s, false); - Gui_Refresh((struct Screen*)s); - TouchOnscreen_UpdateColors(s); -} - -static void TouchOnscreenScreen_ContextLost(void* screen) { - struct TouchOnscreenScreen* s = (struct TouchOnscreenScreen*)screen; - Font_Free(&s->font); - Screen_ContextLost(screen); -} - -static void TouchOnscreenScreen_ContextRecreated(void* screen) { - struct TouchOnscreenScreen* s = (struct TouchOnscreenScreen*)screen; - Gui_MakeTitleFont(&s->font); - Screen_UpdateVb(screen); - Menu_SetButtons(s->btns, &s->font, s->btnDescs, ONSCREEN_PAGE_BTNS); - ButtonWidget_SetConst(&s->back, "Done", &s->font); - ButtonWidget_SetConst(&s->left, "<", &s->font); - ButtonWidget_SetConst(&s->right, ">", &s->font); -} - -static void TouchOnscreenScreen_Layout(void* screen) { - struct TouchOnscreenScreen* s = (struct TouchOnscreenScreen*)screen; - Menu_LayoutButtons(s->btns, s->btnDescs, ONSCREEN_PAGE_BTNS); - Menu_LayoutBack(&s->back); - Widget_SetLocation(&s->left, ANCHOR_CENTRE, ANCHOR_CENTRE, -260, 0); - Widget_SetLocation(&s->right, ANCHOR_CENTRE, ANCHOR_CENTRE, 260, 0); -} - -static void TouchOnscreenScreen_Init(void* screen) { - struct TouchOnscreenScreen* s = (struct TouchOnscreenScreen*)screen; - s->widgets = touchOnscreen_widgets; - s->numWidgets = Array_Elems(touchOnscreen_widgets); - - ButtonWidget_Init(&s->back, 400, TouchOnscreen_More); - ButtonWidget_Init(&s->left, 40, TouchOnscreen_Left); - ButtonWidget_Init(&s->right, 40, TouchOnscreen_Right); - TouchOnscreen_SetPage(s, true); - TouchOnscreen_UpdateColors(screen); - - s->maxVertices = Screen_CalcDefaultMaxVertices(s); -} - -static const struct ScreenVTABLE TouchOnscreenScreen_VTABLE = { - TouchOnscreenScreen_Init, Screen_NullUpdate, Screen_NullFunc, - MenuScreen_Render2, Screen_BuildMesh, - Menu_InputDown, Screen_InputUp, Screen_TKeyPress, Screen_TText, - Menu_PointerDown, Screen_PointerUp, Menu_PointerMove, Screen_TMouseScroll, - TouchOnscreenScreen_Layout, TouchOnscreenScreen_ContextLost, TouchOnscreenScreen_ContextRecreated -}; -void TouchOnscreenScreen_Show(void) { - struct TouchOnscreenScreen* s = &TouchOnscreenScreen; - s->grabsInput = true; - s->closable = true; - s->VTABLE = &TouchOnscreenScreen_VTABLE; - - Gui_Add((struct Screen*)s, GUI_PRIORITY_TOUCHMORE); -} - - -/*########################################################################################################################* -*---------------------------------------------------TouchControlsScreen---------------------------------------------------* -*#########################################################################################################################*/ -#define TOUCHCTRLS_BTNS 5 -static struct TouchCtrlsScreen { - Screen_Body - struct ButtonWidget back; - struct ButtonWidget btns[TOUCHCTRLS_BTNS]; - struct FontDesc font; -} TouchCtrlsScreen; - -static struct Widget* touchCtrls_widgets[1 + TOUCHCTRLS_BTNS] = { - (struct Widget*)&TouchCtrlsScreen.back, (struct Widget*)&TouchCtrlsScreen.btns[0], - (struct Widget*)&TouchCtrlsScreen.btns[1], (struct Widget*)&TouchCtrlsScreen.btns[2], - (struct Widget*)&TouchCtrlsScreen.btns[3], (struct Widget*)&TouchCtrlsScreen.btns[4] -}; - -static const char* GetTapDesc(int mode) { - if (mode == INPUT_MODE_PLACE) return "Tap: Place"; - if (mode == INPUT_MODE_DELETE) return "Tap: Delete"; - return "Tap: None"; -} -static void TouchCtrls_UpdateTapText(void* screen) { - struct TouchCtrlsScreen* s = (struct TouchCtrlsScreen*)screen; - ButtonWidget_SetConst(&s->btns[0], GetTapDesc(Input_TapMode), &s->font); - s->dirty = true; -} - -static const char* GetHoldDesc(int mode) { - if (mode == INPUT_MODE_PLACE) return "Hold: Place"; - if (mode == INPUT_MODE_DELETE) return "Hold: Delete"; - return "Hold: None"; -} -static void TouchCtrls_UpdateHoldText(void* screen) { - struct TouchCtrlsScreen* s = (struct TouchCtrlsScreen*)screen; - ButtonWidget_SetConst(&s->btns[1], GetHoldDesc(Input_HoldMode), &s->font); - s->dirty = true; -} - -static void TouchCtrls_UpdateSensitivity(void* screen) { - cc_string value; char valueBuffer[STRING_SIZE]; - struct TouchCtrlsScreen* s = (struct TouchCtrlsScreen*)screen; - String_InitArray(value, valueBuffer); - - String_AppendConst(&value, "Sensitivity: "); - MiscOptionsScreen_GetSensitivity(&value); - ButtonWidget_Set(&s->btns[2], &value, &s->font); - s->dirty = true; -} - -static void TouchCtrls_UpdateScale(void* screen) { - cc_string value; char valueBuffer[STRING_SIZE]; - struct TouchCtrlsScreen* s = (struct TouchCtrlsScreen*)screen; - String_InitArray(value, valueBuffer); - - String_AppendConst(&value, "Scale: "); - String_AppendFloat(&value, Gui.RawTouchScale, 1); - ButtonWidget_Set(&s->btns[3], &value, &s->font); - s->dirty = true; -} - -static void TouchCtrls_More(void* s, void* w) { TouchMoreScreen_Show(); } -static void TouchCtrls_Onscreen(void* s, void* w) { TouchOnscreenScreen_Show(); } - -static void TouchCtrls_Tap(void* s, void* w) { - Input_TapMode = (Input_TapMode + 1) % INPUT_MODE_COUNT; - TouchCtrls_UpdateTapText(s); -} -static void TouchCtrls_Hold(void* s, void* w) { - Input_HoldMode = (Input_HoldMode + 1) % INPUT_MODE_COUNT; - TouchCtrls_UpdateHoldText(s); -} - -static void TouchCtrls_SensitivityDone(const cc_string* value, cc_bool valid) { - if (!valid) return; - MiscOptionsScreen_SetSensitivity(value); - TouchCtrls_UpdateSensitivity(&TouchCtrlsScreen); -} - -static void TouchCtrls_Sensitivity(void* screen, void* w) { - struct TouchCtrlsScreen* s = (struct TouchCtrlsScreen*)screen; - static struct MenuInputDesc desc; - cc_string value; char valueBuffer[STRING_SIZE]; - String_InitArray(value, valueBuffer); - - MenuInput_Int(desc, 1, 200, 30); - MiscOptionsScreen_GetSensitivity(&value); - MenuInputOverlay_Show(&desc, &value, TouchCtrls_SensitivityDone, true); - /* Fix Sensitivity button getting stuck as 'active' */ - /* (input overlay swallows subsequent pointer events) */ - s->btns[2].active = 0; -} - -static void TouchCtrls_ScaleDone(const cc_string* value, cc_bool valid) { - if (!valid) return; - ChatOptionsScreen_SetScale(value, &Gui.RawTouchScale, OPT_TOUCH_SCALE); - TouchCtrls_UpdateScale(&TouchCtrlsScreen); -} - -static void TouchCtrls_Scale(void* screen, void* w) { - struct TouchCtrlsScreen* s = (struct TouchCtrlsScreen*)screen; - static struct MenuInputDesc desc; - cc_string value; char valueBuffer[STRING_SIZE]; - String_InitArray(value, valueBuffer); - - MenuInput_Float(desc, 0.25f, 5.0f, 1.0f); - String_AppendFloat(&value, Gui.RawTouchScale, 1); - MenuInputOverlay_Show(&desc, &value, TouchCtrls_ScaleDone, true); - s->btns[3].active = 0; -} - -static const struct SimpleButtonDesc touchCtrls_btns[5] = { - { -102, -50, "", TouchCtrls_Tap }, - { 102, -50, "", TouchCtrls_Hold }, - { -102, 0, "", TouchCtrls_Sensitivity }, - { 102, 0, "", TouchCtrls_Scale }, - { 0, 50, "On-screen controls", TouchCtrls_Onscreen } -}; - -static void TouchCtrlsScreen_ContextLost(void* screen) { - struct TouchCtrlsScreen* s = (struct TouchCtrlsScreen*)screen; - Font_Free(&s->font); - Screen_ContextLost(screen); -} - -static void TouchCtrlsScreen_ContextRecreated(void* screen) { - struct TouchCtrlsScreen* s = (struct TouchCtrlsScreen*)screen; - Gui_MakeTitleFont(&s->font); - Screen_UpdateVb(screen); - Menu_SetButtons(s->btns, &s->font, touchCtrls_btns, TOUCHCTRLS_BTNS); - ButtonWidget_SetConst(&s->back, "Done", &s->font); - - TouchCtrls_UpdateTapText(s); - TouchCtrls_UpdateHoldText(s); - TouchCtrls_UpdateSensitivity(s); - TouchCtrls_UpdateScale(s); -} - -static void TouchCtrlsScreen_Layout(void* screen) { - struct TouchCtrlsScreen* s = (struct TouchCtrlsScreen*)screen; - Menu_LayoutButtons(s->btns, touchCtrls_btns, TOUCHCTRLS_BTNS); - Menu_LayoutBack(&s->back); -} - -static void TouchCtrlsScreen_Init(void* screen) { - struct TouchCtrlsScreen* s = (struct TouchCtrlsScreen*)screen; - s->widgets = touchCtrls_widgets; - s->numWidgets = Array_Elems(touchCtrls_widgets); - - Menu_InitButtons(s->btns, 195, touchCtrls_btns, 4); - Menu_InitButtons(s->btns + 4, 400, touchCtrls_btns + 4, 1); - ButtonWidget_Init(&s->back, 400, TouchCtrls_More); - - s->maxVertices = Screen_CalcDefaultMaxVertices(s); -} - -static const struct ScreenVTABLE TouchCtrlsScreen_VTABLE = { - TouchCtrlsScreen_Init, Screen_NullUpdate, Screen_NullFunc, - MenuScreen_Render2, Screen_BuildMesh, - Menu_InputDown, Screen_InputUp, Screen_TKeyPress, Screen_TText, - Menu_PointerDown, Screen_PointerUp, Menu_PointerMove, Screen_TMouseScroll, - TouchCtrlsScreen_Layout, TouchCtrlsScreen_ContextLost, TouchCtrlsScreen_ContextRecreated -}; -void TouchCtrlsScreen_Show(void) { - struct TouchCtrlsScreen* s = &TouchCtrlsScreen; - s->grabsInput = true; - s->closable = true; - s->VTABLE = &TouchCtrlsScreen_VTABLE; - - Gui_Add((struct Screen*)s, GUI_PRIORITY_TOUCHMORE); -} - - -/*########################################################################################################################* -*-----------------------------------------------------TouchMoreScreen-----------------------------------------------------* -*#########################################################################################################################*/ -#define TOUCHMORE_BTNS 6 -static struct TouchMoreScreen { - Screen_Body - struct ButtonWidget back; - struct ButtonWidget btns[TOUCHMORE_BTNS]; -} TouchMoreScreen; - -static struct Widget* touchMore_widgets[1 + TOUCHMORE_BTNS] = { - (struct Widget*)&TouchMoreScreen.back, (struct Widget*)&TouchMoreScreen.btns[0], - (struct Widget*)&TouchMoreScreen.btns[1], (struct Widget*)&TouchMoreScreen.btns[2], - (struct Widget*)&TouchMoreScreen.btns[3], (struct Widget*)&TouchMoreScreen.btns[4], - (struct Widget*)&TouchMoreScreen.btns[5] -}; - -static void TouchMore_Take(void* s, void* w) { - Gui_Remove((struct Screen*)&TouchMoreScreen); - Game_ScreenshotRequested = true; -} -static void TouchMore_Screen(void* s, void* w) { - Gui_Remove((struct Screen*)&TouchMoreScreen); - Game_ToggleFullscreen(); -} -static void TouchMore_Ctrls(void* s, void* w) { TouchCtrlsScreen_Show(); } -static void TouchMore_Menu(void* s, void* w) { - Gui_Remove((struct Screen*)&TouchMoreScreen); - Gui_ShowPauseMenu(); -} -static void TouchMore_Game(void* s, void* w) { - Gui_Remove((struct Screen*)&TouchMoreScreen); -} -static void TouchMore_Chat(void* s, void* w) { - Gui_Remove((struct Screen*)&TouchMoreScreen); - ChatScreen_OpenInput(&String_Empty); -} -static void TouchMore_Fog(void* s, void* w) { Game_CycleViewDistance(); } - -static const struct SimpleButtonDesc touchMore_btns[TOUCHMORE_BTNS] = { - { -102, -50, "Screenshot", TouchMore_Take }, - { -102, 0, "Fullscreen", TouchMore_Screen }, - { 102, -50, "Chat", TouchMore_Chat }, - { 102, 0, "Fog", TouchMore_Fog }, - { 0, 50, "Controls", TouchMore_Ctrls }, - { 0, 100, "Main menu", TouchMore_Menu } -}; - -static void TouchMoreScreen_ContextRecreated(void* screen) { - struct TouchMoreScreen* s = (struct TouchMoreScreen*)screen; - struct FontDesc titleFont; - Gui_MakeTitleFont(&titleFont); - Screen_UpdateVb(screen); - - Menu_SetButtons(s->btns, &titleFont, touchMore_btns, TOUCHMORE_BTNS); - ButtonWidget_SetConst(&s->back, "Back to game", &titleFont); - Font_Free(&titleFont); -} - -static void TouchMoreScreen_Layout(void* screen) { - struct TouchMoreScreen* s = (struct TouchMoreScreen*)screen; - Menu_LayoutButtons(s->btns, touchMore_btns, TOUCHMORE_BTNS); - Menu_LayoutBack(&s->back); -} - -static void TouchMoreScreen_Init(void* screen) { - struct TouchMoreScreen* s = (struct TouchMoreScreen*)screen; - s->widgets = touchMore_widgets; - s->numWidgets = Array_Elems(touchMore_widgets); - - Menu_InitButtons(s->btns, 195, touchMore_btns, 4); - Menu_InitButtons(s->btns + 4, 400, touchMore_btns + 4, 2); - ButtonWidget_Init(&s->back, 400, TouchMore_Game); - - s->maxVertices = Screen_CalcDefaultMaxVertices(s); -} - -static const struct ScreenVTABLE TouchMoreScreen_VTABLE = { - TouchMoreScreen_Init, Screen_NullUpdate, Screen_NullFunc, - MenuScreen_Render2, Screen_BuildMesh, - Menu_InputDown, Screen_InputUp, Screen_TKeyPress, Screen_TText, - Menu_PointerDown, Screen_PointerUp, Menu_PointerMove, Screen_TMouseScroll, - TouchMoreScreen_Layout, Screen_ContextLost, TouchMoreScreen_ContextRecreated -}; -void TouchMoreScreen_Show(void) { - struct TouchMoreScreen* s = &TouchMoreScreen; - s->grabsInput = true; - s->closable = true; - s->VTABLE = &TouchMoreScreen_VTABLE; - - Gui_Add((struct Screen*)s, GUI_PRIORITY_TOUCHMORE); -} -#endif diff --git a/src/Menus.h b/src/Menus.h index 78346ce..84f55d1 100644 --- a/src/Menus.h +++ b/src/Menus.h @@ -1,15 +1,28 @@ #ifndef CC_MENUS_H #define CC_MENUS_H -#include "Core.h" +#include "Gui.h" /* Contains all 2D menu screen implementations. Copyright 2014-2023 ClassiCube | Licensed under BSD-3 */ struct Screen; +struct MenuInputDesc; +struct FontDesc; +struct ButtonWidget; + int Menu_InputDown(void* screen, int key); int Menu_PointerDown(void* screen, int id, int x, int y); int Menu_PointerMove(void* screen, int id, int x, int y); +struct SimpleButtonDesc { short x, y; const char* title; Widget_LeftClick onClick; }; +void Menu_AddButtons(void* screen, struct ButtonWidget* btns, int width, + const struct SimpleButtonDesc* descs, int count); +void Menu_LayoutButtons(struct ButtonWidget* btns, + const struct SimpleButtonDesc* descs, int count); +void Menu_SetButtons(struct ButtonWidget* btns, struct FontDesc* font, + const struct SimpleButtonDesc* descs, int count); +void Menu_LayoutBack(struct ButtonWidget* btn); + void PauseScreen_Show(void); void OptionsGroupScreen_Show(void); void ClassicOptionsScreen_Show(void); @@ -49,4 +62,8 @@ void TouchCtrlsScreen_Show(void); void TouchMoreScreen_Show(void); void TouchOnscreenScreen_Show(void); #endif + +void MenuScreen_Render2(void* screen, float delta); +typedef void (*MenuInputDone)(const cc_string* value, cc_bool valid); +void MenuInputOverlay_Show(struct MenuInputDesc* desc, const cc_string* value, MenuInputDone onDone, cc_bool screenMode); #endif diff --git a/src/Options.c b/src/Options.c index 1a8dd42..cc70838 100644 --- a/src/Options.c +++ b/src/Options.c @@ -201,7 +201,7 @@ void Options_SetSecure(const char* opt, const cc_string* src) { String_InitArray(enc, encData); res = Platform_Encrypt(src->buffer, src->length, &enc); - if (res) { Platform_Log2("Error %h encrypting option %c", &res, opt); return; } + if (res) { Platform_Log2("Error %e encrypting option %c", &res, opt); return; } /* base64 encode the data, as user might edit options.txt with a text editor */ if (enc.length > 1500) Logger_Abort("too large to base64"); @@ -223,5 +223,5 @@ void Options_GetSecure(const char* opt, cc_string* dst) { dataLen = Convert_FromBase64(raw.buffer, raw.length, data); res = Platform_Decrypt(data, dataLen, dst); - if (res) Platform_Log2("Error %h decrypting option %c", &res, opt); + if (res) Platform_Log2("Error %e decrypting option %c", &res, opt); } diff --git a/src/Options.h b/src/Options.h index 4620f64..7110556 100644 --- a/src/Options.h +++ b/src/Options.h @@ -72,6 +72,7 @@ Copyright 2014-2023 ClassiCube | Licensed under BSD-3 #define OPT_CAMERA_SMOOTH "camera-smooth" #define OPT_GRAB_CURSOR "win-grab-cursor" #define OPT_TOUCH_BUTTONS "gui-touchbuttons" +#define OPT_TOUCH_HALIGN "gui-touch-halign" #define OPT_TOUCH_SCALE "gui-touchscale" #define OPT_HTTP_ONLY "http-no-https" #define OPT_HTTPS_VERIFY "https-verify" diff --git a/src/Particle.c b/src/Particle.c index baa9034..b8c4079 100644 --- a/src/Particle.c +++ b/src/Particle.c @@ -97,17 +97,17 @@ static cc_bool IntersectsBlock(struct Particle* p, CanPassThroughFunc canPassThr return !canPassThrough(cur) && p->nextPos.y >= minY && p->nextPos.y < maxY && CollidesHor(&p->nextPos, cur); } -static cc_bool PhysicsTick(struct Particle* p, float gravity, CanPassThroughFunc canPassThrough, double delta) { +static cc_bool PhysicsTick(struct Particle* p, float gravity, CanPassThroughFunc canPassThrough, float delta) { Vec3 velocity; int y, begY, endY; p->lastPos = p->nextPos; if (IntersectsBlock(p, canPassThrough)) return true; - p->velocity.y -= gravity * (float)delta; + p->velocity.y -= gravity * delta; begY = Math_Floor(p->nextPos.y); - Vec3_Mul1(&velocity, &p->velocity, (float)delta * 3.0f); + Vec3_Mul1(&velocity, &p->velocity, delta * 3.0f); Vec3_Add(&p->nextPos, &p->nextPos, &velocity); endY = Math_Floor(p->nextPos.y); @@ -118,7 +118,7 @@ static cc_bool PhysicsTick(struct Particle* p, float gravity, CanPassThroughFunc for (y = begY; y >= endY && ClipY(p, y, true, canPassThrough); y--) {} } - p->lifetime -= (float)delta; + p->lifetime -= delta; return p->lifetime < 0.0f; } @@ -135,7 +135,7 @@ static cc_bool RainParticle_CanPass(BlockID block) { return draw == DRAW_GAS || draw == DRAW_SPRITE; } -static cc_bool RainParticle_Tick(struct Particle* p, double delta) { +static cc_bool RainParticle_Tick(struct Particle* p, float delta) { hitTerrain = false; return PhysicsTick(p, 3.5f, RainParticle_CanPass, delta) || hitTerrain; } @@ -178,7 +178,7 @@ static void Rain_RemoveAt(int i) { rain_count--; } -static void Rain_Tick(double delta) { +static void Rain_Tick(float delta) { int i; for (i = 0; i < rain_count; i++) { if (RainParticle_Tick(&rain_Particles[i], delta)) { @@ -232,7 +232,7 @@ static cc_bool TerrainParticle_CanPass(BlockID block) { return draw == DRAW_GAS || draw == DRAW_SPRITE || Blocks.IsLiquid[block]; } -static cc_bool TerrainParticle_Tick(struct TerrainParticle* p, double delta) { +static cc_bool TerrainParticle_Tick(struct TerrainParticle* p, float delta) { return PhysicsTick(&p->base, Blocks.ParticleGravity[p->block], TerrainParticle_CanPass, delta); } @@ -306,7 +306,7 @@ static void Terrain_RemoveAt(int i) { terrain_count--; } -static void Terrain_Tick(double delta) { +static void Terrain_Tick(float delta) { int i; for (i = 0; i < terrain_count; i++) { if (TerrainParticle_Tick(&terrain_particles[i], delta)) { @@ -428,7 +428,7 @@ static cc_bool CustomParticle_CanPass(BlockID block) { return true; } -static cc_bool CustomParticle_Tick(struct CustomParticle* p, double delta) { +static cc_bool CustomParticle_Tick(struct CustomParticle* p, float delta) { struct CustomParticleEffect* e = &Particles_CustomEffects[p->effectId]; hitTerrain = false; collideFlags = e->collideFlags; @@ -486,7 +486,7 @@ static void Custom_RemoveAt(int i) { custom_count--; } -static void Custom_Tick(double delta) { +static void Custom_Tick(float delta) { int i; for (i = 0; i < custom_count; i++) { if (CustomParticle_Tick(&custom_particles[i], delta)) { @@ -546,7 +546,7 @@ void Particles_CustomEffect(int effectID, float x, float y, float z, float origi static int custom_count; static void Custom_Render(float t) { } -static void Custom_Tick(double delta) { } +static void Custom_Tick(float delta) { } #endif @@ -571,7 +571,7 @@ void Particles_Render(float t) { } static void Particles_Tick(struct ScheduledTask* task) { - double delta = task->interval; + float delta = task->interval; Terrain_Tick(delta); Rain_Tick(delta); Custom_Tick(delta); diff --git a/src/Picking.c b/src/Picking.c index efa43a1..b2e1b88 100644 --- a/src/Picking.c +++ b/src/Picking.c @@ -83,9 +83,9 @@ void RayTracer_Init(struct RayTracer* t, const Vec3* origin, const Vec3* dir) { t->tMax.z = RayTracer_Div(cellBoundary.z - origin->z, dir->z); /* Boundary is a plane on the XY axis. */ /* Determine how far we must travel along the ray before we have crossed a gridcell. */ - t->tDelta.x = RayTracer_Div((float)t->step.x, dir->x); - t->tDelta.y = RayTracer_Div((float)t->step.y, dir->y); - t->tDelta.z = RayTracer_Div((float)t->step.z, dir->z); + t->tDelta.x = (float)t->step.x * t->invDir.x; + t->tDelta.y = (float)t->step.y * t->invDir.y; + t->tDelta.z = (float)t->step.z * t->invDir.z; } void RayTracer_Step(struct RayTracer* t) { @@ -215,7 +215,7 @@ static cc_bool ClipBlock(struct RayTracer* t) { /* Only pick the block if the block is precisely within reach distance. */ lenSq = Vec3_LengthSquared(&scaledDir); - reach = LocalPlayer_Instance.ReachDistance; + reach = Entities.CurPlayer->ReachDistance; if (lenSq <= reach * reach) { SetAsValid(t); @@ -251,8 +251,8 @@ void Picking_CalcPickedBlock(const Vec3* origin, const Vec3* dir, float reach, s } void Picking_ClipCameraPos(const Vec3* origin, const Vec3* dir, float reach, struct RayTracer* t) { - cc_bool noClip = (!Camera.Clipping || LocalPlayer_Instance.Hacks.Noclip) - && LocalPlayer_Instance.Hacks.CanNoclip; + cc_bool noClip = (!Camera.Clipping || Entities.CurPlayer->Hacks.Noclip) + && Entities.CurPlayer->Hacks.CanNoclip; if (noClip || !World.Loaded || !RayTrace(t, origin, dir, reach, ClipCamera)) { RayTracer_SetInvalid(t); Vec3_Mul1(&t->intersect, dir, reach); /* intersect = dir * reach */ diff --git a/src/Platform.h b/src/Platform.h index 7c78eb0..19b2c1b 100644 --- a/src/Platform.h +++ b/src/Platform.h @@ -270,6 +270,8 @@ cc_result Socket_Read(cc_socket s, cc_uint8* data, cc_uint32 count, cc_uint32* m cc_result Socket_Write(cc_socket s, const cc_uint8* data, cc_uint32 count, cc_uint32* modified); /* Attempts to close the given socket */ void Socket_Close(cc_socket s); +/* Attempts to write all data to the given socket, returning ERR_END_OF_STREAM if it could not */ +cc_result Socket_WriteAll(cc_socket socket, const cc_uint8* data, cc_uint32 count); #ifdef CC_BUILD_MOBILE void Platform_ShareScreenshot(const cc_string* filename); diff --git a/src/Platform_Dreamcast.c b/src/Platform_Dreamcast.c index f967c92..0962842 100644 --- a/src/Platform_Dreamcast.c +++ b/src/Platform_Dreamcast.c @@ -71,7 +71,7 @@ void Platform_Log(const char* msg, int len) { if (window_inited) return; // Log details on-screen for initial model initing etc - // (this can take around 40 seconds on average) + // (this can take around 40 seconds on average) LogOnscreen(msg, len); } @@ -446,6 +446,9 @@ static uint8 partition_type; static void InitSDCard(void) { if (sd_init()) { + // Both SD card and debug interface use the serial port + // So if initing SD card fails, need to restore serial port state for debug logging + scif_init(); Platform_LogConst("Failed to init SD card"); return; } diff --git a/src/Platform_GCWii.c b/src/Platform_GCWii.c index 2e498a5..9f660cd 100644 --- a/src/Platform_GCWii.c +++ b/src/Platform_GCWii.c @@ -189,8 +189,6 @@ cc_result Directory_Enum(const cc_string* dirPath, void* obj, Directory_EnumCall } static cc_result File_Do(cc_file* file, const cc_string* path, int mode) { - if (!fat_available) return ENOSYS; - char str[NATIVE_STR_LEN]; GetNativePath(str, path); *file = open(str, mode, 0); @@ -198,12 +196,17 @@ static cc_result File_Do(cc_file* file, const cc_string* path, int mode) { } cc_result File_Open(cc_file* file, const cc_string* path) { + if (!fat_available) return ReturnCode_FileNotFound; return File_Do(file, path, O_RDONLY); } + cc_result File_Create(cc_file* file, const cc_string* path) { + if (!fat_available) return ENOTSUP; return File_Do(file, path, O_RDWR | O_CREAT | O_TRUNC); } + cc_result File_OpenOrCreate(cc_file* file, const cc_string* path) { + if (!fat_available) return ENOTSUP; return File_Do(file, path, O_RDWR | O_CREAT); } diff --git a/src/Platform_N64.c b/src/Platform_N64.c index 99b78f4..81cf6b5 100644 --- a/src/Platform_N64.c +++ b/src/Platform_N64.c @@ -260,9 +260,6 @@ void Platform_Init(void) { DisableFpuExceptions(); Platform_ReadonlyFilesystem = true; - // TODO: Redesign Drawer2D to better handle this - Options_SetBool(OPT_USE_CHAT_FONT, true); - dfs_init(DFS_DEFAULT_LOCATION); timer_init(); rtc_init(); diff --git a/src/Platform_NDS.c b/src/Platform_NDS.c index 9558b05..b0194b3 100644 --- a/src/Platform_NDS.c +++ b/src/Platform_NDS.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -63,30 +64,21 @@ cc_uint64 Stopwatch_Measure(void) { return base_time + raw; } -static void LogConsole(const char* msg, int len) { - char buffer[256 + 2]; - len = min(len, 256); - - Mem_Copy(buffer, msg, len); - buffer[len + 0] = '\n'; - buffer[len + 1] = '\0'; - - fwrite(buffer, 1, len + 1, stdout); -} - static void LogNocash(const char* msg, int len) { // Can only be up to 120 bytes total char buffer[120]; - len = min(len, 119); + len = min(len, 118); Mem_Copy(buffer, msg, len); - buffer[len] = '\n'; - nocashWrite(buffer, len + 1); + buffer[len + 0] = '\n'; + buffer[len + 1] = '\0'; + nocashWrite(buffer, len + 2); } +extern void consolePrintString(const char* ptr, int len); void Platform_Log(const char* msg, int len) { LogNocash(msg, len); - if (!keyboardOpen) LogConsole(msg, len); + consolePrintString(msg, len); } TimeMS DateTime_CurrentUTC(void) { @@ -118,16 +110,17 @@ static bool fat_available; static void GetNativePath(char* str, const cc_string* path) { Mem_Copy(str, root_path.buffer, root_path.length); - str += root_path.length; + str += root_path.length; String_EncodeUtf8(str, path); - Platform_Log1("Open %c", str - root_path.length); } cc_result Directory_Create(const cc_string* path) { - if (!fat_available) return ENOSYS; - + if (!fat_available) return 0; + char str[NATIVE_STR_LEN]; GetNativePath(str, path); + Platform_Log1("mkdir %c", str); + return mkdir(str, 0) == -1 ? errno : 0; } @@ -137,6 +130,8 @@ int File_Exists(const cc_string* path) { char str[NATIVE_STR_LEN]; struct stat sb; GetNativePath(str, path); + Platform_Log1("Check %c", str); + return stat(str, &sb) == 0 && S_ISREG(sb.st_mode); } @@ -145,21 +140,26 @@ cc_result Directory_Enum(const cc_string* dirPath, void* obj, Directory_EnumCall } static cc_result File_Do(cc_file* file, const cc_string* path, int mode) { - if (!fat_available) return ENOSYS; - char str[NATIVE_STR_LEN]; GetNativePath(str, path); + Platform_Log1("Open %c", str); + *file = open(str, mode, 0); return *file == -1 ? errno : 0; } cc_result File_Open(cc_file* file, const cc_string* path) { + if (!fat_available) return ReturnCode_FileNotFound; return File_Do(file, path, O_RDONLY); } + cc_result File_Create(cc_file* file, const cc_string* path) { + if (!fat_available) return ENOTSUP; return File_Do(file, path, O_RDWR | O_CREAT | O_TRUNC); } + cc_result File_OpenOrCreate(cc_file* file, const cc_string* path) { + if (!fat_available) return ENOTSUP; return File_Do(file, path, O_RDWR | O_CREAT); } @@ -193,24 +193,36 @@ cc_result File_Length(cc_file file, cc_uint32* len) { *len = st.st_size; return 0; } +static int LoadFatFilesystem(void* arg) { + fat_available = fatInitDefault(); + return 0; +} + static void InitFilesystem(void) { - // I don't know why I have to call this function, but if I don't, - // then when running in DSi mode AND an SD card is readable, - // fatInitDefault gets stuck somewhere (in disk_initialize it seems) - if (isDSiMode()) { - const DISC_INTERFACE* sd_io = get_io_dsisd(); - if (sd_io) sd_io->startup(); + cothread_t thread = cothread_create(LoadFatFilesystem, NULL, 0, 0); + // If running with DSi mode in melonDS and the internal SD card is enabled, then + // fatInitDefault gets stuck in sdmmc_ReadSectors - because the fifoWaitValue32Async will never return + // (You can tell when this happens - "MMC: unknown CMD 17 00000000" is logged to console) + // However, since it does yield to cothreads, workaround this by running fatInitDefault on another thread + // and then giving up if it takes too long.. not the most elegant solution, but it does work + if (thread == -1) { + LoadFatFilesystem(NULL); + } else { + for (int i = 0; i < 100; i++) + { + cothread_yield(); + if (cothread_has_joined(thread)) break; + + swiDelay(2000); + } } - fat_available = fatInitDefault(); - Platform_ReadonlyFilesystem = !fat_available; - if (!fat_available) return; - char* dir = fatGetDefaultCwd(); - if (dir && dir[0]) { + if (dir) { root_path.buffer = dir; root_path.length = String_Length(dir); } + Platform_ReadonlyFilesystem = !fat_available; } @@ -413,9 +425,6 @@ void Platform_Init(void) { InitNetworking(); cpuStartTiming(1); - // TODO: Redesign Drawer2D to better handle this - Options_Load(); - Options_SetBool(OPT_USE_CHAT_FONT, true); } void Platform_Free(void) { } diff --git a/src/Platform_PS1.c b/src/Platform_PS1.c index e076d2f..f4ad6f5 100644 --- a/src/Platform_PS1.c +++ b/src/Platform_PS1.c @@ -227,8 +227,6 @@ cc_result Socket_CheckWritable(cc_socket s, cc_bool* writable) { void Platform_Init(void) { ResetGraph(0); Stopwatch_Init(); - - Options_SetBool(OPT_USE_CHAT_FONT, true); } void Platform_Free(void) { } diff --git a/src/Platform_Posix.c b/src/Platform_Posix.c index 83942ef..5a95592 100644 --- a/src/Platform_Posix.c +++ b/src/Platform_Posix.c @@ -497,7 +497,7 @@ void Waitable_WaitFor(void* handle, cc_uint32 milliseconds) { *--------------------------------------------------------Font/Text--------------------------------------------------------* *#########################################################################################################################*/ static void FontDirCallback(const cc_string* path, void* obj) { - SysFonts_Register(path); + SysFonts_Register(path, NULL); } void Platform_LoadSysFonts(void) { diff --git a/src/Platform_Saturn.c b/src/Platform_Saturn.c index 82033c1..a390794 100644 --- a/src/Platform_Saturn.c +++ b/src/Platform_Saturn.c @@ -213,8 +213,6 @@ cc_result Socket_CheckWritable(cc_socket s, cc_bool* writable) { *#########################################################################################################################*/ void Platform_Init(void) { Stopwatch_Init(); - - Options_SetBool(OPT_USE_CHAT_FONT, true); } void Platform_Free(void) { } diff --git a/src/Platform_Switch.c b/src/Platform_Switch.c index 80ef117..271e31f 100644 --- a/src/Platform_Switch.c +++ b/src/Platform_Switch.c @@ -500,9 +500,6 @@ static void CreateRootDirectory(void) { } void Platform_Init(void) { - // TODO: Redesign Drawer2D to better handle this - //Options_SetBool(OPT_USE_CHAT_FONT, true); - CreateRootDirectory(); socketInitializeDefault(); } diff --git a/src/Platform_Windows.c b/src/Platform_Windows.c index 00aa6e3..a063355 100644 --- a/src/Platform_Windows.c +++ b/src/Platform_Windows.c @@ -360,7 +360,7 @@ static void FontDirCallback(const cc_string* path, void* obj) { static const cc_string fonExt = String_FromConst(".fon"); /* Completely skip windows .FON files */ if (String_CaselessEnds(path, &fonExt)) return; - SysFonts_Register(path); + SysFonts_Register(path, NULL); } void Platform_LoadSysFonts(void) { @@ -839,7 +839,7 @@ cc_bool DynamicLib_DescribeError(cc_string* dst) { dynamicErr = 0; /* Reset error (match posix behaviour) */ Platform_DescribeError(res, dst); - String_Format1(dst, " (error %i)", &res); + String_Format1(dst, " (error %e)", &res); /* Plugin may have been compiled to load symbols from ClassiCube.exe, */ /* but the user might have renamed it to something else */ diff --git a/src/Platform_Xbox.c b/src/Platform_Xbox.c index 9ac6707..cea3e78 100644 --- a/src/Platform_Xbox.c +++ b/src/Platform_Xbox.c @@ -169,8 +169,6 @@ cc_result Directory_Enum(const cc_string* dirPath, void* obj, Directory_EnumCall } static cc_result DoFile(cc_file* file, const cc_string* path, DWORD access, DWORD createMode) { - if (!hdd_mounted) return ERR_NOT_SUPPORTED; - char str[NATIVE_STR_LEN]; GetNativePath(str, path); cc_result res; @@ -180,12 +178,17 @@ static cc_result DoFile(cc_file* file, const cc_string* path, DWORD access, DWOR } cc_result File_Open(cc_file* file, const cc_string* path) { + if (!hdd_mounted) return ReturnCode_FileNotFound; return DoFile(file, path, GENERIC_READ, OPEN_EXISTING); } + cc_result File_Create(cc_file* file, const cc_string* path) { + if (!hdd_mounted) return ERR_NOT_SUPPORTED; return DoFile(file, path, GENERIC_WRITE | GENERIC_READ, CREATE_ALWAYS); } + cc_result File_OpenOrCreate(cc_file* file, const cc_string* path) { + if (!hdd_mounted) return ERR_NOT_SUPPORTED; return DoFile(file, path, GENERIC_WRITE | GENERIC_READ, OPEN_ALWAYS); } diff --git a/src/Protocol.c b/src/Protocol.c index bd2d1a7..084325b 100644 --- a/src/Protocol.c +++ b/src/Protocol.c @@ -197,7 +197,7 @@ static void CheckName(EntityID id, cc_string* name, cc_string* skin) { static void Classic_ReadAbsoluteLocation(cc_uint8* data, EntityID id, cc_uint8 flags); static void AddEntity(cc_uint8* data, EntityID id, const cc_string* name, const cc_string* skin, cc_bool readPosition) { - struct LocalPlayer* p = &LocalPlayer_Instance; + struct LocalPlayer* p = Entities.CurPlayer; struct Entity* e; if (id != ENTITIES_SELF_ID) { @@ -208,7 +208,7 @@ static void AddEntity(cc_uint8* data, EntityID id, const cc_string* name, const Entities.List[id] = e; Event_RaiseInt(&EntityEvents.Added, id); } else { - e = &LocalPlayer_Instance.Base; + e = &Entities.CurPlayer->Base; } Entity_SetSkin(e, skin); Entity_SetName(e, name); @@ -358,7 +358,7 @@ static void DisconnectInvalidMap(cc_result res) { cc_string tmp; char tmpBuffer[STRING_SIZE]; String_InitArray(tmp, tmpBuffer); - String_Format1(&tmp, "Server sent corrupted map data (error %h)", &res); + String_Format1(&tmp, "Server sent corrupted map data (error %e)", &res); Game_Disconnect(&title, &tmp); return; } @@ -511,7 +511,7 @@ static void Classic_Handshake(cc_uint8* data) { ReadString(&data, &Server.MOTD); Chat_SetLogName(&Server.Name); - hacks = &LocalPlayer_Instance.Hacks; + hacks = &Entities.CurPlayer->Hacks; UpdateUserType(hacks, *data); String_Copy(&hacks->HacksFlags, &Server.Name); @@ -744,7 +744,7 @@ static void Classic_Kick(cc_uint8* data) { } static void Classic_SetPermission(cc_uint8* data) { - struct HacksComp* hacks = &LocalPlayer_Instance.Hacks; + struct HacksComp* hacks = &Entities.CurPlayer->Hacks; UpdateUserType(hacks, data[0]); HacksComp_RecheckFlags(hacks); } @@ -813,7 +813,7 @@ static void Classic_Reset(void) { } static cc_uint8* Classic_Tick(cc_uint8* data) { - struct Entity* e = &LocalPlayer_Instance.Base; + struct Entity* e = &Entities.CurPlayer->Base; if (!classic_receivedFirstPos) return data; /* Report end position of each physics tick, rather than current position */ @@ -850,7 +850,7 @@ static struct CpeExt* CPEExtensions_Find(const cc_string* name) { #define Ext_Deg2Packed(x) ((int)((x) * 65536.0f / 360.0f)) void CPE_SendPlayerClick(int button, cc_bool pressed, cc_uint8 targetId, struct RayTracer* t) { - struct Entity* p = &LocalPlayer_Instance.Base; + struct Entity* p = &Entities.CurPlayer->Base; cc_uint8 data[15]; data[0] = OPCODE_PLAYER_CLICK; @@ -1041,7 +1041,7 @@ static void CPE_ApplyTexturePack(const cc_string* url) { static void CPE_SetClickDistance(cc_uint8* data) { - LocalPlayer_Instance.ReachDistance = Stream_GetU16_BE(data) / 32.0f; + Entities.CurPlayer->ReachDistance = Stream_GetU16_BE(data) / 32.0f; } static void CPE_CustomBlockLevel(cc_uint8* data) { @@ -1209,7 +1209,7 @@ static void CPE_EnvWeatherType(cc_uint8* data) { } static void CPE_HackControl(cc_uint8* data) { - struct LocalPlayer* p = &LocalPlayer_Instance; + struct LocalPlayer* p = Entities.CurPlayer; int jumpHeight; p->Hacks.CanFly = data[0] != 0; @@ -1221,7 +1221,7 @@ static void CPE_HackControl(cc_uint8* data) { jumpHeight = Stream_GetU16_BE(data + 5); if (jumpHeight == UInt16_MaxValue) { /* special value of -1 to reset default */ - LocalPlayer_ResetJumpVelocity(); + LocalPlayer_ResetJumpVelocity(p); } else { p->Physics.JumpVel = PhysicsComp_CalcJumpVelocity(jumpHeight / 32.0f); p->Physics.ServerJumpVel = p->Physics.JumpVel; @@ -1423,7 +1423,7 @@ static void CPE_SetHotbar(cc_uint8* data) { } static void CPE_SetSpawnPoint(cc_uint8* data) { - struct LocalPlayer* p = &LocalPlayer_Instance; + struct LocalPlayer* p = Entities.CurPlayer; int x, y, z; if (IsSupported(extEntityPos_Ext)) { @@ -1457,7 +1457,7 @@ static void CalcVelocity(float* vel, cc_uint8* src, cc_uint8 mode) { } static void CPE_VelocityControl(cc_uint8* data) { - struct LocalPlayer* p = &LocalPlayer_Instance; + struct LocalPlayer* p = Entities.CurPlayer; CalcVelocity(&p->Base.Velocity.x, data + 0, data[12]); CalcVelocity(&p->Base.Velocity.y, data + 4, data[13]); CalcVelocity(&p->Base.Velocity.z, data + 8, data[14]); diff --git a/src/Resources.c b/src/Resources.c index 167fc7a..4040634 100644 --- a/src/Resources.c +++ b/src/Resources.c @@ -297,7 +297,7 @@ static cc_result ZipWriter_FixupLocalFile(struct Stream* s, struct ResourceZipEn e->crc32 = crc ^ 0xffffffffUL; /* then fixup the header */ - if ((res = s->Seek(s, e->offset))) return res; + if ((res = s->Seek(s, e->offset))) return res; if ((res = ZipWriter_LocalFile(s, e))) return res; return s->Seek(s, dataEnd); } diff --git a/src/SSL.c b/src/SSL.c index 389117e..cb6d641 100644 --- a/src/SSL.c +++ b/src/SSL.c @@ -105,21 +105,6 @@ static SECURITY_STATUS SSL_CreateHandle(struct SSLContext* ctx) { &cred, NULL, NULL, &ctx->handle, NULL); } -static cc_result SSL_SendRaw(cc_socket socket, const cc_uint8* data, cc_uint32 count) { - cc_uint32 sent; - cc_result res; - - while (count) - { - if ((res = Socket_Write(socket, data, count, &sent))) return res; - if (!sent) return ERR_END_OF_STREAM; - - data += sent; - count -= sent; - } - return 0; -} - static cc_result SSL_RecvRaw(struct SSLContext* ctx) { cc_uint32 read; cc_result res; @@ -160,7 +145,7 @@ static SECURITY_STATUS SSL_Connect(struct SSLContext* ctx, const char* hostname) /* Send initial handshake to the server (if there is one) */ if (out_buffers[0].pvBuffer) { - res = SSL_SendRaw(ctx->socket, out_buffers[0].pvBuffer, out_buffers[0].cbBuffer); + res = Socket_WriteAll(ctx->socket, out_buffers[0].pvBuffer, out_buffers[0].cbBuffer); FP_FreeContextBuffer(out_buffers[0].pvBuffer); } return res; @@ -221,7 +206,7 @@ static SECURITY_STATUS SSL_Negotiate(struct SSLContext* ctx) { /* Need to send data to the server */ if (sec == SEC_I_CONTINUE_NEEDED) { - res = SSL_SendRaw(ctx->socket, out_buffers[0].pvBuffer, out_buffers[0].cbBuffer); + res = Socket_WriteAll(ctx->socket, out_buffers[0].pvBuffer, out_buffers[0].cbBuffer); FP_FreeContextBuffer(out_buffers[0].pvBuffer); /* TODO always free? */ if (res) return res; @@ -392,13 +377,12 @@ static cc_result SSL_WriteChunk(struct SSLContext* s, const cc_uint8* data, cc_u /* NOTE: Okay to write in one go, since all three buffers will be contiguous */ /* (as TLS record header size will always be the same size) */ total = buffers[0].cbBuffer + buffers[1].cbBuffer + buffers[2].cbBuffer; - return SSL_SendRaw(s->socket, buffer, total); + return Socket_WriteAll(s->socket, buffer, total); } -cc_result SSL_Write(void* ctx, const cc_uint8* data, cc_uint32 count, cc_uint32* wrote) { +cc_result SSL_WriteAll(void* ctx, const cc_uint8* data, cc_uint32 count) { struct SSLContext* s = ctx; cc_result res; - *wrote = 0; /* TODO: Don't loop here? move to HTTPConnection instead?? */ while (count) @@ -406,7 +390,6 @@ cc_result SSL_Write(void* ctx, const cc_uint8* data, cc_uint32 count, cc_uint32* int len = min(count, s->sizes.cbMaximumMessage); if ((res = SSL_WriteChunk(s, data, len))) return res; - *wrote += len; data += len; count -= len; } @@ -558,7 +541,7 @@ cc_result SSL_Read(void* ctx_, cc_uint8* data, cc_uint32 count, cc_uint32* read) return 0; } -cc_result SSL_Write(void* ctx_, const cc_uint8* data, cc_uint32 count, cc_uint32* wrote) { +cc_result SSL_WriteAll(void* ctx_, const cc_uint8* data, cc_uint32 count) { SSLContext* ctx = (SSLContext*)ctx_; // TODO: just br_sslio_write ?? int res = br_sslio_write_all(&ctx->ioc, data, count); @@ -569,7 +552,6 @@ cc_result SSL_Write(void* ctx_, const cc_uint8* data, cc_uint32 count, cc_uint32 } br_sslio_flush(&ctx->ioc); - *wrote = res; return 0; } @@ -592,7 +574,7 @@ cc_result SSL_Read(void* ctx, cc_uint8* data, cc_uint32 count, cc_uint32* read) return ERR_NOT_SUPPORTED; } -cc_result SSL_Write(void* ctx, const cc_uint8* data, cc_uint32 count, cc_uint32* wrote) { +cc_result SSL_WriteAll(void* ctx, const cc_uint8* data, cc_uint32 count) { return ERR_NOT_SUPPORTED; } diff --git a/src/SSL.h b/src/SSL.h index d3805b6..3865d55 100644 --- a/src/SSL.h +++ b/src/SSL.h @@ -11,6 +11,6 @@ cc_bool SSLBackend_DescribeError(cc_result res, cc_string* dst); cc_result SSL_Init(cc_socket socket, const cc_string* host, void** ctx); cc_result SSL_Read(void* ctx, cc_uint8* data, cc_uint32 count, cc_uint32* read); -cc_result SSL_Write(void* ctx, const cc_uint8* data, cc_uint32 count, cc_uint32* wrote); +cc_result SSL_WriteAll(void* ctx, const cc_uint8* data, cc_uint32 count); cc_result SSL_Free(void* ctx); #endif diff --git a/src/Screens.c b/src/Screens.c index bf5ff55..af7a715 100644 --- a/src/Screens.c +++ b/src/Screens.c @@ -40,7 +40,7 @@ int Screen_TMouseScroll(void* s, float delta) { return true; } int Screen_TPointer(void* s, int id, int x, int y) { return true; } void Screen_NullFunc(void* screen) { } -void Screen_NullUpdate(void* screen, double delta) { } +void Screen_NullUpdate(void* screen, float delta) { } /* TODO: Remove these */ struct HUDScreen; @@ -70,7 +70,7 @@ static struct HUDScreen { struct FontDesc font; struct TextWidget line1, line2; struct TextAtlas posAtlas; - double accumulator; + float accumulator; int frames, posCount; cc_bool hacksChanged; float lastSpeed; @@ -135,7 +135,7 @@ static void HUDScreen_BuildPosition(struct HUDScreen* s, struct VertexTextured* tex.width = atlas->offset; Gfx_Make2DQuad(&tex, PACKEDCOL_WHITE, &cur); - IVec3_Floor(&pos, &LocalPlayer_Instance.Base.Position); + IVec3_Floor(&pos, &Entities.CurPlayer->Base.Position); atlas->curX = tex.x + tex.width; /* Make (X, Y, Z) suffix */ @@ -151,14 +151,14 @@ static void HUDScreen_BuildPosition(struct HUDScreen* s, struct VertexTextured* } static cc_bool HUDScreen_HasHacksChanged(struct HUDScreen* s) { - struct HacksComp* hacks = &LocalPlayer_Instance.Hacks; + struct HacksComp* hacks = &Entities.CurPlayer->Hacks; float speed = HacksComp_CalcSpeedFactor(hacks, hacks->CanSpeed); return speed != s->lastSpeed || Camera.Fov != s->lastFov || s->hacksChanged; } static void HUDScreen_RemakeLine2(struct HUDScreen* s) { cc_string status; char statusBuffer[STRING_SIZE * 2]; - struct HacksComp* hacks = &LocalPlayer_Instance.Hacks; + struct HacksComp* hacks = &Entities.CurPlayer->Hacks; float speed; s->dirty = true; @@ -211,7 +211,7 @@ static void HUDScreen_ContextRecreated(void* screen) { HUDScreen_RemakeLine2(s); } -static int HUDScreen_LayoutHotbar(void) { +int HUDScreen_LayoutHotbar(void) { struct HUDScreen* s = &HUDScreen_Instance; s->hotbar.scale = Gui_GetHotbarScale(); Widget_Layout(&s->hotbar); @@ -317,18 +317,18 @@ static void HUDScreen_Free(void* screen) { Event_Unregister_(&BlockEvents.BlockDefChanged, screen, HUDScreen_NeedRedrawing); } -static void HUDScreen_UpdateFPS(struct HUDScreen* s, double delta) { +static void HUDScreen_UpdateFPS(struct HUDScreen* s, float delta) { s->frames++; s->accumulator += delta; - if (s->accumulator < 1.0) return; + if (s->accumulator < 1.0f) return; HUDScreen_RemakeLine1(s); - s->accumulator = 0.0; + s->accumulator = 0.0f; s->frames = 0; Game.ChunkUpdates = 0; } -static void HUDScreen_Update(void* screen, double delta) { +static void HUDScreen_Update(void* screen, float delta) { struct HUDScreen* s = (struct HUDScreen*)screen; IVec3 pos; @@ -340,7 +340,7 @@ static void HUDScreen_Update(void* screen, double delta) { if (HUDScreen_HasHacksChanged(s)) HUDScreen_RemakeLine2(s); } - IVec3_Floor(&pos, &LocalPlayer_Instance.Base.Position); + IVec3_Floor(&pos, &Entities.CurPlayer->Base.Position); if (pos.x != s->lastX || pos.y != s->lastY || pos.z != s->lastZ) s->dirty = true; } @@ -378,7 +378,7 @@ static void HUDScreen_BuildMesh(void* screen) { Gfx_UnlockDynamicVb(s->vb); } -static void HUDScreen_Render(void* screen, double delta) { +static void HUDScreen_Render(void* screen, float delta) { struct HUDScreen* s = (struct HUDScreen*)screen; if (Game_HideGui) return; @@ -815,7 +815,7 @@ static void TabListOverlay_BuildMesh(void* screen) { Gfx_UnlockDynamicVb(s->vb); } -static void TabListOverlay_Render(void* screen, double delta) { +static void TabListOverlay_Render(void* screen, float delta) { struct TabListOverlay* s = (struct TabListOverlay*)screen; int i, offset = 0; PackedCol topCol = PackedCol_Make( 0, 0, 0, 180); @@ -871,10 +871,10 @@ static const struct ScreenVTABLE TabListOverlay_VTABLE = { TabListOverlay_PointerDown, Screen_PointerUp, Screen_FPointer, Screen_FMouseScroll, TabListOverlay_Layout, TabListOverlay_ContextLost, TabListOverlay_ContextRecreated }; -void TabListOverlay_Show(void) { +void TabListOverlay_Show(cc_bool staysOpen) { struct TabListOverlay* s = &TabListOverlay_Instance; s->VTABLE = &TabListOverlay_VTABLE; - s->staysOpen = false; + s->staysOpen = staysOpen; Gui_Add((struct Screen*)s, GUI_PRIORITY_TABLIST); } @@ -1051,7 +1051,7 @@ static void ChatScreen_UpdateTexpackStatus(struct ChatScreen* s) { static void ChatScreen_ColCodeChanged(void* screen, int code) { struct ChatScreen* s = (struct ChatScreen*)screen; - double caretAcc; + float caretAcc; if (Gfx.LostContext) return; SpecialInputWidget_UpdateCols(&s->altText); @@ -1100,7 +1100,7 @@ static void ChatScreen_ChatReceived(void* screen, const cc_string* msg, int type } -static void ChatScreen_Update(void* screen, double delta) { +static void ChatScreen_Update(void* screen, float delta) { struct ChatScreen* s = (struct ChatScreen*)screen; double now = Game.Time; @@ -1134,7 +1134,7 @@ static void ChatScreen_DrawChatBackground(struct ChatScreen* s) { } } -static void ChatScreen_DrawChat(struct ChatScreen* s, double delta) { +static void ChatScreen_DrawChat(struct ChatScreen* s, float delta) { struct Texture tex; double now; int i, logIdx; @@ -1318,7 +1318,7 @@ static int ChatScreen_KeyDown(void* screen, int key) { if (KeyBind_Claims(KEYBIND_TABLIST, key) && handlesList) { if (!tablist_active && !Server.IsSinglePlayer) { - TabListOverlay_Show(); + TabListOverlay_Show(false); } return true; } @@ -1495,7 +1495,7 @@ static void ChatScreen_Init(void* screen) { #endif } -static void ChatScreen_Render(void* screen, double delta) { +static void ChatScreen_Render(void* screen, float delta) { struct ChatScreen* s = (struct ChatScreen*)screen; Gfx_3DS_SetRenderScreen(TOP_SCREEN); @@ -1581,9 +1581,7 @@ static struct InventoryScreen { cc_bool releasedInv, deferredSelect; } InventoryScreen; -static struct Widget* inventory_widgets[] = { - (struct Widget*)&InventoryScreen.title, (struct Widget*)&InventoryScreen.table -}; +static struct Widget* inventory_widgets[2]; static void InventoryScreen_GetTitleText(cc_string* desc, BlockID block) { @@ -1665,10 +1663,11 @@ static void InventoryScreen_MoveToSelected(struct InventoryScreen* s) { static void InventoryScreen_Init(void* screen) { struct InventoryScreen* s = (struct InventoryScreen*)screen; s->widgets = inventory_widgets; - s->numWidgets = Array_Elems(inventory_widgets); + s->numWidgets = 0; + s->maxWidgets = Array_Elems(inventory_widgets); - TextWidget_Init(&s->title); - TableWidget_Create(&s->table, 22 * Options_GetFloat(OPT_INV_SCROLLBAR_SCALE, 0, 10, 1)); + TextWidget_Add(s, &s->title); + TableWidget_Add(s, &s->table, 22 * Options_GetFloat(OPT_INV_SCROLLBAR_SCALE, 0, 10, 1)); s->table.blocksPerRow = Inventory.BlocksPerRow; s->table.UpdateTitle = InventoryScreen_OnUpdateTitle; TableWidget_RecreateBlocks(&s->table); @@ -1693,12 +1692,12 @@ static void InventoryScreen_Free(void* screen) { Event_Unregister_(&BlockEvents.BlockDefChanged, s, InventoryScreen_OnBlockChanged); } -static void InventoryScreen_Update(void* screen, double delta) { +static void InventoryScreen_Update(void* screen, float delta) { struct InventoryScreen* s = (struct InventoryScreen*)screen; if (s->deferredSelect) InventoryScreen_MoveToSelected(s); } -static void InventoryScreen_Render(void* screen, double delta) { +static void InventoryScreen_Render(void* screen, float delta) { struct InventoryScreen* s = (struct InventoryScreen*)screen; Widget_Render2(&s->table, TEXTWIDGET_MAX); Widget_Render2(&s->title, 0); @@ -1917,7 +1916,7 @@ static void LoadingScreen_Init(void* screen) { Event_Register_(&WorldEvents.MapLoaded, s, LoadingScreen_MapLoaded); } -static void LoadingScreen_Render(void* screen, double delta) { +static void LoadingScreen_Render(void* screen, float delta) { struct LoadingScreen* s = (struct LoadingScreen*)screen; int offset, filledWidth; TextureLoc loc; @@ -1996,17 +1995,18 @@ static void GeneratingScreen_Free(void* screen) { } static void GeneratingScreen_EndGeneration(void) { + struct LocationUpdate update; World_SetNewMap(Gen_Blocks, World.Width, World.Height, World.Length); if (!Gen_Blocks) { Chat_AddRaw("&cFailed to generate the map."); return; } Gen_Blocks = NULL; World.Seed = Gen_Seed; - LocalPlayer_CalcDefaultSpawn(); - LocalPlayer_MoveToSpawn(); + LocalPlayer_CalcDefaultSpawn(Entities.CurPlayer, &update); + LocalPlayers_MoveToSpawn(&update); } -static void GeneratingScreen_Update(void* screen, double delta) { +static void GeneratingScreen_Update(void* screen, float delta) { struct LoadingScreen* s = (struct LoadingScreen*)screen; const char* state = (const char*)Gen_CurrentState; if (state == s->lastState) return; @@ -2017,7 +2017,7 @@ static void GeneratingScreen_Update(void* screen, double delta) { LoadingScreen_SetMessage(s); } -static void GeneratingScreen_Render(void* screen, double delta) { +static void GeneratingScreen_Render(void* screen, float delta) { struct LoadingScreen* s = (struct LoadingScreen*)screen; s->progress = Gen_CurrentProgress; LoadingScreen_Render(s, delta); @@ -2135,7 +2135,7 @@ static void DisconnectScreen_Init(void* screen) { s->maxVertices = Screen_CalcDefaultMaxVertices(s); } -static void DisconnectScreen_Update(void* screen, double delta) { +static void DisconnectScreen_Update(void* screen, float delta) { struct DisconnectScreen* s = (struct DisconnectScreen*)screen; int elapsed, secsLeft; @@ -2152,7 +2152,7 @@ static void DisconnectScreen_Update(void* screen, double delta) { s->dirty = true; } -static void DisconnectScreen_Render(void* screen, double delta) { +static void DisconnectScreen_Render(void* screen, float delta) { PackedCol top = PackedCol_Make(64, 32, 32, 255); PackedCol bottom = PackedCol_Make(80, 16, 16, 255); Gfx_Draw2DGradient(0, 0, Window_UI.Width, Window_UI.Height, top, bottom); @@ -2198,298 +2198,3 @@ void DisconnectScreen_Show(const cc_string* title, const cc_string* message) { Gui_Remove(Gui_Screens[i]); } } - - -/*########################################################################################################################* -*--------------------------------------------------------TouchScreen------------------------------------------------------* -*#########################################################################################################################*/ -#ifdef CC_BUILD_TOUCH -#define TOUCH_EXTRA_BTNS 2 -#define TOUCH_MAX_BTNS (ONSCREEN_MAX_BTNS + TOUCH_EXTRA_BTNS + 1) -struct TouchButtonDesc { - const char* text; - cc_uint8 bind, x, y; - Widget_LeftClick OnClick; - cc_bool* enabled; -}; - -static struct TouchScreen { - Screen_Body - const struct TouchButtonDesc* descs; - int numOnscreen, numBtns; - struct FontDesc font; - struct ThumbstickWidget thumbstick; - const struct TouchButtonDesc* onscreenDescs[ONSCREEN_MAX_BTNS]; - struct ButtonWidget onscreen[ONSCREEN_MAX_BTNS]; - struct ButtonWidget btns[TOUCH_EXTRA_BTNS], more; -} TouchScreen; - -static struct Widget* touch_widgets[ONSCREEN_MAX_BTNS + TOUCH_EXTRA_BTNS + 2] = { - NULL,NULL,NULL,NULL, NULL,NULL,NULL,NULL, NULL,NULL,NULL,NULL, NULL, - NULL,NULL, (struct Widget*)&TouchScreen.thumbstick, (struct Widget*)&TouchScreen.more -}; -#define TOUCH_MAX_VERTICES (THUMBSTICKWIDGET_MAX + TOUCH_MAX_BTNS * BUTTONWIDGET_MAX) - -static void TouchScreen_ChatClick(void* s, void* w) { ChatScreen_OpenInput(&String_Empty); } -static void TouchScreen_RespawnClick(void* s, void* w) { LocalPlayer_HandleRespawn(); } -static void TouchScreen_SetSpawnClick(void* s, void* w) { LocalPlayer_HandleSetSpawn(); } -static void TouchScreen_FlyClick(void* s, void* w) { LocalPlayer_HandleFly(); } -static void TouchScreen_NoclipClick(void* s, void* w) { LocalPlayer_HandleNoclip(); } -static void TouchScreen_CameraClick(void* s, void* w) { Camera_CycleActive(); } -static void TouchScreen_MoreClick(void* s, void* w) { TouchMoreScreen_Show(); } -static void TouchScreen_SwitchClick(void* s, void* w) { Inventory_SwitchHotbar(); } -static void TouchScreen_DeleteClick(void* s, void* w) { InputHandler_DeleteBlock(); } /* TODO: also Send CPEClick packet */ -static void TouchScreen_PlaceClick(void* s, void* w) { InputHandler_PlaceBlock(); } -static void TouchScreen_PickClick(void* s, void* w) { InputHandler_PickBlock(); } - -static void TouchScreen_TabClick(void* s, void* w) { - if (tablist_active) { - Gui_Remove((struct Screen*)&TabListOverlay_Instance); - } else { - TabListOverlay_Show(); - TabListOverlay_Instance.staysOpen = true; - } -} - -static void TouchScreen_SpeedClick(void* s, void* w) { - struct HacksComp* hacks = &LocalPlayer_Instance.Hacks; - if (hacks->Enabled) hacks->Speeding = !hacks->Speeding; -} -static void TouchScreen_HalfClick(void* s, void* w) { - struct HacksComp* hacks = &LocalPlayer_Instance.Hacks; - if (hacks->Enabled) hacks->HalfSpeeding = !hacks->HalfSpeeding; -} - -static void TouchScreen_BindClick(void* screen, void* widget) { - struct TouchScreen* s = (struct TouchScreen*)screen; - struct ButtonWidget* btn = (struct ButtonWidget*)widget; - - int i = btn->meta.val; - Input_Set(KeyBinds_Normal[s->descs[i].bind], true); -} - -static const struct TouchButtonDesc onscreenDescs[ONSCREEN_MAX_BTNS] = { - { "Chat", 0,0,0, TouchScreen_ChatClick }, - { "Tablist", 0,0,0, TouchScreen_TabClick }, - { "Respawn", 0,0,0, TouchScreen_RespawnClick, &LocalPlayer_Instance.Hacks.CanRespawn }, - { "Set spawn", 0,0,0, TouchScreen_SetSpawnClick, &LocalPlayer_Instance.Hacks.CanRespawn }, - { "Fly", 0,0,0, TouchScreen_FlyClick, &LocalPlayer_Instance.Hacks.CanFly }, - { "Noclip", 0,0,0, TouchScreen_NoclipClick, &LocalPlayer_Instance.Hacks.CanNoclip }, - { "Speed", 0,0,0, TouchScreen_SpeedClick, &LocalPlayer_Instance.Hacks.CanSpeed }, - { "\xabSpeed", 0,0,0, TouchScreen_HalfClick, &LocalPlayer_Instance.Hacks.CanSpeed }, - { "Camera", 0,0,0, TouchScreen_CameraClick, &LocalPlayer_Instance.Hacks.CanUseThirdPerson }, - { "Delete", 0,0,0, TouchScreen_DeleteClick }, - { "Pick", 0,0,0, TouchScreen_PickClick }, - { "Place", 0,0,0, TouchScreen_PlaceClick }, - { "Hotbar", 0,0,0, TouchScreen_SwitchClick } -}; -static const struct TouchButtonDesc normDescs[1] = { - { "\x1E", KEYBIND_JUMP, 50, 10, TouchScreen_BindClick } -}; -static const struct TouchButtonDesc hackDescs[2] = { - { "\x1E", KEYBIND_FLY_UP, 50, 70, TouchScreen_BindClick }, - { "\x1F", KEYBIND_FLY_DOWN, 50, 10, TouchScreen_BindClick } -}; - -#define TOUCHSCREEN_BTN_COLOR PackedCol_Make(255, 255, 255, 220) -static void TouchScreen_InitButtons(struct TouchScreen* s) { - struct HacksComp* hacks = &LocalPlayer_Instance.Hacks; - const struct TouchButtonDesc* desc; - int i, j; - for (i = 0; i < ONSCREEN_MAX_BTNS + TOUCH_EXTRA_BTNS; i++) s->widgets[i] = NULL; - - for (i = 0, j = 0; i < ONSCREEN_MAX_BTNS; i++) - { - if (!(Gui._onscreenButtons & (1 << i))) continue; - desc = &onscreenDescs[i]; - - ButtonWidget_Init(&s->onscreen[j], 100, desc->OnClick); - if (desc->enabled) Widget_SetDisabled(&s->onscreen[j], !(*desc->enabled)); - - s->onscreenDescs[j] = desc; - s->widgets[j] = (struct Widget*)&s->onscreen[j]; - j++; - } - - s->numOnscreen = j; - if (hacks->Flying || hacks->Noclip) { - s->descs = hackDescs; - s->numBtns = Array_Elems(hackDescs); - } else { - s->descs = normDescs; - s->numBtns = Array_Elems(normDescs); - } - - for (i = 0; i < s->numBtns; i++) - { - s->widgets[i + ONSCREEN_MAX_BTNS] = (struct Widget*)&s->btns[i]; - ButtonWidget_Init(&s->btns[i], 60, s->descs[i].OnClick); - s->btns[i].color = TOUCHSCREEN_BTN_COLOR; - s->btns[i].meta.val = i; - } -} - -void TouchScreen_Refresh(void) { - struct TouchScreen* s = &TouchScreen; - /* 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_HacksChanged(void* s) { TouchScreen_Refresh(); } - -static void TouchScreen_ContextLost(void* screen) { - struct TouchScreen* s = (struct TouchScreen*)screen; - Font_Free(&s->font); - Screen_ContextLost(screen); -} - -static void TouchScreen_ContextRecreated(void* screen) { - struct TouchScreen* s = (struct TouchScreen*)screen; - const struct TouchButtonDesc* desc; - int i; - Screen_UpdateVb(screen); - Gui_MakeTitleFont(&s->font); - - for (i = 0; i < s->numOnscreen; i++) - { - desc = s->onscreenDescs[i]; - ButtonWidget_SetConst(&s->onscreen[i], desc->text, &s->font); - } - for (i = 0; i < s->numBtns; i++) - { - desc = &s->descs[i]; - ButtonWidget_SetConst(&s->btns[i], desc->text, &s->font); - } - ButtonWidget_SetConst(&s->more, "...", &s->font); -} - -static void TouchScreen_Render(void* screen, double delta) { - if (Gui.InputGrab) return; - Screen_Render2Widgets(screen, delta); -} - -static int TouchScreen_PointerDown(void* screen, int id, int x, int y) { - struct TouchScreen* s = (struct TouchScreen*)screen; - struct Widget* w; - int i; - //Chat_Add1("POINTER DOWN: %i", &id); - if (Gui.InputGrab) return false; - - i = Screen_DoPointerDown(screen, id, x, y); - if (i < ONSCREEN_MAX_BTNS) return i >= 0; - - /* Clicking on other buttons then */ - w = s->widgets[i]; - w->active |= id; - - /* Clicking on jump or fly buttons should still move camera */ - for (i = 0; i < s->numBtns; i++) - { - if (w == (struct Widget*)&s->btns[i]) return TOUCH_TYPE_GUI | TOUCH_TYPE_CAMERA; - } - return TOUCH_TYPE_GUI; -} - -static void 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; - s->more.active &= ~id; - - for (i = 0; i < s->numBtns; i++) - { - if (!(s->btns[i].active & id)) continue; - - if (s->descs[i].bind < KEYBIND_COUNT) { - Input_Set(KeyBinds_Normal[s->descs[i].bind], false); - } - s->btns[i].active &= ~id; - return; - } -} - -static void TouchScreen_Layout(void* screen) { - struct TouchScreen* s = (struct TouchScreen*)screen; - const struct TouchButtonDesc* desc; - float scale = Gui.RawTouchScale; - int i, x, y, height; - - /* Need to align these relative to the hotbar */ - height = HUDScreen_LayoutHotbar(); - - for (i = 0; i < s->numBtns; i++) - { - desc = &s->descs[i]; - Widget_SetLocation(&s->btns[i], ANCHOR_MAX, ANCHOR_MAX, desc->x, desc->y); - s->btns[i].yOffset += height; - - /* TODO: Maybe move scaling to be part of button instead */ - s->btns[i].minWidth = Display_ScaleX(60 * scale); - s->btns[i].minHeight = Display_ScaleY(60 * scale); - Widget_Layout(&s->btns[i]); - } - - for (i = 0, x = 10, y = 10; i < s->numOnscreen; i++, y += 40) - { - Widget_SetLocation(&s->onscreen[i], ANCHOR_MAX, ANCHOR_MIN, x, y); - if (s->onscreen[i].y + s->onscreen[i].height <= s->btns[0].y) continue; - - // overflowed onto jump/fly buttons, move to next column - y = 10; - x += 110; - Widget_SetLocation(&s->onscreen[i], ANCHOR_MAX, ANCHOR_MIN, x, y); - } - Widget_SetLocation(&s->more, ANCHOR_CENTRE, ANCHOR_MIN, 0, 10); - - Widget_SetLocation(&s->thumbstick, ANCHOR_MIN, ANCHOR_MAX, 30, 5); - s->thumbstick.yOffset += height; - s->thumbstick.scale = scale; - Widget_Layout(&s->thumbstick); -} - -struct LocalPlayerInput touchInput; -static void TouchScreen_GetMovement(float* xMoving, float* zMoving) { - ThumbstickWidget_GetMovement(&TouchScreen.thumbstick, xMoving, zMoving); -} - -static void TouchScreen_Init(void* screen) { - struct TouchScreen* s = (struct TouchScreen*)screen; - - s->widgets = touch_widgets; - s->numWidgets = Array_Elems(touch_widgets); - s->maxVertices = TOUCH_MAX_VERTICES; - Event_Register_(&UserEvents.HacksStateChanged, screen, TouchScreen_HacksChanged); - Event_Register_(&UserEvents.HackPermsChanged, screen, TouchScreen_HacksChanged); - - TouchScreen_InitButtons(s); - ButtonWidget_Init(&s->more, 40, TouchScreen_MoreClick); - s->more.color = TOUCHSCREEN_BTN_COLOR; - - ThumbstickWidget_Init(&s->thumbstick); - touchInput.GetMovement = TouchScreen_GetMovement; - LocalPlayer_Instance.input.next = &touchInput; -} - -static void TouchScreen_Free(void* s) { - Event_Unregister_(&UserEvents.HacksStateChanged, s, TouchScreen_HacksChanged); - Event_Unregister_(&UserEvents.HackPermsChanged, s, TouchScreen_HacksChanged); -} - -static const struct ScreenVTABLE TouchScreen_VTABLE = { - TouchScreen_Init, Screen_NullUpdate, TouchScreen_Free, - TouchScreen_Render, Screen_BuildMesh, - Screen_FInput, Screen_InputUp, Screen_FKeyPress, Screen_FText, - TouchScreen_PointerDown, TouchScreen_PointerUp, Screen_FPointer, Screen_FMouseScroll, - TouchScreen_Layout, TouchScreen_ContextLost, TouchScreen_ContextRecreated -}; -void TouchScreen_Show(void) { - struct TouchScreen* s = &TouchScreen; - s->VTABLE = &TouchScreen_VTABLE; - - if (!Gui.TouchUI) return; - Gui_Add((struct Screen*)s, GUI_PRIORITY_TOUCH); -} -#endif diff --git a/src/Screens.h b/src/Screens.h index 2f7b824..f0d2c57 100644 --- a/src/Screens.h +++ b/src/Screens.h @@ -21,7 +21,7 @@ int Screen_TMouseScroll(void* s, float delta); int Screen_TPointer(void* s, int id, int x, int y); void Screen_NullFunc(void* screen); -void Screen_NullUpdate(void* screen, double delta); +void Screen_NullUpdate(void* screen, float delta); void InventoryScreen_Show(void); void HUDScreen_Show(void); @@ -34,6 +34,9 @@ void TouchScreen_Refresh(void); void TouchScreen_Show(void); #endif +int HUDScreen_LayoutHotbar(void); +void TabListOverlay_Show(cc_bool staysOpen); + /* Opens chat input for the HUD with the given initial text. */ void ChatScreen_OpenInput(const cc_string* text); /* Appends text to the chat input in the HUD. */ diff --git a/src/Server.c b/src/Server.c index 44742b9..1a898eb 100644 --- a/src/Server.c +++ b/src/Server.c @@ -264,7 +264,7 @@ static void MPConnection_FailConnect(cc_result result) { String_InitArray(msg, msgBuffer); if (result) { - String_Format3(&msg, "Error connecting to %s:%i: %i" _NL, &Server.Address, &Server.Port, &result); + String_Format3(&msg, "Error connecting to %s:%i: %e" _NL, &Server.Address, &Server.Port, &result); Logger_Log(&msg); } MPConnection_Fail(&reason); @@ -355,7 +355,7 @@ static void MPConnection_Disconnect(void) { static void DisconnectReadFailed(cc_result res) { cc_string msg; char msgBuffer[STRING_SIZE * 2]; String_InitArray(msg, msgBuffer); - String_Format3(&msg, "Error reading from %s:%i: %i" _NL, &Server.Address, &Server.Port, &res); + String_Format3(&msg, "Error reading from %s:%i: %e" _NL, &Server.Address, &Server.Port, &res); Logger_Log(&msg); MPConnection_Disconnect(); @@ -407,7 +407,7 @@ static void MPConnection_Tick(struct ScheduledTask* task) { if (cpe_needD3Fix && lastOpcode == OPCODE_HACK_CONTROL && (opcode == 0x00 || opcode == 0xFF)) { Platform_LogConst("Skipping invalid HackControl byte from D3 server"); readCur++; - LocalPlayer_ResetJumpVelocity(); + LocalPlayer_ResetJumpVelocity(Entities.CurPlayer); continue; } @@ -432,7 +432,7 @@ static void MPConnection_Tick(struct ScheduledTask* task) { } if (net_writeFailure) { - Platform_Log1("Error from send: %i", &net_writeFailure); + Platform_Log1("Error from send: %e", &net_writeFailure); MPConnection_Disconnect(); return; } @@ -491,7 +491,7 @@ static void OnNewMap(void) { if (Server.IsSinglePlayer) return; /* wipe all existing entities */ - for (i = 0; i < ENTITIES_SELF_ID; i++) + for (i = 0; i < MAX_NET_PLAYERS; i++) { Entities_Remove((EntityID)i); } diff --git a/src/Stream.c b/src/Stream.c index 32b890f..80199f0 100644 --- a/src/Stream.c +++ b/src/Stream.c @@ -339,7 +339,7 @@ static cc_result Stream_BufferedSeek(struct Stream* s, cc_uint32 position) { s->meta.buffered.cur = s->meta.buffered.base; s->meta.buffered.left = 0; - s->meta.buffered.end = position; + s->meta.buffered.end = position; return res; } @@ -350,7 +350,7 @@ void Stream_ReadonlyBuffered(struct Stream* s, struct Stream* source, void* data s->Seek = Stream_BufferedSeek; s->meta.buffered.left = 0; - s->meta.buffered.end = 0; + s->meta.buffered.end = 0; s->meta.buffered.cur = (cc_uint8*)data; s->meta.buffered.base = (cc_uint8*)data; s->meta.buffered.length = size; diff --git a/src/String.c b/src/String.c index e6aae78..4802502 100644 --- a/src/String.c +++ b/src/String.c @@ -441,33 +441,52 @@ void String_Format4(cc_string* str, const char* format, const void* a1, const vo switch (format[++i]) { case 'b': - String_AppendInt(str, *((cc_uint8*)arg)); break; + String_AppendInt(str, *((cc_uint8*)arg)); + break; case 'i': - String_AppendInt(str, *((int*)arg)); break; + String_AppendInt(str, *((int*)arg)); + break; case 'f': digits = format[++i] - '0'; - String_AppendFloat(str, *((float*)arg), digits); break; + String_AppendFloat(str, *((float*)arg), digits); + break; case 'p': digits = format[++i] - '0'; - String_AppendPaddedInt(str, *((int*)arg), digits); break; + String_AppendPaddedInt(str, *((int*)arg), digits); + break; case 't': - String_AppendBool(str, *((cc_bool*)arg)); break; + String_AppendBool(str, *((cc_bool*)arg)); + break; case 'c': - String_AppendConst(str, (char*)arg); break; + String_AppendConst(str, (char*)arg); + break; case 's': - String_AppendString(str, (cc_string*)arg); break; + String_AppendString(str, (cc_string*)arg); + break; case 'r': - String_Append(str, *((char*)arg)); break; + String_Append(str, *((char*)arg)); + break; case 'x': if (sizeof(cc_uintptr) == 4) { - String_Hex32(str, *((cc_uint32*)arg)); break; + String_Hex32(str, *((cc_uint32*)arg)); } else { - String_Hex64(str, *((cc_uint64*)arg)); break; + String_Hex64(str, *((cc_uint64*)arg)); } + break; case 'h': - String_Hex32(str, *((cc_uint32*)arg)); break; + String_Hex32(str, *((cc_uint32*)arg)); + break; + case 'e': + digits = *((int*)arg); + if (digits >= -0xFFFF && digits <= 0xFFFF) { + String_AppendInt(str, digits); + } else { + String_Hex32(str, (cc_uint32)digits); + } + break; case '%': - String_Append(str, '%'); break; + String_Append(str, '%'); + break; default: Logger_Abort("Invalid type for string format"); } diff --git a/src/SystemFonts.c b/src/SystemFonts.c index 102ffc1..fe9d2f2 100644 --- a/src/SystemFonts.c +++ b/src/SystemFonts.c @@ -31,6 +31,224 @@ struct IGameComponent SystemFonts_Component = { }; +/*########################################################################################################################* +*------------------------------------------------------Fallback font------------------------------------------------------* +*#########################################################################################################################*/ +#define FallbackFont_ValidChar(c) ((c) > 32 && (c) < 127) +#define FallbackFont_ToIndex(c) ((c) - 33) /* First valid char is ! */ +#define SPACE_WIDTH 2 +#define CELL_SIZE 8 + +#define FallbackFont_GetRows(c) (FallbackFont_ValidChar(c) ? font_bitmap[FallbackFont_ToIndex(c)] : missing_cell) +#define FallbackFont_GetScale(size) ((size) >> 3) + +static const cc_uint8 missing_cell[CELL_SIZE] = { + 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF +}; + +/* 8x8 font bitmap, represented with 1 bit for each pixel */ +/* Source: Goodly's texture pack for ClassiCube */ +static const cc_uint8 font_bitmap[][CELL_SIZE] = { + { 0x01,0x01,0x01,0x01,0x01,0x00,0x01,0x00 }, /* ! */ + { 0x05,0x05,0x05,0x00,0x00,0x00,0x00,0x00 }, /* " */ + { 0x0A,0x0A,0x1F,0x0A,0x1F,0x0A,0x0A,0x00 }, /* # */ + { 0x04,0x1F,0x01,0x1F,0x10,0x1F,0x04,0x00 }, /* $ */ + { 0x00,0x21,0x11,0x08,0x04,0x22,0x21,0x00 }, /* % */ + { 0x0C,0x12,0x0C,0x2E,0x19,0x11,0x2E,0x00 }, /* & */ + { 0x01,0x01,0x01,0x00,0x00,0x00,0x00,0x00 }, /* ' */ + { 0x04,0x02,0x01,0x01,0x01,0x02,0x04,0x00 }, /* ( */ + { 0x01,0x02,0x04,0x04,0x04,0x02,0x01,0x00 }, /* ) */ + { 0x00,0x02,0x07,0x02,0x05,0x00,0x00,0x00 }, /* * */ + { 0x00,0x04,0x04,0x1F,0x04,0x04,0x00,0x00 }, /* + */ + { 0x00,0x00,0x00,0x00,0x00,0x02,0x02,0x01 }, /* , */ + { 0x00,0x00,0x00,0x1F,0x00,0x00,0x00,0x00 }, /* - */ + { 0x00,0x00,0x00,0x00,0x00,0x01,0x01,0x00 }, /* . */ + { 0x08,0x08,0x04,0x04,0x02,0x02,0x01,0x00 }, /* / */ + { 0x06,0x09,0x0D,0x0B,0x09,0x09,0x06,0x00 }, /* 0 */ + { 0x02,0x03,0x02,0x02,0x02,0x02,0x07,0x00 }, /* 1 */ + { 0x06,0x09,0x08,0x04,0x02,0x09,0x0F,0x00 }, /* 2 */ + { 0x06,0x09,0x08,0x06,0x08,0x09,0x06,0x00 }, /* 3 */ + { 0x05,0x05,0x05,0x0F,0x04,0x04,0x04,0x00 }, /* 4 */ + { 0x0F,0x01,0x07,0x08,0x08,0x09,0x06,0x00 }, /* 5 */ + { 0x06,0x09,0x01,0x07,0x09,0x09,0x06,0x00 }, /* 6 */ + { 0x0F,0x08,0x08,0x04,0x04,0x02,0x02,0x00 }, /* 7 */ + { 0x06,0x09,0x09,0x06,0x09,0x09,0x06,0x00 }, /* 8 */ + { 0x06,0x09,0x09,0x0E,0x08,0x09,0x06,0x00 }, /* 9 */ + { 0x00,0x01,0x01,0x00,0x00,0x01,0x01,0x00 }, /* : */ + { 0x00,0x02,0x02,0x00,0x00,0x02,0x02,0x01 }, /* ; */ + { 0x00,0x04,0x02,0x01,0x02,0x04,0x00,0x00 }, /* < */ + { 0x00,0x00,0x1F,0x00,0x00,0x1F,0x00,0x00 }, /* = */ + { 0x00,0x01,0x02,0x04,0x02,0x01,0x00,0x00 }, /* > */ + { 0x07,0x09,0x08,0x04,0x02,0x00,0x02,0x00 }, /* ? */ + { 0x0E,0x11,0x1D,0x1D,0x1D,0x01,0x0E,0x00 }, /* @ */ + { 0x06,0x09,0x09,0x0F,0x09,0x09,0x09,0x00 }, /* A */ + { 0x07,0x09,0x09,0x07,0x09,0x09,0x07,0x00 }, /* B */ + { 0x06,0x09,0x01,0x01,0x01,0x09,0x06,0x00 }, /* C */ + { 0x07,0x09,0x09,0x09,0x09,0x09,0x07,0x00 }, /* D */ + { 0x0F,0x01,0x01,0x07,0x01,0x01,0x0F,0x00 }, /* E */ + { 0x0F,0x01,0x01,0x07,0x01,0x01,0x01,0x00 }, /* F */ + { 0x06,0x09,0x01,0x0D,0x09,0x09,0x06,0x00 }, /* G */ + { 0x09,0x09,0x09,0x0F,0x09,0x09,0x09,0x00 }, /* H */ + { 0x07,0x02,0x02,0x02,0x02,0x02,0x07,0x00 }, /* I */ + { 0x08,0x08,0x08,0x08,0x08,0x09,0x07,0x00 }, /* J */ + { 0x09,0x09,0x05,0x03,0x05,0x09,0x09,0x00 }, /* K */ + { 0x01,0x01,0x01,0x01,0x01,0x01,0x0F,0x00 }, /* L */ + { 0x11,0x1B,0x15,0x11,0x11,0x11,0x11,0x00 }, /* M */ + { 0x09,0x0B,0x0D,0x09,0x09,0x09,0x09,0x00 }, /* N */ + { 0x06,0x09,0x09,0x09,0x09,0x09,0x06,0x00 }, /* O */ + { 0x07,0x09,0x09,0x07,0x01,0x01,0x01,0x00 }, /* P */ + { 0x06,0x09,0x09,0x09,0x09,0x05,0x0E,0x00 }, /* Q */ + { 0x07,0x09,0x09,0x07,0x09,0x09,0x09,0x00 }, /* R */ + { 0x06,0x09,0x01,0x06,0x08,0x09,0x06,0x00 }, /* S */ + { 0x07,0x02,0x02,0x02,0x02,0x02,0x02,0x00 }, /* T */ + { 0x09,0x09,0x09,0x09,0x09,0x09,0x06,0x00 }, /* U */ + { 0x11,0x11,0x11,0x11,0x11,0x0A,0x04,0x00 }, /* V */ + { 0x11,0x11,0x11,0x11,0x15,0x1B,0x11,0x00 }, /* W */ + { 0x11,0x11,0x0A,0x04,0x0A,0x11,0x11,0x00 }, /* X */ + { 0x11,0x11,0x0A,0x04,0x04,0x04,0x04,0x00 }, /* Y */ + { 0x0F,0x08,0x04,0x02,0x01,0x01,0x0F,0x00 }, /* Z */ + { 0x07,0x01,0x01,0x01,0x01,0x01,0x07,0x00 }, /* [ */ + { 0x01,0x01,0x02,0x02,0x04,0x04,0x08,0x00 }, /* \ */ + { 0x07,0x04,0x04,0x04,0x04,0x04,0x07,0x00 }, /* ] */ + { 0x04,0x0A,0x11,0x00,0x00,0x00,0x00,0x00 }, /* ^ */ + { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1F }, /* _ */ + { 0x01,0x01,0x02,0x00,0x00,0x00,0x00,0x00 }, /* ` */ + { 0x00,0x00,0x0E,0x09,0x09,0x0D,0x0B,0x00 }, /* a */ + { 0x01,0x01,0x07,0x09,0x09,0x09,0x07,0x00 }, /* b */ + { 0x00,0x00,0x06,0x09,0x01,0x09,0x06,0x00 }, /* c */ + { 0x08,0x08,0x0E,0x09,0x09,0x09,0x0E,0x00 }, /* d */ + { 0x00,0x00,0x06,0x09,0x0F,0x01,0x0E,0x00 }, /* e */ + { 0x06,0x01,0x07,0x01,0x01,0x01,0x01,0x00 }, /* f */ + { 0x00,0x00,0x0E,0x09,0x09,0x0E,0x08,0x07 }, /* g */ + { 0x01,0x01,0x07,0x09,0x09,0x09,0x09,0x00 }, /* h */ + { 0x01,0x00,0x01,0x01,0x01,0x01,0x01,0x00 }, /* i */ + { 0x08,0x00,0x08,0x08,0x08,0x08,0x09,0x06 }, /* j */ + { 0x01,0x01,0x09,0x05,0x03,0x05,0x09,0x00 }, /* k */ + { 0x01,0x01,0x01,0x01,0x01,0x01,0x02,0x00 }, /* l */ + { 0x00,0x00,0x0B,0x15,0x15,0x11,0x11,0x00 }, /* m */ + { 0x00,0x00,0x07,0x09,0x09,0x09,0x09,0x00 }, /* n */ + { 0x00,0x00,0x06,0x09,0x09,0x09,0x06,0x00 }, /* o */ + { 0x00,0x00,0x07,0x09,0x09,0x07,0x01,0x01 }, /* p */ + { 0x00,0x00,0x0E,0x09,0x09,0x0E,0x08,0x08 }, /* q */ + { 0x00,0x00,0x05,0x03,0x01,0x01,0x01,0x00 }, /* r */ + { 0x00,0x00,0x0E,0x01,0x06,0x08,0x07,0x00 }, /* s */ + { 0x02,0x02,0x07,0x02,0x02,0x02,0x02,0x00 }, /* t */ + { 0x00,0x00,0x09,0x09,0x09,0x09,0x0E,0x00 }, /* u */ + { 0x00,0x00,0x09,0x09,0x09,0x05,0x03,0x00 }, /* v */ + { 0x00,0x00,0x11,0x11,0x15,0x15,0x1A,0x00 }, /* w */ + { 0x00,0x00,0x05,0x05,0x02,0x05,0x05,0x00 }, /* x */ + { 0x00,0x00,0x09,0x09,0x09,0x0E,0x08,0x07 }, /* y */ + { 0x00,0x00,0x0F,0x08,0x04,0x02,0x0F,0x00 }, /* z */ + { 0x04,0x02,0x02,0x01,0x02,0x02,0x04,0x00 }, /* { */ + { 0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01 }, /* | */ + { 0x01,0x02,0x02,0x04,0x02,0x02,0x01,0x00 }, /* } */ + { 0x00,0x00,0x26,0x19,0x00,0x00,0x00,0x00 }, /* ~ */ +}; + +static int Fallback_CellWidth(const cc_uint8* rows) { + int y, width, widest = 0; + + for (y = 0; y < CELL_SIZE; y++) + { + widest = max(widest, rows[y]); + } + width = Math_ilog2(widest) + 1; + + return width + 1; /* add 1 for padding */ +} + +int FallbackFont_TextWidth(const struct DrawTextArgs* args) { + cc_string left = args->text, part; + int size = args->font->size; + int scale = FallbackFont_GetScale(size); + char colorCode = 'f'; + int i, width = 0; + + while (Drawer2D_UNSAFE_NextPart(&left, &part, &colorCode)) + { + for (i = 0; i < part.length; i++) + { + cc_uint8 c = part.buffer[i]; + if (c == ' ') { + width += SPACE_WIDTH * scale; + } else { + width += Fallback_CellWidth(FallbackFont_GetRows(c)) * scale; + } + } + } + + width = max(1, width); + if (args->useShadow) width += 1 * scale; + return width; +} + +static void Fallback_DrawCell(struct Bitmap* bmp, int x, int y, + int scale, const cc_uint8* rows, BitmapCol color) { + int dst_width = CELL_SIZE * scale; + int dst_height = CELL_SIZE * scale; + int xx, srcX, dstX; + int yy, srcY, dstY; + BitmapCol* dst_row; + cc_uint8 src_row; + + for (yy = 0; yy < dst_height; yy++) + { + srcY = yy / scale; + dstY = y + yy; + if (dstY < 0 || dstY >= bmp->height) continue; + + dst_row = Bitmap_GetRow(bmp, dstY); + src_row = rows[srcY]; + + for (xx = 0; xx < dst_width; xx++) + { + srcX = xx / scale; + dstX = x + xx; + if (dstX < 0 || dstX >= bmp->width) continue; + + if (src_row & (1 << srcX)) { + dst_row[dstX] = color; + } + } + } +} + +void FallbackFont_DrawText(struct DrawTextArgs* args, struct Bitmap* bmp, int x, int y, cc_bool shadow) { + cc_string left = args->text, part; + int size = args->font->size; + int scale = FallbackFont_GetScale(size); + char colorCode = 'f'; + const cc_uint8* rows; + BitmapCol color; + int i; + + if (shadow) { + x += 1 * scale; + y += 1 * scale; + } + + /* adjust coords to make drawn text match GDI fonts */ + y += (args->font->height - size) / 2; + + while (Drawer2D_UNSAFE_NextPart(&left, &part, &colorCode)) + { + color = Drawer2D_GetColor(colorCode); + if (shadow) color = GetShadowColor(color); + + for (i = 0; i < part.length; i++) + { + cc_uint8 c = part.buffer[i]; + if (c == ' ') { x += SPACE_WIDTH * scale; continue; } + + rows = FallbackFont_GetRows(c); + + Fallback_DrawCell(bmp, x, y, scale, rows, color); + x += Fallback_CellWidth(rows) * scale; + } + } +} + + /*########################################################################################################################* *--------------------------------------------------------Freetype---------------------------------------------------------* *#########################################################################################################################*/ @@ -80,11 +298,13 @@ static void SysFont_Done(struct SysFont* font) { if (!source->meta.file) return; source->Close(source); - for (i = 0; i < 256; i++) { + for (i = 0; i < 256; i++) + { if (!font->glyphs[i]) continue; FT_Done_Glyph((FT_Glyph)font->glyphs[i]); } - for (i = 0; i < 256; i++) { + for (i = 0; i < 256; i++) + { if (!font->shadow_glyphs[i]) continue; FT_Done_Glyph((FT_Glyph)font->shadow_glyphs[i]); } @@ -191,7 +411,7 @@ static void SysFonts_LoadPlatform(void) { InitFreeTypeLibrary(); Platform_LoadSysFonts(); - if (fonts_changed) EntryList_Save(&font_list, FONT_CACHE_FILE); + if (fonts_changed) SysFonts_SaveCache(); } static cc_bool loadedCachedFonts; @@ -202,6 +422,10 @@ static void SysFonts_LoadCached(void) { EntryList_UNSAFE_Load(&font_list, FONT_CACHE_FILE); } +void SysFonts_SaveCache(void) { + EntryList_Save(&font_list, FONT_CACHE_FILE); +} + /* Some language-specific fonts don't support English letters */ /* and show entirely as '[]' - better off ignoring such fonts */ @@ -240,7 +464,7 @@ static void SysFonts_Add(const cc_string* path, FT_Face face, int index, char ty fonts_changed = true; } -static int SysFonts_DoRegister(const cc_string* path, int faceIndex) { +static int SysFonts_DoRegister(const cc_string* path, int faceIndex, SysFont_RegisterCallback callback) { struct SysFont font; FT_Open_Args args; FT_Error err; @@ -263,11 +487,12 @@ static int SysFonts_DoRegister(const cc_string* path, int faceIndex) { SysFonts_Add(path, font.face, faceIndex, 'R', "Regular"); } + if (callback) callback(path); FT_Done_Face(font.face); return count; } -void SysFonts_Register(const cc_string* path) { +cc_result SysFonts_Register(const cc_string* path, SysFont_RegisterCallback callback) { cc_string entry, name, value; cc_string fontPath, index; int i, count; @@ -278,14 +503,15 @@ void SysFonts_Register(const cc_string* path) { String_UNSAFE_Separate(&entry, '=', &name, &value); String_UNSAFE_Separate(&value, ',', &fontPath, &index); - if (String_CaselessEquals(path, &fontPath)) return; + if (String_CaselessEquals(path, &fontPath)) return 0; } - count = SysFonts_DoRegister(path, 0); + count = SysFonts_DoRegister(path, 0, callback); /* there may be more than one font in a font file */ for (i = 1; i < count; i++) { - SysFonts_DoRegister(path, i); + SysFonts_DoRegister(path, i, callback); } + return 0; } @@ -413,7 +639,9 @@ void SysFont_MakeDefault(struct FontDesc* desc, int size, int flags) { return; } } - Logger_Abort2(res, "Failed to init default font"); + + Window_ShowDialog("Failed to init default font", "Falling back to built-in font"); + Font_MakeBitmapped(desc, size, flags); } void SysFont_Free(struct FontDesc* desc) { @@ -443,7 +671,7 @@ int SysFont_TextWidth(struct DrawTextArgs* args) { res = FT_Load_Char(face, uc, 0); if (res) { - Platform_Log2("Error %i measuring width of %r", &res, &c); + Platform_Log2("Error %e measuring width of %r", &res, &c); charWidth = 0; } else { charWidth = face->glyph->advance.x; @@ -554,7 +782,7 @@ void SysFont_DrawText(struct DrawTextArgs* args, struct Bitmap* bmp, int x, int res = FT_Load_Char(face, uc, FT_LOAD_RENDER); if (res) { - Platform_Log2("Error %i drawing %r", &res, &text.buffer[i]); + Platform_Log2("Error %e drawing %r", &res, &text.buffer[i]); continue; } @@ -631,7 +859,11 @@ void SysFont_Free(struct FontDesc* desc) { Mem_Free(desc->handle); } -void SysFonts_Register(const cc_string* path) { } +void SysFonts_SaveCache(void) { } +cc_result SysFonts_Register(const cc_string* path, SysFont_RegisterCallback callback) { + return ERR_NOT_SUPPORTED; +} + extern void interop_SetFont(const char* font, int size, int flags); extern double interop_TextWidth(const char* text, const int len); extern double interop_TextDraw(const char* text, const int len, struct Bitmap* bmp, int x, int y, cc_bool shadow, const char* hex); @@ -692,7 +924,10 @@ extern void interop_SysFontFree(void* handle); extern int interop_SysTextWidth(struct DrawTextArgs* args); extern void interop_SysTextDraw(struct DrawTextArgs* args, struct Bitmap* bmp, int x, int y, cc_bool shadow); -void SysFonts_Register(const cc_string* path) { } +void SysFonts_SaveCache(void) { } +cc_result SysFonts_Register(const cc_string* path, SysFont_RegisterCallback callback) { + return ERR_NOT_SUPPORTED; +} const cc_string* SysFonts_UNSAFE_GetDefault(void) { return &String_Empty; @@ -710,7 +945,7 @@ void SysFont_MakeDefault(struct FontDesc* desc, int size, int flags) { interop_SysMakeDefault(desc, size, flags); } -void SysFont_Free(struct FontDesc* desc) { +void Font_Free(struct FontDesc* desc) { interop_SysFontFree(desc->handle); } @@ -722,119 +957,10 @@ void SysFont_DrawText(struct DrawTextArgs* args, struct Bitmap* bmp, int x, int interop_SysTextDraw(args, bmp, x, y, shadow); } #else - -#define SysFont_ValidChar(c) ((c) > 32 && (c) < 127) -#define SysFont_ToIndex(c) ((c) - 33) /* First valid char is ! */ -#define SPACE_WIDTH 2 -#define CELL_SIZE 8 - -#define SysFont_GetRows(c) (SysFont_ValidChar(c) ? font_bitmap[SysFont_ToIndex(c)] : missing_cell) - -static cc_uint8 missing_cell[CELL_SIZE] = { - 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF -}; - -/* 8x8 font bitmap, represented with 1 bit for each pixel */ -/* Source: Goodly's texture pack for ClassiCube */ -static cc_uint8 font_bitmap[][CELL_SIZE] = { - { 0x01,0x01,0x01,0x01,0x01,0x00,0x01,0x00 }, /* ! */ - { 0x05,0x05,0x05,0x00,0x00,0x00,0x00,0x00 }, /* " */ - { 0x0A,0x0A,0x1F,0x0A,0x1F,0x0A,0x0A,0x00 }, /* # */ - { 0x04,0x1F,0x01,0x1F,0x10,0x1F,0x04,0x00 }, /* $ */ - { 0x00,0x21,0x11,0x08,0x04,0x22,0x21,0x00 }, /* % */ - { 0x0C,0x12,0x0C,0x2E,0x19,0x11,0x2E,0x00 }, /* & */ - { 0x01,0x01,0x01,0x00,0x00,0x00,0x00,0x00 }, /* ' */ - { 0x04,0x02,0x01,0x01,0x01,0x02,0x04,0x00 }, /* ( */ - { 0x01,0x02,0x04,0x04,0x04,0x02,0x01,0x00 }, /* ) */ - { 0x00,0x02,0x07,0x02,0x05,0x00,0x00,0x00 }, /* * */ - { 0x00,0x04,0x04,0x1F,0x04,0x04,0x00,0x00 }, /* + */ - { 0x00,0x00,0x00,0x00,0x00,0x02,0x02,0x01 }, /* , */ - { 0x00,0x00,0x00,0x1F,0x00,0x00,0x00,0x00 }, /* - */ - { 0x00,0x00,0x00,0x00,0x00,0x01,0x01,0x00 }, /* . */ - { 0x08,0x08,0x04,0x04,0x02,0x02,0x01,0x00 }, /* / */ - { 0x06,0x09,0x0D,0x0B,0x09,0x09,0x06,0x00 }, /* 0 */ - { 0x02,0x03,0x02,0x02,0x02,0x02,0x07,0x00 }, /* 1 */ - { 0x06,0x09,0x08,0x04,0x02,0x09,0x0F,0x00 }, /* 2 */ - { 0x06,0x09,0x08,0x06,0x08,0x09,0x06,0x00 }, /* 3 */ - { 0x05,0x05,0x05,0x0F,0x04,0x04,0x04,0x00 }, /* 4 */ - { 0x0F,0x01,0x07,0x08,0x08,0x09,0x06,0x00 }, /* 5 */ - { 0x06,0x09,0x01,0x07,0x09,0x09,0x06,0x00 }, /* 6 */ - { 0x0F,0x08,0x08,0x04,0x04,0x02,0x02,0x00 }, /* 7 */ - { 0x06,0x09,0x09,0x06,0x09,0x09,0x06,0x00 }, /* 8 */ - { 0x06,0x09,0x09,0x0E,0x08,0x09,0x06,0x00 }, /* 9 */ - { 0x00,0x01,0x01,0x00,0x00,0x01,0x01,0x00 }, /* : */ - { 0x00,0x02,0x02,0x00,0x00,0x02,0x02,0x01 }, /* ; */ - { 0x00,0x04,0x02,0x01,0x02,0x04,0x00,0x00 }, /* < */ - { 0x00,0x00,0x1F,0x00,0x00,0x1F,0x00,0x00 }, /* = */ - { 0x00,0x01,0x02,0x04,0x02,0x01,0x00,0x00 }, /* > */ - { 0x07,0x09,0x08,0x04,0x02,0x00,0x02,0x00 }, /* ? */ - { 0x0E,0x11,0x1D,0x1D,0x1D,0x01,0x0E,0x00 }, /* @ */ - { 0x06,0x09,0x09,0x0F,0x09,0x09,0x09,0x00 }, /* A */ - { 0x07,0x09,0x09,0x07,0x09,0x09,0x07,0x00 }, /* B */ - { 0x06,0x09,0x01,0x01,0x01,0x09,0x06,0x00 }, /* C */ - { 0x07,0x09,0x09,0x09,0x09,0x09,0x07,0x00 }, /* D */ - { 0x0F,0x01,0x01,0x07,0x01,0x01,0x0F,0x00 }, /* E */ - { 0x0F,0x01,0x01,0x07,0x01,0x01,0x01,0x00 }, /* F */ - { 0x06,0x09,0x01,0x0D,0x09,0x09,0x06,0x00 }, /* G */ - { 0x09,0x09,0x09,0x0F,0x09,0x09,0x09,0x00 }, /* H */ - { 0x07,0x02,0x02,0x02,0x02,0x02,0x07,0x00 }, /* I */ - { 0x08,0x08,0x08,0x08,0x08,0x09,0x07,0x00 }, /* J */ - { 0x09,0x09,0x05,0x03,0x05,0x09,0x09,0x00 }, /* K */ - { 0x01,0x01,0x01,0x01,0x01,0x01,0x0F,0x00 }, /* L */ - { 0x11,0x1B,0x15,0x11,0x11,0x11,0x11,0x00 }, /* M */ - { 0x09,0x0B,0x0D,0x09,0x09,0x09,0x09,0x00 }, /* N */ - { 0x06,0x09,0x09,0x09,0x09,0x09,0x06,0x00 }, /* O */ - { 0x07,0x09,0x09,0x07,0x01,0x01,0x01,0x00 }, /* P */ - { 0x06,0x09,0x09,0x09,0x09,0x05,0x0E,0x00 }, /* Q */ - { 0x07,0x09,0x09,0x07,0x09,0x09,0x09,0x00 }, /* R */ - { 0x06,0x09,0x01,0x06,0x08,0x09,0x06,0x00 }, /* S */ - { 0x07,0x02,0x02,0x02,0x02,0x02,0x02,0x00 }, /* T */ - { 0x09,0x09,0x09,0x09,0x09,0x09,0x06,0x00 }, /* U */ - { 0x11,0x11,0x11,0x11,0x11,0x0A,0x04,0x00 }, /* V */ - { 0x11,0x11,0x11,0x11,0x15,0x1B,0x11,0x00 }, /* W */ - { 0x11,0x11,0x0A,0x04,0x0A,0x11,0x11,0x00 }, /* X */ - { 0x11,0x11,0x0A,0x04,0x04,0x04,0x04,0x00 }, /* Y */ - { 0x0F,0x08,0x04,0x02,0x01,0x01,0x0F,0x00 }, /* Z */ - { 0x07,0x01,0x01,0x01,0x01,0x01,0x07,0x00 }, /* [ */ - { 0x01,0x01,0x02,0x02,0x04,0x04,0x08,0x00 }, /* \ */ - { 0x07,0x04,0x04,0x04,0x04,0x04,0x07,0x00 }, /* ] */ - { 0x04,0x0A,0x11,0x00,0x00,0x00,0x00,0x00 }, /* ^ */ - { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1F }, /* _ */ - { 0x01,0x01,0x02,0x00,0x00,0x00,0x00,0x00 }, /* ` */ - { 0x00,0x00,0x0E,0x09,0x09,0x0D,0x0B,0x00 }, /* a */ - { 0x01,0x01,0x07,0x09,0x09,0x09,0x07,0x00 }, /* b */ - { 0x00,0x00,0x06,0x09,0x01,0x09,0x06,0x00 }, /* c */ - { 0x08,0x08,0x0E,0x09,0x09,0x09,0x0E,0x00 }, /* d */ - { 0x00,0x00,0x06,0x09,0x0F,0x01,0x0E,0x00 }, /* e */ - { 0x06,0x01,0x07,0x01,0x01,0x01,0x01,0x00 }, /* f */ - { 0x00,0x00,0x0E,0x09,0x09,0x0E,0x08,0x07 }, /* g */ - { 0x01,0x01,0x07,0x09,0x09,0x09,0x09,0x00 }, /* h */ - { 0x01,0x00,0x01,0x01,0x01,0x01,0x01,0x00 }, /* i */ - { 0x08,0x00,0x08,0x08,0x08,0x08,0x09,0x06 }, /* j */ - { 0x01,0x01,0x09,0x05,0x03,0x05,0x09,0x00 }, /* k */ - { 0x01,0x01,0x01,0x01,0x01,0x01,0x02,0x00 }, /* l */ - { 0x00,0x00,0x0B,0x15,0x15,0x11,0x11,0x00 }, /* m */ - { 0x00,0x00,0x07,0x09,0x09,0x09,0x09,0x00 }, /* n */ - { 0x00,0x00,0x06,0x09,0x09,0x09,0x06,0x00 }, /* o */ - { 0x00,0x00,0x07,0x09,0x09,0x07,0x01,0x01 }, /* p */ - { 0x00,0x00,0x0E,0x09,0x09,0x0E,0x08,0x08 }, /* q */ - { 0x00,0x00,0x05,0x03,0x01,0x01,0x01,0x00 }, /* r */ - { 0x00,0x00,0x0E,0x01,0x06,0x08,0x07,0x00 }, /* s */ - { 0x02,0x02,0x07,0x02,0x02,0x02,0x02,0x00 }, /* t */ - { 0x00,0x00,0x09,0x09,0x09,0x09,0x0E,0x00 }, /* u */ - { 0x00,0x00,0x09,0x09,0x09,0x05,0x03,0x00 }, /* v */ - { 0x00,0x00,0x11,0x11,0x15,0x15,0x1A,0x00 }, /* w */ - { 0x00,0x00,0x05,0x05,0x02,0x05,0x05,0x00 }, /* x */ - { 0x00,0x00,0x09,0x09,0x09,0x0E,0x08,0x07 }, /* y */ - { 0x00,0x00,0x0F,0x08,0x04,0x02,0x0F,0x00 }, /* z */ - { 0x04,0x02,0x02,0x01,0x02,0x02,0x04,0x00 }, /* { */ - { 0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01 }, /* | */ - { 0x01,0x02,0x02,0x04,0x02,0x02,0x01,0x00 }, /* } */ - { 0x00,0x00,0x26,0x19,0x00,0x00,0x00,0x00 }, /* ~ */ -}; - - -void SysFonts_Register(const cc_string* path) { } +void SysFonts_SaveCache(void) { } +cc_result SysFonts_Register(const cc_string* path, SysFont_RegisterCallback callback) { + return ERR_NOT_SUPPORTED; +} const cc_string* SysFonts_UNSAFE_GetDefault(void) { return &String_Empty; } @@ -849,7 +975,7 @@ cc_result SysFont_Make(struct FontDesc* desc, const cc_string* fontName, int siz desc->flags = flags; desc->height = Drawer2D_AdjHeight(size); - desc->handle = (void*)(size / 8); + desc->handle = (void*)1; return 0; } @@ -861,106 +987,11 @@ void SysFont_Free(struct FontDesc* desc) { desc->handle = NULL; } - -static int CellWidth(cc_uint8* rows) { - int y, width, widest = 0; - - for (y = 0; y < CELL_SIZE; y++) - { - widest = max(widest, rows[y]); - } - width = Math_ilog2(widest) + 1; - - return width + 1; /* add 1 for padding */ -} - int SysFont_TextWidth(struct DrawTextArgs* args) { - cc_string left = args->text, part; - int scale = (int)args->font->handle; - char colorCode = 'f'; - int i, width = 0; - - while (Drawer2D_UNSAFE_NextPart(&left, &part, &colorCode)) - { - for (i = 0; i < part.length; i++) - { - cc_uint8 c = part.buffer[i]; - if (c == ' ') { - width += SPACE_WIDTH * scale; - } else { - width += CellWidth(SysFont_GetRows(c)) * scale; - } - } - } - - width = max(1, width); - if (args->useShadow) width += 1 * scale; - return width; -} - -static void DrawCell(struct Bitmap* bmp, int x, int y, - int scale, cc_uint8 * rows, BitmapCol color) { - int dst_width = CELL_SIZE * scale; - int dst_height = CELL_SIZE * scale; - int xx, srcX, dstX; - int yy, srcY, dstY; - BitmapCol* dst_row; - cc_uint8 src_row; - - for (yy = 0; yy < dst_height; yy++) - { - srcY = yy / scale; - dstY = y + yy; - if (dstY < 0 || dstY >= bmp->height) continue; - - dst_row = Bitmap_GetRow(bmp, dstY); - src_row = rows[srcY]; - - for (xx = 0; xx < dst_width; xx++) - { - srcX = xx / scale; - dstX = x + xx; - if (dstX < 0 || dstX >= bmp->width) continue; - - if (src_row & (1 << srcX)) { - dst_row[dstX] = color; - } - } - } + return FallbackFont_TextWidth(args); } void SysFont_DrawText(struct DrawTextArgs* args, struct Bitmap* bmp, int x, int y, cc_bool shadow) { - cc_string left = args->text, part; - int scale = (int)args->font->handle; - int size = args->font->size; - char colorCode = 'f'; - cc_uint8* rows; - BitmapCol color; - int i; - - if (shadow) { - x += 1 * scale; - y += 1 * scale; - } - - /* adjust coords to make drawn text match GDI fonts */ - y += (args->font->height - size) / 2; - - while (Drawer2D_UNSAFE_NextPart(&left, &part, &colorCode)) - { - color = Drawer2D_GetColor(colorCode); - if (shadow) color = GetShadowColor(color); - - for (i = 0; i < part.length; i++) - { - cc_uint8 c = part.buffer[i]; - if (c == ' ') { x += SPACE_WIDTH * scale; continue; } - - rows = SysFont_GetRows(c); - - DrawCell(bmp, x, y, scale, rows, color); - x += CellWidth(rows) * scale; - } - } + FallbackFont_DrawText(args, bmp, x, y, shadow); } #endif diff --git a/src/SystemFonts.h b/src/SystemFonts.h index 66b4482..3573f4d 100644 --- a/src/SystemFonts.h +++ b/src/SystemFonts.h @@ -11,6 +11,9 @@ struct IGameComponent; struct StringsBuffer; extern struct IGameComponent SystemFonts_Component; +int FallbackFont_TextWidth(const struct DrawTextArgs* args); +void FallbackFont_DrawText(struct DrawTextArgs* args, struct Bitmap* bmp, int x, int y, cc_bool shadow); + /* Allocates a new system font from the given arguments */ cc_result SysFont_Make(struct FontDesc* desc, const cc_string* fontName, int size, int flags); /* Frees an allocated system font */ @@ -26,11 +29,13 @@ int SysFont_TextWidth(struct DrawTextArgs* args); /* Draws the given text with the given system font onto the given bitmap */ void SysFont_DrawText(struct DrawTextArgs* args, struct Bitmap* bmp, int x, int y, cc_bool shadow); +typedef void (*SysFont_RegisterCallback)(const cc_string* path); /* Gets the name of the default system font used */ const cc_string* SysFonts_UNSAFE_GetDefault(void); /* Gets the list of all supported system font names on this platform */ CC_API void SysFonts_GetNames(struct StringsBuffer* buffer); /* Attempts to decode one or more fonts from the given file */ /* NOTE: If this file has been decoded before (fontscache.txt), does nothing */ -void SysFonts_Register(const cc_string* path); +cc_result SysFonts_Register(const cc_string* path, SysFont_RegisterCallback callback); +void SysFonts_SaveCache(void); #endif diff --git a/src/TexturePack.c b/src/TexturePack.c index af5473a..af50b9b 100644 --- a/src/TexturePack.c +++ b/src/TexturePack.c @@ -44,6 +44,21 @@ static BitmapCol fallback_terrain[16 * 8] = { BitmapColor_RGB( 52, 90, 134), BitmapColor_RGB( 57, 115, 158), BitmapColor_RGB( 52, 90, 134), BitmapColor_RGB( 57, 115, 158), BitmapColor_RGB( 52, 90, 134), BitmapColor_RGB( 57, 115, 158), BitmapColor_RGB( 52, 90, 134), BitmapColor_RGB( 57, 115, 158), }; +static void LoadFallbackAtlas(void) { + struct Bitmap bmp, src; + src.width = 16; + src.height = 8; + src.scan0 = fallback_terrain; + + if (Gfx.MinTexWidth || Gfx.MinTexHeight) { + Bitmap_Allocate(&bmp, 16 * Gfx.MinTexWidth, 8 * Gfx.MinTexHeight); + Bitmap_Scale(&bmp, &src, 0, 0, 16, 8); + Atlas_TryChange(&bmp); + } else { + Atlas_TryChange(&src); + } +} + /*########################################################################################################################* *------------------------------------------------------TerrainAtlas-------------------------------------------------------* *#########################################################################################################################*/ @@ -499,13 +514,7 @@ cc_result TexturePack_ExtractCurrent(cc_bool forceReload) { } /* Use fallback terrain texture with 1 pixel per tile */ - if (!Atlas2D.Bmp.scan0) { - struct Bitmap tmp; - tmp.width = 16; - tmp.height = 8; - tmp.scan0 = fallback_terrain; - Atlas_TryChange(&tmp); - } + if (!Atlas2D.Bmp.scan0) LoadFallbackAtlas(); return res; } diff --git a/src/TouchUI.c b/src/TouchUI.c new file mode 100644 index 0000000..a6ae410 --- /dev/null +++ b/src/TouchUI.c @@ -0,0 +1,800 @@ +#include "Screens.h" +#ifdef CC_BUILD_TOUCH +#include "Widgets.h" +#include "Game.h" +#include "Event.h" +#include "Platform.h" +#include "Inventory.h" +#include "Drawer2D.h" +#include "Graphics.h" +#include "Funcs.h" +#include "TexturePack.h" +#include "Model.h" +#include "Generator.h" +#include "Server.h" +#include "Chat.h" +#include "ExtMath.h" +#include "Window.h" +#include "Camera.h" +#include "Http.h" +#include "Block.h" +#include "Menus.h" +#include "World.h" +#include "Input.h" +#include "Utils.h" +#include "Options.h" + + +/* Enumeration of on-screen buttons for touch GUI */ +#define ONSCREEN_BTN_CHAT (1 << 0) +#define ONSCREEN_BTN_LIST (1 << 1) +#define ONSCREEN_BTN_SPAWN (1 << 2) +#define ONSCREEN_BTN_SETSPAWN (1 << 3) +#define ONSCREEN_BTN_FLY (1 << 4) +#define ONSCREEN_BTN_NOCLIP (1 << 5) +#define ONSCREEN_BTN_SPEED (1 << 6) +#define ONSCREEN_BTN_HALFSPEED (1 << 7) +#define ONSCREEN_BTN_CAMERA (1 << 8) +#define ONSCREEN_BTN_DELETE (1 << 9) +#define ONSCREEN_BTN_PICK (1 << 10) +#define ONSCREEN_BTN_PLACE (1 << 11) +#define ONSCREEN_BTN_SWITCH (1 << 12) +#define ONSCREEN_MAX_BTNS 13 + +static int GetOnscreenButtons(void) { + #define DEFAULT_SP_ONSCREEN (ONSCREEN_BTN_FLY | ONSCREEN_BTN_SPEED) + #define DEFAULT_MP_ONSCREEN (ONSCREEN_BTN_FLY | ONSCREEN_BTN_SPEED | ONSCREEN_BTN_CHAT) + + return Options_GetInt(OPT_TOUCH_BUTTONS, 0, Int32_MaxValue, + Server.IsSinglePlayer ? DEFAULT_SP_ONSCREEN : DEFAULT_MP_ONSCREEN); +} + +static int GetOnscreenHAligns(void) { + return Options_GetInt(OPT_TOUCH_HALIGN, 0, Int32_MaxValue, 0); +} + +/*########################################################################################################################* +*---------------------------------------------------TouchControlsScreen---------------------------------------------------* +*#########################################################################################################################*/ +#define ONSCREEN_PAGE_BTNS 4 +#define ONSCREEN_NUM_PAGES 4 +static struct TouchOnscreenScreen { + Screen_Body + struct ButtonWidget back, left, right; + struct ButtonWidget btns[ONSCREEN_PAGE_BTNS]; + struct FontDesc font; + int page; +} TouchOnscreenScreen; + +static struct Widget* touchOnscreen_widgets[3 + ONSCREEN_PAGE_BTNS]; + +static const char* const touchOnscreen[ONSCREEN_PAGE_BTNS * ONSCREEN_NUM_PAGES] = { + "Chat", "Tablist", "Spawn", "Set spawn", + "Fly", "Noclip", "Speed", "Half speed", + "Third person", "Delete", "Pick", "Place", + "Switch hotbar", "---", "---", "---", +}; + +static void TouchOnscreen_UpdateButton(struct TouchOnscreenScreen* s, struct ButtonWidget* btn) { + PackedCol grey = PackedCol_Make(0x7F, 0x7F, 0x7F, 0xFF); + int buttons = GetOnscreenButtons(); + int haligns = GetOnscreenHAligns(); + const char* label; + char buffer[64]; + cc_string str; + int bit; + + bit = 1 << btn->meta.val; + btn->color = (buttons & bit) ? PACKEDCOL_WHITE : grey; + + String_InitArray(str, buffer); + label = touchOnscreen[btn->meta.val]; + + if ((buttons & bit) && (haligns & bit)) { + String_Format1(&str, "%c: Left aligned", label); + } else if (buttons & bit) { + String_Format1(&str, "%c: Right aligned", label); + } else { + String_AppendConst(&str, label); + } + ButtonWidget_Set(btn, &str, &s->font); +} + +static void TouchOnscreen_UpdateAll(struct TouchOnscreenScreen* s) { + int i; + for (i = 0; i < ONSCREEN_PAGE_BTNS; i++) + { + TouchOnscreen_UpdateButton(s, &s->btns[i]); + } +} + +static void TouchOnscreen_Any(void* screen, void* w) { + struct TouchOnscreenScreen* s = (struct TouchOnscreenScreen*)screen; + struct ButtonWidget* btn = (struct ButtonWidget*)w; + int buttons = GetOnscreenButtons(); + int haligns = GetOnscreenHAligns(); + int bit = 1 << btn->meta.val; + + if ((buttons & bit) & (haligns & bit)) { + buttons &= ~bit; + haligns &= ~bit; + } else if (buttons & bit) { + haligns |= bit; + } else { + buttons |= bit; + } + + Options_SetInt(OPT_TOUCH_BUTTONS, buttons); + Options_SetInt(OPT_TOUCH_HALIGN, haligns); + TouchOnscreen_UpdateButton(s, btn); + TouchScreen_Refresh(); +} +static void TouchOnscreen_More(void* s, void* w) { TouchCtrlsScreen_Show(); } + +static void TouchOnscreen_Left(void* screen, void* b); +static void TouchOnscreen_Right(void* screen, void* b); + +static void TouchOnscreen_RemakeWidgets(struct TouchOnscreenScreen* s) { + int i; + int offset = s->page * ONSCREEN_PAGE_BTNS; + s->widgets = touchOnscreen_widgets; + s->numWidgets = 0; + s->maxWidgets = Array_Elems(touchOnscreen_widgets); + + for (i = 0; i < ONSCREEN_PAGE_BTNS; i++) + { + ButtonWidget_Add(s, &s->btns[i], 300, TouchOnscreen_Any); + s->btns[i].meta.val = i + offset; + } + ButtonWidget_Add(s, &s->back, 400, TouchOnscreen_More); + ButtonWidget_Add(s, &s->left, 40, TouchOnscreen_Left); + ButtonWidget_Add(s, &s->right, 40, TouchOnscreen_Right); + + Widget_SetDisabled(&s->left, s->page == 0); + Widget_SetDisabled(&s->right, s->page == ONSCREEN_NUM_PAGES - 1); +} + +static void TouchOnscreen_Left(void* screen, void* b) { + struct TouchOnscreenScreen* s = (struct TouchOnscreenScreen*)screen; + s->page--; + TouchOnscreen_RemakeWidgets(s); + Gui_Refresh((struct Screen*)s); + TouchOnscreen_UpdateAll(s); +} + +static void TouchOnscreen_Right(void* screen, void* b) { + struct TouchOnscreenScreen* s = (struct TouchOnscreenScreen*)screen; + s->page++; + TouchOnscreen_RemakeWidgets(s); + Gui_Refresh((struct Screen*)s); + TouchOnscreen_UpdateAll(s); +} + +static void TouchOnscreenScreen_ContextRecreated(void* screen) { + struct TouchOnscreenScreen* s = (struct TouchOnscreenScreen*)screen; + Screen_UpdateVb(screen); + TouchOnscreen_UpdateAll(s); + ButtonWidget_SetConst(&s->back, "Done", &s->font); + ButtonWidget_SetConst(&s->left, "<", &s->font); + ButtonWidget_SetConst(&s->right, ">", &s->font); +} + +static void TouchOnscreenScreen_Layout(void* screen) { + struct TouchOnscreenScreen* s = (struct TouchOnscreenScreen*)screen; + int i; + for (i = 0; i < ONSCREEN_PAGE_BTNS; i++) + { + Widget_SetLocation(&s->btns[i], ANCHOR_CENTRE, ANCHOR_CENTRE, 0, -75 + i * 50); + } + + Menu_LayoutBack(&s->back); + Widget_SetLocation(&s->left, ANCHOR_CENTRE, ANCHOR_CENTRE, -220, 0); + Widget_SetLocation(&s->right, ANCHOR_CENTRE, ANCHOR_CENTRE, 220, 0); +} + +static void TouchOnscreenScreen_Init(void* screen) { + struct TouchOnscreenScreen* s = (struct TouchOnscreenScreen*)screen; + s->page = 0; + Gui_MakeTitleFont(&s->font); + TouchOnscreen_RemakeWidgets(s); + TouchOnscreen_UpdateAll(screen); + + s->maxVertices = Screen_CalcDefaultMaxVertices(s); +} + +static void TouchOnscreenScreen_Free(void* screen) { + struct TouchOnscreenScreen* s = (struct TouchOnscreenScreen*)screen; + Font_Free(&s->font); +} + +static const struct ScreenVTABLE TouchOnscreenScreen_VTABLE = { + TouchOnscreenScreen_Init, Screen_NullUpdate, TouchOnscreenScreen_Free, + MenuScreen_Render2, Screen_BuildMesh, + Menu_InputDown, Screen_InputUp, Screen_TKeyPress, Screen_TText, + Menu_PointerDown, Screen_PointerUp, Menu_PointerMove, Screen_TMouseScroll, + TouchOnscreenScreen_Layout, Screen_ContextLost, TouchOnscreenScreen_ContextRecreated +}; +void TouchOnscreenScreen_Show(void) { + struct TouchOnscreenScreen* s = &TouchOnscreenScreen; + s->grabsInput = true; + s->closable = true; + s->VTABLE = &TouchOnscreenScreen_VTABLE; + + Gui_Add((struct Screen*)s, GUI_PRIORITY_TOUCHMORE); +} + + +/*########################################################################################################################* +*---------------------------------------------------TouchControlsScreen---------------------------------------------------* +*#########################################################################################################################*/ +#define TOUCHCTRLS_BTNS 5 +static struct TouchCtrlsScreen { + Screen_Body + struct ButtonWidget back; + struct ButtonWidget btns[TOUCHCTRLS_BTNS]; + struct FontDesc font; +} TouchCtrlsScreen; + +static struct Widget* touchCtrls_widgets[TOUCHCTRLS_BTNS + 1]; + +static const char* GetTapDesc(int mode) { + if (mode == INPUT_MODE_PLACE) return "Tap: Place"; + if (mode == INPUT_MODE_DELETE) return "Tap: Delete"; + return "Tap: None"; +} +static void TouchCtrls_UpdateTapText(void* screen) { + struct TouchCtrlsScreen* s = (struct TouchCtrlsScreen*)screen; + ButtonWidget_SetConst(&s->btns[0], GetTapDesc(Input_TapMode), &s->font); + s->dirty = true; +} + +static const char* GetHoldDesc(int mode) { + if (mode == INPUT_MODE_PLACE) return "Hold: Place"; + if (mode == INPUT_MODE_DELETE) return "Hold: Delete"; + return "Hold: None"; +} +static void TouchCtrls_UpdateHoldText(void* screen) { + struct TouchCtrlsScreen* s = (struct TouchCtrlsScreen*)screen; + ButtonWidget_SetConst(&s->btns[1], GetHoldDesc(Input_HoldMode), &s->font); + s->dirty = true; +} + +static void TouchCtrls_UpdateSensitivity(void* screen) { + cc_string value; char valueBuffer[STRING_SIZE]; + struct TouchCtrlsScreen* s = (struct TouchCtrlsScreen*)screen; + String_InitArray(value, valueBuffer); + + String_Format1(&value, "Sensitivity: %i", &Camera.Sensitivity); + ButtonWidget_Set(&s->btns[2], &value, &s->font); + s->dirty = true; +} + +static void TouchCtrls_UpdateScale(void* screen) { + cc_string value; char valueBuffer[STRING_SIZE]; + struct TouchCtrlsScreen* s = (struct TouchCtrlsScreen*)screen; + String_InitArray(value, valueBuffer); + + String_AppendConst(&value, "Scale: "); + String_AppendFloat(&value, Gui.RawTouchScale, 1); + ButtonWidget_Set(&s->btns[3], &value, &s->font); + s->dirty = true; +} + +static void TouchCtrls_More(void* s, void* w) { TouchMoreScreen_Show(); } +static void TouchCtrls_Onscreen(void* s, void* w) { TouchOnscreenScreen_Show(); } + +static void TouchCtrls_Tap(void* s, void* w) { + Input_TapMode = (Input_TapMode + 1) % INPUT_MODE_COUNT; + TouchCtrls_UpdateTapText(s); +} +static void TouchCtrls_Hold(void* s, void* w) { + Input_HoldMode = (Input_HoldMode + 1) % INPUT_MODE_COUNT; + TouchCtrls_UpdateHoldText(s); +} + +static void TouchCtrls_SensitivityDone(const cc_string* value, cc_bool valid) { + int sensitivity; + if (!valid) return; + + Convert_ParseInt(value, &sensitivity); + Camera.Sensitivity = sensitivity; + Options_Set(OPT_SENSITIVITY, value); + TouchCtrls_UpdateSensitivity(&TouchCtrlsScreen); +} + +static void TouchCtrls_Sensitivity(void* screen, void* w) { + struct TouchCtrlsScreen* s = (struct TouchCtrlsScreen*)screen; + static struct MenuInputDesc desc; + cc_string value; char valueBuffer[STRING_SIZE]; + String_InitArray(value, valueBuffer); + + MenuInput_Int(desc, 1, 200, 30); + String_AppendInt(&value, Camera.Sensitivity); + MenuInputOverlay_Show(&desc, &value, TouchCtrls_SensitivityDone, true); + /* Fix Sensitivity button getting stuck as 'active' */ + /* (input overlay swallows subsequent pointer events) */ + s->btns[2].active = 0; +} + +static void TouchCtrls_ScaleDone(const cc_string* value, cc_bool valid) { + if (!valid) return; + Convert_ParseFloat(value, &Gui.RawTouchScale); + Options_Set(OPT_TOUCH_SCALE, value); + + TouchCtrls_UpdateScale(&TouchCtrlsScreen); + Gui_LayoutAll(); +} + +static void TouchCtrls_Scale(void* screen, void* w) { + struct TouchCtrlsScreen* s = (struct TouchCtrlsScreen*)screen; + static struct MenuInputDesc desc; + cc_string value; char valueBuffer[STRING_SIZE]; + String_InitArray(value, valueBuffer); + + MenuInput_Float(desc, 0.25f, 5.0f, 1.0f); + String_AppendFloat(&value, Gui.RawTouchScale, 1); + MenuInputOverlay_Show(&desc, &value, TouchCtrls_ScaleDone, true); + s->btns[3].active = 0; +} + +static const struct SimpleButtonDesc touchCtrls_btns[5] = { + { -102, -50, "", TouchCtrls_Tap }, + { 102, -50, "", TouchCtrls_Hold }, + { -102, 0, "", TouchCtrls_Sensitivity }, + { 102, 0, "", TouchCtrls_Scale }, + { 0, 50, "On-screen controls", TouchCtrls_Onscreen } +}; + +static void TouchCtrlsScreen_ContextLost(void* screen) { + struct TouchCtrlsScreen* s = (struct TouchCtrlsScreen*)screen; + Font_Free(&s->font); + Screen_ContextLost(screen); +} + +static void TouchCtrlsScreen_ContextRecreated(void* screen) { + struct TouchCtrlsScreen* s = (struct TouchCtrlsScreen*)screen; + Gui_MakeTitleFont(&s->font); + Screen_UpdateVb(screen); + Menu_SetButtons(s->btns, &s->font, touchCtrls_btns, TOUCHCTRLS_BTNS); + ButtonWidget_SetConst(&s->back, "Done", &s->font); + + TouchCtrls_UpdateTapText(s); + TouchCtrls_UpdateHoldText(s); + TouchCtrls_UpdateSensitivity(s); + TouchCtrls_UpdateScale(s); +} + +static void TouchCtrlsScreen_Layout(void* screen) { + struct TouchCtrlsScreen* s = (struct TouchCtrlsScreen*)screen; + Menu_LayoutButtons(s->btns, touchCtrls_btns, TOUCHCTRLS_BTNS); + Menu_LayoutBack(&s->back); +} + +static void TouchCtrlsScreen_Init(void* screen) { + struct TouchCtrlsScreen* s = (struct TouchCtrlsScreen*)screen; + s->widgets = touchCtrls_widgets; + s->numWidgets = 0; + s->maxWidgets = Array_Elems(touchCtrls_widgets); + + Menu_AddButtons(s, s->btns, 195, touchCtrls_btns, 4); + Menu_AddButtons(s, s->btns + 4, 400, touchCtrls_btns + 4, 1); + ButtonWidget_Add(s, &s->back, 400, TouchCtrls_More); + + s->maxVertices = Screen_CalcDefaultMaxVertices(s); +} + +static const struct ScreenVTABLE TouchCtrlsScreen_VTABLE = { + TouchCtrlsScreen_Init, Screen_NullUpdate, Screen_NullFunc, + MenuScreen_Render2, Screen_BuildMesh, + Menu_InputDown, Screen_InputUp, Screen_TKeyPress, Screen_TText, + Menu_PointerDown, Screen_PointerUp, Menu_PointerMove, Screen_TMouseScroll, + TouchCtrlsScreen_Layout, TouchCtrlsScreen_ContextLost, TouchCtrlsScreen_ContextRecreated +}; +void TouchCtrlsScreen_Show(void) { + struct TouchCtrlsScreen* s = &TouchCtrlsScreen; + s->grabsInput = true; + s->closable = true; + s->VTABLE = &TouchCtrlsScreen_VTABLE; + + Gui_Add((struct Screen*)s, GUI_PRIORITY_TOUCHMORE); +} + + +/*########################################################################################################################* +*-----------------------------------------------------TouchMoreScreen-----------------------------------------------------* +*#########################################################################################################################*/ +#define TOUCHMORE_BTNS 6 +static struct TouchMoreScreen { + Screen_Body + struct ButtonWidget back; + struct ButtonWidget btns[TOUCHMORE_BTNS]; +} TouchMoreScreen; + +static struct Widget* touchMore_widgets[TOUCHMORE_BTNS + 1]; + +static void TouchMore_Take(void* s, void* w) { + Gui_Remove((struct Screen*)&TouchMoreScreen); + Game_ScreenshotRequested = true; +} +static void TouchMore_Screen(void* s, void* w) { + Gui_Remove((struct Screen*)&TouchMoreScreen); + Game_ToggleFullscreen(); +} +static void TouchMore_Ctrls(void* s, void* w) { TouchCtrlsScreen_Show(); } +static void TouchMore_Menu(void* s, void* w) { + Gui_Remove((struct Screen*)&TouchMoreScreen); + Gui_ShowPauseMenu(); +} +static void TouchMore_Game(void* s, void* w) { + Gui_Remove((struct Screen*)&TouchMoreScreen); +} +static void TouchMore_Chat(void* s, void* w) { + Gui_Remove((struct Screen*)&TouchMoreScreen); + ChatScreen_OpenInput(&String_Empty); +} +static void TouchMore_Fog(void* s, void* w) { Game_CycleViewDistance(); } + +static const struct SimpleButtonDesc touchMore_btns[TOUCHMORE_BTNS] = { + { -102, -50, "Screenshot", TouchMore_Take }, + { -102, 0, "Fullscreen", TouchMore_Screen }, + { 102, -50, "Chat", TouchMore_Chat }, + { 102, 0, "Fog", TouchMore_Fog }, + { 0, 50, "Controls", TouchMore_Ctrls }, + { 0, 100, "Main menu", TouchMore_Menu } +}; + +static void TouchMoreScreen_ContextRecreated(void* screen) { + struct TouchMoreScreen* s = (struct TouchMoreScreen*)screen; + struct FontDesc titleFont; + Gui_MakeTitleFont(&titleFont); + Screen_UpdateVb(screen); + + Menu_SetButtons(s->btns, &titleFont, touchMore_btns, TOUCHMORE_BTNS); + ButtonWidget_SetConst(&s->back, "Back to game", &titleFont); + Font_Free(&titleFont); +} + +static void TouchMoreScreen_Layout(void* screen) { + struct TouchMoreScreen* s = (struct TouchMoreScreen*)screen; + Menu_LayoutButtons(s->btns, touchMore_btns, TOUCHMORE_BTNS); + Menu_LayoutBack(&s->back); +} + +static void TouchMoreScreen_Init(void* screen) { + struct TouchMoreScreen* s = (struct TouchMoreScreen*)screen; + s->widgets = touchMore_widgets; + s->numWidgets = 0; + s->maxWidgets = Array_Elems(touchMore_widgets); + + Menu_AddButtons(s, s->btns, 195, touchMore_btns, 4); + Menu_AddButtons(s, s->btns + 4, 400, touchMore_btns + 4, 2); + ButtonWidget_Add(s, &s->back, 400, TouchMore_Game); + + s->maxVertices = Screen_CalcDefaultMaxVertices(s); +} + +static const struct ScreenVTABLE TouchMoreScreen_VTABLE = { + TouchMoreScreen_Init, Screen_NullUpdate, Screen_NullFunc, + MenuScreen_Render2, Screen_BuildMesh, + Menu_InputDown, Screen_InputUp, Screen_TKeyPress, Screen_TText, + Menu_PointerDown, Screen_PointerUp, Menu_PointerMove, Screen_TMouseScroll, + TouchMoreScreen_Layout, Screen_ContextLost, TouchMoreScreen_ContextRecreated +}; +void TouchMoreScreen_Show(void) { + struct TouchMoreScreen* s = &TouchMoreScreen; + s->grabsInput = true; + s->closable = true; + s->VTABLE = &TouchMoreScreen_VTABLE; + + Gui_Add((struct Screen*)s, GUI_PRIORITY_TOUCHMORE); +} + + +/*########################################################################################################################* +*--------------------------------------------------------TouchScreen------------------------------------------------------* +*#########################################################################################################################*/ +#define TOUCH_EXTRA_BTNS 2 +#define TOUCH_MAX_BTNS (ONSCREEN_MAX_BTNS + TOUCH_EXTRA_BTNS + 1) +struct TouchButtonDesc { + const char* text; + cc_uint8 bind, x, y; + Widget_LeftClick OnClick; + cc_bool* enabled; +}; + +static struct TouchScreen { + Screen_Body + const struct TouchButtonDesc* descs; + int numOnscreen, numBtns; + struct FontDesc font; + struct ThumbstickWidget thumbstick; + struct ButtonWidget onscreen[ONSCREEN_MAX_BTNS]; + struct ButtonWidget btns[TOUCH_EXTRA_BTNS], more; +} TouchScreen; + +static struct Widget* touch_widgets[ONSCREEN_MAX_BTNS + TOUCH_EXTRA_BTNS + 2] = { + NULL,NULL,NULL,NULL, NULL,NULL,NULL,NULL, NULL,NULL,NULL,NULL, NULL, + NULL,NULL, (struct Widget*)&TouchScreen.thumbstick, (struct Widget*)&TouchScreen.more +}; +#define TOUCH_MAX_VERTICES (THUMBSTICKWIDGET_MAX + TOUCH_MAX_BTNS * BUTTONWIDGET_MAX) + +static void TouchScreen_ChatClick(void* s, void* w) { ChatScreen_OpenInput(&String_Empty); } +static void TouchScreen_RespawnClick(void* s, void* w) { LocalPlayer_HandleRespawn(Entities.CurPlayer); } +static void TouchScreen_SetSpawnClick(void* s, void* w) { LocalPlayer_HandleSetSpawn(Entities.CurPlayer); } +static void TouchScreen_FlyClick(void* s, void* w) { LocalPlayer_HandleFly(Entities.CurPlayer); } +static void TouchScreen_NoclipClick(void* s, void* w) { LocalPlayer_HandleNoclip(Entities.CurPlayer); } +static void TouchScreen_CameraClick(void* s, void* w) { Camera_CycleActive(); } +static void TouchScreen_MoreClick(void* s, void* w) { TouchMoreScreen_Show(); } +static void TouchScreen_SwitchClick(void* s, void* w) { Inventory_SwitchHotbar(); } +static void TouchScreen_DeleteClick(void* s, void* w) { InputHandler_DeleteBlock(); } /* TODO: also Send CPEClick packet */ +static void TouchScreen_PlaceClick(void* s, void* w) { InputHandler_PlaceBlock(); } +static void TouchScreen_PickClick(void* s, void* w) { InputHandler_PickBlock(); } + +static void TouchScreen_TabClick(void* s, void* w) { + struct Screen* tablist = Gui_GetScreen(GUI_PRIORITY_TABLIST); + if (tablist) { + Gui_Remove(tablist); + } else { + TabListOverlay_Show(true); + } +} + +static void TouchScreen_SpeedClick(void* s, void* w) { + struct HacksComp* hacks = &Entities.CurPlayer->Hacks; + if (hacks->Enabled) hacks->Speeding = !hacks->Speeding; +} +static void TouchScreen_HalfClick(void* s, void* w) { + struct HacksComp* hacks = &Entities.CurPlayer->Hacks; + if (hacks->Enabled) hacks->HalfSpeeding = !hacks->HalfSpeeding; +} + +static void TouchScreen_BindClick(void* screen, void* widget) { + struct TouchScreen* s = (struct TouchScreen*)screen; + struct ButtonWidget* btn = (struct ButtonWidget*)widget; + + int i = btn->meta.val; + Input_Set(KeyBinds_Normal[s->descs[i].bind], true); +} + +static const struct TouchButtonDesc onscreenDescs[ONSCREEN_MAX_BTNS] = { + { "Chat", 0,0,0, TouchScreen_ChatClick }, + { "Tablist", 0,0,0, TouchScreen_TabClick }, + { "Respawn", 0,0,0, TouchScreen_RespawnClick, &LocalPlayer_Instances[0].Hacks.CanRespawn }, + { "Set spawn", 0,0,0, TouchScreen_SetSpawnClick, &LocalPlayer_Instances[0].Hacks.CanRespawn }, + { "Fly", 0,0,0, TouchScreen_FlyClick, &LocalPlayer_Instances[0].Hacks.CanFly }, + { "Noclip", 0,0,0, TouchScreen_NoclipClick, &LocalPlayer_Instances[0].Hacks.CanNoclip }, + { "Speed", 0,0,0, TouchScreen_SpeedClick, &LocalPlayer_Instances[0].Hacks.CanSpeed }, + { "\xabSpeed", 0,0,0, TouchScreen_HalfClick, &LocalPlayer_Instances[0].Hacks.CanSpeed }, + { "Camera", 0,0,0, TouchScreen_CameraClick, &LocalPlayer_Instances[0].Hacks.CanUseThirdPerson }, + { "Delete", 0,0,0, TouchScreen_DeleteClick }, + { "Pick", 0,0,0, TouchScreen_PickClick }, + { "Place", 0,0,0, TouchScreen_PlaceClick }, + { "Hotbar", 0,0,0, TouchScreen_SwitchClick } +}; +static const struct TouchButtonDesc normDescs[1] = { + { "\x1E", KEYBIND_JUMP, 50, 10, TouchScreen_BindClick } +}; +static const struct TouchButtonDesc hackDescs[2] = { + { "\x1E", KEYBIND_FLY_UP, 50, 70, TouchScreen_BindClick }, + { "\x1F", KEYBIND_FLY_DOWN, 50, 10, TouchScreen_BindClick } +}; + +#define TOUCHSCREEN_BTN_COLOR PackedCol_Make(255, 255, 255, 200) +static void TouchScreen_InitButtons(struct TouchScreen* s) { + struct HacksComp* hacks = &Entities.CurPlayer->Hacks; + const struct TouchButtonDesc* desc; + int buttons = GetOnscreenButtons(); + int i, j; + for (i = 0; i < ONSCREEN_MAX_BTNS + TOUCH_EXTRA_BTNS; i++) s->widgets[i] = NULL; + + for (i = 0, j = 0; i < ONSCREEN_MAX_BTNS; i++) + { + if (!(buttons & (1 << i))) continue; + desc = &onscreenDescs[i]; + + ButtonWidget_Init(&s->onscreen[j], 100, desc->OnClick); + if (desc->enabled) Widget_SetDisabled(&s->onscreen[j], !(*desc->enabled)); + + s->onscreen[j].meta.val = i; + s->onscreen[j].color = TOUCHSCREEN_BTN_COLOR; + s->widgets[j] = (struct Widget*)&s->onscreen[j]; + j++; + } + + s->numOnscreen = j; + if (hacks->Flying || hacks->Noclip) { + s->descs = hackDescs; + s->numBtns = Array_Elems(hackDescs); + } else { + s->descs = normDescs; + s->numBtns = Array_Elems(normDescs); + } + + for (i = 0; i < s->numBtns; i++) + { + s->widgets[i + ONSCREEN_MAX_BTNS] = (struct Widget*)&s->btns[i]; + ButtonWidget_Init(&s->btns[i], 60, s->descs[i].OnClick); + s->btns[i].color = TOUCHSCREEN_BTN_COLOR; + s->btns[i].meta.val = i; + } +} + +void TouchScreen_Refresh(void) { + struct TouchScreen* s = &TouchScreen; + /* 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_HacksChanged(void* s) { TouchScreen_Refresh(); } + +static void TouchScreen_ContextLost(void* screen) { + struct TouchScreen* s = (struct TouchScreen*)screen; + Font_Free(&s->font); + Screen_ContextLost(screen); +} + +static void TouchScreen_ContextRecreated(void* screen) { + struct TouchScreen* s = (struct TouchScreen*)screen; + const struct TouchButtonDesc* desc; + int i; + Screen_UpdateVb(screen); + Gui_MakeTitleFont(&s->font); + + for (i = 0; i < s->numOnscreen; i++) + { + desc = &onscreenDescs[s->onscreen[i].meta.val]; + ButtonWidget_SetConst(&s->onscreen[i], desc->text, &s->font); + } + for (i = 0; i < s->numBtns; i++) + { + desc = &s->descs[i]; + ButtonWidget_SetConst(&s->btns[i], desc->text, &s->font); + } + ButtonWidget_SetConst(&s->more, "...", &s->font); +} + +static void TouchScreen_Render(void* screen, float delta) { + if (Gui.InputGrab) return; + Screen_Render2Widgets(screen, delta); +} + +static int TouchScreen_PointerDown(void* screen, int id, int x, int y) { + struct TouchScreen* s = (struct TouchScreen*)screen; + struct Widget* w; + int i; + //Chat_Add1("POINTER DOWN: %i", &id); + if (Gui.InputGrab) return false; + + i = Screen_DoPointerDown(screen, id, x, y); + if (i < ONSCREEN_MAX_BTNS) return i >= 0; + + /* Clicking on other buttons then */ + w = s->widgets[i]; + w->active |= id; + + /* Clicking on jump or fly buttons should still move camera */ + for (i = 0; i < s->numBtns; i++) + { + if (w == (struct Widget*)&s->btns[i]) return TOUCH_TYPE_GUI | TOUCH_TYPE_CAMERA; + } + return TOUCH_TYPE_GUI; +} + +static void 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; + s->more.active &= ~id; + + for (i = 0; i < s->numBtns; i++) + { + if (!(s->btns[i].active & id)) continue; + + if (s->descs[i].bind < KEYBIND_COUNT) { + Input_Set(KeyBinds_Normal[s->descs[i].bind], false); + } + s->btns[i].active &= ~id; + return; + } +} + +static void TouchScreen_LayoutOnscreen(struct TouchScreen* s, cc_uint8 alignment) { + int haligns = GetOnscreenHAligns(); + cc_uint8 halign; + int i, index, x, y; + + for (i = 0, x = 10, y = 10; i < s->numOnscreen; i++) + { + index = s->onscreen[i].meta.val; + halign = (haligns & (1 << index)) ? ANCHOR_MIN : ANCHOR_MAX; + if (halign != alignment) continue; + + Widget_SetLocation(&s->onscreen[i], halign, ANCHOR_MIN, x, y); + if (s->onscreen[i].y + s->onscreen[i].height <= s->btns[0].y){ y += 40; continue; } + + // overflowed onto jump/fly buttons, move to next column + y = 10; + x += 110; + Widget_SetLocation(&s->onscreen[i], halign, ANCHOR_MIN, x, y); + } +} + +static void TouchScreen_Layout(void* screen) { + struct TouchScreen* s = (struct TouchScreen*)screen; + const struct TouchButtonDesc* desc; + float scale = Gui.RawTouchScale; + int i, height; + + /* Need to align these relative to the hotbar */ + height = HUDScreen_LayoutHotbar(); + + for (i = 0; i < s->numBtns; i++) + { + desc = &s->descs[i]; + Widget_SetLocation(&s->btns[i], ANCHOR_MAX, ANCHOR_MAX, desc->x, desc->y); + s->btns[i].yOffset += height; + + /* TODO: Maybe move scaling to be part of button instead */ + s->btns[i].minWidth = Display_ScaleX(60 * scale); + s->btns[i].minHeight = Display_ScaleY(60 * scale); + Widget_Layout(&s->btns[i]); + } + + TouchScreen_LayoutOnscreen(s, ANCHOR_MIN); + TouchScreen_LayoutOnscreen(s, ANCHOR_MAX); + Widget_SetLocation(&s->more, ANCHOR_CENTRE, ANCHOR_MIN, 0, 10); + + Widget_SetLocation(&s->thumbstick, ANCHOR_MIN, ANCHOR_MAX, 30, 5); + s->thumbstick.yOffset += height; + s->thumbstick.scale = scale; + Widget_Layout(&s->thumbstick); +} + +static void TouchScreen_GetMovement(struct LocalPlayer* p, float* xMoving, float* zMoving) { + ThumbstickWidget_GetMovement(&TouchScreen.thumbstick, xMoving, zMoving); +} +static struct LocalPlayerInput touchInput = { TouchScreen_GetMovement }; +static cc_bool touchHooked; + +static void TouchScreen_Init(void* screen) { + struct TouchScreen* s = (struct TouchScreen*)screen; + + s->widgets = touch_widgets; + s->numWidgets = Array_Elems(touch_widgets); + s->maxVertices = TOUCH_MAX_VERTICES; + Event_Register_(&UserEvents.HacksStateChanged, screen, TouchScreen_HacksChanged); + Event_Register_(&UserEvents.HackPermsChanged, screen, TouchScreen_HacksChanged); + + TouchScreen_InitButtons(s); + ButtonWidget_Init(&s->more, 40, TouchScreen_MoreClick); + s->more.color = TOUCHSCREEN_BTN_COLOR; + ThumbstickWidget_Init(&s->thumbstick); + + if (touchHooked) return; + touchHooked = true; + LocalPlayerInput_Add(&touchInput); +} + +static void TouchScreen_Free(void* s) { + Event_Unregister_(&UserEvents.HacksStateChanged, s, TouchScreen_HacksChanged); + Event_Unregister_(&UserEvents.HackPermsChanged, s, TouchScreen_HacksChanged); +} + +static const struct ScreenVTABLE TouchScreen_VTABLE = { + TouchScreen_Init, Screen_NullUpdate, TouchScreen_Free, + TouchScreen_Render, Screen_BuildMesh, + Screen_FInput, Screen_InputUp, Screen_FKeyPress, Screen_FText, + TouchScreen_PointerDown, TouchScreen_PointerUp, Screen_FPointer, Screen_FMouseScroll, + TouchScreen_Layout, TouchScreen_ContextLost, TouchScreen_ContextRecreated +}; +void TouchScreen_Show(void) { + struct TouchScreen* s = &TouchScreen; + s->VTABLE = &TouchScreen_VTABLE; + + if (!Gui.TouchUI) return; + Gui_Add((struct Screen*)s, GUI_PRIORITY_TOUCH); +} +#endif diff --git a/src/VirtualKeyboard.h b/src/VirtualKeyboard.h index d24ffca..2c6047c 100644 --- a/src/VirtualKeyboard.h +++ b/src/VirtualKeyboard.h @@ -47,7 +47,7 @@ static const char* kb_table_upper[] = "Caps", "Shift", "Space", "Close" }; -extern void LWidget_DrawBorder(struct Context2D* ctx, BitmapCol color, int insetX, int insetY, +extern void LWidget_DrawBorder(struct Context2D* ctx, BitmapCol color, int borderX, int borderY, int x, int y, int width, int height); static void VirtualKeyboard_Init(void) { @@ -154,6 +154,12 @@ static void VirtualKeyboard_AppendChar(char c) { if (kb_shift) { VirtualKeyboard_ToggleTable(); kb_shift = false; } } +static void VirtualKeyboard_Backspace(void) { + if (kb_str.length) kb_str.length--; + Event_RaiseString(&InputEvents.TextChanged, &kb_str); + KB_MarkDirty(); +} + static void VirtualKeyboard_ClickSelected(void) { int selected = VirtualKeyboard_GetSelected(); if (selected < 0) return; @@ -161,9 +167,7 @@ static void VirtualKeyboard_ClickSelected(void) { /* TODO kinda hacky, redo this */ switch (selected) { case KB_INDEX(KB_LAST_CELL, 0): - if (kb_str.length) kb_str.length--; - Event_RaiseString(&InputEvents.TextChanged, &kb_str); - KB_MarkDirty(); + VirtualKeyboard_Backspace(); break; case KB_INDEX(KB_LAST_CELL, 2): OnscreenKeyboard_Close(); @@ -192,22 +196,21 @@ static void VirtualKeyboard_ClickSelected(void) { } static void VirtualKeyboard_ProcessDown(void* obj, int key, cc_bool was) { - if (Input_IsLeftButton(key)) { - VirtualKeyboard_Scroll(-1); - } else if (Input_IsRightButton(key)) { - VirtualKeyboard_Scroll(+1); - } else if (Input_IsUpButton(key)) { - VirtualKeyboard_Scroll(-KB_CELLS_PER_ROW); - } else if (Input_IsDownButton(key)) { - VirtualKeyboard_Scroll(+KB_CELLS_PER_ROW); - } else if (Input_IsEnterButton(key) || key == CCPAD_A) { + int delta = Input_CalcDelta(key, 1, KB_CELLS_PER_ROW); + if (delta) { + VirtualKeyboard_Scroll(delta); + } else if (key == CCPAD_START || key == CCPAD_A) { VirtualKeyboard_ClickSelected(); - } else if (Input_IsEscapeButton(key) || key == CCPAD_B) { + } else if (key == CCPAD_SELECT || key == CCPAD_B) { VirtualKeyboard_Close(); + } else if (key == CCPAD_X) { + VirtualKeyboard_Backspace(); + } else if (key == CCPAD_Y) { + VirtualKeyboard_AppendChar(' '); } } -static void VirtualKeyboard_PadAxis(void* obj, int axis, float x, float y) { +static void VirtualKeyboard_PadAxis(void* obj, int port, int axis, float x, float y) { int xSteps, ySteps; xSteps = Utils_AccumulateWheelDelta(&kb_padXAcc, x / 100.0f); diff --git a/src/Widgets.c b/src/Widgets.c index 61fccc3..85e66be 100644 --- a/src/Widgets.c +++ b/src/Widgets.c @@ -35,7 +35,7 @@ static void AddWidget(void* screen, void* w) { /*########################################################################################################################* *-------------------------------------------------------TextWidget--------------------------------------------------------* *#########################################################################################################################*/ -static void TextWidget_Render(void* widget, double delta) { +static void TextWidget_Render(void* widget, float delta) { struct TextWidget* w = (struct TextWidget*)widget; if (w->tex.ID) Texture_RenderShaded(&w->tex, w->color); } @@ -131,7 +131,7 @@ static void ButtonWidget_Reposition(void* widget) { w->tex.y = w->y + (w->height / 2 - w->tex.height / 2); } -static void ButtonWidget_Render(void* widget, double delta) { +static void ButtonWidget_Render(void* widget, float delta) { PackedCol normColor = PackedCol_Make(224, 224, 224, 255); PackedCol activeColor = PackedCol_Make(255, 255, 160, 255); PackedCol disabledColor = PackedCol_Make(160, 160, 160, 255); @@ -232,10 +232,6 @@ static const struct WidgetVTABLE ButtonWidget_VTABLE = { Widget_Pointer, Widget_PointerUp, Widget_PointerMove, ButtonWidget_BuildMesh, ButtonWidget_Render2, ButtonWidget_MaxVertices }; -void ButtonWidget_Make(struct ButtonWidget* w, int minWidth, Widget_LeftClick onClick, cc_uint8 horAnchor, cc_uint8 verAnchor, int xOffset, int yOffset) { - ButtonWidget_Init(w, minWidth, onClick); - Widget_SetLocation(w, horAnchor, verAnchor, xOffset, yOffset); -} void ButtonWidget_Init(struct ButtonWidget* w, int minWidth, Widget_LeftClick onClick) { Widget_Reset(w); @@ -297,7 +293,7 @@ static void ScrollbarWidget_GetScrollbarCoords(struct ScrollbarWidget* w, int* y *height = min(*y + *height, w->height - w->borderY) - *y; } -static void ScrollbarWidget_Render(void* widget, double delta) { +static void ScrollbarWidget_Render(void* widget, float delta) { struct ScrollbarWidget* w = (struct ScrollbarWidget*)widget; int x, y, width, height; PackedCol barCol; @@ -485,20 +481,21 @@ static int HotbarWidget_Render2(void* widget, int offset) { static int HotbarWidget_MaxVertices(void* w) { return HOTBAR_MAX_VERTICES; } -void HotbarWidget_Update(struct HotbarWidget* w, double delta) { +void HotbarWidget_Update(struct HotbarWidget* w, float delta) { #ifdef CC_BUILD_TOUCH int i; if (!Gui.TouchUI) return; - for (i = 0; i < HOTBAR_MAX_INDEX; i++) { - if(w->touchId[i] != -1) { - w->touchTime[i] += delta; - if(w->touchTime[i] > 1) { - w->touchId[i] = -1; - w->touchTime[i] = 0; - Inventory_Set(i, 0); - } - } + for (i = 0; i < HOTBAR_MAX_INDEX; i++) + { + if (w->touchId[i] < 0) continue; + + w->touchTime[i] += delta; + if (w->touchTime[i] <= 1.0f) continue; + + w->touchId[i] = -1; + w->touchTime[i] = 0; + Inventory_Set(i, 0); } #endif } @@ -978,20 +975,15 @@ static int TableWidget_PointerMove(void* widget, int id, int x, int y) { static int TableWidget_KeyDown(void* widget, int key) { struct TableWidget* w = (struct TableWidget*)widget; + int delta; if (w->selectedIndex == -1) return false; - if (Input_IsLeftButton(key) || key == CCKEY_KP4) { - TableWidget_ScrollRelative(w, -1); - } else if (Input_IsRightButton(key) || key == CCKEY_KP6) { - TableWidget_ScrollRelative(w, 1); - } else if (Input_IsUpButton(key) || key == CCKEY_KP8) { - TableWidget_ScrollRelative(w, -w->blocksPerRow); - } else if (Input_IsDownButton(key) || key == CCKEY_KP2) { - TableWidget_ScrollRelative(w, w->blocksPerRow); - } else { - return false; + delta = Input_CalcDelta(key, 1, w->blocksPerRow); + if (delta) { + TableWidget_ScrollRelative(w, delta); + return true; } - return true; + return false; } static int TableWidget_PadAxis(void* widget, int axis, float x, float y) { @@ -1015,7 +1007,7 @@ static const struct WidgetVTABLE TableWidget_VTABLE = { TableWidget_BuildMesh, TableWidget_Render2, TableWidget_MaxVertices, TableWidget_PadAxis }; -void TableWidget_Create(struct TableWidget* w, int sbWidth) { +void TableWidget_Add(void* screen, struct TableWidget* w, int sbWidth) { cc_bool classic; Widget_Reset(w); w->VTABLE = &TableWidget_VTABLE; @@ -1032,6 +1024,7 @@ void TableWidget_Create(struct TableWidget* w, int sbWidth) { w->everCreated = true; w->selectedIndex = -1; } + AddWidget(screen, w); classic = Gui.ClassicInventory; w->paddingL = Display_ScaleX(classic ? 20 : 15); @@ -1188,12 +1181,12 @@ static void InputWidget_UpdateCaret(struct InputWidget* w) { } } -static void InputWidget_RenderCaret(struct InputWidget* w, double delta) { +static void InputWidget_RenderCaret(struct InputWidget* w, float delta) { float second; if (!w->showCaret) return; w->caretAccumulator += delta; - second = Math_Mod1((float)w->caretAccumulator); + second = Math_Mod1(w->caretAccumulator); if (second < 0.5f) Texture_RenderShaded(&w->caretTex, w->caretCol); } @@ -1599,7 +1592,7 @@ const struct MenuInputVTABLE StringInput_VTABLE = { /*########################################################################################################################* *-----------------------------------------------------TextInputWidget-----------------------------------------------------* *#########################################################################################################################*/ -static void TextInputWidget_Render(void* widget, double delta) { +static void TextInputWidget_Render(void* widget, float delta) { struct InputWidget* w = (struct InputWidget*)widget; Texture_Render(&w->inputTex); InputWidget_RenderCaret(w, delta); @@ -1818,7 +1811,7 @@ static void ChatInputWidget_RemakeTexture(void* widget) { w->inputTex.y = w->y; } -static void ChatInputWidget_Render(void* widget, double delta) { +static void ChatInputWidget_Render(void* widget, float delta) { struct InputWidget* w = (struct InputWidget*)widget; PackedCol backColor = PackedCol_Make(0, 0, 0, 127); int x = w->x, y = w->y; @@ -2405,7 +2398,7 @@ void TextGroupWidget_SetFont(struct TextGroupWidget* w, struct FontDesc* font) { Widget_Layout(w); } -static void TextGroupWidget_Render(void* widget, double delta) { +static void TextGroupWidget_Render(void* widget, float delta) { struct TextGroupWidget* w = (struct TextGroupWidget*)widget; struct Texture* textures = w->textures; int i; @@ -2660,7 +2653,7 @@ void SpecialInputWidget_Redraw(struct SpecialInputWidget* w) { Widget_Layout(w); } -static void SpecialInputWidget_Render(void* widget, double delta) { +static void SpecialInputWidget_Render(void* widget, float delta) { struct SpecialInputWidget* w = (struct SpecialInputWidget*)widget; Texture_Render(&w->tex); } @@ -2785,7 +2778,7 @@ static int ThumbstickWidget_CalcDirs(struct ThumbstickWidget* w) { 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; + angle = Math_Atan2f(dx, dy) * MATH_RAD2DEG; /* 4 quadrants diagonally, but slightly expanded for overlap*/ if (angle >= 30 && angle <= 150) dirs |= DIR_YMAX; diff --git a/src/Widgets.h b/src/Widgets.h index 93808d9..85a9f5c 100644 --- a/src/Widgets.h +++ b/src/Widgets.h @@ -43,9 +43,6 @@ struct ButtonWidget { }; #define BUTTONWIDGET_MAX 12 -/* Initialises a button widget. */ -CC_NOINLINE void ButtonWidget_Make(struct ButtonWidget* w, int minWidth, Widget_LeftClick onClick, - cc_uint8 horAnchor, cc_uint8 verAnchor, int xOffset, int yOffset); /* Initialises a button widget. */ CC_NOINLINE void ButtonWidget_Init(struct ButtonWidget* w, int minWidth, Widget_LeftClick onClick); /* Initialises then adds a button widget. */ @@ -82,7 +79,7 @@ struct HotbarWidget { int verticesCount; #ifdef CC_BUILD_TOUCH int touchId[HOTBAR_MAX_INDEX]; - double touchTime[HOTBAR_MAX_INDEX]; + float touchTime[HOTBAR_MAX_INDEX]; #endif }; #define HOTBAR_MAX_VERTICES (4 + 4 + HOTBAR_CORE_VERTICES) @@ -90,7 +87,7 @@ struct HotbarWidget { /* Resets state of the given hotbar widget to default. */ CC_NOINLINE void HotbarWidget_Create(struct HotbarWidget* w); CC_NOINLINE void HotbarWidget_SetFont(struct HotbarWidget* w, struct FontDesc* font); -CC_NOINLINE void HotbarWidget_Update(struct HotbarWidget* w, double delta); +CC_NOINLINE void HotbarWidget_Update(struct HotbarWidget* w, float delta); #define TABLE_MAX_VERTICES (8 * 10 * ISOMETRICDRAWER_MAXVERTICES) /* A table of blocks. */ @@ -116,7 +113,7 @@ struct TableWidget { int verticesCount; }; -CC_NOINLINE void TableWidget_Create(struct TableWidget* w, int sbWidth); +CC_NOINLINE void TableWidget_Add(void* screen, struct TableWidget* w, int sbWidth); /* Sets the selected block in the table to the given block. */ /* Also adjusts scrollbar and moves cursor to be over the given block. */ CC_NOINLINE void TableWidget_SetToBlock(struct TableWidget* w, BlockID block); @@ -153,7 +150,7 @@ struct InputWidget { int caretOffset; PackedCol caretCol; struct Texture caretTex; - double caretAccumulator; + float caretAccumulator; }; /* Removes all characters and then deletes the input texture. */ diff --git a/src/Window.h b/src/Window.h index d82ed37..1fb30ac 100644 --- a/src/Window.h +++ b/src/Window.h @@ -135,7 +135,9 @@ void Window_SetSize(int width, int height); /* May raise the WindowClosing and WindowClosed events. */ void Window_RequestClose(void); /* Processes all pending window messages/events. */ -void Window_ProcessEvents(double delta); +void Window_ProcessEvents(float delta); +/* Processes all pending gamepad/joystick input. */ +void Window_ProcessGamepads(float delta); /* Sets the position of the cursor. */ /* NOTE: This should be avoided because it is unsupported on some platforms. */ diff --git a/src/Window_3DS.c b/src/Window_3DS.c index 4b665d8..a17147b 100644 --- a/src/Window_3DS.c +++ b/src/Window_3DS.c @@ -89,36 +89,6 @@ void Window_RequestClose(void) { /*########################################################################################################################* *----------------------------------------------------Input processing-----------------------------------------------------* *#########################################################################################################################*/ -static void HandleButtons(u32 mods) { - Gamepad_SetButton(CCPAD_L, mods & KEY_L); - Gamepad_SetButton(CCPAD_R, mods & KEY_R); - - Gamepad_SetButton(CCPAD_A, mods & KEY_A); - Gamepad_SetButton(CCPAD_B, mods & KEY_B); - Gamepad_SetButton(CCPAD_X, mods & KEY_X); - Gamepad_SetButton(CCPAD_Y, mods & KEY_Y); - - Gamepad_SetButton(CCPAD_START, mods & KEY_START); - Gamepad_SetButton(CCPAD_SELECT, mods & KEY_SELECT); - - Gamepad_SetButton(CCPAD_LEFT, mods & KEY_DLEFT); - Gamepad_SetButton(CCPAD_RIGHT, mods & KEY_DRIGHT); - Gamepad_SetButton(CCPAD_UP, mods & KEY_DUP); - Gamepad_SetButton(CCPAD_DOWN, mods & KEY_DDOWN); - - Gamepad_SetButton(CCPAD_ZL, mods & KEY_ZL); - Gamepad_SetButton(CCPAD_ZR, mods & KEY_ZR); -} - -#define AXIS_SCALE 8.0f -static void ProcessCircleInput(int axis, circlePosition* pos, double delta) { - // May not be exactly 0 on actual hardware - if (Math_AbsI(pos->dx) <= 24) pos->dx = 0; - if (Math_AbsI(pos->dy) <= 24) pos->dy = 0; - - Gamepad_SetAxis(axis, pos->dx / AXIS_SCALE, -pos->dy / AXIS_SCALE, delta); -} - static void ProcessTouchInput(int mods) { touchPosition touch; hidTouchRead(&touch); @@ -130,9 +100,8 @@ static void ProcessTouchInput(int mods) { } } -void Window_ProcessEvents(double delta) { +void Window_ProcessEvents(float delta) { hidScanInput(); - Input.JoystickMovement = false; if (!aptMainLoop()) { Window_Main.Exists = false; @@ -141,9 +110,53 @@ void Window_ProcessEvents(double delta) { } u32 mods = hidKeysDown() | hidKeysHeld(); - HandleButtons(mods); - ProcessTouchInput(mods); +} + +void Cursor_SetPosition(int x, int y) { } // Makes no sense for 3DS + +void Window_EnableRawMouse(void) { Input.RawMode = true; } +void Window_DisableRawMouse(void) { Input.RawMode = false; } + +void Window_UpdateRawMouse(void) { } + + +/*########################################################################################################################* +*-------------------------------------------------------Gamepads----------------------------------------------------------* +*#########################################################################################################################*/ +static void HandleButtons(u32 mods) { + Gamepad_SetButton(0, CCPAD_L, mods & KEY_L); + Gamepad_SetButton(0, CCPAD_R, mods & KEY_R); + + Gamepad_SetButton(0, CCPAD_A, mods & KEY_A); + Gamepad_SetButton(0, CCPAD_B, mods & KEY_B); + Gamepad_SetButton(0, CCPAD_X, mods & KEY_X); + Gamepad_SetButton(0, CCPAD_Y, mods & KEY_Y); + + Gamepad_SetButton(0, CCPAD_START, mods & KEY_START); + Gamepad_SetButton(0, CCPAD_SELECT, mods & KEY_SELECT); + + Gamepad_SetButton(0, CCPAD_LEFT, mods & KEY_DLEFT); + Gamepad_SetButton(0, CCPAD_RIGHT, mods & KEY_DRIGHT); + Gamepad_SetButton(0, CCPAD_UP, mods & KEY_DUP); + Gamepad_SetButton(0, CCPAD_DOWN, mods & KEY_DDOWN); + + Gamepad_SetButton(0, CCPAD_ZL, mods & KEY_ZL); + Gamepad_SetButton(0, CCPAD_ZR, mods & KEY_ZR); +} + +#define AXIS_SCALE 8.0f +static void ProcessCircleInput(int axis, circlePosition* pos, float delta) { + // May not be exactly 0 on actual hardware + if (Math_AbsI(pos->dx) <= 24) pos->dx = 0; + if (Math_AbsI(pos->dy) <= 24) pos->dy = 0; + + Gamepad_SetAxis(0, axis, pos->dx / AXIS_SCALE, -pos->dy / AXIS_SCALE, delta); +} + +void Window_ProcessGamepads(float delta) { + u32 mods = hidKeysDown() | hidKeysHeld(); + HandleButtons(mods); circlePosition hid_pos; hidCircleRead(&hid_pos); @@ -160,12 +173,6 @@ void Window_ProcessEvents(double delta) { } } -void Cursor_SetPosition(int x, int y) { } // Makes no sense for 3DS - -void Window_EnableRawMouse(void) { Input.RawMode = true; } -void Window_DisableRawMouse(void) { Input.RawMode = false; } - -void Window_UpdateRawMouse(void) { } /*########################################################################################################################* *------------------------------------------------------Framebuffer--------------------------------------------------------* diff --git a/src/Window_Android.c b/src/Window_Android.c index 3357c6a..f9b5e06 100644 --- a/src/Window_Android.c +++ b/src/Window_Android.c @@ -306,7 +306,7 @@ static void RemakeWindowSurface(void) { /* Loop until window gets created by main UI thread */ /* (i.e. until processSurfaceCreated is received) */ while (!winCreated) { - Window_ProcessEvents(0.01); + Window_ProcessEvents(0.01f); Thread_Sleep(10); } @@ -366,13 +366,15 @@ void Window_RequestClose(void) { /* ANativeActivity_finish(app->activity); */ } -void Window_ProcessEvents(double delta) { +void Window_ProcessEvents(float delta) { JNIEnv* env; JavaGetCurrentEnv(env); /* TODO: Cache the java env */ JavaICall_Void(env, JAVA_processEvents, NULL); } +void Window_ProcessGamepads(float delta) { } + /* No actual mouse cursor */ static void Cursor_GetRawPos(int* x, int* y) { *x = 0; *y = 0; } void Cursor_SetPosition(int x, int y) { } diff --git a/src/Window_Dreamcast.c b/src/Window_Dreamcast.c index e415dbe..f80b0fc 100644 --- a/src/Window_Dreamcast.c +++ b/src/Window_Dreamcast.c @@ -173,53 +173,7 @@ static void ProcessKeyboardInput(void) { /*########################################################################################################################* *----------------------------------------------------Input processing-----------------------------------------------------* *#########################################################################################################################*/ -static void HandleButtons(int mods) { - // TODO CONT_Z - - Gamepad_SetButton(CCPAD_A, mods & CONT_A); - Gamepad_SetButton(CCPAD_B, mods & CONT_B); - Gamepad_SetButton(CCPAD_X, mods & CONT_X); - Gamepad_SetButton(CCPAD_Y, mods & CONT_Y); - - Gamepad_SetButton(CCPAD_START, mods & CONT_START); - Gamepad_SetButton(CCPAD_SELECT, mods & CONT_D); - - Gamepad_SetButton(CCPAD_LEFT, mods & CONT_DPAD_LEFT); - Gamepad_SetButton(CCPAD_RIGHT, mods & CONT_DPAD_RIGHT); - Gamepad_SetButton(CCPAD_UP, mods & CONT_DPAD_UP); - Gamepad_SetButton(CCPAD_DOWN, mods & CONT_DPAD_DOWN); -} - -#define AXIS_SCALE 8.0f -static void HandleJoystick(int axis, int x, int y, double delta) { - if (Math_AbsI(x) <= 8) x = 0; - if (Math_AbsI(y) <= 8) y = 0; - - Gamepad_SetAxis(axis, x / AXIS_SCALE, y / AXIS_SCALE, delta); -} - -static void HandleController(cont_state_t* state, double delta) { - Gamepad_SetButton(CCPAD_L, state->ltrig > 10); - Gamepad_SetButton(CCPAD_R, state->rtrig > 10); - // TODO CONT_Z, joysticks - // TODO: verify values are right - HandleJoystick(PAD_AXIS_RIGHT, state->joyx, state->joyy, delta); -} - -static void ProcessControllerInput(double delta) { - maple_device_t* cont; - cont_state_t* state; - - cont = maple_enum_type(0, MAPLE_FUNC_CONTROLLER); - if (!cont) return; - state = (cont_state_t*)maple_dev_status(cont); - if (!state) return; - - HandleButtons(state->buttons); - HandleController(state, delta); -} - -static void ProcessMouseInput(double delta) { +static void ProcessMouseInput(float delta) { maple_device_t* mouse; mouse_state_t* state; @@ -239,8 +193,7 @@ static void ProcessMouseInput(double delta) { state->dx * scale, state->dy * scale); } -void Window_ProcessEvents(double delta) { - ProcessControllerInput(delta); +void Window_ProcessEvents(float delta) { ProcessKeyboardInput(); ProcessMouseInput(delta); } @@ -252,6 +205,64 @@ void Window_DisableRawMouse(void) { Input.RawMode = false; } void Window_UpdateRawMouse(void) { } +/*########################################################################################################################* +*-------------------------------------------------------Gamepads----------------------------------------------------------* +*#########################################################################################################################*/ +static void HandleButtons(int port, int mods) { + Gamepad_SetButton(port, CCPAD_A, mods & CONT_A); + Gamepad_SetButton(port, CCPAD_B, mods & CONT_B); + Gamepad_SetButton(port, CCPAD_X, mods & CONT_X); + Gamepad_SetButton(port, CCPAD_Y, mods & CONT_Y); + + Gamepad_SetButton(port, CCPAD_START, mods & CONT_START); + Gamepad_SetButton(port, CCPAD_SELECT, mods & CONT_D); + + Gamepad_SetButton(port, CCPAD_LEFT, mods & CONT_DPAD_LEFT); + Gamepad_SetButton(port, CCPAD_RIGHT, mods & CONT_DPAD_RIGHT); + Gamepad_SetButton(port, CCPAD_UP, mods & CONT_DPAD_UP); + Gamepad_SetButton(port, CCPAD_DOWN, mods & CONT_DPAD_DOWN); + + // Buttons not on standard controller (todo C) + Gamepad_SetButton(port, CCPAD_Z, mods & CONT_Z); + Gamepad_SetButton(port, CCPAD_CLEFT, mods & CONT_DPAD2_LEFT); + Gamepad_SetButton(port, CCPAD_CRIGHT, mods & CONT_DPAD2_RIGHT); + Gamepad_SetButton(port, CCPAD_CUP, mods & CONT_DPAD2_UP); + Gamepad_SetButton(port, CCPAD_CDOWN, mods & CONT_DPAD2_DOWN); +} + +#define AXIS_SCALE 8.0f +static void HandleJoystick(int port, int axis, int x, int y, float delta) { + if (Math_AbsI(x) <= 8) x = 0; + if (Math_AbsI(y) <= 8) y = 0; + + Gamepad_SetAxis(port, axis, x / AXIS_SCALE, y / AXIS_SCALE, delta); +} + +static void HandleController(int port, cont_state_t* state, float delta) { + Gamepad_SetButton(port, CCPAD_L, state->ltrig > 10); + Gamepad_SetButton(port, CCPAD_R, state->rtrig > 10); + // TODO CONT_Z, joysticks + // TODO: verify values are right + HandleJoystick(port, PAD_AXIS_RIGHT, state->joyx, state->joyy, delta); +} + +void Window_ProcessGamepads(float delta) { + maple_device_t* cont; + cont_state_t* state; + + for (int port = 0; port < INPUT_MAX_GAMEPADS; port++) + { + cont = maple_enum_type(port, MAPLE_FUNC_CONTROLLER); + if (!cont) return; + state = (cont_state_t*)maple_dev_status(cont); + if (!state) return; + + HandleButtons(port, state->buttons); + HandleController(port, state, delta); + } +} + + /*########################################################################################################################* *------------------------------------------------------Framebuffer--------------------------------------------------------* *#########################################################################################################################*/ diff --git a/src/Window_GCWii.c b/src/Window_GCWii.c index 832cc79..61bd5d0 100644 --- a/src/Window_GCWii.c +++ b/src/Window_GCWii.c @@ -104,52 +104,51 @@ void Window_RequestClose(void) { /*########################################################################################################################* *---------------------------------------------GameCube controller processing----------------------------------------------* *#########################################################################################################################*/ -static PADStatus gc_pad; +static PADStatus gc_pads[INPUT_MAX_GAMEPADS]; #define PAD_AXIS_SCALE 8.0f -static void ProcessPAD_Joystick(int axis, int x, int y, double delta) { +static void ProcessPAD_Joystick(int port, int axis, int x, int y, float delta) { // May not be exactly 0 on actual hardware if (Math_AbsI(x) <= 8) x = 0; if (Math_AbsI(y) <= 8) y = 0; - Gamepad_SetAxis(axis, x / PAD_AXIS_SCALE, -y / PAD_AXIS_SCALE, delta); + Gamepad_SetAxis(port, axis, x / PAD_AXIS_SCALE, -y / PAD_AXIS_SCALE, delta); } -static void ProcessPAD_Buttons(void) { - int mods = gc_pad.button; - Gamepad_SetButton(CCPAD_L, mods & PAD_TRIGGER_L); - Gamepad_SetButton(CCPAD_R, mods & PAD_TRIGGER_R); +static void ProcessPAD_Buttons(int port, int mods) { + Gamepad_SetButton(port, CCPAD_L, mods & PAD_TRIGGER_L); + Gamepad_SetButton(port, CCPAD_R, mods & PAD_TRIGGER_R); - Gamepad_SetButton(CCPAD_A, mods & PAD_BUTTON_A); - Gamepad_SetButton(CCPAD_B, mods & PAD_BUTTON_B); - Gamepad_SetButton(CCPAD_X, mods & PAD_BUTTON_X); - Gamepad_SetButton(CCPAD_Y, mods & PAD_BUTTON_Y); + Gamepad_SetButton(port, CCPAD_A, mods & PAD_BUTTON_A); + Gamepad_SetButton(port, CCPAD_B, mods & PAD_BUTTON_B); + Gamepad_SetButton(port, CCPAD_X, mods & PAD_BUTTON_X); + Gamepad_SetButton(port, CCPAD_Y, mods & PAD_BUTTON_Y); - Gamepad_SetButton(CCPAD_START, mods & PAD_BUTTON_START); - Gamepad_SetButton(CCPAD_SELECT, mods & PAD_TRIGGER_Z); + Gamepad_SetButton(port, CCPAD_START, mods & PAD_BUTTON_START); + Gamepad_SetButton(port, CCPAD_SELECT, mods & PAD_TRIGGER_Z); - Gamepad_SetButton(CCPAD_LEFT, mods & PAD_BUTTON_LEFT); - Gamepad_SetButton(CCPAD_RIGHT, mods & PAD_BUTTON_RIGHT); - Gamepad_SetButton(CCPAD_UP, mods & PAD_BUTTON_UP); - Gamepad_SetButton(CCPAD_DOWN, mods & PAD_BUTTON_DOWN); + Gamepad_SetButton(port, CCPAD_LEFT, mods & PAD_BUTTON_LEFT); + Gamepad_SetButton(port, CCPAD_RIGHT, mods & PAD_BUTTON_RIGHT); + Gamepad_SetButton(port, CCPAD_UP, mods & PAD_BUTTON_UP); + Gamepad_SetButton(port, CCPAD_DOWN, mods & PAD_BUTTON_DOWN); } -static void ProcessPADInput(double delta) { +static void ProcessPADInput(int port, float delta) { PADStatus pads[4]; PAD_Read(pads); - int error = pads[0].err; + int error = pads[port].err; if (error == 0) { - gc_pad = pads[0]; // new state arrived + gc_pads[port] = pads[port]; // new state arrived } else if (error == PAD_ERR_TRANSFER) { // usually means still busy transferring state - use last state } else { return; // not connected, still busy, etc } - ProcessPAD_Buttons(); - ProcessPAD_Joystick(PAD_AXIS_LEFT, gc_pad.stickX, gc_pad.stickY, delta); - ProcessPAD_Joystick(PAD_AXIS_RIGHT, gc_pad.substickX, gc_pad.substickY, delta); + ProcessPAD_Buttons(0, gc_pads[port].button); + ProcessPAD_Joystick(0, PAD_AXIS_LEFT, gc_pads[port].stickX, gc_pads[port].stickY, delta); + ProcessPAD_Joystick(0, PAD_AXIS_RIGHT, gc_pads[port].substickX, gc_pads[port].substickY, delta); } @@ -225,45 +224,123 @@ static int dragCurX, dragCurY; static int dragStartX, dragStartY; static cc_bool dragActive; -static void ProcessWPAD_Buttons(int mods) { - Gamepad_SetButton(CCPAD_L, mods & WPAD_BUTTON_1); - Gamepad_SetButton(CCPAD_R, mods & WPAD_BUTTON_2); +void Window_ProcessEvents(float delta) { + ProcessKeyboardInput(); +} + +static void GetIRPos(int res, int* x, int* y) { + if (res == WPAD_ERR_NONE) { + WPADData* wd = WPAD_Data(0); + + *x = wd->ir.x; + *y = wd->ir.y; + } else { + *x = 0; + *y = 0; + } +} + +static void ScanAndGetIRPos(int* x, int* y) { + u32 type; + WPAD_ScanPads(); + + int res = WPAD_Probe(0, &type); + GetIRPos(res, x, y); +} + + +static void ProcessWPADDrag(int res, u32 mods) { + int x, y; + GetIRPos(res, &x, &y); + + if (mods & WPAD_BUTTON_B) { + if (!dragActive) { + dragStartX = dragCurX = x; + dragStartY = dragCurY = y; + } + dragActive = true; + } else { + dragActive = false; + } + Pointer_SetPosition(0, x, y); +} + +#define FACTOR 2 +void Window_UpdateRawMouse(void) { + if (!dragActive) return; + int x, y; + ScanAndGetIRPos(&x, &y); + + // TODO: Refactor the logic. is it 100% right too? + dragCurX = dragStartX + (dragCurX - dragStartX) / FACTOR; + dragCurY = dragStartY + (dragCurY - dragStartY) / FACTOR; + + int dx = x - dragCurX; Math_Clamp(dx, -40, 40); + int dy = y - dragCurY; Math_Clamp(dy, -40, 40); + Event_RaiseRawMove(&PointerEvents.RawMoved, dx, dy); + + dragCurX = x; dragCurY = y; +} +#else +void Window_ProcessEvents(float delta) { +} + +void Window_UpdateRawMouse(void) { } +#endif + +void Cursor_SetPosition(int x, int y) { } // No point in GameCube/Wii +// TODO: Display cursor on Wii when not raw mode +void Window_EnableRawMouse(void) { Input.RawMode = true; } +void Window_DisableRawMouse(void) { Input.RawMode = false; } + + +/*########################################################################################################################* +*-------------------------------------------------------Gamepads----------------------------------------------------------* +*#########################################################################################################################*/ +#if defined HW_RVL +static int dragCurX, dragCurY; +static int dragStartX, dragStartY; +static cc_bool dragActive; + +static void ProcessWPAD_Buttons(int port, int mods) { + Gamepad_SetButton(port, CCPAD_L, mods & WPAD_BUTTON_1); + Gamepad_SetButton(port, CCPAD_R, mods & WPAD_BUTTON_2); - Gamepad_SetButton(CCPAD_A, mods & WPAD_BUTTON_A); - Gamepad_SetButton(CCPAD_B, mods & WPAD_BUTTON_B); - Gamepad_SetButton(CCPAD_X, mods & WPAD_BUTTON_PLUS); + Gamepad_SetButton(port, CCPAD_A, mods & WPAD_BUTTON_A); + Gamepad_SetButton(port, CCPAD_B, mods & WPAD_BUTTON_B); + Gamepad_SetButton(port, CCPAD_X, mods & WPAD_BUTTON_PLUS); - Gamepad_SetButton(CCPAD_START, mods & WPAD_BUTTON_HOME); - Gamepad_SetButton(CCPAD_SELECT, mods & WPAD_BUTTON_MINUS); + Gamepad_SetButton(port, CCPAD_START, mods & WPAD_BUTTON_HOME); + Gamepad_SetButton(port, CCPAD_SELECT, mods & WPAD_BUTTON_MINUS); - Gamepad_SetButton(CCPAD_LEFT, mods & WPAD_BUTTON_LEFT); - Gamepad_SetButton(CCPAD_RIGHT, mods & WPAD_BUTTON_RIGHT); - Gamepad_SetButton(CCPAD_UP, mods & WPAD_BUTTON_UP); - Gamepad_SetButton(CCPAD_DOWN, mods & WPAD_BUTTON_DOWN); + Gamepad_SetButton(port, CCPAD_LEFT, mods & WPAD_BUTTON_LEFT); + Gamepad_SetButton(port, CCPAD_RIGHT, mods & WPAD_BUTTON_RIGHT); + Gamepad_SetButton(port, CCPAD_UP, mods & WPAD_BUTTON_UP); + Gamepad_SetButton(port, CCPAD_DOWN, mods & WPAD_BUTTON_DOWN); } -static void ProcessNunchuck_Game(int mods, double delta) { +static void ProcessNunchuck_Game(int port, int mods, float delta) { WPADData* wd = WPAD_Data(0); joystick_t analog = wd->exp.nunchuk.js; - Gamepad_SetButton(CCPAD_L, mods & WPAD_NUNCHUK_BUTTON_C); - Gamepad_SetButton(CCPAD_R, mods & WPAD_NUNCHUK_BUTTON_Z); + Gamepad_SetButton(port, CCPAD_L, mods & WPAD_NUNCHUK_BUTTON_C); + Gamepad_SetButton(port, CCPAD_R, mods & WPAD_NUNCHUK_BUTTON_Z); - Gamepad_SetButton(CCPAD_A, mods & WPAD_BUTTON_A); - Gamepad_SetButton(CCPAD_Y, mods & WPAD_BUTTON_1); - Gamepad_SetButton(CCPAD_X, mods & WPAD_BUTTON_2); + Gamepad_SetButton(port, CCPAD_A, mods & WPAD_BUTTON_A); + Gamepad_SetButton(port, CCPAD_Y, mods & WPAD_BUTTON_1); + Gamepad_SetButton(port, CCPAD_X, mods & WPAD_BUTTON_2); - Gamepad_SetButton(CCPAD_START, mods & WPAD_BUTTON_HOME); - Gamepad_SetButton(CCPAD_SELECT, mods & WPAD_BUTTON_MINUS); + Gamepad_SetButton(port, CCPAD_START, mods & WPAD_BUTTON_HOME); + Gamepad_SetButton(port, CCPAD_SELECT, mods & WPAD_BUTTON_MINUS); - Gamepad_SetButton(KeyBinds_Normal[KEYBIND_FLY], mods & WPAD_BUTTON_LEFT); + Input_SetNonRepeatable(KeyBinds_Normal[KEYBIND_FLY], mods & WPAD_BUTTON_LEFT); if (mods & WPAD_BUTTON_RIGHT) { Mouse_ScrollWheel(1.0*delta); } - Gamepad_SetButton(KeyBinds_Normal[KEYBIND_THIRD_PERSON], mods & WPAD_BUTTON_UP); - Gamepad_SetButton(KeyBinds_Normal[KEYBIND_FLY_DOWN], mods & WPAD_BUTTON_DOWN); + Input_SetNonRepeatable(KeyBinds_Normal[KEYBIND_THIRD_PERSON], mods & WPAD_BUTTON_UP); + Input_SetNonRepeatable(KeyBinds_Normal[KEYBIND_FLY_DOWN], mods & WPAD_BUTTON_DOWN); const float ANGLE_DELTA = 50; bool nunchuckUp = (analog.ang > -ANGLE_DELTA) && (analog.ang < ANGLE_DELTA) && (analog.mag > 0.5); @@ -271,14 +348,14 @@ static void ProcessNunchuck_Game(int mods, double delta) { bool nunchuckLeft = (analog.ang > -90-ANGLE_DELTA) && (analog.ang < -90+ANGLE_DELTA) && (analog.mag > 0.5); bool nunchuckRight = (analog.ang > 90-ANGLE_DELTA) && (analog.ang < 90+ANGLE_DELTA) && (analog.mag > 0.5); - Gamepad_SetButton(CCPAD_LEFT, nunchuckLeft); - Gamepad_SetButton(CCPAD_RIGHT, nunchuckRight); - Gamepad_SetButton(CCPAD_UP, nunchuckUp); - Gamepad_SetButton(CCPAD_DOWN, nunchuckDown); + Gamepad_SetButton(port, CCPAD_LEFT, nunchuckLeft); + Gamepad_SetButton(port, CCPAD_RIGHT, nunchuckRight); + Gamepad_SetButton(port, CCPAD_UP, nunchuckUp); + Gamepad_SetButton(port, CCPAD_DOWN, nunchuckDown); } #define CLASSIC_AXIS_SCALE 2.0f -static void ProcessClassic_Joystick(int axis, struct joystick_t* js, double delta) { +static void ProcessClassic_Joystick(int port, int axis, struct joystick_t* js, float delta) { // TODO: need to account for min/max?? see libogc int x = js->pos.x - js->center.x; int y = js->pos.y - js->center.y; @@ -286,132 +363,76 @@ static void ProcessClassic_Joystick(int axis, struct joystick_t* js, double delt if (Math_AbsI(x) <= 8) x = 0; if (Math_AbsI(y) <= 8) y = 0; - Gamepad_SetAxis(axis, x / CLASSIC_AXIS_SCALE, -y / CLASSIC_AXIS_SCALE, delta); + Gamepad_SetAxis(port, axis, x / CLASSIC_AXIS_SCALE, -y / CLASSIC_AXIS_SCALE, delta); } -static void ProcessClassicButtons(int mods) { - Gamepad_SetButton(CCPAD_L, mods & CLASSIC_CTRL_BUTTON_FULL_L); - Gamepad_SetButton(CCPAD_R, mods & CLASSIC_CTRL_BUTTON_FULL_R); +static void ProcessClassicButtons(int port, int mods) { + Gamepad_SetButton(port, CCPAD_L, mods & CLASSIC_CTRL_BUTTON_FULL_L); + Gamepad_SetButton(port, CCPAD_R, mods & CLASSIC_CTRL_BUTTON_FULL_R); - Gamepad_SetButton(CCPAD_A, mods & CLASSIC_CTRL_BUTTON_A); - Gamepad_SetButton(CCPAD_B, mods & CLASSIC_CTRL_BUTTON_B); - Gamepad_SetButton(CCPAD_X, mods & CLASSIC_CTRL_BUTTON_X); - Gamepad_SetButton(CCPAD_Y, mods & CLASSIC_CTRL_BUTTON_Y); + Gamepad_SetButton(port, CCPAD_A, mods & CLASSIC_CTRL_BUTTON_A); + Gamepad_SetButton(port, CCPAD_B, mods & CLASSIC_CTRL_BUTTON_B); + Gamepad_SetButton(port, CCPAD_X, mods & CLASSIC_CTRL_BUTTON_X); + Gamepad_SetButton(port, CCPAD_Y, mods & CLASSIC_CTRL_BUTTON_Y); - Gamepad_SetButton(CCPAD_START, mods & CLASSIC_CTRL_BUTTON_PLUS); - Gamepad_SetButton(CCPAD_SELECT, mods & CLASSIC_CTRL_BUTTON_MINUS); + Gamepad_SetButton(port, CCPAD_START, mods & CLASSIC_CTRL_BUTTON_PLUS); + Gamepad_SetButton(port, CCPAD_SELECT, mods & CLASSIC_CTRL_BUTTON_MINUS); - Gamepad_SetButton(CCPAD_LEFT, mods & CLASSIC_CTRL_BUTTON_LEFT); - Gamepad_SetButton(CCPAD_RIGHT, mods & CLASSIC_CTRL_BUTTON_RIGHT); - Gamepad_SetButton(CCPAD_UP, mods & CLASSIC_CTRL_BUTTON_UP); - Gamepad_SetButton(CCPAD_DOWN, mods & CLASSIC_CTRL_BUTTON_DOWN); + Gamepad_SetButton(port, CCPAD_LEFT, mods & CLASSIC_CTRL_BUTTON_LEFT); + Gamepad_SetButton(port, CCPAD_RIGHT, mods & CLASSIC_CTRL_BUTTON_RIGHT); + Gamepad_SetButton(port, CCPAD_UP, mods & CLASSIC_CTRL_BUTTON_UP); + Gamepad_SetButton(port, CCPAD_DOWN, mods & CLASSIC_CTRL_BUTTON_DOWN); - Gamepad_SetButton(CCPAD_ZL, mods & CLASSIC_CTRL_BUTTON_ZL); - Gamepad_SetButton(CCPAD_ZR, mods & CLASSIC_CTRL_BUTTON_ZR); + Gamepad_SetButton(port, CCPAD_ZL, mods & CLASSIC_CTRL_BUTTON_ZL); + Gamepad_SetButton(port, CCPAD_ZR, mods & CLASSIC_CTRL_BUTTON_ZR); } -static void ProcessClassicInput(double delta) { +static void ProcessClassicInput(int port, float delta) { WPADData* wd = WPAD_Data(0); classic_ctrl_t ctrls = wd->exp.classic; int mods = ctrls.btns | ctrls.btns_held; - ProcessClassicButtons(mods); - ProcessClassic_Joystick(PAD_AXIS_LEFT, &ctrls.ljs, delta); - ProcessClassic_Joystick(PAD_AXIS_RIGHT, &ctrls.rjs, delta); -} - - -static void GetIRPos(int res, int* x, int* y) { - if (res == WPAD_ERR_NONE) { - WPADData* wd = WPAD_Data(0); - - *x = wd->ir.x; - *y = wd->ir.y; - } else { - *x = 0; - *y = 0; - } + ProcessClassicButtons(port, mods); + ProcessClassic_Joystick(port, PAD_AXIS_LEFT, &ctrls.ljs, delta); + ProcessClassic_Joystick(port, PAD_AXIS_RIGHT, &ctrls.rjs, delta); } -static void ProcessWPADInput(double delta) { +static void ProcessWPADInput(int port, float delta) { WPAD_ScanPads(); - u32 mods = WPAD_ButtonsDown(0) | WPAD_ButtonsHeld(0); u32 type; - int res = WPAD_Probe(0, &type); + int res = WPAD_Probe(port, &type); if (res) return; + u32 mods = WPAD_ButtonsDown(port) | WPAD_ButtonsHeld(port); if (type == WPAD_EXP_CLASSIC) { - ProcessClassicInput(delta); + ProcessClassicInput(port, delta); } else if (launcherMode) { - ProcessWPAD_Buttons(mods); + ProcessWPAD_Buttons(port, mods); } else if (type == WPAD_EXP_NUNCHUK) { - ProcessNunchuck_Game(mods, delta); + ProcessNunchuck_Game(port, mods, delta); } else { - ProcessWPAD_Buttons(mods); + ProcessWPAD_Buttons(port, mods); } - int x, y; - GetIRPos(res, &x, &y); - - if (mods & WPAD_BUTTON_B) { - if (!dragActive) { - dragStartX = dragCurX = x; - dragStartY = dragCurY = y; - } - dragActive = true; - } else { - dragActive = false; - } - Pointer_SetPosition(0, x, y); -} - -void Window_ProcessEvents(double delta) { - Input.JoystickMovement = false; - Input.Sources = INPUT_SOURCE_GAMEPAD; - - ProcessWPADInput(delta); - ProcessPADInput(delta); - ProcessKeyboardInput(); + ProcessWPADDrag(res, mods); } -static void ScanAndGetIRPos(int* x, int* y) { - u32 type; - WPAD_ScanPads(); - - int res = WPAD_Probe(0, &type); - GetIRPos(res, x, y); -} -#define FACTOR 2 -void Window_UpdateRawMouse(void) { - if (!dragActive) return; - int x, y; - ScanAndGetIRPos(&x, &y); - - // TODO: Refactor the logic. is it 100% right too? - dragCurX = dragStartX + (dragCurX - dragStartX) / FACTOR; - dragCurY = dragStartY + (dragCurY - dragStartY) / FACTOR; - - int dx = x - dragCurX; Math_Clamp(dx, -40, 40); - int dy = y - dragCurY; Math_Clamp(dy, -40, 40); - Event_RaiseRawMove(&PointerEvents.RawMoved, dx, dy); - - dragCurX = x; dragCurY = y; +void Window_ProcessGamepads(float delta) { + for (int port = 0; port < INPUT_MAX_GAMEPADS; port++) + { + ProcessWPADInput(port, delta); + ProcessPADInput( port, delta); + } } #else -void Window_ProcessEvents(double delta) { - Input.JoystickMovement = false; - - ProcessPADInput(delta); +void Window_ProcessGamepads(float delta) { + for (int port = 0; port < INPUT_MAX_GAMEPADS; port++) + { + ProcessPADInput(port, delta); + } } - -void Window_UpdateRawMouse(void) { } #endif -void Cursor_SetPosition(int x, int y) { } // No point in GameCube/Wii -// TODO: Display cursor on Wii when not raw mode -void Window_EnableRawMouse(void) { Input.RawMode = true; } -void Window_DisableRawMouse(void) { Input.RawMode = false; } - /*########################################################################################################################* *------------------------------------------------------Framebuffer--------------------------------------------------------* diff --git a/src/Window_N64.c b/src/Window_N64.c index e21b414..d42f41d 100644 --- a/src/Window_N64.c +++ b/src/Window_N64.c @@ -38,6 +38,7 @@ void Window_Init(void) { // change defaults to make more sense for N64 cc_uint8* binds = (cc_uint8*)KeyBind_GamepadDefaults; + binds[KEYBIND_JUMP] = CCPAD_A; binds[KEYBIND_INVENTORY] = CCPAD_B; binds[KEYBIND_PLACE_BLOCK] = CCPAD_Z; binds[KEYBIND_HOTBAR_RIGHT] = CCPAD_L; @@ -47,6 +48,11 @@ void Window_Init(void) { binds[KEYBIND_BACK] = CCPAD_CDOWN; binds[KEYBIND_LEFT] = CCPAD_CLEFT; binds[KEYBIND_RIGHT] = CCPAD_CRIGHT; + + binds[KEYBIND_FLY_UP] = CCPAD_UP; + binds[KEYBIND_FLY_DOWN] = CCPAD_DOWN; + binds[KEYBIND_SPEED] = CCPAD_LEFT; + binds[KEYBIND_FLY] = CCPAD_RIGHT; } void Window_Free(void) { } @@ -74,51 +80,62 @@ void Window_RequestClose(void) { /*########################################################################################################################* *----------------------------------------------------Input processing-----------------------------------------------------* *#########################################################################################################################*/ -static void HandleButtons(joypad_buttons_t btns) { - Gamepad_SetButton(CCPAD_L, btns.l); - Gamepad_SetButton(CCPAD_R, btns.r); +void Window_ProcessEvents(float delta) { + joypad_poll(); +} + +void Cursor_SetPosition(int x, int y) { } // Makes no sense for PSP +void Window_EnableRawMouse(void) { Input.RawMode = true; } +void Window_DisableRawMouse(void) { Input.RawMode = false; } +void Window_UpdateRawMouse(void) { } + + +/*########################################################################################################################* +*-------------------------------------------------------Gamepads----------------------------------------------------------* +*#########################################################################################################################*/ +static void HandleButtons(int port, joypad_buttons_t btns) { + Gamepad_SetButton(port, CCPAD_L, btns.l); + Gamepad_SetButton(port, CCPAD_R, btns.r); - Gamepad_SetButton(CCPAD_A, btns.a); - Gamepad_SetButton(CCPAD_B, btns.b); - Gamepad_SetButton(CCPAD_Z, btns.z); + Gamepad_SetButton(port, CCPAD_A, btns.a); + Gamepad_SetButton(port, CCPAD_B, btns.b); + Gamepad_SetButton(port, CCPAD_Z, btns.z); - Gamepad_SetButton(CCPAD_START, btns.start); + Gamepad_SetButton(port, CCPAD_START, btns.start); - Gamepad_SetButton(CCPAD_LEFT, btns.d_left); - Gamepad_SetButton(CCPAD_RIGHT, btns.d_right); - Gamepad_SetButton(CCPAD_UP, btns.d_up); - Gamepad_SetButton(CCPAD_DOWN, btns.d_down); - - Gamepad_SetButton(CCPAD_CLEFT, btns.c_left); - Gamepad_SetButton(CCPAD_CRIGHT, btns.c_right); - Gamepad_SetButton(CCPAD_CUP, btns.c_up); - Gamepad_SetButton(CCPAD_CDOWN, btns.c_down); + Gamepad_SetButton(port, CCPAD_LEFT, btns.d_left); + Gamepad_SetButton(port, CCPAD_RIGHT, btns.d_right); + Gamepad_SetButton(port, CCPAD_UP, btns.d_up); + Gamepad_SetButton(port, CCPAD_DOWN, btns.d_down); + + Gamepad_SetButton(port, CCPAD_CLEFT, btns.c_left); + Gamepad_SetButton(port, CCPAD_CRIGHT, btns.c_right); + Gamepad_SetButton(port, CCPAD_CUP, btns.c_up); + Gamepad_SetButton(port, CCPAD_CDOWN, btns.c_down); } #define AXIS_SCALE 8.0f -static void ProcessAnalogInput(joypad_inputs_t* inputs, double delta) { +static void ProcessAnalogInput(int port, joypad_inputs_t* inputs, float delta) { int x = inputs->stick_x; int y = inputs->stick_y; if (Math_AbsI(x) <= 8) x = 0; - if (Math_AbsI(y) <= 8) y = 0; + if (Math_AbsI(y) <= 8) y = 0; - Gamepad_SetAxis(PAD_AXIS_RIGHT, x / AXIS_SCALE, -y / AXIS_SCALE, delta); + Gamepad_SetAxis(port, PAD_AXIS_RIGHT, x / AXIS_SCALE, -y / AXIS_SCALE, delta); } -void Window_ProcessEvents(double delta) { - joypad_poll(); - - joypad_inputs_t inputs = joypad_get_inputs(JOYPAD_PORT_1); - HandleButtons(inputs.btn); - ProcessAnalogInput(&inputs, delta); +void Window_ProcessGamepads(float delta) { + for (int port = 0; port < INPUT_MAX_GAMEPADS; port++) + { + if (!joypad_is_connected(port)) continue; + + joypad_inputs_t inputs = joypad_get_inputs(port); + HandleButtons(port, inputs.btn); + ProcessAnalogInput(port, &inputs, delta); + } } -void Cursor_SetPosition(int x, int y) { } // Makes no sense for PSP -void Window_EnableRawMouse(void) { Input.RawMode = true; } -void Window_DisableRawMouse(void) { Input.RawMode = false; } -void Window_UpdateRawMouse(void) { } - /*########################################################################################################################* *------------------------------------------------------Framebuffer--------------------------------------------------------* diff --git a/src/Window_NDS.c b/src/Window_NDS.c index d8f1b42..87516b5 100644 --- a/src/Window_NDS.c +++ b/src/Window_NDS.c @@ -13,10 +13,118 @@ #include "Camera.h" #include #include -#include #include #include +#include +#include + +/*########################################################################################################################* +*----------------------------------------------------Onscreen console-----------------------------------------------------* +*#########################################################################################################################*/ +// A majorly cutdown version of the Console included in libnds +#define CON_WIDTH 32 +#define CON_HEIGHT 24 + +extern u8 default_fontTiles[]; +#define FONT_NUM_CHARACTERS 96 + +#define FONT_ASCII_OFFSET 32 +static u16* conFontBgMap; +static int conFontCurPal; +static int conCursorX, conCurrentRow; + +static void consoleClear(void) { + for (int i = 0; i < CON_WIDTH * CON_HEIGHT; i++) + { + conFontBgMap[i] = ' ' - FONT_ASCII_OFFSET; + } + + conCursorX = 0; + conCurrentRow = 0; +} + +static void consoleNewLine(void) { + conCursorX = 0; + conCurrentRow++; + if (conCurrentRow < CON_HEIGHT) return; + + // Shift entire screen upwards by one row + conCurrentRow--; + + for (int y = 0; y < CON_HEIGHT - 1; y++) + { + for (int x = 0; x < CON_WIDTH; x++) + { + int src = x + (y + 1) * CON_WIDTH; + int dst = x + (y ) * CON_WIDTH; + conFontBgMap[dst] = conFontBgMap[src]; + } + } + + for (int x = 0; x < CON_WIDTH; x++) + { + int index = x + (CON_HEIGHT - 1) * CON_WIDTH; + conFontBgMap[index] = ' ' - FONT_ASCII_OFFSET; + } +} + +static void consolePrintChar(char c) { + if (c < ' ') return; // only ASCII supported + + if (conCursorX >= CON_WIDTH) + consoleNewLine(); + + u16 value = conFontCurPal | (c - FONT_ASCII_OFFSET); + conFontBgMap[conCursorX + conCurrentRow * CON_WIDTH] = value; + conCursorX++; +} + +void consolePrintString(const char* ptr, int len) { + if (!conFontBgMap) return; + + for (int i = 0; i < len; i++) + { + consolePrintChar(ptr[i]); + } + consoleNewLine(); +} + +static void consoleLoadFont(u16* fontBgGfx) { + u16* palette = BG_PALETTE_SUB; + conFontCurPal = 15 << 12; + + for (int i = 0; i < FONT_NUM_CHARACTERS * 8; i++) + { + u8 row = default_fontTiles[i]; + u32 gfx = 0; + if (row & 0x01) gfx |= 0x0000000F; + if (row & 0x02) gfx |= 0x000000F0; + if (row & 0x04) gfx |= 0x00000F00; + if (row & 0x08) gfx |= 0x0000F000; + if (row & 0x10) gfx |= 0x000F0000; + if (row & 0x20) gfx |= 0x00F00000; + if (row & 0x40) gfx |= 0x0F000000; + if (row & 0x80) gfx |= 0xF0000000; + ((u32 *)fontBgGfx)[i] = gfx; + } + + palette[16 * 16 - 1] = RGB15(31, 31, 31); + palette[0] = RGB15( 0, 0, 0); +} + +static void consoleInit(void) { + int bgId = bgInitSub(0, BgType_Text4bpp, BgSize_T_256x256, 22, 2); + conFontBgMap = (u16*)bgGetMapPtr(bgId); + + consoleLoadFont((u16*)bgGetGfxPtr(bgId)); + consoleClear(); +} + + +/*########################################################################################################################* +*------------------------------------------------------General data-------------------------------------------------------* +*#########################################################################################################################*/ static cc_bool launcherMode; cc_bool keyboardOpen; static int bg_id; @@ -25,21 +133,6 @@ static u16* bg_ptr; struct _DisplayData DisplayInfo; struct _WindowData WindowInfo; -// Console and Keyboard combined need more than 32 kb of H VRAM bank -// The simple solution is to allocate the C VRAM bank, but ClassiCube -// needs as much VRAM as it can get for textures -// So the solution is to share the H VRAM bank between console and keyboard -static void ResetHBank(void) { - // Map all VRAM banks to LCDC mode so that the CPU can access it - vramSetBankH(VRAM_H_LCD); - dmaFillWords(0, VRAM_H, 32 * 1024); - vramSetBankH(VRAM_H_SUB_BG); -} - -static void InitConsoleWindow(void) { - consoleInit(NULL, 0, BgType_Text4bpp, BgSize_T_256x256, 14, 0, false, true); -} - void Window_Init(void) { DisplayInfo.Width = SCREEN_WIDTH; DisplayInfo.Height = SCREEN_HEIGHT; @@ -57,8 +150,16 @@ void Window_Init(void) { videoSetModeSub(MODE_0_2D); vramSetBankH(VRAM_H_SUB_BG); + vramSetBankI(VRAM_I_SUB_BG_0x06208000); setBrightness(2, 0); - InitConsoleWindow(); + consoleInit(); + + cc_bool dsiMode = isDSiMode(); + Platform_Log1("Running in %c mode", dsiMode ? "DSi" : "DS"); + + char* dir = fatGetDefaultCwd(); + if (dir) Platform_Log1("CWD: %c", dir); + Mem_Free(dir); } void Window_Free(void) { } @@ -97,28 +198,10 @@ void Window_RequestClose(void) { /*########################################################################################################################* *----------------------------------------------------Input processing-----------------------------------------------------* *#########################################################################################################################*/ -static void HandleButtons(int mods) { - Gamepad_SetButton(CCPAD_L, mods & KEY_L); - Gamepad_SetButton(CCPAD_R, mods & KEY_R); - - Gamepad_SetButton(CCPAD_A, mods & KEY_A); - Gamepad_SetButton(CCPAD_B, mods & KEY_B); - Gamepad_SetButton(CCPAD_X, mods & KEY_X); - Gamepad_SetButton(CCPAD_Y, mods & KEY_Y); - - Gamepad_SetButton(CCPAD_START, mods & KEY_START); - Gamepad_SetButton(CCPAD_SELECT, mods & KEY_SELECT); - - Gamepad_SetButton(CCPAD_LEFT, mods & KEY_LEFT); - Gamepad_SetButton(CCPAD_RIGHT, mods & KEY_RIGHT); - Gamepad_SetButton(CCPAD_UP, mods & KEY_UP); - Gamepad_SetButton(CCPAD_DOWN, mods & KEY_DOWN); -} - static void ProcessTouchInput(int mods) { touchPosition touch; touchRead(&touch); - Camera.Sensitivity = 100; // TODO not hardcode this + Camera.Sensitivity = 100; // TODO not hardcode this if (mods & KEY_TOUCH) { Input_AddTouch(0, touch.px, touch.py); @@ -127,16 +210,14 @@ static void ProcessTouchInput(int mods) { } } -void Window_ProcessEvents(double delta) { +void Window_ProcessEvents(float delta) { scanKeys(); - int keys = keysDown() | keysHeld(); - HandleButtons(keys); - if (keyboardOpen) { - keyboardUpdate(); - } else { - ProcessTouchInput(keys); - } + if (keyboardOpen) { + keyboardUpdate(); + } else { + ProcessTouchInput(keysDown() | keysHeld()); + } } void Cursor_SetPosition(int x, int y) { } // Makes no sense for PSP @@ -146,6 +227,30 @@ void Window_DisableRawMouse(void) { Input.RawMode = false; } void Window_UpdateRawMouse(void) { } +/*########################################################################################################################* +*-------------------------------------------------------Gamepads----------------------------------------------------------* +*#########################################################################################################################*/ +void Window_ProcessGamepads(float delta) { + int mods = keysDown() | keysHeld(); + + Gamepad_SetButton(0, CCPAD_L, mods & KEY_L); + Gamepad_SetButton(0, CCPAD_R, mods & KEY_R); + + Gamepad_SetButton(0, CCPAD_A, mods & KEY_A); + Gamepad_SetButton(0, CCPAD_B, mods & KEY_B); + Gamepad_SetButton(0, CCPAD_X, mods & KEY_X); + Gamepad_SetButton(0, CCPAD_Y, mods & KEY_Y); + + Gamepad_SetButton(0, CCPAD_START, mods & KEY_START); + Gamepad_SetButton(0, CCPAD_SELECT, mods & KEY_SELECT); + + Gamepad_SetButton(0, CCPAD_LEFT, mods & KEY_LEFT); + Gamepad_SetButton(0, CCPAD_RIGHT, mods & KEY_RIGHT); + Gamepad_SetButton(0, CCPAD_UP, mods & KEY_UP); + Gamepad_SetButton(0, CCPAD_DOWN, mods & KEY_DOWN); +} + + /*########################################################################################################################* *------------------------------------------------------Framebuffer--------------------------------------------------------* *#########################################################################################################################*/ @@ -205,7 +310,6 @@ void OnscreenKeyboard_Open(struct OpenKeyboardArgs* args) { Keyboard* kbd = keyboardGetDefault(); videoBgDisableSub(0); // hide console - ResetHBank(); // reset shared VRAM keyboardInit(kbd, 3, BgType_Text4bpp, BgSize_T_256x512, 14, 0, false, true); keyboardShow(); @@ -223,11 +327,10 @@ void OnscreenKeyboard_Draw3D(void) { } void OnscreenKeyboard_Close(void) { keyboardHide(); + if (!keyboardOpen) return; keyboardOpen = false; - ResetHBank(); // reset shared VRAM videoBgEnableSub(0); // show console - InitConsoleWindow(); } diff --git a/src/Window_PS1.c b/src/Window_PS1.c index 0e6e1ec..7fe7759 100644 --- a/src/Window_PS1.c +++ b/src/Window_PS1.c @@ -78,58 +78,65 @@ void Window_RequestClose(void) { /*########################################################################################################################* *----------------------------------------------------Input processing-----------------------------------------------------* *#########################################################################################################################*/ -static void HandleButtons(int buttons) { +void Window_ProcessEvents(float delta) { +} + +void Cursor_SetPosition(int x, int y) { } // Makes no sense for PS Vita + +void Window_EnableRawMouse(void) { Input.RawMode = true; } +void Window_UpdateRawMouse(void) { } +void Window_DisableRawMouse(void) { Input.RawMode = false; } + + +/*########################################################################################################################* +*-------------------------------------------------------Gamepads----------------------------------------------------------* +*#########################################################################################################################*/ +static void HandleButtons(int port, int buttons) { // Confusingly, it seems that when a bit is on, it means the button is NOT pressed // So just flip the bits to make more sense buttons = ~buttons; - Gamepad_SetButton(CCPAD_A, buttons & PAD_TRIANGLE); - Gamepad_SetButton(CCPAD_B, buttons & PAD_SQUARE); - Gamepad_SetButton(CCPAD_X, buttons & PAD_CROSS); - Gamepad_SetButton(CCPAD_Y, buttons & PAD_CIRCLE); + Gamepad_SetButton(port, CCPAD_A, buttons & PAD_TRIANGLE); + Gamepad_SetButton(port, CCPAD_B, buttons & PAD_SQUARE); + Gamepad_SetButton(port, CCPAD_X, buttons & PAD_CROSS); + Gamepad_SetButton(port, CCPAD_Y, buttons & PAD_CIRCLE); - Gamepad_SetButton(CCPAD_START, buttons & PAD_START); - Gamepad_SetButton(CCPAD_SELECT, buttons & PAD_SELECT); + Gamepad_SetButton(port, CCPAD_START, buttons & PAD_START); + Gamepad_SetButton(port, CCPAD_SELECT, buttons & PAD_SELECT); - Gamepad_SetButton(CCPAD_LEFT, buttons & PAD_LEFT); - Gamepad_SetButton(CCPAD_RIGHT, buttons & PAD_RIGHT); - Gamepad_SetButton(CCPAD_UP, buttons & PAD_UP); - Gamepad_SetButton(CCPAD_DOWN, buttons & PAD_DOWN); + Gamepad_SetButton(port, CCPAD_LEFT, buttons & PAD_LEFT); + Gamepad_SetButton(port, CCPAD_RIGHT, buttons & PAD_RIGHT); + Gamepad_SetButton(port, CCPAD_UP, buttons & PAD_UP); + Gamepad_SetButton(port, CCPAD_DOWN, buttons & PAD_DOWN); - Gamepad_SetButton(CCPAD_L, buttons & PAD_L1); - Gamepad_SetButton(CCPAD_R, buttons & PAD_R1); - Gamepad_SetButton(CCPAD_ZL, buttons & PAD_L2); - Gamepad_SetButton(CCPAD_ZR, buttons & PAD_R2); + Gamepad_SetButton(port, CCPAD_L, buttons & PAD_L1); + Gamepad_SetButton(port, CCPAD_R, buttons & PAD_R1); + Gamepad_SetButton(port, CCPAD_ZL, buttons & PAD_L2); + Gamepad_SetButton(port, CCPAD_ZR, buttons & PAD_R2); } #define AXIS_SCALE 16.0f -static void HandleJoystick(int axis, int x, int y, double delta) { +static void HandleJoystick(int port, int axis, int x, int y, float delta) { if (Math_AbsI(x) <= 8) x = 0; if (Math_AbsI(y) <= 8) y = 0; - Gamepad_SetAxis(axis, x / AXIS_SCALE, y / AXIS_SCALE, delta); + Gamepad_SetAxis(port, axis, x / AXIS_SCALE, y / AXIS_SCALE, delta); } -static void ProcessPadInput(PADTYPE* pad, double delta) { - HandleButtons(pad->btn); +static void ProcessPadInput(int port, PADTYPE* pad, float delta) { + HandleButtons(port, pad->btn); if (pad->type == PAD_ID_ANALOG_STICK || pad->type == PAD_ID_ANALOG) { - HandleJoystick(PAD_AXIS_LEFT, pad->ls_x - 0x80, pad->ls_y - 0x80, delta); - HandleJoystick(PAD_AXIS_RIGHT, pad->rs_x - 0x80, pad->rs_y - 0x80, delta); + HandleJoystick(port, PAD_AXIS_LEFT, pad->ls_x - 0x80, pad->ls_y - 0x80, delta); + HandleJoystick(port, PAD_AXIS_RIGHT, pad->rs_x - 0x80, pad->rs_y - 0x80, delta); } } -void Window_ProcessEvents(double delta) { +void Window_ProcessGamepads(float delta) { PADTYPE* pad = (PADTYPE*)&pad_buff[0][0]; - if (pad->stat == 0) ProcessPadInput(pad, delta); + if (pad->stat == 0) ProcessPadInput(0, pad, delta); } -void Cursor_SetPosition(int x, int y) { } // Makes no sense for PS Vita - -void Window_EnableRawMouse(void) { Input.RawMode = true; } -void Window_UpdateRawMouse(void) { } -void Window_DisableRawMouse(void) { Input.RawMode = false; } - /*########################################################################################################################* *------------------------------------------------------Framebuffer--------------------------------------------------------* diff --git a/src/Window_PS2.c b/src/Window_PS2.c index 2f74440..7442818 100644 --- a/src/Window_PS2.c +++ b/src/Window_PS2.c @@ -84,68 +84,83 @@ void Window_RequestClose(void) { /*########################################################################################################################* *----------------------------------------------------Input processing-----------------------------------------------------* *#########################################################################################################################*/ -static void HandleButtons(int buttons) { +void Window_ProcessEvents(float delta) { +} + +void Cursor_SetPosition(int x, int y) { } // Makes no sense for PS Vita + +void Window_EnableRawMouse(void) { Input.RawMode = true; } +void Window_UpdateRawMouse(void) { } +void Window_DisableRawMouse(void) { Input.RawMode = false; } + + +/*########################################################################################################################* +*-------------------------------------------------------Gamepads----------------------------------------------------------* +*#########################################################################################################################*/ +static void HandleButtons(int port, int buttons) { // Confusingly, it seems that when a bit is on, it means the button is NOT pressed // So just flip the bits to make more sense buttons = buttons ^ 0xFFFF; //Platform_Log1("BUTTONS: %h", &buttons); - Gamepad_SetButton(CCPAD_A, buttons & PAD_TRIANGLE); - Gamepad_SetButton(CCPAD_B, buttons & PAD_SQUARE); - Gamepad_SetButton(CCPAD_X, buttons & PAD_CROSS); - Gamepad_SetButton(CCPAD_Y, buttons & PAD_CIRCLE); + Gamepad_SetButton(port, CCPAD_A, buttons & PAD_TRIANGLE); + Gamepad_SetButton(port, CCPAD_B, buttons & PAD_SQUARE); + Gamepad_SetButton(port, CCPAD_X, buttons & PAD_CROSS); + Gamepad_SetButton(port, CCPAD_Y, buttons & PAD_CIRCLE); - Gamepad_SetButton(CCPAD_START, buttons & PAD_START); - Gamepad_SetButton(CCPAD_SELECT, buttons & PAD_SELECT); - - Gamepad_SetButton(CCPAD_LEFT, buttons & PAD_LEFT); - Gamepad_SetButton(CCPAD_RIGHT, buttons & PAD_RIGHT); - Gamepad_SetButton(CCPAD_UP, buttons & PAD_UP); - Gamepad_SetButton(CCPAD_DOWN, buttons & PAD_DOWN); + Gamepad_SetButton(port, CCPAD_START, buttons & PAD_START); + Gamepad_SetButton(port, CCPAD_SELECT, buttons & PAD_SELECT); + Gamepad_SetButton(port, CCPAD_LSTICK, buttons & PAD_L3); + Gamepad_SetButton(port, CCPAD_RSTICK, buttons & PAD_L3); + + Gamepad_SetButton(port, CCPAD_LEFT, buttons & PAD_LEFT); + Gamepad_SetButton(port, CCPAD_RIGHT, buttons & PAD_RIGHT); + Gamepad_SetButton(port, CCPAD_UP, buttons & PAD_UP); + Gamepad_SetButton(port, CCPAD_DOWN, buttons & PAD_DOWN); - Gamepad_SetButton(CCPAD_L, buttons & PAD_L1); - Gamepad_SetButton(CCPAD_R, buttons & PAD_R1); - Gamepad_SetButton(CCPAD_ZL, buttons & PAD_L2); - Gamepad_SetButton(CCPAD_ZR, buttons & PAD_R2); + Gamepad_SetButton(port, CCPAD_L, buttons & PAD_L1); + Gamepad_SetButton(port, CCPAD_R, buttons & PAD_R1); + Gamepad_SetButton(port, CCPAD_ZL, buttons & PAD_L2); + Gamepad_SetButton(port, CCPAD_ZR, buttons & PAD_R2); } #define AXIS_SCALE 16.0f -static void HandleJoystick(int axis, int x, int y, double delta) { +static void HandleJoystick(int port, int axis, int x, int y, float delta) { if (Math_AbsI(x) <= 8) x = 0; if (Math_AbsI(y) <= 8) y = 0; - Gamepad_SetAxis(axis, x / AXIS_SCALE, y / AXIS_SCALE, delta); + Gamepad_SetAxis(port, axis, x / AXIS_SCALE, y / AXIS_SCALE, delta); } -static void ProcessPadInput(double delta, struct padButtonStatus* pad) { - HandleButtons(pad->btns); - HandleJoystick(PAD_AXIS_LEFT, pad->ljoy_h - 0x80, pad->ljoy_v - 0x80, delta); - HandleJoystick(PAD_AXIS_RIGHT, pad->rjoy_h - 0x80, pad->rjoy_v - 0x80, delta); +static void ProcessPadInput(int port, float delta, struct padButtonStatus* pad) { + HandleButtons(port, pad->btns); + HandleJoystick(port, PAD_AXIS_LEFT, pad->ljoy_h - 0x80, pad->ljoy_v - 0x80, delta); + HandleJoystick(port, PAD_AXIS_RIGHT, pad->rjoy_h - 0x80, pad->rjoy_v - 0x80, delta); } -static cc_bool setMode; -void Window_ProcessEvents(double delta) { - struct padButtonStatus pad; - Input.JoystickMovement = false; +static cc_bool setMode[INPUT_MAX_GAMEPADS]; +static void ProcessPad(int port, float delta) { + struct padButtonStatus pad; - int state = padGetState(0, 0); - if (state != PAD_STATE_STABLE) return; - - // Change to DUALSHOCK mode so analog joysticks return values - if (!setMode) { - padSetMainMode(0, 0, PAD_MMODE_DUALSHOCK, PAD_MMODE_LOCK); - setMode = true; - } - - int ret = padRead(0, 0, &pad); - if (ret != 0) ProcessPadInput(delta, &pad); -} + int state = padGetState(port, 0); + if (state != PAD_STATE_STABLE) return; -void Cursor_SetPosition(int x, int y) { } // Makes no sense for PS Vita + // Change to DUALSHOCK mode so analog joysticks return values + if (!setMode[port]) { + padSetMainMode(port, 0, PAD_MMODE_DUALSHOCK, PAD_MMODE_LOCK); + setMode[port] = true; + } -void Window_EnableRawMouse(void) { Input.RawMode = true; } -void Window_UpdateRawMouse(void) { } -void Window_DisableRawMouse(void) { Input.RawMode = false; } + int ret = padRead(port, 0, &pad); + if (ret != 0) ProcessPadInput(port, delta, &pad); +} + +void Window_ProcessGamepads(float delta) { + for (int port = 0; port < 2; port++) + { + ProcessPad(port, delta); + } +} /*########################################################################################################################* diff --git a/src/Window_PS3.c b/src/Window_PS3.c index 4ada25a..445e271 100644 --- a/src/Window_PS3.c +++ b/src/Window_PS3.c @@ -252,60 +252,69 @@ static void ProcessKBInput(void) { /*########################################################################################################################* *----------------------------------------------------Input processing-----------------------------------------------------* *#########################################################################################################################*/ -static void HandleButtons(padData* data) { +void Window_ProcessEvents(float delta) { + ioKbGetInfo(&kb_info); + if (kb_info.status[0]) ProcessKBInput(); +} + +void Cursor_SetPosition(int x, int y) { } // Makes no sense for PS Vita + +void Window_EnableRawMouse(void) { Input.RawMode = true; } +void Window_UpdateRawMouse(void) { } +void Window_DisableRawMouse(void) { Input.RawMode = false; } + + +/*########################################################################################################################* +*-------------------------------------------------------Gamepads----------------------------------------------------------* +*#########################################################################################################################*/ +static void HandleButtons(int port, padData* data) { //Platform_Log2("BUTTONS: %h (%h)", &data->button[2], &data->button[0]); - Gamepad_SetButton(CCPAD_A, data->BTN_TRIANGLE); - Gamepad_SetButton(CCPAD_B, data->BTN_SQUARE); - Gamepad_SetButton(CCPAD_X, data->BTN_CROSS); - Gamepad_SetButton(CCPAD_Y, data->BTN_CIRCLE); + Gamepad_SetButton(port, CCPAD_A, data->BTN_TRIANGLE); + Gamepad_SetButton(port, CCPAD_B, data->BTN_SQUARE); + Gamepad_SetButton(port, CCPAD_X, data->BTN_CROSS); + Gamepad_SetButton(port, CCPAD_Y, data->BTN_CIRCLE); - Gamepad_SetButton(CCPAD_START, data->BTN_START); - Gamepad_SetButton(CCPAD_SELECT, data->BTN_SELECT); - - Gamepad_SetButton(CCPAD_LEFT, data->BTN_LEFT); - Gamepad_SetButton(CCPAD_RIGHT, data->BTN_RIGHT); - Gamepad_SetButton(CCPAD_UP, data->BTN_UP); - Gamepad_SetButton(CCPAD_DOWN, data->BTN_DOWN); + Gamepad_SetButton(port, CCPAD_START, data->BTN_START); + Gamepad_SetButton(port, CCPAD_SELECT, data->BTN_SELECT); + Gamepad_SetButton(port, CCPAD_LSTICK, data->BTN_L3); + Gamepad_SetButton(port, CCPAD_RSTICK, data->BTN_R3); + + Gamepad_SetButton(port, CCPAD_LEFT, data->BTN_LEFT); + Gamepad_SetButton(port, CCPAD_RIGHT, data->BTN_RIGHT); + Gamepad_SetButton(port, CCPAD_UP, data->BTN_UP); + Gamepad_SetButton(port, CCPAD_DOWN, data->BTN_DOWN); - Gamepad_SetButton(CCPAD_L, data->BTN_L1); - Gamepad_SetButton(CCPAD_R, data->BTN_R1); - Gamepad_SetButton(CCPAD_ZL, data->BTN_L2); - Gamepad_SetButton(CCPAD_ZR, data->BTN_R2); + Gamepad_SetButton(port, CCPAD_L, data->BTN_L1); + Gamepad_SetButton(port, CCPAD_R, data->BTN_R1); + Gamepad_SetButton(port, CCPAD_ZL, data->BTN_L2); + Gamepad_SetButton(port, CCPAD_ZR, data->BTN_R2); } #define AXIS_SCALE 32.0f -static void HandleJoystick(int axis, int x, int y, double delta) { +static void HandleJoystick(int port, int axis, int x, int y, float delta) { if (Math_AbsI(x) <= 32) x = 0; if (Math_AbsI(y) <= 32) y = 0; - Gamepad_SetAxis(axis, x / AXIS_SCALE, y / AXIS_SCALE, delta); + Gamepad_SetAxis(port, axis, x / AXIS_SCALE, y / AXIS_SCALE, delta); } -static void ProcessPadInput(double delta, padData* pad) { - HandleButtons(pad); - HandleJoystick(PAD_AXIS_LEFT, pad->ANA_L_H - 0x80, pad->ANA_L_V - 0x80, delta); - HandleJoystick(PAD_AXIS_RIGHT, pad->ANA_R_H - 0x80, pad->ANA_R_V - 0x80, delta); +static void ProcessPadInput(int port, float delta, padData* pad) { + HandleButtons(port, pad); + HandleJoystick(port, PAD_AXIS_LEFT, pad->ANA_L_H - 0x80, pad->ANA_L_V - 0x80, delta); + HandleJoystick(port, PAD_AXIS_RIGHT, pad->ANA_R_H - 0x80, pad->ANA_R_V - 0x80, delta); } -void Window_ProcessEvents(double delta) { - Input.JoystickMovement = false; - +void Window_ProcessGamepads(float delta) { ioPadGetInfo(&pad_info); - if (pad_info.status[0]) { - ioPadGetData(0, &pad_data); - ProcessPadInput(delta, &pad_data); + for (int port = 0; port < INPUT_MAX_GAMEPADS; port++) + { + if (!pad_info.status[port]) continue; + + ioPadGetData(port, &pad_data); + ProcessPadInput(port, delta, &pad_data); } - - ioKbGetInfo(&kb_info); - if (kb_info.status[0]) ProcessKBInput(); } -void Cursor_SetPosition(int x, int y) { } // Makes no sense for PS Vita - -void Window_EnableRawMouse(void) { Input.RawMode = true; } -void Window_UpdateRawMouse(void) { } -void Window_DisableRawMouse(void) { Input.RawMode = false; } - /*########################################################################################################################* *------------------------------------------------------Framebuffer--------------------------------------------------------* diff --git a/src/Window_PSP.c b/src/Window_PSP.c index 87b3756..9fd59bf 100644 --- a/src/Window_PSP.c +++ b/src/Window_PSP.c @@ -67,51 +67,58 @@ void Window_RequestClose(void) { /*########################################################################################################################* *----------------------------------------------------Input processing-----------------------------------------------------* *#########################################################################################################################*/ -static void HandleButtons(int mods) { - Gamepad_SetButton(CCPAD_L, mods & PSP_CTRL_LTRIGGER); - Gamepad_SetButton(CCPAD_R, mods & PSP_CTRL_RTRIGGER); +void Window_ProcessEvents(float delta) { +} + +void Cursor_SetPosition(int x, int y) { } // Makes no sense for PSP +void Window_EnableRawMouse(void) { Input.RawMode = true; } +void Window_DisableRawMouse(void) { Input.RawMode = false; } +void Window_UpdateRawMouse(void) { } + + +/*########################################################################################################################* +*-------------------------------------------------------Gamepads----------------------------------------------------------* +*#########################################################################################################################*/ +static void HandleButtons(int port, int mods) { + Gamepad_SetButton(port, CCPAD_L, mods & PSP_CTRL_LTRIGGER); + Gamepad_SetButton(port, CCPAD_R, mods & PSP_CTRL_RTRIGGER); - Gamepad_SetButton(CCPAD_A, mods & PSP_CTRL_TRIANGLE); - Gamepad_SetButton(CCPAD_B, mods & PSP_CTRL_SQUARE); - Gamepad_SetButton(CCPAD_X, mods & PSP_CTRL_CROSS); - Gamepad_SetButton(CCPAD_Y, mods & PSP_CTRL_CIRCLE); + Gamepad_SetButton(port, CCPAD_A, mods & PSP_CTRL_TRIANGLE); + Gamepad_SetButton(port, CCPAD_B, mods & PSP_CTRL_SQUARE); + Gamepad_SetButton(port, CCPAD_X, mods & PSP_CTRL_CROSS); + Gamepad_SetButton(port, CCPAD_Y, mods & PSP_CTRL_CIRCLE); - Gamepad_SetButton(CCPAD_START, mods & PSP_CTRL_START); - Gamepad_SetButton(CCPAD_SELECT, mods & PSP_CTRL_SELECT); + Gamepad_SetButton(port, CCPAD_START, mods & PSP_CTRL_START); + Gamepad_SetButton(port, CCPAD_SELECT, mods & PSP_CTRL_SELECT); - Gamepad_SetButton(CCPAD_LEFT, mods & PSP_CTRL_LEFT); - Gamepad_SetButton(CCPAD_RIGHT, mods & PSP_CTRL_RIGHT); - Gamepad_SetButton(CCPAD_UP, mods & PSP_CTRL_UP); - Gamepad_SetButton(CCPAD_DOWN, mods & PSP_CTRL_DOWN); + Gamepad_SetButton(port, CCPAD_LEFT, mods & PSP_CTRL_LEFT); + Gamepad_SetButton(port, CCPAD_RIGHT, mods & PSP_CTRL_RIGHT); + Gamepad_SetButton(port, CCPAD_UP, mods & PSP_CTRL_UP); + Gamepad_SetButton(port, CCPAD_DOWN, mods & PSP_CTRL_DOWN); } #define AXIS_SCALE 16.0f -static void ProcessCircleInput(SceCtrlData* pad, double delta) { +static void ProcessCircleInput(int port, SceCtrlData* pad, float delta) { int x = pad->Lx - 127; int y = pad->Ly - 127; if (Math_AbsI(x) <= 8) x = 0; if (Math_AbsI(y) <= 8) y = 0; - Gamepad_SetAxis(PAD_AXIS_RIGHT, x / AXIS_SCALE, y / AXIS_SCALE, delta); + Gamepad_SetAxis(port, PAD_AXIS_RIGHT, x / AXIS_SCALE, y / AXIS_SCALE, delta); } -void Window_ProcessEvents(double delta) { +void Window_ProcessGamepads(float delta) { SceCtrlData pad; /* TODO implement */ int ret = sceCtrlPeekBufferPositive(&pad, 1); if (ret <= 0) return; // TODO: need to use cached version still? like GameCube/Wii - HandleButtons(pad.Buttons); - ProcessCircleInput(&pad, delta); + HandleButtons(0, pad.Buttons); + ProcessCircleInput(0, &pad, delta); } -void Cursor_SetPosition(int x, int y) { } // Makes no sense for PSP -void Window_EnableRawMouse(void) { Input.RawMode = true; } -void Window_DisableRawMouse(void) { Input.RawMode = false; } -void Window_UpdateRawMouse(void) { } - /*########################################################################################################################* *------------------------------------------------------Framebuffer--------------------------------------------------------* diff --git a/src/Window_PSVita.c b/src/Window_PSVita.c index 5565c29..2f9c733 100644 --- a/src/Window_PSVita.c +++ b/src/Window_PSVita.c @@ -86,33 +86,6 @@ void Window_RequestClose(void) { /*########################################################################################################################* *----------------------------------------------------Input processing-----------------------------------------------------* *#########################################################################################################################*/ -static void HandleButtons(int mods) { - Gamepad_SetButton(CCPAD_A, mods & SCE_CTRL_TRIANGLE); - Gamepad_SetButton(CCPAD_B, mods & SCE_CTRL_SQUARE); - Gamepad_SetButton(CCPAD_X, mods & SCE_CTRL_CROSS); - Gamepad_SetButton(CCPAD_Y, mods & SCE_CTRL_CIRCLE); - - Gamepad_SetButton(CCPAD_START, mods & SCE_CTRL_START); - Gamepad_SetButton(CCPAD_SELECT, mods & SCE_CTRL_SELECT); - - Gamepad_SetButton(CCPAD_LEFT, mods & SCE_CTRL_LEFT); - Gamepad_SetButton(CCPAD_RIGHT, mods & SCE_CTRL_RIGHT); - Gamepad_SetButton(CCPAD_UP, mods & SCE_CTRL_UP); - Gamepad_SetButton(CCPAD_DOWN, mods & SCE_CTRL_DOWN); - - Gamepad_SetButton(CCPAD_L, mods & SCE_CTRL_LTRIGGER); - Gamepad_SetButton(CCPAD_R, mods & SCE_CTRL_RTRIGGER); -} - -#define AXIS_SCALE 16.0f -static void ProcessCircleInput(int axis, int x, int y, double delta) { - // May not be exactly 0 on actual hardware - if (Math_AbsI(x) <= 8) x = 0; - if (Math_AbsI(y) <= 8) y = 0; - - Gamepad_SetAxis(axis, x / AXIS_SCALE, y / AXIS_SCALE, delta); -} - static void AdjustTouchPress(int* x, int* y) { if (!frontPanel.maxDispX || !frontPanel.maxDispY) return; // TODO: Shouldn't ever happen? need to check @@ -146,7 +119,48 @@ static void ProcessTouchInput(void) { } } -static void ProcessPadInput(double delta) { +void Window_ProcessEvents(float delta) { + ProcessTouchInput(); +} + +void Cursor_SetPosition(int x, int y) { } // Makes no sense for PS Vita + +void Window_EnableRawMouse(void) { Input.RawMode = true; } +void Window_UpdateRawMouse(void) { } +void Window_DisableRawMouse(void) { Input.RawMode = false; } + + +/*########################################################################################################################* +*-------------------------------------------------------Gamepads----------------------------------------------------------* +*#########################################################################################################################*/ +static void HandleButtons(int port, int mods) { + Gamepad_SetButton(port, CCPAD_A, mods & SCE_CTRL_TRIANGLE); + Gamepad_SetButton(port, CCPAD_B, mods & SCE_CTRL_SQUARE); + Gamepad_SetButton(port, CCPAD_X, mods & SCE_CTRL_CROSS); + Gamepad_SetButton(port, CCPAD_Y, mods & SCE_CTRL_CIRCLE); + + Gamepad_SetButton(port, CCPAD_START, mods & SCE_CTRL_START); + Gamepad_SetButton(port, CCPAD_SELECT, mods & SCE_CTRL_SELECT); + + Gamepad_SetButton(port, CCPAD_LEFT, mods & SCE_CTRL_LEFT); + Gamepad_SetButton(port, CCPAD_RIGHT, mods & SCE_CTRL_RIGHT); + Gamepad_SetButton(port, CCPAD_UP, mods & SCE_CTRL_UP); + Gamepad_SetButton(port, CCPAD_DOWN, mods & SCE_CTRL_DOWN); + + Gamepad_SetButton(port, CCPAD_L, mods & SCE_CTRL_LTRIGGER); + Gamepad_SetButton(port, CCPAD_R, mods & SCE_CTRL_RTRIGGER); +} + +#define AXIS_SCALE 16.0f +static void ProcessCircleInput(int port, int axis, int x, int y, float delta) { + // May not be exactly 0 on actual hardware + if (Math_AbsI(x) <= 8) x = 0; + if (Math_AbsI(y) <= 8) y = 0; + + Gamepad_SetAxis(port, axis, x / AXIS_SCALE, y / AXIS_SCALE, delta); +} + +static void ProcessPadInput(float delta) { SceCtrlData pad; // sceCtrlReadBufferPositive is blocking (seems to block until vblank), and don't want that @@ -155,24 +169,15 @@ static void ProcessPadInput(double delta) { if (res < 0) return; // error occurred // TODO: need to use cached version still? like GameCube/Wii - HandleButtons(pad.buttons); - ProcessCircleInput(PAD_AXIS_LEFT, pad.lx - 127, pad.ly - 127, delta); - ProcessCircleInput(PAD_AXIS_RIGHT, pad.rx - 127, pad.ry - 127, delta); + HandleButtons(0, pad.buttons); + ProcessCircleInput(0, PAD_AXIS_LEFT, pad.lx - 127, pad.ly - 127, delta); + ProcessCircleInput(0, PAD_AXIS_RIGHT, pad.rx - 127, pad.ry - 127, delta); } -void Window_ProcessEvents(double delta) { - Input.JoystickMovement = false; - +void Window_ProcessGamepads(float delta) { ProcessPadInput(delta); - ProcessTouchInput(); } -void Cursor_SetPosition(int x, int y) { } // Makes no sense for PS Vita - -void Window_EnableRawMouse(void) { Input.RawMode = true; } -void Window_UpdateRawMouse(void) { } -void Window_DisableRawMouse(void) { Input.RawMode = false; } - /*########################################################################################################################* *------------------------------------------------------Framebuffer--------------------------------------------------------* @@ -222,7 +227,7 @@ static void DisplayDialog(const char* msg) { msgParam.buttonType = SCE_MSG_DIALOG_BUTTON_TYPE_OK; int ret = sceMsgDialogInit(¶m); - if (ret) { Platform_Log1("ERROR SHOWING DIALOG: %i", &ret); return; } + if (ret) { Platform_Log1("ERROR SHOWING DIALOG: %e", &ret); return; } void (*prevCallback)(void* fb); prevCallback = DQ_OnNextFrame; @@ -310,7 +315,7 @@ void OnscreenKeyboard_Open(struct OpenKeyboardArgs* args) { param.inputTextBuffer = imeBuffer; int ret = sceImeDialogInit(¶m); - if (ret) { Platform_Log1("ERROR SHOWING IME: %i", &ret); return; } + if (ret) { Platform_Log1("ERROR SHOWING IME: %e", &ret); return; } void (*prevCallback)(void* fb); prevCallback = DQ_OnNextFrame; diff --git a/src/Window_SDL.c b/src/Window_SDL.c index 86848a4..5eb653f 100644 --- a/src/Window_SDL.c +++ b/src/Window_SDL.c @@ -7,11 +7,11 @@ #include "Bitmap.h" #include "Errors.h" #include + static SDL_Window* win_handle; +#warning "Some features are missing from the SDL backend. If possible, it is recommended that you use a native windowing backend instead" -#ifndef CC_BUILD_OS2 -#error "Some features are missing from the SDL backend. If possible, it is recommended that you use a native windowing backend instead" -#else +#ifdef CC_BUILD_OS2 #define INCL_PM #include // Internal OS/2 driver data @@ -258,7 +258,7 @@ static void OnWindowEvent(const SDL_Event* e) { } } -void Window_ProcessEvents(double delta) { +void Window_ProcessEvents(float delta) { SDL_Event e; while (SDL_PollEvent(&e)) { switch (e.type) { @@ -295,6 +295,8 @@ void Window_ProcessEvents(double delta) { } } +void Window_ProcessGamepads(float delta) { } + static void Cursor_GetRawPos(int* x, int* y) { SDL_GetMouseState(x, y); } diff --git a/src/Window_SDL3.c b/src/Window_SDL3.c index bf60dfe..b2d7d33 100644 --- a/src/Window_SDL3.c +++ b/src/Window_SDL3.c @@ -218,7 +218,7 @@ static void OnTextEvent(const SDL_Event* e) { } static void ProcessDialogEvent(SDL_Event* e); -void Window_ProcessEvents(double delta) { +void Window_ProcessEvents(float delta) { SDL_Event e; while (SDL_PollEvent(&e)) { switch (e.type) { @@ -281,6 +281,8 @@ void Window_ProcessEvents(double delta) { } } +void Window_ProcessGamepads(float delta) { } + static void Cursor_GetRawPos(int* x, int* y) { float xPos, yPos; SDL_GetMouseState(&xPos, &yPos); diff --git a/src/Window_Saturn.c b/src/Window_Saturn.c index e4df97b..df8677c 100644 --- a/src/Window_Saturn.c +++ b/src/Window_Saturn.c @@ -78,28 +78,8 @@ void Window_RequestClose(void) { /*########################################################################################################################* *----------------------------------------------------Input processing-----------------------------------------------------* *#########################################################################################################################*/ -static void ProcessButtons(int mods) { - Gamepad_SetButton(CCPAD_A, mods & PERIPHERAL_DIGITAL_A); - Gamepad_SetButton(CCPAD_B, mods & PERIPHERAL_DIGITAL_B); - Gamepad_SetButton(CCPAD_X, mods & PERIPHERAL_DIGITAL_C); - - Gamepad_SetButton(CCPAD_L, mods & PERIPHERAL_DIGITAL_L); - Gamepad_SetButton(CCPAD_R, mods & PERIPHERAL_DIGITAL_R); - - Gamepad_SetButton(CCPAD_START, mods & PERIPHERAL_DIGITAL_START); - Gamepad_SetButton(CCPAD_SELECT, mods & PERIPHERAL_DIGITAL_Z); - - Gamepad_SetButton(CCPAD_LEFT, mods & PERIPHERAL_DIGITAL_LEFT); - Gamepad_SetButton(CCPAD_RIGHT, mods & PERIPHERAL_DIGITAL_RIGHT); - Gamepad_SetButton(CCPAD_UP, mods & PERIPHERAL_DIGITAL_UP); - Gamepad_SetButton(CCPAD_DOWN, mods & PERIPHERAL_DIGITAL_DOWN); -} - -void Window_ProcessEvents(double delta) { +void Window_ProcessEvents(float delta) { smpc_peripheral_process(); - smpc_peripheral_digital_port(1, &state); - - ProcessButtons(state.pressed.raw | state.held.raw); } void Cursor_SetPosition(int x, int y) { } // Makes no sense for PS Vita @@ -109,6 +89,32 @@ void Window_UpdateRawMouse(void) { } void Window_DisableRawMouse(void) { Input.RawMode = false; } +/*########################################################################################################################* +*-------------------------------------------------------Gamepads----------------------------------------------------------* +*#########################################################################################################################*/ +static void ProcessButtons(int port, int mods) { + Gamepad_SetButton(port, CCPAD_A, mods & PERIPHERAL_DIGITAL_A); + Gamepad_SetButton(port, CCPAD_B, mods & PERIPHERAL_DIGITAL_B); + Gamepad_SetButton(port, CCPAD_X, mods & PERIPHERAL_DIGITAL_C); + + Gamepad_SetButton(port, CCPAD_L, mods & PERIPHERAL_DIGITAL_L); + Gamepad_SetButton(port, CCPAD_R, mods & PERIPHERAL_DIGITAL_R); + + Gamepad_SetButton(port, CCPAD_START, mods & PERIPHERAL_DIGITAL_START); + Gamepad_SetButton(port, CCPAD_SELECT, mods & PERIPHERAL_DIGITAL_Z); + + Gamepad_SetButton(port, CCPAD_LEFT, mods & PERIPHERAL_DIGITAL_LEFT); + Gamepad_SetButton(port, CCPAD_RIGHT, mods & PERIPHERAL_DIGITAL_RIGHT); + Gamepad_SetButton(port, CCPAD_UP, mods & PERIPHERAL_DIGITAL_UP); + Gamepad_SetButton(port, CCPAD_DOWN, mods & PERIPHERAL_DIGITAL_DOWN); +} + +void Window_ProcessGamepads(float delta) { + smpc_peripheral_digital_port(1, &state); + ProcessButtons(0, state.pressed.raw | state.held.raw); +} + + /*########################################################################################################################* *------------------------------------------------------Framebuffer--------------------------------------------------------* *#########################################################################################################################*/ diff --git a/src/Window_Switch.c b/src/Window_Switch.c index 529c7fa..94b695a 100644 --- a/src/Window_Switch.c +++ b/src/Window_Switch.c @@ -108,33 +108,6 @@ void Window_RequestClose(void) { /*########################################################################################################################* *----------------------------------------------------Input processing-----------------------------------------------------* *#########################################################################################################################*/ -static void HandleButtons(u64 mods) { - Gamepad_SetButton(CCPAD_L, mods & HidNpadButton_L); - Gamepad_SetButton(CCPAD_R, mods & HidNpadButton_R); - - Gamepad_SetButton(CCPAD_A, mods & HidNpadButton_A); - Gamepad_SetButton(CCPAD_B, mods & HidNpadButton_B); - Gamepad_SetButton(CCPAD_X, mods & HidNpadButton_X); - Gamepad_SetButton(CCPAD_Y, mods & HidNpadButton_Y); - - Gamepad_SetButton(CCPAD_START, mods & HidNpadButton_Plus); - Gamepad_SetButton(CCPAD_SELECT, mods & HidNpadButton_Minus); - - Gamepad_SetButton(CCPAD_LEFT, mods & HidNpadButton_Left); - Gamepad_SetButton(CCPAD_RIGHT, mods & HidNpadButton_Right); - Gamepad_SetButton(CCPAD_UP, mods & HidNpadButton_Up); - Gamepad_SetButton(CCPAD_DOWN, mods & HidNpadButton_Down); -} - -#define AXIS_SCALE 512.0f -static void ProcessJoystickInput(int axis, HidAnalogStickState* pos, double delta) { - // May not be exactly 0 on actual hardware - if (Math_AbsI(pos->x) <= 16) pos->x = 0; - if (Math_AbsI(pos->y) <= 16) pos->y = 0; - - Gamepad_SetAxis(axis, pos->x / AXIS_SCALE, -pos->y / AXIS_SCALE, delta); -} - static void ProcessTouchInput(void) { static int prev_touchcount = 0; HidTouchScreenState state = {0}; @@ -148,26 +121,15 @@ static void ProcessTouchInput(void) { prev_touchcount = state.count; } -void Window_ProcessEvents(double delta) { +void Window_ProcessEvents(float delta) { // Scan the gamepad. This should be done once for each frame padUpdate(&pad); - Input.JoystickMovement = false; if (!appletMainLoop()) { Window_Main.Exists = false; Window_RequestClose(); return; } - - u64 keys = padGetButtons(&pad); - HandleButtons(keys); - - // Read the sticks' position - HidAnalogStickState analog_stick_l = padGetStickPos(&pad, 0); - HidAnalogStickState analog_stick_r = padGetStickPos(&pad, 1); - ProcessJoystickInput(PAD_AXIS_LEFT, &analog_stick_l, delta); - ProcessJoystickInput(PAD_AXIS_RIGHT, &analog_stick_r, delta); - ProcessTouchInput(); } @@ -178,6 +140,48 @@ void Window_DisableRawMouse(void) { Input.RawMode = false; } void Window_UpdateRawMouse(void) { } +/*########################################################################################################################* +*-------------------------------------------------------Gamepads----------------------------------------------------------* +*#########################################################################################################################*/ +static void HandleButtons(int port, u64 mods) { + Gamepad_SetButton(port, CCPAD_L, mods & HidNpadButton_L); + Gamepad_SetButton(port, CCPAD_R, mods & HidNpadButton_R); + + Gamepad_SetButton(port, CCPAD_A, mods & HidNpadButton_A); + Gamepad_SetButton(port, CCPAD_B, mods & HidNpadButton_B); + Gamepad_SetButton(port, CCPAD_X, mods & HidNpadButton_X); + Gamepad_SetButton(port, CCPAD_Y, mods & HidNpadButton_Y); + + Gamepad_SetButton(port, CCPAD_START, mods & HidNpadButton_Plus); + Gamepad_SetButton(port, CCPAD_SELECT, mods & HidNpadButton_Minus); + + Gamepad_SetButton(port, CCPAD_LEFT, mods & HidNpadButton_Left); + Gamepad_SetButton(port, CCPAD_RIGHT, mods & HidNpadButton_Right); + Gamepad_SetButton(port, CCPAD_UP, mods & HidNpadButton_Up); + Gamepad_SetButton(port, CCPAD_DOWN, mods & HidNpadButton_Down); +} + +#define AXIS_SCALE 512.0f +static void ProcessJoystickInput(int port, int axis, HidAnalogStickState* pos, float delta) { + // May not be exactly 0 on actual hardware + if (Math_AbsI(pos->x) <= 16) pos->x = 0; + if (Math_AbsI(pos->y) <= 16) pos->y = 0; + + Gamepad_SetAxis(port, axis, pos->x / AXIS_SCALE, -pos->y / AXIS_SCALE, delta); +} + +void Window_ProcessGamepads(float delta) { + u64 keys = padGetButtons(&pad); + HandleButtons(0, keys); + + // Read the sticks' position + HidAnalogStickState analog_stick_l = padGetStickPos(&pad, 0); + HidAnalogStickState analog_stick_r = padGetStickPos(&pad, 1); + ProcessJoystickInput(0, PAD_AXIS_LEFT, &analog_stick_l, delta); + ProcessJoystickInput(0, PAD_AXIS_RIGHT, &analog_stick_r, delta); +} + + /*########################################################################################################################* *------------------------------------------------------Framebuffer--------------------------------------------------------* *#########################################################################################################################*/ diff --git a/src/Window_Web.c b/src/Window_Web.c index 4147b5e..a259140 100644 --- a/src/Window_Web.c +++ b/src/Window_Web.c @@ -529,55 +529,74 @@ static void ProcessPendingResize(void) { UpdateWindowBounds(); } +void Window_ProcessEvents(float delta) { + if (!needResize) return; + needResize = false; + ProcessPendingResize(); +} + +/* Not needed because browser provides relative mouse and touch events */ +static void Cursor_GetRawPos(int* x, int* y) { *x = 0; *y = 0; } +/* Not allowed to move cursor from javascript */ +void Cursor_SetPosition(int x, int y) { } + +extern void interop_SetCursorVisible(int visible); +static void Cursor_DoSetVisible(cc_bool visible) { + interop_SetCursorVisible(visible); +} + + +/*########################################################################################################################* +*-------------------------------------------------------Gamepads----------------------------------------------------------* +*#########################################################################################################################*/ /* https://www.w3.org/TR/gamepad/#dfn-standard-gamepad */ #define GetGamepadButton(i) i < numButtons ? ev->digitalButton[i] : 0 -static void ProcessGamepadButtons(EmscriptenGamepadEvent* ev) { +static void ProcessGamepadButtons(int port, EmscriptenGamepadEvent* ev) { int numButtons = ev->numButtons; - Gamepad_SetButton(CCPAD_A, GetGamepadButton(0)); - Gamepad_SetButton(CCPAD_B, GetGamepadButton(1)); - Gamepad_SetButton(CCPAD_X, GetGamepadButton(2)); - Gamepad_SetButton(CCPAD_Y, GetGamepadButton(3)); + Gamepad_SetButton(port, CCPAD_A, GetGamepadButton(0)); + Gamepad_SetButton(port, CCPAD_B, GetGamepadButton(1)); + Gamepad_SetButton(port, CCPAD_X, GetGamepadButton(2)); + Gamepad_SetButton(port, CCPAD_Y, GetGamepadButton(3)); - Gamepad_SetButton(CCPAD_ZL, GetGamepadButton(4)); - Gamepad_SetButton(CCPAD_ZR, GetGamepadButton(5)); - Gamepad_SetButton(CCPAD_L, GetGamepadButton(6)); - Gamepad_SetButton(CCPAD_R, GetGamepadButton(7)); + Gamepad_SetButton(port, CCPAD_ZL, GetGamepadButton(4)); + Gamepad_SetButton(port, CCPAD_ZR, GetGamepadButton(5)); + Gamepad_SetButton(port, CCPAD_L, GetGamepadButton(6)); + Gamepad_SetButton(port, CCPAD_R, GetGamepadButton(7)); - Gamepad_SetButton(CCPAD_SELECT, GetGamepadButton( 8)); - Gamepad_SetButton(CCPAD_START, GetGamepadButton( 9)); - Gamepad_SetButton(CCPAD_LSTICK, GetGamepadButton(10)); - Gamepad_SetButton(CCPAD_RSTICK, GetGamepadButton(11)); + Gamepad_SetButton(port, CCPAD_SELECT, GetGamepadButton( 8)); + Gamepad_SetButton(port, CCPAD_START, GetGamepadButton( 9)); + Gamepad_SetButton(port, CCPAD_LSTICK, GetGamepadButton(10)); + Gamepad_SetButton(port, CCPAD_RSTICK, GetGamepadButton(11)); - Gamepad_SetButton(CCPAD_UP, GetGamepadButton(12)); - Gamepad_SetButton(CCPAD_DOWN, GetGamepadButton(13)); - Gamepad_SetButton(CCPAD_LEFT, GetGamepadButton(14)); - Gamepad_SetButton(CCPAD_RIGHT, GetGamepadButton(15)); + Gamepad_SetButton(port, CCPAD_UP, GetGamepadButton(12)); + Gamepad_SetButton(port, CCPAD_DOWN, GetGamepadButton(13)); + Gamepad_SetButton(port, CCPAD_LEFT, GetGamepadButton(14)); + Gamepad_SetButton(port, CCPAD_RIGHT, GetGamepadButton(15)); } #define AXIS_SCALE 8.0f -static void ProcessGamepadAxis(int axis, float x, float y, double delta) { +static void ProcessGamepadAxis(int port, int axis, float x, float y, float delta) { /* Deadzone adjustment */ if (x >= -0.1 && x <= 0.1) x = 0; if (y >= -0.1 && y <= 0.1) y = 0; - Gamepad_SetAxis(axis, x * AXIS_SCALE, y * AXIS_SCALE, delta); + Gamepad_SetAxis(port, axis, x * AXIS_SCALE, y * AXIS_SCALE, delta); } -static void ProcessGamepadInput(EmscriptenGamepadEvent* ev, double delta) { +static void ProcessGamepadInput(int port, EmscriptenGamepadEvent* ev, float delta) { Input.Sources |= INPUT_SOURCE_GAMEPAD; - Input.JoystickMovement = false; - ProcessGamepadButtons(ev); + ProcessGamepadButtons(port, ev); if (ev->numAxes >= 4) { - ProcessGamepadAxis(PAD_AXIS_LEFT, ev->axis[0], ev->axis[1], delta); - ProcessGamepadAxis(PAD_AXIS_RIGHT, ev->axis[2], ev->axis[3], delta); + ProcessGamepadAxis(port, PAD_AXIS_LEFT, ev->axis[0], ev->axis[1], delta); + ProcessGamepadAxis(port, PAD_AXIS_RIGHT, ev->axis[2], ev->axis[3], delta); } else if (ev->numAxes >= 2) { - ProcessGamepadAxis(PAD_AXIS_RIGHT, ev->axis[0], ev->axis[1], delta); + ProcessGamepadAxis(port, PAD_AXIS_RIGHT, ev->axis[0], ev->axis[1], delta); } } -void Window_ProcessEvents(double delta) { +void Window_ProcessGamepads(float delta) { int i, res, count; Input.Sources = INPUT_SOURCE_NORMAL; @@ -588,25 +607,15 @@ void Window_ProcessEvents(double delta) { { EmscriptenGamepadEvent ev; res = emscripten_get_gamepad_status(i, &ev); - if (res == 0) ProcessGamepadInput(&ev, delta); + if (res == 0) ProcessGamepadInput(i, &ev, delta); } } - - if (!needResize) return; - needResize = false; - ProcessPendingResize(); } -/* Not needed because browser provides relative mouse and touch events */ -static void Cursor_GetRawPos(int* x, int* y) { *x = 0; *y = 0; } -/* Not allowed to move cursor from javascript */ -void Cursor_SetPosition(int x, int y) { } - -extern void interop_SetCursorVisible(int visible); -static void Cursor_DoSetVisible(cc_bool visible) { - interop_SetCursorVisible(visible); -} +/*########################################################################################################################* +*-------------------------------------------------------Misc/Other--------------------------------------------------------* +*#########################################################################################################################*/ extern void interop_ShowDialog(const char* title, const char* msg); static void ShowDialogCore(const char* title, const char* msg) { interop_ShowDialog(title, msg); diff --git a/src/Window_WiiU.cpp b/src/Window_WiiU.cpp new file mode 100644 index 0000000..b046ea4 --- /dev/null +++ b/src/Window_WiiU.cpp @@ -0,0 +1,606 @@ +#include "Core.h" +#if defined CC_BUILD_WIIU +extern "C" { +#include "Window.h" +#include "Platform.h" +#include "Input.h" +#include "Event.h" +#include "String.h" +#include "Funcs.h" +#include "Bitmap.h" +#include "Errors.h" +#include "ExtMath.h" +#include "Graphics.h" +#include "Launcher.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +} +#include + +static cc_bool launcherMode; +static cc_bool keyboardOpen; +struct _DisplayData DisplayInfo; +struct _WindowData WindowInfo; +struct _WindowData Window_Alt; +cc_bool launcherTop; + + + +static void OnscreenKeyboard_Update(void); +static void OnscreenKeyboard_DrawTV(void); +static void OnscreenKeyboard_DrawDRC(void); + +static void LoadTVDimensions(void) { + switch(GX2GetSystemTVScanMode()) + { + case GX2_TV_SCAN_MODE_480I: + case GX2_TV_SCAN_MODE_480P: + DisplayInfo.Width = 854; + DisplayInfo.Height = 480; + break; + case GX2_TV_SCAN_MODE_1080I: + case GX2_TV_SCAN_MODE_1080P: + DisplayInfo.Width = 1920; + DisplayInfo.Height = 1080; + break; + case GX2_TV_SCAN_MODE_720P: + default: + DisplayInfo.Width = 1280; + DisplayInfo.Height = 720; + break; + } +} + +static uint32_t OnAcquired(void* context) { + Window_Main.Inactive = false; + Event_RaiseVoid(&WindowEvents.InactiveChanged); + return 0; +} + +static uint32_t OnReleased(void* context) { + Window_Main.Inactive = true; + Event_RaiseVoid(&WindowEvents.InactiveChanged); + return 0; +} + +void Window_Init(void) { + LoadTVDimensions(); + DisplayInfo.ScaleX = 1; + DisplayInfo.ScaleY = 1; + + Window_Main.Width = DisplayInfo.Width; + Window_Main.Height = DisplayInfo.Height; + Window_Main.Focused = true; + Window_Main.Exists = true; + + Input.Sources = INPUT_SOURCE_GAMEPAD; + DisplayInfo.ContentOffsetX = 10; + DisplayInfo.ContentOffsetY = 10; + + Window_Main.SoftKeyboard = SOFT_KEYBOARD_RESIZE; + Input_SetTouchMode(true); + + Window_Alt.Width = 854; + Window_Alt.Height = 480; + + KPADInit(); + VPADInit(); + + ProcUIRegisterCallback(PROCUI_CALLBACK_ACQUIRE, OnAcquired, NULL, 100); + ProcUIRegisterCallback(PROCUI_CALLBACK_RELEASE, OnReleased, NULL, 100); + WHBGfxInit(); +} + +void Window_Free(void) { } + +// OSScreen is always this buffer size, regardless of the current TV resolution +#define OSSCREEN_TV_WIDTH 1280 +#define OSSCREEN_TV_HEIGHT 720 +#define OSSCREEN_DRC_WIDTH 854 +#define OSSCREEN_DRC_HEIGHT 480 +static void LauncherInactiveChanged(void* obj); +static void Init2DResources(void); + +void Window_Create2D(int width, int height) { + Window_Main.Width = OSSCREEN_DRC_WIDTH; + Window_Main.Height = OSSCREEN_DRC_HEIGHT; + + launcherMode = true; + Event_Register_(&WindowEvents.InactiveChanged, NULL, LauncherInactiveChanged); + Init2DResources(); +} + +void Window_Create3D(int width, int height) { + Window_Main.Width = DisplayInfo.Width; + Window_Main.Height = DisplayInfo.Height; + + launcherMode = false; + Event_Unregister_(&WindowEvents.InactiveChanged, NULL, LauncherInactiveChanged); +} + +void Window_RequestClose(void) { + Event_RaiseVoid(&WindowEvents.Closing); +} + + +/*########################################################################################################################* +*----------------------------------------------------Input processing-----------------------------------------------------* +*#########################################################################################################################*/ +extern Rect2D dirty_rect; +void Window_ProcessEvents(float delta) { + if (!dirty_rect.width) dirty_rect.width = 1; + + if (!WHBProcIsRunning()) { + Window_Main.Exists = false; + Window_RequestClose(); + } +} + +void Window_UpdateRawMouse(void) { } + +void Cursor_SetPosition(int x, int y) { } +void Window_EnableRawMouse(void) { Input.RawMode = true; } +void Window_DisableRawMouse(void) { Input.RawMode = false; } + + +/*########################################################################################################################* +*-------------------------------------------------------Gamepads----------------------------------------------------------* +*#########################################################################################################################*/ +static VPADStatus vpadStatus; +static bool kpad_valid[4]; +static KPADStatus kpads[4]; + +static void ProcessKPadButtons(int port, int mods) { + Gamepad_SetButton(port, CCPAD_L, mods & WPAD_BUTTON_1); + Gamepad_SetButton(port, CCPAD_R, mods & WPAD_BUTTON_2); + + Gamepad_SetButton(port, CCPAD_A, mods & WPAD_BUTTON_A); + Gamepad_SetButton(port, CCPAD_B, mods & WPAD_BUTTON_B); + Gamepad_SetButton(port, CCPAD_X, mods & WPAD_BUTTON_PLUS); + + Gamepad_SetButton(port, CCPAD_START, mods & WPAD_BUTTON_HOME); + Gamepad_SetButton(port, CCPAD_SELECT, mods & WPAD_BUTTON_MINUS); + + Gamepad_SetButton(port, CCPAD_LEFT, mods & WPAD_BUTTON_LEFT); + Gamepad_SetButton(port, CCPAD_RIGHT, mods & WPAD_BUTTON_RIGHT); + Gamepad_SetButton(port, CCPAD_UP, mods & WPAD_BUTTON_UP); + Gamepad_SetButton(port, CCPAD_DOWN, mods & WPAD_BUTTON_DOWN); +} + +static void ProcessNunchuckButtons(int port, int mods) { + Gamepad_SetButton(port, CCPAD_L, mods & WPAD_NUNCHUK_BUTTON_Z); + Gamepad_SetButton(port, CCPAD_R, mods & WPAD_NUNCHUK_BUTTON_C); +} + +static void ProcessClassicButtons(int port, int mods) { + Gamepad_SetButton(port, CCPAD_L, mods & WPAD_CLASSIC_BUTTON_L); + Gamepad_SetButton(port, CCPAD_R, mods & WPAD_CLASSIC_BUTTON_R); + Gamepad_SetButton(port, CCPAD_ZL, mods & WPAD_CLASSIC_BUTTON_ZL); + Gamepad_SetButton(port, CCPAD_ZR, mods & WPAD_CLASSIC_BUTTON_ZR); + + Gamepad_SetButton(port, CCPAD_A, mods & WPAD_CLASSIC_BUTTON_A); + Gamepad_SetButton(port, CCPAD_B, mods & WPAD_CLASSIC_BUTTON_B); + Gamepad_SetButton(port, CCPAD_X, mods & WPAD_CLASSIC_BUTTON_X); + Gamepad_SetButton(port, CCPAD_Y, mods & WPAD_CLASSIC_BUTTON_Y); + + Gamepad_SetButton(port, CCPAD_START, mods & WPAD_CLASSIC_BUTTON_HOME); + Gamepad_SetButton(port, CCPAD_SELECT, mods & WPAD_CLASSIC_BUTTON_MINUS); + Gamepad_SetButton(port, CCPAD_Z, mods & WPAD_CLASSIC_BUTTON_PLUS); + + Gamepad_SetButton(port, CCPAD_LEFT, mods & WPAD_CLASSIC_BUTTON_LEFT); + Gamepad_SetButton(port, CCPAD_RIGHT, mods & WPAD_CLASSIC_BUTTON_RIGHT); + Gamepad_SetButton(port, CCPAD_UP, mods & WPAD_CLASSIC_BUTTON_UP); + Gamepad_SetButton(port, CCPAD_DOWN, mods & WPAD_CLASSIC_BUTTON_DOWN); +} + +static void ProcessProButtons(int port, int mods) { + Gamepad_SetButton(port, CCPAD_L, mods & WPAD_PRO_TRIGGER_L); + Gamepad_SetButton(port, CCPAD_R, mods & WPAD_PRO_TRIGGER_R); + Gamepad_SetButton(port, CCPAD_ZL, mods & WPAD_PRO_TRIGGER_ZL); + Gamepad_SetButton(port, CCPAD_ZR, mods & WPAD_PRO_TRIGGER_ZR); + + Gamepad_SetButton(port, CCPAD_A, mods & WPAD_PRO_BUTTON_A); + Gamepad_SetButton(port, CCPAD_B, mods & WPAD_PRO_BUTTON_B); + Gamepad_SetButton(port, CCPAD_X, mods & WPAD_PRO_BUTTON_X); + Gamepad_SetButton(port, CCPAD_Y, mods & WPAD_PRO_BUTTON_Y); + + Gamepad_SetButton(port, CCPAD_START, mods & WPAD_PRO_BUTTON_HOME); + Gamepad_SetButton(port, CCPAD_SELECT, mods & WPAD_PRO_BUTTON_MINUS); + Gamepad_SetButton(port, CCPAD_Z, mods & WPAD_PRO_BUTTON_PLUS); + Gamepad_SetButton(port, CCPAD_LSTICK, mods & WPAD_PRO_BUTTON_STICK_L); + Gamepad_SetButton(port, CCPAD_RSTICK, mods & WPAD_PRO_BUTTON_STICK_R); + + Gamepad_SetButton(port, CCPAD_LEFT, mods & WPAD_PRO_BUTTON_LEFT); + Gamepad_SetButton(port, CCPAD_RIGHT, mods & WPAD_PRO_BUTTON_RIGHT); + Gamepad_SetButton(port, CCPAD_UP, mods & WPAD_PRO_BUTTON_UP); + Gamepad_SetButton(port, CCPAD_DOWN, mods & WPAD_PRO_BUTTON_DOWN); +} + +static void ProcessKPAD(float delta, int i) { + kpad_valid[i] = false; + int res = KPADRead((WPADChan)(WPAD_CHAN_0 + i), &kpads[i], 1); + + if (res != KPAD_ERROR_OK) return; + kpad_valid[i] = true; + + switch (kpads[i].extensionType) + { + case WPAD_EXT_CLASSIC: + ProcessClassicButtons(i, kpads[i].classic.hold | kpads[i].classic.trigger); + break; + case WPAD_EXT_PRO_CONTROLLER: + ProcessProButtons( i, kpads[i].pro.hold | kpads[i].pro.trigger); + break; + case WPAD_EXT_NUNCHUK: + ProcessKPadButtons(i, kpads[i].hold | kpads[i].trigger); + ProcessNunchuckButtons(i, kpads[i].nunchuck.hold | kpads[i].nunchuck.trigger); + break; + default: + ProcessKPadButtons(i, kpads[i].hold | kpads[i].trigger); + break; + } +} + + +#define AXIS_SCALE 4.0f +static void ProcessVpadStick(int port, int axis, float x, float y, float delta) { + // May not be exactly 0 on actual hardware + if (Math_AbsF(x) <= 0.1f) x = 0; + if (Math_AbsF(y) <= 0.1f) y = 0; + + Gamepad_SetAxis(port, axis, x * AXIS_SCALE, -y * AXIS_SCALE, delta); +} + +static void ProcessVpadButtons(int port, int mods) { + Gamepad_SetButton(port, CCPAD_L, mods & VPAD_BUTTON_L); + Gamepad_SetButton(port, CCPAD_R, mods & VPAD_BUTTON_R); + Gamepad_SetButton(port, CCPAD_ZL, mods & VPAD_BUTTON_ZL); + Gamepad_SetButton(port, CCPAD_ZR, mods & VPAD_BUTTON_ZR); + + Gamepad_SetButton(port, CCPAD_A, mods & VPAD_BUTTON_A); + Gamepad_SetButton(port, CCPAD_B, mods & VPAD_BUTTON_B); + Gamepad_SetButton(port, CCPAD_X, mods & VPAD_BUTTON_X); + Gamepad_SetButton(port, CCPAD_Y, mods & VPAD_BUTTON_Y); + + Gamepad_SetButton(port, CCPAD_START, mods & VPAD_BUTTON_PLUS); + Gamepad_SetButton(port, CCPAD_SELECT, mods & VPAD_BUTTON_MINUS); + + Gamepad_SetButton(port, CCPAD_LEFT, mods & VPAD_BUTTON_LEFT); + Gamepad_SetButton(port, CCPAD_RIGHT, mods & VPAD_BUTTON_RIGHT); + Gamepad_SetButton(port, CCPAD_UP, mods & VPAD_BUTTON_UP); + Gamepad_SetButton(port, CCPAD_DOWN, mods & VPAD_BUTTON_DOWN); + +} + +static void ProcessVpadTouch(VPADTouchData* data) { + static int was_touched; + + // TODO rescale to main screen size + if (data->touched) { + int x = data->x; + int y = data->y; + Platform_Log2("TOUCH: %i, %i", &x, &y); + + x = x * Window_Main.Width / 1280; + y = y * Window_Main.Height / 720; + + Input_AddTouch(0, x, y); + } else if (was_touched) { + Input_RemoveTouch(0, Pointers[0].x, Pointers[0].y); + } + was_touched = data->touched; +} + +static void ProcessVPAD(float delta) { + VPADReadError error = VPAD_READ_SUCCESS; + VPADRead(VPAD_CHAN_0, &vpadStatus, 1, &error); + if (error != VPAD_READ_SUCCESS) return; + + VPADGetTPCalibratedPoint(VPAD_CHAN_0, &vpadStatus.tpNormal, &vpadStatus.tpNormal); + ProcessVpadButtons(0, vpadStatus.hold); + ProcessVpadTouch(&vpadStatus.tpNormal); + + ProcessVpadStick(0, PAD_AXIS_LEFT, vpadStatus.leftStick.x, vpadStatus.leftStick.y, delta); + ProcessVpadStick(0, PAD_AXIS_RIGHT, vpadStatus.rightStick.x, vpadStatus.rightStick.y, delta); +} + + +void Window_ProcessGamepads(float delta) { + ProcessVPAD(delta); + for (int i = 0; i < 4; i++) + ProcessKPAD(delta, i); + + if (keyboardOpen) OnscreenKeyboard_Update(); +} + + +/*########################################################################################################################* +*------------------------------------------------------Framebuffer--------------------------------------------------------* +*#########################################################################################################################*/ +static GfxResourceID framebuffer_vb; + +static void LauncherInactiveChanged(void* obj) { + // TODO +} + +static void Init2DResources(void) { + Gfx_Create(); + if (framebuffer_vb) return; + + struct VertexTextured* data = (struct VertexTextured*)Gfx_RecreateAndLockVb(&framebuffer_vb, + VERTEX_FORMAT_TEXTURED, 4); + data[0].x = -1.0f; data[0].y = -1.0f; data[0].z = 0.0f; data[0].Col = PACKEDCOL_WHITE; data[0].U = 0.0f; data[0].V = 1.0f; + data[1].x = 1.0f; data[1].y = -1.0f; data[1].z = 0.0f; data[1].Col = PACKEDCOL_WHITE; data[1].U = 1.0f; data[1].V = 1.0f; + data[2].x = 1.0f; data[2].y = 1.0f; data[2].z = 0.0f; data[2].Col = PACKEDCOL_WHITE; data[2].U = 1.0f; data[2].V = 0.0f; + data[3].x = -1.0f; data[3].y = 1.0f; data[3].z = 0.0f; data[3].Col = PACKEDCOL_WHITE; data[3].U = 0.0f; data[2].V = 0.0f; + + Gfx_UnlockVb(framebuffer_vb); +} + +static GX2Texture fb; +void Window_AllocFramebuffer(struct Bitmap* bmp) { + fb.surface.width = bmp->width; + fb.surface.height = bmp->height; + fb.surface.depth = 1; + fb.surface.dim = GX2_SURFACE_DIM_TEXTURE_2D; + fb.surface.format = GX2_SURFACE_FORMAT_UNORM_R8_G8_B8_A8; + fb.surface.tileMode = GX2_TILE_MODE_LINEAR_ALIGNED; + fb.viewNumSlices = 1; + fb.compMap = 0x00010203; + GX2CalcSurfaceSizeAndAlignment(&fb.surface); + GX2InitTextureRegs(&fb); + + fb.surface.image = MEMAllocFromDefaultHeapEx(fb.surface.imageSize, fb.surface.alignment); + bmp->scan0 = (BitmapCol*)Mem_Alloc(bmp->width * bmp->height, 4, "window pixels"); +} + +static void DrawLauncher(void) { + Gfx_LoadIdentityMatrix(MATRIX_VIEW); + Gfx_LoadIdentityMatrix(MATRIX_PROJECTION); + Gfx_SetDepthTest(false); + + Gfx_SetVertexFormat(VERTEX_FORMAT_COLOURED); + Gfx_SetVertexFormat(VERTEX_FORMAT_TEXTURED); + Gfx_BindTexture(&fb); + Gfx_BindVb(framebuffer_vb); + Gfx_DrawVb_IndexedTris(4); +} + +static void DrawTV(void) { + WHBGfxBeginRenderTV(); + WHBGfxClearColor(0.7f, 0.7f, 0.7f, 1.0f); + DrawLauncher(); + if (keyboardOpen) OnscreenKeyboard_DrawTV(); + WHBGfxFinishRenderTV(); +} + +static void DrawDRC(void) { + WHBGfxBeginRenderDRC(); + WHBGfxClearColor(0.7f, 0.7f, 0.7f, 1.0f); + DrawLauncher(); + if (keyboardOpen) OnscreenKeyboard_DrawDRC(); + WHBGfxFinishRenderDRC(); +} + +void Window_DrawFramebuffer(Rect2D r, struct Bitmap* bmp) { + if (launcherTop || Window_Main.Inactive) return; + + struct Bitmap part; + part.scan0 = Bitmap_GetRow(bmp, r.y) + r.x; + part.width = r.width; + part.height = r.height; + Gfx_UpdateTexture(&fb, r.x, r.y, &part, bmp->width, false); + + WHBGfxBeginRender(); + DrawDRC(); + DrawTV(); + WHBGfxFinishRender(); +} + +void Window_FreeFramebuffer(struct Bitmap* bmp) { + MEMFreeToDefaultHeap(fb.surface.image); + Mem_Free(bmp->scan0); +} + + +/*########################################################################################################################* +*-------------------------------------------------------Misc/Other--------------------------------------------------------* +*#########################################################################################################################*/ +void Window_SetTitle(const cc_string* title) { } +void Clipboard_GetText(cc_string* value) { } +void Clipboard_SetText(const cc_string* value) { } + +int Window_GetWindowState(void) { return WINDOW_STATE_FULLSCREEN; } +cc_result Window_EnterFullscreen(void) { return 0; } +cc_result Window_ExitFullscreen(void) { return 0; } +int Window_IsObscured(void) { return 0; } + +void Window_Show(void) { } +void Window_SetSize(int width, int height) { } + +void Window_ShowDialog(const char* title, const char* msg) { + /* TODO implement */ + Platform_LogConst(title); + Platform_LogConst(msg); +} + +cc_result Window_OpenFileDialog(const struct OpenFileDialogArgs* args) { + return ERR_NOT_SUPPORTED; +} + +cc_result Window_SaveFileDialog(const struct SaveFileDialogArgs* args) { + return ERR_NOT_SUPPORTED; +} + + +/*########################################################################################################################* +*----------------------------------------------------Onscreen keyboard----------------------------------------------------* +*#########################################################################################################################*/ +static FSClient* fs_client; +static nn::swkbd::CreateArg create_arg; +static nn::swkbd::AppearArg appear_arg; + +static char kb_buffer[512]; +static cc_string kb_str = String_FromArray(kb_buffer); +#define UNI_STR_LENGTH 64 + +static int UniString_Length(const char16_t* raw) { + int length = 0; + while (length < UInt16_MaxValue && *raw) { raw++; length++; } + return length; +} + +static void UniString_WriteConst(const char* src, char16_t* dst) { + while (*src) { *dst++ = *src++; } + *dst = '\0'; +} + +static void UniString_WriteString(const cc_string* src, char16_t* dst) { + int len = min(src->length, UNI_STR_LENGTH); + + for (int i = 0; i < len; i++) + { + *dst++ = Convert_CP437ToUnicode(src->buffer[i]); + } + *dst = '\0'; +} + + +void OnscreenKeyboard_Open(struct OpenKeyboardArgs* args) { + if (keyboardOpen) OnscreenKeyboard_Close(); + char16_t hint[UNI_STR_LENGTH + 1] = { 0 }; + char16_t initial[UNI_STR_LENGTH + 1] = { 0 }; + int mode = args->type & 0xFF; + + kb_str.length = 0; + keyboardOpen = true; + Window_Main.SoftKeyboardFocus = true; + + fs_client = (FSClient *)MEMAllocFromDefaultHeap(sizeof(FSClient)); + FSAddClient(fs_client, FS_ERROR_FLAG_NONE); + + Mem_Set(&create_arg, 0, sizeof(create_arg)); + create_arg.regionType = nn::swkbd::RegionType::Europe; + create_arg.workMemory = MEMAllocFromDefaultHeap(nn::swkbd::GetWorkMemorySize(0)); + create_arg.fsClient = fs_client; + + if (!nn::swkbd::Create(create_arg)) { + Platform_LogConst("nn::swkbd::Create failed"); + return; + } + + nn::swkbd::MuteAllSound(false); + Mem_Set(&appear_arg, 0, sizeof(appear_arg)); + + nn::swkbd::ConfigArg* cfg = &appear_arg.keyboardArg.configArg; + cfg->languageType = nn::swkbd::LanguageType::English; + cfg->okString = args->type & KEYBOARD_FLAG_SEND ? u"Send" : u"OK"; + + if (mode == KEYBOARD_TYPE_INTEGER) { + cfg->keyboardMode = nn::swkbd::KeyboardMode::Numpad; + cfg->numpadCharLeft = '-'; + cfg->numpadCharRight = 0; + } else if (mode == KEYBOARD_TYPE_NUMBER) { + cfg->keyboardMode = nn::swkbd::KeyboardMode::Numpad; + cfg->numpadCharLeft = '-'; + cfg->numpadCharRight = '.'; + } + + nn::swkbd::InputFormArg* ipt = &appear_arg.inputFormArg; + UniString_WriteConst(args->placeholder, hint); + UniString_WriteString(args->text, initial); + ipt->hintText = hint; + ipt->initialText = initial; + + if (mode == KEYBOARD_TYPE_PASSWORD) + ipt->passwordMode = nn::swkbd::PasswordMode::Hide; + + if (!nn::swkbd::AppearInputForm(appear_arg)) { + Platform_LogConst("nn::swkbd::AppearInputForm failed"); + return; + } +} + +static void ProcessKeyboardInput(void) { + char tmpBuffer[NATIVE_STR_LEN]; + cc_string tmp = String_FromArray(tmpBuffer); + + const char16_t* str = nn::swkbd::GetInputFormString(); + if (!str) return; + String_AppendUtf16(&tmp, str, UniString_Length(str)); + + if (String_Equals(&tmp, &kb_str)) return; + String_Copy(&kb_str, &tmp); + Event_RaiseString(&InputEvents.TextChanged, &tmp); +} + +static void OnscreenKeyboard_Update(void) { + nn::swkbd::ControllerInfo controllerInfo; + controllerInfo.vpad = &vpadStatus; + controllerInfo.kpad[0] = kpad_valid[0] ? &kpads[0] : nullptr; + controllerInfo.kpad[1] = kpad_valid[1] ? &kpads[1] : nullptr; + controllerInfo.kpad[2] = kpad_valid[2] ? &kpads[2] : nullptr; + controllerInfo.kpad[3] = kpad_valid[3] ? &kpads[3] : nullptr; + nn::swkbd::Calc(controllerInfo); + + if (nn::swkbd::IsNeedCalcSubThreadFont()) { + nn::swkbd::CalcSubThreadFont(); + } + + if (nn::swkbd::IsNeedCalcSubThreadPredict()) { + nn::swkbd::CalcSubThreadPredict(); + } + ProcessKeyboardInput(); + + if (nn::swkbd::IsDecideOkButton(nullptr)) { + Input_SetPressed(CCKEY_ENTER); + Input_SetReleased(CCKEY_ENTER); + OnscreenKeyboard_Close(); + return; + } + + if (nn::swkbd::IsDecideCancelButton(nullptr)) { + OnscreenKeyboard_Close(); + return; + } +} + +static void OnscreenKeyboard_DrawTV(void) { + nn::swkbd::DrawTV(); +} + +static void OnscreenKeyboard_DrawDRC(void) { + nn::swkbd::DrawDRC(); +} + + +void OnscreenKeyboard_SetText(const cc_string* text) { } +void OnscreenKeyboard_Draw2D(Rect2D* r, struct Bitmap* bmp) { } +void OnscreenKeyboard_Draw3D(void) { } + +void OnscreenKeyboard_Close(void) { + if (!keyboardOpen) return; + keyboardOpen = false; + Window_Main.SoftKeyboardFocus = false; + + nn::swkbd::DisappearInputForm(); + nn::swkbd::Destroy(); + MEMFreeToDefaultHeap(create_arg.workMemory); + + FSDelClient(fs_client, FS_ERROR_FLAG_NONE); + MEMFreeToDefaultHeap(fs_client); +} +#endif diff --git a/src/Window_Win.c b/src/Window_Win.c index bf2a123..3e8ac81 100644 --- a/src/Window_Win.c +++ b/src/Window_Win.c @@ -53,7 +53,7 @@ static cc_bool is_ansiWindow, grabCursor; static int windowX, windowY; static const cc_uint8 key_map[14 * 16] = { - 0, 0, 0, 0, 0, 0, 0, 0, CCKEY_BACKSPACE, CCKEY_TAB, 0, 0, 0, CCKEY_ENTER, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, CCKEY_BACKSPACE, CCKEY_TAB, 0, 0, CCKEY_F5, CCKEY_ENTER, 0, 0, 0, 0, 0, CCKEY_PAUSE, CCKEY_CAPSLOCK, 0, 0, 0, 0, 0, 0, CCKEY_ESCAPE, 0, 0, 0, 0, CCKEY_SPACE, CCKEY_PAGEUP, CCKEY_PAGEDOWN, CCKEY_END, CCKEY_HOME, CCKEY_LEFT, CCKEY_UP, CCKEY_RIGHT, CCKEY_DOWN, 0, CCKEY_PRINTSCREEN, 0, CCKEY_PRINTSCREEN, CCKEY_INSERT, CCKEY_DELETE, 0, '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 0, 0, 0, 0, 0, 0, @@ -513,7 +513,7 @@ void Window_RequestClose(void) { PostMessageA(win_handle, WM_CLOSE, 0, 0); } -void Window_ProcessEvents(double delta) { +void Window_ProcessEvents(float delta) { HWND foreground; MSG msg; @@ -533,6 +533,8 @@ void Window_ProcessEvents(double delta) { } } +void Window_ProcessGamepads(float delta) { } + static void Cursor_GetRawPos(int* x, int* y) { POINT point; GetCursorPos(&point); diff --git a/src/Window_X11.c b/src/Window_X11.c index 4d82b95..0c55e07 100644 --- a/src/Window_X11.c +++ b/src/Window_X11.c @@ -525,7 +525,7 @@ static void HandleWMPing(XEvent* e) { } static void HandleGenericEvent(XEvent* e); -void Window_ProcessEvents(double delta) { +void Window_ProcessEvents(float delta) { XEvent e; Window focus; int focusRevert; @@ -699,6 +699,8 @@ void Window_ProcessEvents(double delta) { } } +void Window_ProcessGamepads(float delta) { } + static void Cursor_GetRawPos(int* x, int* y) { Window rootW, childW; int childX, childY; diff --git a/src/Window_Xbox.c b/src/Window_Xbox.c index e416e39..43f3c0b 100644 --- a/src/Window_Xbox.c +++ b/src/Window_Xbox.c @@ -41,17 +41,17 @@ static void OnDataReceived(UTR_T* utr) { static void OnDeviceChanged(xid_dev_t *xid_dev__, int status__) { xid_dev_t* xid_dev = usbh_xid_get_device_list(); - Platform_LogConst("DEVICE CHECK!!!"); + Platform_LogConst("Devices check"); - while (xid_dev) + for (; xid_dev; xid_dev = xid_dev->next) { int DEV = xid_dev->xid_desc.bType; - Platform_Log1("DEV: %i", &DEV); + Platform_Log1("DEVICE: %i", &DEV); if (xid_dev->xid_desc.bType != XID_TYPE_GAMECONTROLLER) continue; xid_ctrl = xid_dev; - usbh_xid_read(xid_ctrl, 0, OnDataReceived); + usbh_xid_read(xid_dev, 0, OnDataReceived); return; } xid_ctrl = NULL; @@ -107,6 +107,20 @@ void Window_RequestClose(void) { /*########################################################################################################################* *----------------------------------------------------Input processing-----------------------------------------------------* *#########################################################################################################################*/ +void Window_ProcessEvents(float delta) { + usbh_pooling_hubs(); +} + +void Cursor_SetPosition(int x, int y) { } // Makes no sense for Xbox + +void Window_EnableRawMouse(void) { Input.RawMode = true; } +void Window_DisableRawMouse(void) { Input.RawMode = false; } +void Window_UpdateRawMouse(void) { } + + +/*########################################################################################################################* +*-------------------------------------------------------Gamepads----------------------------------------------------------* +*#########################################################################################################################*/ // https://docs.microsoft.com/en-us/windows/win32/api/xinput/ns-xinput-xinput_gamepad // NOTE: Analog buttons use dedicated field rather than being part of dButtons #define XINPUT_GAMEPAD_DPAD_UP 0x0001 @@ -118,53 +132,45 @@ void Window_RequestClose(void) { #define XINPUT_GAMEPAD_LEFT_THUMB 0x0040 #define XINPUT_GAMEPAD_RIGHT_THUMB 0x0080 -static void HandleButtons(xid_gamepad_in* gp) { +static void HandleButtons(int port, xid_gamepad_in* gp) { int mods = gp->dButtons; - Gamepad_SetButton(CCPAD_L, gp->l > 0x7F); - Gamepad_SetButton(CCPAD_R, gp->r > 0x7F); - Gamepad_SetButton(CCPAD_ZL, gp->white > 0x7F); - Gamepad_SetButton(CCPAD_ZR, gp->black > 0x7F); + Gamepad_SetButton(port, CCPAD_L, gp->l > 0x7F); + Gamepad_SetButton(port, CCPAD_R, gp->r > 0x7F); + Gamepad_SetButton(port, CCPAD_ZL, gp->white > 0x7F); + Gamepad_SetButton(port, CCPAD_ZR, gp->black > 0x7F); - Gamepad_SetButton(CCPAD_A, gp->a > 0x7F); - Gamepad_SetButton(CCPAD_B, gp->b > 0x7F); - Gamepad_SetButton(CCPAD_X, gp->x > 0x7F); - Gamepad_SetButton(CCPAD_Y, gp->y > 0x7F); + Gamepad_SetButton(port, CCPAD_A, gp->a > 0x7F); + Gamepad_SetButton(port, CCPAD_B, gp->b > 0x7F); + Gamepad_SetButton(port, CCPAD_X, gp->x > 0x7F); + Gamepad_SetButton(port, CCPAD_Y, gp->y > 0x7F); - Gamepad_SetButton(CCPAD_START, mods & XINPUT_GAMEPAD_START); - Gamepad_SetButton(CCPAD_SELECT, mods & XINPUT_GAMEPAD_BACK); - Gamepad_SetButton(CCPAD_LSTICK, mods & XINPUT_GAMEPAD_LEFT_THUMB); - Gamepad_SetButton(CCPAD_RSTICK, mods & XINPUT_GAMEPAD_RIGHT_THUMB); + Gamepad_SetButton(port, CCPAD_START, mods & XINPUT_GAMEPAD_START); + Gamepad_SetButton(port, CCPAD_SELECT, mods & XINPUT_GAMEPAD_BACK); + Gamepad_SetButton(port, CCPAD_LSTICK, mods & XINPUT_GAMEPAD_LEFT_THUMB); + Gamepad_SetButton(port, CCPAD_RSTICK, mods & XINPUT_GAMEPAD_RIGHT_THUMB); - Gamepad_SetButton(CCPAD_LEFT, mods & XINPUT_GAMEPAD_DPAD_LEFT); - Gamepad_SetButton(CCPAD_RIGHT, mods & XINPUT_GAMEPAD_DPAD_RIGHT); - Gamepad_SetButton(CCPAD_UP, mods & XINPUT_GAMEPAD_DPAD_UP); - Gamepad_SetButton(CCPAD_DOWN, mods & XINPUT_GAMEPAD_DPAD_DOWN); + Gamepad_SetButton(port, CCPAD_LEFT, mods & XINPUT_GAMEPAD_DPAD_LEFT); + Gamepad_SetButton(port, CCPAD_RIGHT, mods & XINPUT_GAMEPAD_DPAD_RIGHT); + Gamepad_SetButton(port, CCPAD_UP, mods & XINPUT_GAMEPAD_DPAD_UP); + Gamepad_SetButton(port, CCPAD_DOWN, mods & XINPUT_GAMEPAD_DPAD_DOWN); } #define AXIS_SCALE 8192.0f -static void HandleJoystick(int axis, int x, int y, double delta) { +static void HandleJoystick(int port, int axis, int x, int y, float delta) { if (Math_AbsI(x) <= 512) x = 0; if (Math_AbsI(y) <= 512) y = 0; - Gamepad_SetAxis(axis, x / AXIS_SCALE, -y / AXIS_SCALE, delta); + Gamepad_SetAxis(port, axis, x / AXIS_SCALE, -y / AXIS_SCALE, delta); } -void Window_ProcessEvents(double delta) { - Input.JoystickMovement = false; - usbh_pooling_hubs(); +void Window_ProcessGamepads(float delta) { if (!xid_ctrl) return; - HandleButtons(&gp_state); - HandleJoystick(PAD_AXIS_LEFT, gp_state.leftStickX, gp_state.leftStickY, delta); - HandleJoystick(PAD_AXIS_RIGHT, gp_state.rightStickX, gp_state.rightStickY, delta); + HandleButtons(0, &gp_state); + HandleJoystick(0, PAD_AXIS_LEFT, gp_state.leftStickX, gp_state.leftStickY, delta); + HandleJoystick(0, PAD_AXIS_RIGHT, gp_state.rightStickX, gp_state.rightStickY, delta); } -void Cursor_SetPosition(int x, int y) { } // Makes no sense for Xbox - -void Window_EnableRawMouse(void) { Input.RawMode = true; } -void Window_DisableRawMouse(void) { Input.RawMode = false; } -void Window_UpdateRawMouse(void) { } - /*########################################################################################################################* *------------------------------------------------------Framebuffer--------------------------------------------------------* diff --git a/src/Window_Xbox360.c b/src/Window_Xbox360.c index aa9a475..5da252e 100644 --- a/src/Window_Xbox360.c +++ b/src/Window_Xbox360.c @@ -71,6 +71,20 @@ void Window_RequestClose(void) { /*########################################################################################################################* *----------------------------------------------------Input processing-----------------------------------------------------* *#########################################################################################################################*/ +void Window_ProcessEvents(float delta) { + usb_do_poll(); +} + +void Cursor_SetPosition(int x, int y) { } // Makes no sense for Xbox + +void Window_EnableRawMouse(void) { Input.RawMode = true; } +void Window_DisableRawMouse(void) { Input.RawMode = false; } +void Window_UpdateRawMouse(void) { } + + +/*########################################################################################################################* +*-------------------------------------------------------Gamepads----------------------------------------------------------* +*#########################################################################################################################*/ /* struct controller_data_s { @@ -81,40 +95,32 @@ struct controller_data_s }; */ -static void HandleButtons(struct controller_data_s* pad) { - Gamepad_SetButton(CCPAD_L, pad->lb); - Gamepad_SetButton(CCPAD_R, pad->rb); +static void HandleButtons(int port, struct controller_data_s* pad) { + Gamepad_SetButton(port, CCPAD_L, pad->lb); + Gamepad_SetButton(port, CCPAD_R, pad->rb); - Gamepad_SetButton(CCPAD_A, pad->a); - Gamepad_SetButton(CCPAD_B, pad->b); - Gamepad_SetButton(CCPAD_X, pad->x); - Gamepad_SetButton(CCPAD_Y, pad->y); + Gamepad_SetButton(port, CCPAD_A, pad->a); + Gamepad_SetButton(port, CCPAD_B, pad->b); + Gamepad_SetButton(port, CCPAD_X, pad->x); + Gamepad_SetButton(port, CCPAD_Y, pad->y); - Gamepad_SetButton(CCPAD_START, pad->start); - Gamepad_SetButton(CCPAD_SELECT, pad->back); + Gamepad_SetButton(port, CCPAD_START, pad->start); + Gamepad_SetButton(port, CCPAD_SELECT, pad->back); - Gamepad_SetButton(CCPAD_LEFT, pad->left); - Gamepad_SetButton(CCPAD_RIGHT, pad->right); - Gamepad_SetButton(CCPAD_UP, pad->up); - Gamepad_SetButton(CCPAD_DOWN, pad->down); + Gamepad_SetButton(port, CCPAD_LEFT, pad->left); + Gamepad_SetButton(port, CCPAD_RIGHT, pad->right); + Gamepad_SetButton(port, CCPAD_UP, pad->up); + Gamepad_SetButton(port, CCPAD_DOWN, pad->down); } -void Window_ProcessEvents(double delta) { - usb_do_poll(); - +void Window_ProcessGamepads(float delta) { struct controller_data_s pad; - int res = get_controller_data(&pad, 0); - if (res == 0) return; - - HandleButtons(&pad); + int res = get_controller_data(&pad, 0); + if (res == 0) return; + + HandleButtons(0, &pad); } -void Cursor_SetPosition(int x, int y) { } // Makes no sense for Xbox - -void Window_EnableRawMouse(void) { Input.RawMode = true; } -void Window_DisableRawMouse(void) { Input.RawMode = false; } -void Window_UpdateRawMouse(void) { } - /*########################################################################################################################* *------------------------------------------------------Framebuffer--------------------------------------------------------* diff --git a/src/_GLShared.h b/src/_GLShared.h index 99fbb77..bc0b470 100644 --- a/src/_GLShared.h +++ b/src/_GLShared.h @@ -215,10 +215,10 @@ void Gfx_CalcOrthoMatrix(struct Matrix* matrix, float width, float height, float matrix->row4.z = -(zFar + zNear) / (zFar - zNear); } -static double Cotangent(double x) { return Math_Cos(x) / Math_Sin(x); } +static float Cotangent(float x) { return Math_CosF(x) / Math_SinF(x); } void Gfx_CalcPerspectiveMatrix(struct Matrix* matrix, float fov, float aspect, float zFar) { float zNear = 0.1f; - float c = (float)Cotangent(0.5f * fov); + float c = Cotangent(0.5f * fov); /* Transposed, source https://learn.microsoft.com/en-us/windows/win32/opengl/glfrustum */ /* For a FOV based perspective matrix, left/right/top/bottom are calculated as: */ @@ -325,7 +325,7 @@ void Gfx_EndFrame(void) { } void Gfx_OnWindowResize(void) { - glViewport(0, 0, Game.Width, Game.Height); + Gfx_SetViewport(0, 0, Game.Width, Game.Height); /* With cocoa backend, in some cases [NSOpenGLContext update] will actually */ /* call glViewport with the size of the window framebuffer */ /* https://github.com/glfw/glfw/issues/80 */ @@ -335,3 +335,7 @@ void Gfx_OnWindowResize(void) { /* https://github.com/ClassiCube/ClassiCube/issues/888 */ GLContext_Update(); } + +void Gfx_SetViewport(int x, int y, int w, int h) { + glViewport(x, y, w, h); +} diff --git a/src/_PlatformBase.h b/src/_PlatformBase.h index f6889ce..d2b9e0b 100644 --- a/src/_PlatformBase.h +++ b/src/_PlatformBase.h @@ -2,6 +2,7 @@ #include "String.h" #include "Logger.h" #include "Constants.h" +#include "Errors.h" cc_bool Platform_ReadonlyFilesystem; /*########################################################################################################################* @@ -89,6 +90,21 @@ int Stopwatch_ElapsedMS(cc_uint64 beg, cc_uint64 end) { return (int)raw / 1000; } +cc_result Socket_WriteAll(cc_socket socket, const cc_uint8* data, cc_uint32 count) { + cc_uint32 sent; + cc_result res; + + while (count) + { + if ((res = Socket_Write(socket, data, count, &sent))) return res; + if (!sent) return ERR_END_OF_STREAM; + + data += sent; + count -= sent; + } + return 0; +} + /*########################################################################################################################* *-------------------------------------------------------Dynamic lib-------------------------------------------------------* diff --git a/src/interop_BeOS.cpp b/src/interop_BeOS.cpp index 3cdaaf3..20fc57a 100644 --- a/src/interop_BeOS.cpp +++ b/src/interop_BeOS.cpp @@ -574,7 +574,7 @@ static int MapNativeKey(int raw) { return key; } -void Window_ProcessEvents(double delta) { +void Window_ProcessEvents(float delta) { CCEvent event; int key; @@ -628,6 +628,8 @@ void Window_ProcessEvents(double delta) { } } +void Window_ProcessGamepads(float delta) { } + static void Cursor_GetRawPos(int* x, int* y) { BPoint where; uint32 buttons; diff --git a/src/interop_cocoa.m b/src/interop_cocoa.m index c42bd13..7e1b36b 100644 --- a/src/interop_cocoa.m +++ b/src/interop_cocoa.m @@ -486,7 +486,7 @@ static void DebugScrollEvent(NSEvent* ev) { #endif } -void Window_ProcessEvents(double delta) { +void Window_ProcessEvents(float delta) { NSEvent* ev; int key, type, steps, x, y; float dy; @@ -568,6 +568,8 @@ void Window_ProcessEvents(double delta) { } } +void Window_ProcessGamepads(float delta) { } + /*########################################################################################################################* *-----------------------------------------------------------Dialogs-------------------------------------------------------* diff --git a/src/interop_ios.m b/src/interop_ios.m index 5089926..0ae0c0d 100644 --- a/src/interop_ios.m +++ b/src/interop_ios.m @@ -44,6 +44,7 @@ @interface CCAppDelegate : UIResponder static CCViewController* cc_controller; static UIWindow* win_handle; static UIView* view_handle; +static cc_bool launcherMode; static void AddTouch(UITouch* t) { CGPoint loc = [t locationInView:view_handle]; @@ -75,7 +76,7 @@ static UIInterfaceOrientationMask SupportedOrientations(void) { static cc_bool fullscreen = true; static void UpdateStatusBar(void) { - if ([cc_controller respondsToSelector:@selector(setNeedsStatusBarAppearanceUpdate)]) { + if (@available(iOS 10.7, *)) { // setNeedsStatusBarAppearanceUpdate - iOS 7.0 [cc_controller setNeedsStatusBarAppearanceUpdate]; } else { @@ -93,6 +94,9 @@ @implementation CCWindow - (void)touchesBegan:(NSSet*)touches withEvent:(UIEvent *)event { // touchesBegan:withEvent - iOS 2.0 for (UITouch* t in touches) AddTouch(t); + + // clicking on the background should dismiss onscren keyboard + if (launcherMode) { [view_handle endEditing:NO]; } } - (void)touchesMoved:(NSSet*)touches withEvent:(UIEvent *)event { @@ -485,7 +489,7 @@ void Window_RequestClose(void) { Event_RaiseVoid(&WindowEvents.Closing); } -void Window_ProcessEvents(double delta) { +void Window_ProcessEvents(float delta) { SInt32 res; // manually tick event queue do { @@ -493,6 +497,8 @@ void Window_ProcessEvents(double delta) { } while (res == kCFRunLoopRunHandledSource); } +void Window_ProcessGamepads(float delta) { } + void ShowDialogCore(const char* title, const char* msg) { // UIAlertController - iOS 8.0 // UIAlertAction - iOS 8.0 @@ -503,16 +509,16 @@ void ShowDialogCore(const char* title, const char* msg) { NSString* _msg = [NSString stringWithCString:msg encoding:NSASCIIStringEncoding]; alert_completed = false; -#ifdef TARGET_OS_TV - UIAlertController* alert = [UIAlertController alertControllerWithTitle:_title message:_msg preferredStyle:UIAlertControllerStyleAlert]; - UIAlertAction* okBtn = [UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:^(UIAlertAction* act) { alert_completed = true; }]; - [alert addAction:okBtn]; - [cc_controller presentViewController:alert animated:YES completion: Nil]; -#else - UIAlertView* alert = [UIAlertView alloc]; - alert = [alert initWithTitle:_title message:_msg delegate:cc_controller cancelButtonTitle:@"OK" otherButtonTitles:nil]; - [alert show]; -#endif + if (@available(iOS 10.8, *)) { + UIAlertController* alert = [UIAlertController alertControllerWithTitle:_title message:_msg preferredStyle:UIAlertControllerStyleAlert]; + UIAlertAction* okBtn = [UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:^(UIAlertAction* act) { alert_completed = true; }]; + [alert addAction:okBtn]; + [cc_controller presentViewController:alert animated:YES completion: Nil]; + } else { + UIAlertView* alert = [UIAlertView alloc]; + alert = [alert initWithTitle:_title message:_msg delegate:cc_controller cancelButtonTitle:@"OK" otherButtonTitles:nil]; + [alert show]; + } // TODO clicking outside message box crashes launcher // loop until alert is closed TODO avoid sleeping @@ -645,15 +651,18 @@ cc_result Window_OpenFileDialog(const struct OpenFileDialogArgs* args) { if (utType) [types addObject:utType]; } - UIDocumentPickerViewController* dlg; - dlg = [UIDocumentPickerViewController alloc]; - dlg = [dlg initWithDocumentTypes:types inMode:UIDocumentPickerModeOpen]; - //dlg = [dlg initWithDocumentTypes:types inMode:UIDocumentPickerModeImport]; - - open_dlg_callback = args->Callback; - dlg.delegate = cc_controller; - [cc_controller presentViewController:dlg animated:YES completion: Nil]; - return 0; // TODO still unfinished + if (@available(iOS 10.8, *)) { + UIDocumentPickerViewController* dlg; + dlg = [UIDocumentPickerViewController alloc]; + dlg = [dlg initWithDocumentTypes:types inMode:UIDocumentPickerModeOpen]; + //dlg = [dlg initWithDocumentTypes:types inMode:UIDocumentPickerModeImport]; + + open_dlg_callback = args->Callback; + dlg.delegate = cc_controller; + [cc_controller presentViewController:dlg animated:YES completion: Nil]; + return 0; // TODO still unfinished + } + return ERR_NOT_SUPPORTED; } cc_result Window_SaveFileDialog(const struct SaveFileDialogArgs* args) { @@ -671,13 +680,16 @@ cc_result Window_SaveFileDialog(const struct SaveFileDialogArgs* args) { NSString* str = ToNSString(&save_path); NSURL* url = [NSURL fileURLWithPath:str isDirectory:NO]; - UIDocumentPickerViewController* dlg; - dlg = [UIDocumentPickerViewController alloc]; - dlg = [dlg initWithURL:url inMode:UIDocumentPickerModeExportToService]; - - dlg.delegate = cc_controller; - [cc_controller presentViewController:dlg animated:YES completion: Nil]; - return 0; + if (@available(iOS 10.8, *)) { + UIDocumentPickerViewController* dlg; + dlg = [UIDocumentPickerViewController alloc]; + dlg = [dlg initWithURL:url inMode:UIDocumentPickerModeExportToService]; + + dlg.delegate = cc_controller; + [cc_controller presentViewController:dlg animated:YES completion: Nil]; + return 0; // TODO still unfinished + } + return ERR_NOT_SUPPORTED; } @@ -685,6 +697,7 @@ cc_result Window_SaveFileDialog(const struct SaveFileDialogArgs* args) { *--------------------------------------------------------2D window--------------------------------------------------------* *#########################################################################################################################*/ void Window_Create2D(int width, int height) { + launcherMode = true; CGRect bounds = DoCreateWindow(); view_handle = [[UIView alloc] initWithFrame:bounds]; @@ -714,8 +727,10 @@ - (void)layoutSubviews { @end void Window_Create3D(int width, int height) { - // CAEAGLLayer - iOS 2.0 + launcherMode = false; CGRect bounds = DoCreateWindow(); + + // CAEAGLLayer - iOS 2.0 view_handle = [[CCGLView alloc] initWithFrame:bounds]; view_handle.multipleTouchEnabled = true; cc_controller.view = view_handle; @@ -1676,17 +1691,6 @@ void LBackend_TableUpdate(struct LTable* w) { [tbl reloadData]; } -// TODO only redraw flags -void LBackend_TableFlagAdded(struct LTable* w) { - UITableView* tbl = (__bridge UITableView*)w->meta; - - // trying to update cell.imageView.image doesn't seem to work, - // so pointlessly reload entire table data instead - NSIndexPath* selected = [tbl indexPathForSelectedRow]; - [tbl reloadData]; - [tbl selectRowAtIndexPath:selected animated:NO scrollPosition:UITableViewScrollPositionNone]; -} - void LBackend_TableDraw(struct LTable* w) { } void LBackend_TableReposition(struct LTable* w) { } void LBackend_TableMouseDown(struct LTable* w, int idx) { } @@ -1694,7 +1698,7 @@ void LBackend_TableMouseUp(struct LTable* w, int idx) { } void LBackend_TableMouseMove(struct LTable* w, int idx) { } static void LTable_UpdateCellColor(UIView* view, struct ServerInfo* server, int row, cc_bool selected) { - BitmapCol color = LTable_RowColor(server, row, selected); + BitmapCol color = LTable_RowColor(row, selected, server && server->featured); if (color) { view.backgroundColor = ToUIColor(color, 1.0f); view.opaque = YES; @@ -1714,10 +1718,6 @@ static void LTable_UpdateCell(UITableView* table, UITableViewCell* cell, int row LTable_FormatUptime(&desc, server->uptime); if (server->software.length) String_Format1(&desc, " | %s", &server->software); - if (flag && !flag->meta && flag->bmp.scan0) { - UIImage* img = ToUIImage(&flag->bmp); - flag->meta = CFBridgingRetain(img); - } if (flag && flag->meta) cell.imageView.image = (__bridge UIImage*)flag->meta; @@ -1732,9 +1732,33 @@ static void LTable_UpdateCell(UITableView* table, UITableViewCell* cell, int row LTable_UpdateCellColor(cell, server, row, selected); } +// TODO only redraw flags +static void OnFlagsChanged(void) { + struct LScreen* s = Launcher_Active; + for (int i = 0; i < s->numWidgets; i++) + { + if (s->widgets[i]->type != LWIDGET_TABLE) continue; + UITableView* tbl = (__bridge UITableView*)s->widgets[i]->meta; + + // trying to update cell.imageView.image doesn't seem to work, + // so pointlessly reload entire table data instead + NSIndexPath* selected = [tbl indexPathForSelectedRow]; + [tbl reloadData]; + [tbl selectRowAtIndexPath:selected animated:NO scrollPosition:UITableViewScrollPositionNone]; + } +} + /*########################################################################################################################* *------------------------------------------------------UI Backend--------------------------------------------------------* *#########################################################################################################################*/ +void LBackend_DecodeFlag(struct Flag* flag, cc_uint8* data, cc_uint32 len) { + NSData* ns_data = [NSData dataWithBytes:data length:len]; + UIImage* img = [UIImage imageWithData:ns_data]; + if (!img) return; + + flag->meta = CFBridgingRetain(img); + OnFlagsChanged(); +} static void LBackend_LayoutDimensions(struct LWidget* w, CGRect* r) { const struct LLayout* l = w->layouts + 2;