Cleaned Up AppPlatform & Input Classes

* Cleaned up AppPlatform classes
* Documented & improved Keyboard & Mouse classes
* Improved input-handling code in the Windows & SDL main.cpp files
This commit is contained in:
Brent Da Mage
2023-08-19 06:26:50 -05:00
committed by iProgramInCpp
parent e731fefbea
commit d5ee7bfc08
21 changed files with 422 additions and 375 deletions

View File

@@ -13,28 +13,6 @@ AppPlatform_sdl::AppPlatform_sdl(std::string storageDir, SDL_Window *window)
{
}
// Ensure Screenshots Folder Exists
void ensure_screenshots_folder(const char *screenshots)
{
// Check Screenshots Folder
struct stat obj;
if (stat(screenshots, &obj) != 0 || !S_ISDIR(obj.st_mode))
{
// Create Screenshots Folder
#ifdef _WIN32
int ret = mkdir(screenshots);
#else
int ret = mkdir(screenshots, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
#endif
if (ret != 0)
{
// Unable To Create Folder
LogMsg("Error Creating Directory: %s: %s", screenshots, strerror(errno));
exit(EXIT_FAILURE);
}
}
}
// Take Screenshot
static int save_png(const char *filename, unsigned char *pixels, int line_size, int width, int height)
{
@@ -110,6 +88,28 @@ ret:
return ret;
}
// Ensure Screenshots Folder Exists
void AppPlatform_sdl::ensureDirectoryExists(const char* path)
{
// Check Screenshots Folder
struct stat obj;
if (stat(screenshots, &obj) != 0 || !S_ISDIR(obj.st_mode))
{
// Create Screenshots Folder
#ifdef _WIN32
int ret = mkdir(screenshots);
#else
int ret = mkdir(screenshots, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
#endif
if (ret != 0)
{
// Unable To Create Folder
LogMsg("Error Creating Directory: %s: %s", screenshots, strerror(errno));
exit(EXIT_FAILURE);
}
}
}
void AppPlatform_sdl::saveScreenshot(const std::string& filename, int glWidth, int glHeight)
{
// Get Directory

View File

@@ -2,12 +2,8 @@
#include <string>
#include <SDL2/SDL.h>
#include "AppPlatform_sdlbase.hpp"
void ensure_screenshots_folder(const char *screenshots);
class AppPlatform_sdl : public AppPlatform_sdlbase
{
public:
@@ -15,4 +11,6 @@ public:
void saveScreenshot(const std::string& fileName, int width, int height) override;
Texture loadTexture(const std::string& path, bool b = false) override;
protected:
void ensureDirectoryExists(const char* path) override;
};

View File

@@ -7,8 +7,6 @@
#ifdef __EMSCRIPTEN__
#include <emscripten.h>
#else
#include <png.h>
#include "compat/GL.hpp"
#endif
@@ -24,6 +22,8 @@ void AppPlatform_sdlbase::_init(std::string storageDir, SDL_Window *window)
m_bShiftPressed[0] = false;
m_bShiftPressed[1] = false;
ensureDirectoryExists(_storageDir.c_str());
}
void AppPlatform_sdlbase::_init(std::string storageDir, SDL_Window *window, const Texture& icon)
@@ -68,6 +68,11 @@ int AppPlatform_sdlbase::checkLicense()
return 1;
}
const char* const AppPlatform_sdlbase::getWindowTitle() const
{
return SDL_GetWindowTitle(_window);
}
int AppPlatform_sdlbase::getScreenWidth() const
{
int width;
@@ -120,3 +125,65 @@ int AppPlatform_sdlbase::getUserInputStatus()
{
return -1;
}
Mouse::ButtonType AppPlatform_sdlbase::GetMouseButtonType(SDL_Event event)
{
switch (event.button.button)
{
case SDL_BUTTON_LEFT:
return Mouse::ButtonType::LEFT;
case SDL_BUTTON_RIGHT:
return Mouse::ButtonType::RIGHT;
case SDL_BUTTON_MIDDLE:
return Mouse::ButtonType::MIDDLE;
default:
return Mouse::ButtonType::NONE;
}
}
Mouse::ButtonState AppPlatform_sdlbase::GetMouseButtonState(SDL_Event event)
{
Mouse::ButtonState result;
switch (event.type)
{
case SDL_MOUSEBUTTONDOWN:
result = Mouse::ButtonState::DOWN;
break;
case SDL_MOUSEBUTTONUP:
result = Mouse::ButtonState::UP;
break;
case SDL_MOUSEWHEEL:
{
short wheelDelta = event.wheel.y;
if (wheelDelta > 0)
{
// "A positive value indicates that the wheel was rotated forward, away from the user."
result = Mouse::ButtonState::UP;
}
else
{
// "A negative value indicates that the wheel was rotated backward, toward the user."
result = Mouse::ButtonState::DOWN;
}
break;
}
default:
result = Mouse::ButtonState::UP;
break;
}
return result;
}
Keyboard::KeyState AppPlatform_sdlbase::GetKeyState(SDL_Event event)
{
switch (event.key.state)
{
case SDL_RELEASED:
return Keyboard::KeyState::UP;
case SDL_PRESSED:
default:
return Keyboard::KeyState::DOWN;
}
}

View File

@@ -1,16 +1,12 @@
#pragma once
#include <string>
#include <SDL2/SDL.h>
#include "AppPlatform.hpp"
#ifdef ORIGINAL_CODE
#error "This isn't original code. You probably shouldn't try to compile this"
#endif
void ensure_screenshots_folder(const char *screenshots);
#include "client/player/input/Mouse.hpp"
#include "client/player/input/Keyboard.hpp"
class AppPlatform_sdlbase : public AppPlatform
{
@@ -28,6 +24,7 @@ public:
~AppPlatform_sdlbase();
int checkLicense() override;
const char* const getWindowTitle() const;
int getScreenWidth() const override;
int getScreenHeight() const override;
Texture loadTexture(const std::string& path, bool b = false) override = 0;
@@ -42,6 +39,10 @@ public:
// Also add these to allow proper text input within the game.
bool shiftPressed() override;
void setShiftPressed(bool b, bool isLeft);
static Mouse::ButtonType GetMouseButtonType(SDL_Event event);
static Mouse::ButtonState GetMouseButtonState(SDL_Event event);
static Keyboard::KeyState GetKeyState(SDL_Event event);
private:
SDL_Window *_window;
@@ -56,4 +57,6 @@ private:
static SDL_Surface* getSurfaceForTexture(const Texture* const texture);
protected:
std::string _storageDir;
virtual void ensureDirectoryExists(const char* path) { }
};

View File

@@ -3,15 +3,16 @@
#include <SDL2/SDL.h>
#include "compat/GL.hpp"
#include "compat/AKeyCodes.hpp"
#include "App.hpp"
#ifdef __EMSCRIPTEN__
#if defined(__EMSCRIPTEN__)
#include "../emscripten/AppPlatform_emscripten.hpp"
typedef AppPlatform_emscripten UsedAppPlatform;
#else
#include "AppPlatform_sdl.hpp"
typedef AppPlatform_sdl UsedAppPlatform;
#endif
#include "NinecraftApp.hpp"
#ifdef __EMSCRIPTEN__
@@ -82,6 +83,7 @@ static void handle_events()
case SDL_KEYDOWN:
case SDL_KEYUP:
{
// TODO: Shouldn't we be handling this in Keyboard?
if (event.key.keysym.sym == SDLK_F2)
{
if (event.key.state == SDL_PRESSED && g_pAppPlatform != nullptr)
@@ -90,7 +92,7 @@ static void handle_events()
}
break;
}
Keyboard::feed(event.key.state == SDL_PRESSED ? 1 : 0, translate_sdl_key_to_mcpe(event.key.keysym.sym));
Keyboard::feed(AppPlatform_sdlbase::GetKeyState(event), translate_sdl_key_to_mcpe(event.key.keysym.sym));
if (event.key.keysym.sym == SDLK_LSHIFT || event.key.keysym.sym == SDLK_RSHIFT)
{
g_pAppPlatform->setShiftPressed(event.key.state == SDL_PRESSED, event.key.keysym.sym == SDLK_LSHIFT);
@@ -100,8 +102,8 @@ static void handle_events()
case SDL_MOUSEBUTTONDOWN:
case SDL_MOUSEBUTTONUP:
{
float scale = g_fPointToPixelScale;
Mouse::feed(event.button.button == SDL_BUTTON_LEFT ? 1 : 2, event.button.state == SDL_PRESSED ? 1 : 0, event.button.x * scale, event.button.y * scale);
const float scale = g_fPointToPixelScale;
Mouse::feed(AppPlatform_sdlbase::GetMouseButtonType(event), AppPlatform_sdlbase::GetMouseButtonState(event), event.button.x * scale, event.button.y * scale);
break;
}
case SDL_MOUSEMOTION:
@@ -109,14 +111,13 @@ static void handle_events()
float scale = g_fPointToPixelScale;
float x = event.motion.x * scale;
float y = event.motion.y * scale;
Mouse::setX(x); Mouse::setY(y);
Mouse::feed(0, 0, x, y);
g_pAppPlatform->setMouseDiff(event.motion.xrel * scale, event.motion.yrel * scale);
Mouse::feed(Mouse::ButtonType::NONE, Mouse::ButtonState::UP, x, y);
g_AppPlatform->setMouseDiff(event.motion.xrel * scale, event.motion.yrel * scale);
break;
}
case SDL_MOUSEWHEEL:
{
Mouse::feed(3, event.wheel.y * g_fPointToPixelScale, Mouse::getX(), Mouse::getY());
Mouse::feed(Mouse::ButtonType::MIDDLE, AppPlatform_sdlbase::GetMouseButtonState(event), Mouse::getX(), Mouse::getY());
break;
}
case SDL_TEXTINPUT:
@@ -308,9 +309,6 @@ int main(int argc, char *argv[])
storagePath = getenv("HOME");
#endif
storagePath += "/.reminecraftpe";
#ifndef __EMSCRIPTEN__
ensure_screenshots_folder(storagePath.c_str());
#endif
// Start MCPE
g_pApp = new NinecraftApp;

View File

@@ -12,15 +12,16 @@
#include <shlobj.h>
#include "AppPlatform_windows.hpp"
#include "client/player/input/Mouse.hpp"
#include "thirdparty/stb_image.h"
#include "thirdparty/stb_image_write.h"
extern LPCTSTR g_GameTitle;
AppPlatform_windows::AppPlatform_windows()
{
m_WindowTitle = "ReMinecraftPE";
// just assume an 854x480 window for now:
m_ScreenWidth = C_DEFAULT_SCREEN_WIDTH;
m_ScreenHeight = C_DEFAULT_SCREEN_HEIGHT;
m_UserInputStatus = -1;
m_bIsFocused = false;
@@ -32,13 +33,6 @@ AppPlatform_windows::AppPlatform_windows()
m_MouseDiffX = 0, m_MouseDiffY = 0;
}
void AppPlatform_windows::initConsts()
{
// just assume an 854x480 window for now:
m_ScreenWidth = C_DEFAULT_SCREEN_WIDTH;
m_ScreenHeight = C_DEFAULT_SCREEN_HEIGHT;
}
int AppPlatform_windows::checkLicense()
{
// we own the game!!
@@ -47,7 +41,7 @@ int AppPlatform_windows::checkLicense()
void AppPlatform_windows::buyGame()
{
MessageBox(GetHWND(), TEXT("Buying the game!"), g_GameTitle, MB_OK | MB_ICONINFORMATION);
MessageBox(GetHWND(), TEXT("Buying the game!"), getWindowTitle(), MB_OK | MB_ICONINFORMATION);
}
void AppPlatform_windows::saveScreenshot(const std::string& fileName, int width, int height)
@@ -93,26 +87,6 @@ void AppPlatform_windows::saveScreenshot(const std::string& fileName, int width,
delete[] pixels;
}
int AppPlatform_windows::getScreenWidth() const
{
return m_ScreenWidth;
}
int AppPlatform_windows::getScreenHeight() const
{
return m_ScreenHeight;
}
std::vector<std::string> AppPlatform_windows::getUserInput()
{
return m_UserInput;
}
int AppPlatform_windows::getUserInputStatus()
{
return m_UserInputStatus;
}
void AppPlatform_windows::createUserInput()
{
m_UserInput.clear();
@@ -167,7 +141,7 @@ Texture AppPlatform_windows::loadTexture(const std::string& str, bool b)
_error:
const std::string msg = "Error loading " + realPath + ". Did you unzip the Minecraft assets?";
MessageBoxA(GetHWND(), msg.c_str(), g_GameTitle, MB_OK);
MessageBoxA(GetHWND(), msg.c_str(), getWindowTitle(), MB_OK);
if (f)
fclose(f);
@@ -196,9 +170,6 @@ std::vector<std::string> AppPlatform_windows::getOptionStrings()
{
std::vector<std::string> o;
//o.push_back("mp_username");
//o.push_back("iProgramInCpp");
std::ifstream ifs("options.txt");
if (!ifs.is_open())
return o;
@@ -360,12 +331,67 @@ void AppPlatform_windows::updateFocused(bool focused)
setMouseGrabbed(m_bGrabbedMouse);
}
bool AppPlatform_windows::shiftPressed()
Mouse::ButtonType AppPlatform_windows::GetMouseButtonType(UINT iMsg)
{
return m_bShiftPressed;
switch (iMsg)
{
case WM_LBUTTONUP:
case WM_LBUTTONDOWN:
return Mouse::ButtonType::LEFT;
case WM_RBUTTONUP:
case WM_RBUTTONDOWN:
return Mouse::ButtonType::RIGHT;
case WM_MBUTTONUP:
case WM_MBUTTONDOWN:
case WM_MOUSEWHEEL:
return Mouse::ButtonType::MIDDLE;
default:
return Mouse::ButtonType::NONE;
}
}
void AppPlatform_windows::setShiftPressed(bool b)
Mouse::ButtonState AppPlatform_windows::GetMouseButtonState(UINT iMsg, WPARAM wParam)
{
m_bShiftPressed = b;
Mouse::ButtonState result;
switch (iMsg)
{
case WM_LBUTTONDOWN:
case WM_RBUTTONDOWN:
case WM_MBUTTONDOWN:
result = Mouse::ButtonState::DOWN;
break;
case WM_MOUSEWHEEL:
{
short wheelDelta = GET_WHEEL_DELTA_WPARAM(wParam);
if (wheelDelta > 0)
{
// "A positive value indicates that the wheel was rotated forward, away from the user."
result = Mouse::ButtonState::UP;
}
else
{
// "A negative value indicates that the wheel was rotated backward, toward the user."
result = Mouse::ButtonState::DOWN;
}
break;
}
default:
result = Mouse::ButtonState::UP;
break;
}
return result;
}
Keyboard::KeyState AppPlatform_windows::GetKeyState(UINT iMsg)
{
switch (iMsg)
{
case WM_KEYUP:
return Keyboard::KeyState::UP;
case WM_KEYDOWN:
default:
return Keyboard::KeyState::DOWN;
}
}

View File

@@ -8,35 +8,31 @@
#pragma once
#include "compat/GL.hpp"
#include <ctime>
#include "compat/GL.hpp"
#include "AppPlatform.hpp"
#include "client/player/input/Mouse.hpp"
#include "client/player/input/Keyboard.hpp"
#include "common/Utils.hpp"
#ifdef ORIGINAL_CODE
#error "This isn't original code. You probably shouldn't try to compile this"
#endif
// note: probably won't add AppPlatform_android until it's time
// to build an Android app
class AppPlatform_windows : public AppPlatform
{
public:
AppPlatform_windows();
void initConsts();
void buyGame() override;
void saveScreenshot(const std::string& fileName, int width, int height) override;
int checkLicense() override;
void createUserInput() override;
std::vector<std::string> getUserInput() override;
int getUserInputStatus() override;
int getScreenWidth() const override;
int getScreenHeight() const override;
std::vector<std::string> getUserInput() override { return m_UserInput; }
int getUserInputStatus() override { return m_UserInputStatus; }
int getScreenWidth() const override { return m_ScreenWidth; }
int getScreenHeight() const override { return m_ScreenHeight; }
void showDialog(eDialogType) override;
std::string getDateString(int time) override;
Texture loadTexture(const std::string& str, bool b) override;
std::vector<std::string> getOptionStrings() override;
std::vector<std::string> getOptionStrings() override;
// Also add these to allow proper turning within the game.
void recenterMouse() override;
@@ -46,8 +42,8 @@ public:
void updateFocused(bool focused) override;
// Also add these to allow proper text input within the game.
bool shiftPressed() override;
void setShiftPressed(bool b);
bool shiftPressed() override { return m_bShiftPressed; }
void setShiftPressed(bool b) { m_bShiftPressed = b; }
// Also add these to allow saving options.
void setOptionStrings(const std::vector <std::string>& str) override;
@@ -56,8 +52,14 @@ public:
std::string getPatchData() override;
void setScreenSize(int width, int height);
const char* const getWindowTitle() const { return m_WindowTitle; }
static Mouse::ButtonType GetMouseButtonType(UINT iMsg);
static Mouse::ButtonState GetMouseButtonState(UINT iMsg, WPARAM wParam);
static Keyboard::KeyState GetKeyState(UINT iMsg);
private:
const char* m_WindowTitle;
int m_ScreenWidth;
int m_ScreenHeight;

View File

@@ -16,9 +16,11 @@
#include "AppPlatform_windows.hpp"
#include "NinecraftApp.hpp"
LPCTSTR g_GameTitle = TEXT("ReMinecraftPE");
LPCTSTR g_WindowClassName = TEXT("MCPEClass");
AppPlatform_windows g_AppPlatform;
NinecraftApp* g_pApp;
void LogMsg(const char* fmt, ...)
{
va_list lst;
@@ -58,18 +60,6 @@ void LogMsgNoCR(const char* fmt, ...)
va_end(lst);
}
AppPlatform_windows g_AppPlatform;
NinecraftApp* g_pApp;
bool g_LButtonDown, g_RButtonDown;
int g_MousePosX, g_MousePosY;
void UpdateMouse()
{
Mouse::setX(g_MousePosX);
Mouse::setY(g_MousePosY);
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
{
switch (iMsg)
@@ -85,69 +75,31 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
}
case WM_LBUTTONUP:
{
if (g_LButtonDown)
{
g_LButtonDown = false;
UpdateMouse();
Mouse::feed(1, 0, g_MousePosX, g_MousePosY);
}
break;
}
case WM_LBUTTONDOWN:
{
if (!g_LButtonDown)
{
g_LButtonDown = true;
UpdateMouse();
Mouse::feed(1, 1, g_MousePosX, g_MousePosY);
}
break;
}
case WM_RBUTTONUP:
{
if (g_RButtonDown)
{
g_RButtonDown = false;
UpdateMouse();
Mouse::feed(2, 0, g_MousePosX, g_MousePosY);
}
break;
}
case WM_RBUTTONDOWN:
{
if (!g_RButtonDown)
{
g_RButtonDown = true;
UpdateMouse();
Mouse::feed(2, 1, g_MousePosX, g_MousePosY);
}
break;
}
case WM_MBUTTONUP:
case WM_MBUTTONDOWN:
case WM_MOUSEMOVE:
case WM_MOUSEWHEEL:
{
int xPos = GET_X_LPARAM(lParam);
int yPos = GET_Y_LPARAM(lParam);
g_MousePosX = xPos;
g_MousePosY = yPos;
UpdateMouse();
Mouse::feed(0, 0, g_MousePosX, g_MousePosY);
Mouse::ButtonType buttonType = AppPlatform_windows::GetMouseButtonType(iMsg);
Mouse::ButtonState buttonState = AppPlatform_windows::GetMouseButtonState(iMsg, wParam);
int posX, posY;
if (iMsg == WM_MOUSEMOVE)
{
posX = GET_X_LPARAM(lParam);
posY = GET_Y_LPARAM(lParam);
}
else
{
posX = Mouse::getX();
posY = Mouse::getY();
}
Mouse::feed(buttonType, buttonState, posX, posY);
break;
}
#ifdef ENH_ALLOW_SCROLL_WHEEL
case WM_MOUSEWHEEL:
Mouse::feed(3, GET_WHEEL_DELTA_WPARAM(wParam), g_MousePosX, g_MousePosY);
break;
#endif
case WM_SIZE:
{
UINT width = LOWORD(lParam);
@@ -164,24 +116,20 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
break;
}
case WM_KEYUP:
case WM_KEYDOWN:
{
Keyboard::feed(1, int(wParam));
Keyboard::KeyState state = AppPlatform_windows::GetKeyState(iMsg);
Keyboard::feed(state, int(wParam));
if (wParam == VK_SHIFT)
g_AppPlatform.setShiftPressed(true);
g_AppPlatform.setShiftPressed(state == Keyboard::KeyState::DOWN);
break;
}
case WM_KEYUP:
{
Keyboard::feed(0, int(wParam));
if (wParam == VK_SHIFT)
g_AppPlatform.setShiftPressed(false);
break;
}
case WM_CHAR:
{
if (lParam & (1 << 31))
@@ -193,6 +141,7 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
g_pApp->handleCharInput(char(wParam));
break;
}
case WM_DESTROY:
PostQuitMessage(0);
return 0;
@@ -205,6 +154,7 @@ extern bool g_bAreCloudsAvailable; // client/renderer/LevelRenderer.cpp
void CheckOptionalTextureAvailability()
{
// TODO: These should be inside of an initialized "Minecraft" instance rather than the global namespace
// Optional features that you really should be able to get away with not including.
g_bIsMenuBackgroundAvailable = XPL_ACCESS("assets/gui/background/panorama_0.png", 0) == 0;
g_bAreCloudsAvailable = XPL_ACCESS("assets/environment/clouds.png", 0) == 0;
@@ -214,8 +164,6 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLin
{
SetInstance(hInstance);
g_AppPlatform.initConsts();
// register the window class:
WNDCLASS wc;
wc.style = CS_OWNDC;
@@ -238,11 +186,11 @@ int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLin
if (!RegisterClass(&wc))
{
MessageBox(NULL, TEXT("Could not register Minecraft class"), g_GameTitle, MB_ICONERROR | MB_OK);
MessageBox(NULL, TEXT("Could not register Minecraft class"), g_AppPlatform.getWindowTitle(), MB_ICONERROR | MB_OK);
return 1;
}
HWND hWnd = CreateWindowEx(0, g_WindowClassName, g_GameTitle, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, w, h, NULL, NULL, hInstance, g_pApp);
HWND hWnd = CreateWindowEx(0, g_WindowClassName, g_AppPlatform.getWindowTitle(), WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, w, h, NULL, NULL, hInstance, g_pApp);
CenterWindow(hWnd);
ShowWindow(hWnd, nCmdShow);
@@ -307,4 +255,4 @@ _cleanup:
delete g_pApp;
return 0;
}
}