mirror of
https://git.huckle.dev/Huckles-Minecraft-Archive/LCE-Revelations.git
synced 2026-05-25 08:55:49 +00:00
Before this change, turning VSync off did not actually uncap your frame rate. The game ran in borderless fullscreen, where Windows' desktop compositor owns the display pipeline and applies its own VSync regardless of what the game asks for. So on a 240Hz monitor with a GPU that could draw 800fps, you still only saw 240 frames per second and the other 560 were thrown away. Worse, the frames you did see were up to a refresh cycle stale by the time they hit your eyes, which is input latency you can feel when moving the camera or aiming. Fullscreen now uses true DXGI exclusive mode, where the compositor is out of the way and the swap chain writes directly to the display. Every frame the GPU produces lands on screen as soon as it is ready, so "VSync off" actually does something. Expect FPS to climb well past your monitor's refresh rate and the mouse to feel noticeably more responsive. Exclusive fullscreen also displays at your monitor's native resolution with no driver-side scaling or filtering. The backbuffer is grown to match the monitor exactly before the transition, and the display mode is pinned to the backbuffer size so nothing in the output pipeline resamples your pixels on the way to the screen. The result is a crisp 1:1 image with none of the softening or greyish filter that stretched output can introduce. Yes, this is the mode where screen tearing can happen. Tearing gets a bad reputation but it is a visual tradeoff, not a bug, and many players prefer it over the latency VSync causes. If you want to avoid tearing, just turn VSync on in the settings and the game will cap cleanly to your refresh rate. You now have a real choice between the two instead of "off" quietly being broken. Under the hood, F11 and the saved fullscreen preference both route through a new ApplyExclusiveFullscreen path that does Microsoft's recommended transition: grow the window to cover the monitor, ResizeTarget with no scaling so the display mode is pinned to the backbuffer size, SetFullscreenState(TRUE), SetColorSpace1(sRGB), then a second ResizeTarget so picky drivers actually apply the mode. Exit forces a real decorated windowed state so F11 cycles cleanly between windowed and exclusive fullscreen. ResizeD3D skips its swap-chain-recreate path while in exclusive mode so it does not fight DXGI for ownership. The swap chain's RefreshRate changes from a hardcoded 60Hz to 0/0 so DXGI matches the current display mode. Fixes an "input signal out of range" error that could happen on high-refresh monitors after entering fullscreen, where the monitor was being asked to renegotiate timing off of 240Hz down to 60Hz on every launch.
2382 lines
79 KiB
C++
2382 lines
79 KiB
C++
// Minecraft.cpp : Defines the entry point for the application.
|
|
//
|
|
|
|
#include "stdafx.h"
|
|
|
|
#include <dxgi1_4.h> // IDXGISwapChain3 for SetColorSpace1
|
|
|
|
#include <assert.h>
|
|
#include <iostream>
|
|
#include <ShellScalingApi.h>
|
|
#include <shellapi.h>
|
|
#include "GameConfig/Minecraft.spa.h"
|
|
#include "../MinecraftServer.h"
|
|
#include "../LocalPlayer.h"
|
|
#include "../../Minecraft.World/ItemInstance.h"
|
|
#include "../../Minecraft.World/MapItem.h"
|
|
#include "../../Minecraft.World/Recipes.h"
|
|
#include "../../Minecraft.World/Recipy.h"
|
|
#include "../../Minecraft.World/Language.h"
|
|
#include "../../Minecraft.World/StringHelpers.h"
|
|
#include "../../Minecraft.World/AABB.h"
|
|
#include "../../Minecraft.World/Vec3.h"
|
|
#include "../../Minecraft.World/Level.h"
|
|
#include "../../Minecraft.World/net.minecraft.world.level.tile.h"
|
|
|
|
#include "../ClientConnection.h"
|
|
#include "../Minecraft.h"
|
|
#include "../ChatScreen.h"
|
|
#include "KeyboardMouseInput.h"
|
|
#include "../User.h"
|
|
#include "../../Minecraft.World/Socket.h"
|
|
#include "../../Minecraft.World/ThreadName.h"
|
|
#include "../../Minecraft.Client/StatsCounter.h"
|
|
#include "../ConnectScreen.h"
|
|
//#include "Social/SocialManager.h"
|
|
//#include "Leaderboards/LeaderboardManager.h"
|
|
//#include "XUI/XUI_Scene_Container.h"
|
|
//#include "NetworkManager.h"
|
|
#include "../../Minecraft.Client/Tesselator.h"
|
|
#include "../../Minecraft.Client/Options.h"
|
|
#include "../Gui.h"
|
|
#include "Sentient/SentientManager.h"
|
|
#include "../../Minecraft.World/IntCache.h"
|
|
#include "../Textures.h"
|
|
#include "../Settings.h"
|
|
#include "Resource.h"
|
|
#include "../../Minecraft.World/compression.h"
|
|
#include "../../Minecraft.World/OldChunkStorage.h"
|
|
#include "Common/PostProcesser.h"
|
|
#include "../GameRenderer.h"
|
|
#include "Network/WinsockNetLayer.h"
|
|
#include "Windows64_Xuid.h"
|
|
#include "Common/UI/UI.h"
|
|
#include "stb_image_write.h"
|
|
|
|
// Forward-declare the internal Renderer class and its global instance from 4J_Render_PC_d.lib.
|
|
// C4JRender (RenderManager) is a stateless wrapper — all D3D state lives in InternalRenderManager.
|
|
class Renderer;
|
|
extern Renderer InternalRenderManager;
|
|
|
|
#include "Xbox/Resource.h"
|
|
|
|
#ifdef _MSC_VER
|
|
#pragma comment(lib, "legacy_stdio_definitions.lib")
|
|
#endif
|
|
|
|
HINSTANCE hMyInst;
|
|
LRESULT CALLBACK DlgProc(HWND hWndDlg, UINT Msg, WPARAM wParam, LPARAM lParam);
|
|
char chGlobalText[256];
|
|
uint16_t ui16GlobalText[256];
|
|
|
|
#define THEME_NAME "584111F70AAAAAAA"
|
|
#define THEME_FILESIZE 2797568
|
|
|
|
//#define THREE_MB 3145728 // minimum save size (checking for this on a selected device)
|
|
//#define FIVE_MB 5242880 // minimum save size (checking for this on a selected device)
|
|
//#define FIFTY_TWO_MB (1024*1024*52) // Maximum TCR space required for a save (checking for this on a selected device)
|
|
#define FIFTY_ONE_MB (1000000*51) // Maximum TCR space required for a save is 52MB (checking for this on a selected device)
|
|
|
|
//#define PROFILE_VERSION 3 // new version for the interim bug fix 166 TU
|
|
#define NUM_PROFILE_VALUES 5
|
|
#define NUM_PROFILE_SETTINGS 4
|
|
DWORD dwProfileSettingsA[NUM_PROFILE_VALUES]=
|
|
{
|
|
#ifdef _XBOX
|
|
XPROFILE_OPTION_CONTROLLER_VIBRATION,
|
|
XPROFILE_GAMER_YAXIS_INVERSION,
|
|
XPROFILE_GAMER_CONTROL_SENSITIVITY,
|
|
XPROFILE_GAMER_ACTION_MOVEMENT_CONTROL,
|
|
XPROFILE_TITLE_SPECIFIC1,
|
|
#else
|
|
0,0,0,0,0
|
|
#endif
|
|
};
|
|
//-------------------------------------------------------------------------------------
|
|
// Time Since fAppTime is a float, we need to keep the quadword app time
|
|
// as a LARGE_INTEGER so that we don't lose precision after running
|
|
// for a long time.
|
|
//-------------------------------------------------------------------------------------
|
|
|
|
BOOL g_bWidescreen = TRUE;
|
|
|
|
// Screen resolution — auto-detected from the monitor at startup.
|
|
// The 3D world renders at native resolution; Flash UI is 16:9-fitted and centered
|
|
// within each viewport (pillarboxed on ultrawide, letterboxed on tall displays).
|
|
// ApplyScreenMode() can still override these for debug/test resolutions via launch args.
|
|
int g_iScreenWidth = 1920;
|
|
int g_iScreenHeight = 1080;
|
|
|
|
// Real window dimensions — updated on every WM_SIZE so the 3D perspective
|
|
// always matches the current window, even after a resize.
|
|
int g_rScreenWidth = 1920;
|
|
int g_rScreenHeight = 1080;
|
|
static bool f3ComboUsed = false;
|
|
|
|
float g_iAspectRatio = static_cast<float>(g_iScreenWidth) / g_iScreenHeight;
|
|
static bool g_bResizeReady = false;
|
|
|
|
char g_Win64Username[17] = { 0 };
|
|
wchar_t g_Win64UsernameW[17] = { 0 };
|
|
|
|
// Fullscreen toggle state
|
|
static bool g_isFullscreen = false;
|
|
static WINDOWPLACEMENT g_wpPrev = { sizeof(g_wpPrev) };
|
|
|
|
struct Win64LaunchOptions
|
|
{
|
|
int screenMode;
|
|
bool fullscreen;
|
|
};
|
|
|
|
static void CopyWideArgToAnsi(LPCWSTR source, char* dest, size_t destSize)
|
|
{
|
|
if (destSize == 0)
|
|
return;
|
|
|
|
dest[0] = 0;
|
|
if (source == nullptr)
|
|
return;
|
|
|
|
WideCharToMultiByte(CP_ACP, 0, source, -1, dest, static_cast<int>(destSize), nullptr, nullptr);
|
|
dest[destSize - 1] = 0;
|
|
}
|
|
|
|
// ---------- Persistent options (options.txt next to exe) ----------
|
|
static void GetOptionsFilePath(char *out, size_t outSize)
|
|
{
|
|
GetModuleFileNameA(nullptr, out, static_cast<DWORD>(outSize));
|
|
char *p = strrchr(out, '\\');
|
|
if (p) *(p + 1) = '\0';
|
|
strncat_s(out, outSize, "options.txt", _TRUNCATE);
|
|
}
|
|
|
|
static void SaveFullscreenOption(bool fullscreen)
|
|
{
|
|
char path[MAX_PATH];
|
|
GetOptionsFilePath(path, sizeof(path));
|
|
FILE *f = nullptr;
|
|
if (fopen_s(&f, path, "w") == 0 && f)
|
|
{
|
|
fprintf(f, "fullscreen=%d\n", fullscreen ? 1 : 0);
|
|
fclose(f);
|
|
}
|
|
}
|
|
|
|
static bool LoadFullscreenOption()
|
|
{
|
|
char path[MAX_PATH];
|
|
GetOptionsFilePath(path, sizeof(path));
|
|
FILE *f = nullptr;
|
|
if (fopen_s(&f, path, "r") == 0 && f)
|
|
{
|
|
char line[256];
|
|
while (fgets(line, sizeof(line), f))
|
|
{
|
|
int val = 0;
|
|
if (sscanf_s(line, "fullscreen=%d", &val) == 1)
|
|
{
|
|
fclose(f);
|
|
return val != 0;
|
|
}
|
|
}
|
|
fclose(f);
|
|
}
|
|
return false;
|
|
}
|
|
// ------------------------------------------------------------------
|
|
|
|
static void ApplyScreenMode(int screenMode)
|
|
{
|
|
switch (screenMode)
|
|
{
|
|
case 1:
|
|
g_iScreenWidth = 1280;
|
|
g_iScreenHeight = 720;
|
|
break;
|
|
case 2:
|
|
g_iScreenWidth = 640;
|
|
g_iScreenHeight = 480;
|
|
break;
|
|
case 3:
|
|
g_iScreenWidth = 720;
|
|
g_iScreenHeight = 408;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
static Win64LaunchOptions ParseLaunchOptions()
|
|
{
|
|
Win64LaunchOptions options = {};
|
|
options.screenMode = 0;
|
|
|
|
g_Win64MultiplayerJoin = false;
|
|
g_Win64MultiplayerPort = WIN64_NET_DEFAULT_PORT;
|
|
|
|
int argc = 0;
|
|
LPWSTR* argv = CommandLineToArgvW(GetCommandLineW(), &argc);
|
|
if (argv == nullptr)
|
|
return options;
|
|
|
|
if (argc > 1 && lstrlenW(argv[1]) == 1)
|
|
{
|
|
if (argv[1][0] >= L'1' && argv[1][0] <= L'3')
|
|
options.screenMode = argv[1][0] - L'0';
|
|
}
|
|
|
|
for (int i = 1; i < argc; ++i)
|
|
{
|
|
if (_wcsicmp(argv[i], L"-name") == 0 && (i + 1) < argc)
|
|
{
|
|
CopyWideArgToAnsi(argv[++i], g_Win64Username, sizeof(g_Win64Username));
|
|
}
|
|
else if (_wcsicmp(argv[i], L"-ip") == 0 && (i + 1) < argc)
|
|
{
|
|
char ipBuf[256];
|
|
CopyWideArgToAnsi(argv[++i], ipBuf, sizeof(ipBuf));
|
|
strncpy_s(g_Win64MultiplayerIP, sizeof(g_Win64MultiplayerIP), ipBuf, _TRUNCATE);
|
|
g_Win64MultiplayerJoin = true;
|
|
}
|
|
else if (_wcsicmp(argv[i], L"-port") == 0 && (i + 1) < argc)
|
|
{
|
|
wchar_t* endPtr = nullptr;
|
|
const long port = wcstol(argv[++i], &endPtr, 10);
|
|
if (endPtr != argv[i] && *endPtr == 0 && port > 0 && port <= 65535)
|
|
{
|
|
g_Win64MultiplayerPort = static_cast<int>(port);
|
|
}
|
|
}
|
|
else if (_wcsicmp(argv[i], L"-fullscreen") == 0)
|
|
options.fullscreen = true;
|
|
}
|
|
|
|
LocalFree(argv);
|
|
return options;
|
|
}
|
|
|
|
void DefineActions(void)
|
|
{
|
|
// The app needs to define the actions required, and the possible mappings for these
|
|
|
|
// Split into Menu actions, and in-game actions
|
|
|
|
InputManager.SetGameJoypadMaps(MAP_STYLE_0,ACTION_MENU_A, _360_JOY_BUTTON_A);
|
|
InputManager.SetGameJoypadMaps(MAP_STYLE_0,ACTION_MENU_B, _360_JOY_BUTTON_B);
|
|
InputManager.SetGameJoypadMaps(MAP_STYLE_0,ACTION_MENU_X, _360_JOY_BUTTON_X);
|
|
InputManager.SetGameJoypadMaps(MAP_STYLE_0,ACTION_MENU_Y, _360_JOY_BUTTON_Y);
|
|
InputManager.SetGameJoypadMaps(MAP_STYLE_0,ACTION_MENU_OK, _360_JOY_BUTTON_A);
|
|
InputManager.SetGameJoypadMaps(MAP_STYLE_0,ACTION_MENU_CANCEL, _360_JOY_BUTTON_B);
|
|
InputManager.SetGameJoypadMaps(MAP_STYLE_0,ACTION_MENU_UP, _360_JOY_BUTTON_DPAD_UP | _360_JOY_BUTTON_LSTICK_UP);
|
|
InputManager.SetGameJoypadMaps(MAP_STYLE_0,ACTION_MENU_DOWN, _360_JOY_BUTTON_DPAD_DOWN | _360_JOY_BUTTON_LSTICK_DOWN);
|
|
InputManager.SetGameJoypadMaps(MAP_STYLE_0,ACTION_MENU_LEFT, _360_JOY_BUTTON_DPAD_LEFT | _360_JOY_BUTTON_LSTICK_LEFT);
|
|
InputManager.SetGameJoypadMaps(MAP_STYLE_0,ACTION_MENU_RIGHT, _360_JOY_BUTTON_DPAD_RIGHT | _360_JOY_BUTTON_LSTICK_RIGHT);
|
|
InputManager.SetGameJoypadMaps(MAP_STYLE_0,ACTION_MENU_PAGEUP, _360_JOY_BUTTON_LT);
|
|
InputManager.SetGameJoypadMaps(MAP_STYLE_0,ACTION_MENU_PAGEDOWN, _360_JOY_BUTTON_RT);
|
|
InputManager.SetGameJoypadMaps(MAP_STYLE_0,ACTION_MENU_RIGHT_SCROLL, _360_JOY_BUTTON_RB);
|
|
InputManager.SetGameJoypadMaps(MAP_STYLE_0,ACTION_MENU_LEFT_SCROLL, _360_JOY_BUTTON_LB);
|
|
InputManager.SetGameJoypadMaps(MAP_STYLE_0,ACTION_MENU_PAUSEMENU, _360_JOY_BUTTON_START);
|
|
|
|
InputManager.SetGameJoypadMaps(MAP_STYLE_0,ACTION_MENU_STICK_PRESS, _360_JOY_BUTTON_LTHUMB);
|
|
InputManager.SetGameJoypadMaps(MAP_STYLE_0,ACTION_MENU_OTHER_STICK_PRESS, _360_JOY_BUTTON_RTHUMB);
|
|
InputManager.SetGameJoypadMaps(MAP_STYLE_0,ACTION_MENU_OTHER_STICK_UP, _360_JOY_BUTTON_RSTICK_UP);
|
|
InputManager.SetGameJoypadMaps(MAP_STYLE_0,ACTION_MENU_OTHER_STICK_DOWN, _360_JOY_BUTTON_RSTICK_DOWN);
|
|
InputManager.SetGameJoypadMaps(MAP_STYLE_0,ACTION_MENU_OTHER_STICK_LEFT, _360_JOY_BUTTON_RSTICK_LEFT);
|
|
InputManager.SetGameJoypadMaps(MAP_STYLE_0,ACTION_MENU_OTHER_STICK_RIGHT, _360_JOY_BUTTON_RSTICK_RIGHT);
|
|
|
|
InputManager.SetGameJoypadMaps(MAP_STYLE_0,MINECRAFT_ACTION_JUMP, _360_JOY_BUTTON_A);
|
|
InputManager.SetGameJoypadMaps(MAP_STYLE_0,MINECRAFT_ACTION_FORWARD, _360_JOY_BUTTON_LSTICK_UP);
|
|
InputManager.SetGameJoypadMaps(MAP_STYLE_0,MINECRAFT_ACTION_BACKWARD, _360_JOY_BUTTON_LSTICK_DOWN);
|
|
InputManager.SetGameJoypadMaps(MAP_STYLE_0,MINECRAFT_ACTION_LEFT, _360_JOY_BUTTON_LSTICK_LEFT);
|
|
InputManager.SetGameJoypadMaps(MAP_STYLE_0,MINECRAFT_ACTION_RIGHT, _360_JOY_BUTTON_LSTICK_RIGHT);
|
|
InputManager.SetGameJoypadMaps(MAP_STYLE_0,MINECRAFT_ACTION_LOOK_LEFT, _360_JOY_BUTTON_RSTICK_LEFT);
|
|
InputManager.SetGameJoypadMaps(MAP_STYLE_0,MINECRAFT_ACTION_LOOK_RIGHT, _360_JOY_BUTTON_RSTICK_RIGHT);
|
|
InputManager.SetGameJoypadMaps(MAP_STYLE_0,MINECRAFT_ACTION_LOOK_UP, _360_JOY_BUTTON_RSTICK_UP);
|
|
InputManager.SetGameJoypadMaps(MAP_STYLE_0,MINECRAFT_ACTION_LOOK_DOWN, _360_JOY_BUTTON_RSTICK_DOWN);
|
|
InputManager.SetGameJoypadMaps(MAP_STYLE_0,MINECRAFT_ACTION_USE, _360_JOY_BUTTON_LT);
|
|
InputManager.SetGameJoypadMaps(MAP_STYLE_0,MINECRAFT_ACTION_ACTION, _360_JOY_BUTTON_RT);
|
|
InputManager.SetGameJoypadMaps(MAP_STYLE_0,MINECRAFT_ACTION_RIGHT_SCROLL, _360_JOY_BUTTON_RB);
|
|
InputManager.SetGameJoypadMaps(MAP_STYLE_0,MINECRAFT_ACTION_LEFT_SCROLL, _360_JOY_BUTTON_LB);
|
|
InputManager.SetGameJoypadMaps(MAP_STYLE_0,MINECRAFT_ACTION_INVENTORY, _360_JOY_BUTTON_Y);
|
|
InputManager.SetGameJoypadMaps(MAP_STYLE_0,MINECRAFT_ACTION_PAUSEMENU, _360_JOY_BUTTON_START);
|
|
InputManager.SetGameJoypadMaps(MAP_STYLE_0,MINECRAFT_ACTION_DROP, _360_JOY_BUTTON_B);
|
|
InputManager.SetGameJoypadMaps(MAP_STYLE_0,MINECRAFT_ACTION_SNEAK_TOGGLE, _360_JOY_BUTTON_RTHUMB);
|
|
InputManager.SetGameJoypadMaps(MAP_STYLE_0,MINECRAFT_ACTION_CRAFTING, _360_JOY_BUTTON_X);
|
|
InputManager.SetGameJoypadMaps(MAP_STYLE_0,MINECRAFT_ACTION_RENDER_THIRD_PERSON, _360_JOY_BUTTON_LTHUMB);
|
|
InputManager.SetGameJoypadMaps(MAP_STYLE_0,MINECRAFT_ACTION_GAME_INFO, _360_JOY_BUTTON_BACK);
|
|
|
|
InputManager.SetGameJoypadMaps(MAP_STYLE_0,MINECRAFT_ACTION_DPAD_LEFT, _360_JOY_BUTTON_DPAD_LEFT);
|
|
InputManager.SetGameJoypadMaps(MAP_STYLE_0,MINECRAFT_ACTION_DPAD_RIGHT, _360_JOY_BUTTON_DPAD_RIGHT);
|
|
InputManager.SetGameJoypadMaps(MAP_STYLE_0,MINECRAFT_ACTION_DPAD_UP, _360_JOY_BUTTON_DPAD_UP);
|
|
InputManager.SetGameJoypadMaps(MAP_STYLE_0,MINECRAFT_ACTION_DPAD_DOWN, _360_JOY_BUTTON_DPAD_DOWN);
|
|
|
|
InputManager.SetGameJoypadMaps(MAP_STYLE_1,ACTION_MENU_A, _360_JOY_BUTTON_A);
|
|
InputManager.SetGameJoypadMaps(MAP_STYLE_1,ACTION_MENU_B, _360_JOY_BUTTON_B);
|
|
InputManager.SetGameJoypadMaps(MAP_STYLE_1,ACTION_MENU_X, _360_JOY_BUTTON_X);
|
|
InputManager.SetGameJoypadMaps(MAP_STYLE_1,ACTION_MENU_Y, _360_JOY_BUTTON_Y);
|
|
InputManager.SetGameJoypadMaps(MAP_STYLE_1,ACTION_MENU_OK, _360_JOY_BUTTON_A);
|
|
InputManager.SetGameJoypadMaps(MAP_STYLE_1,ACTION_MENU_CANCEL, _360_JOY_BUTTON_B);
|
|
InputManager.SetGameJoypadMaps(MAP_STYLE_1,ACTION_MENU_UP, _360_JOY_BUTTON_DPAD_UP | _360_JOY_BUTTON_LSTICK_UP);
|
|
InputManager.SetGameJoypadMaps(MAP_STYLE_1,ACTION_MENU_DOWN, _360_JOY_BUTTON_DPAD_DOWN | _360_JOY_BUTTON_LSTICK_DOWN);
|
|
InputManager.SetGameJoypadMaps(MAP_STYLE_1,ACTION_MENU_LEFT, _360_JOY_BUTTON_DPAD_LEFT | _360_JOY_BUTTON_LSTICK_LEFT);
|
|
InputManager.SetGameJoypadMaps(MAP_STYLE_1,ACTION_MENU_RIGHT, _360_JOY_BUTTON_DPAD_RIGHT | _360_JOY_BUTTON_LSTICK_RIGHT);
|
|
InputManager.SetGameJoypadMaps(MAP_STYLE_1,ACTION_MENU_PAGEUP, _360_JOY_BUTTON_LB);
|
|
InputManager.SetGameJoypadMaps(MAP_STYLE_1,ACTION_MENU_PAGEDOWN, _360_JOY_BUTTON_RT);
|
|
InputManager.SetGameJoypadMaps(MAP_STYLE_1,ACTION_MENU_RIGHT_SCROLL, _360_JOY_BUTTON_RB);
|
|
InputManager.SetGameJoypadMaps(MAP_STYLE_1,ACTION_MENU_LEFT_SCROLL, _360_JOY_BUTTON_LB);
|
|
InputManager.SetGameJoypadMaps(MAP_STYLE_1,ACTION_MENU_PAUSEMENU, _360_JOY_BUTTON_START);
|
|
|
|
InputManager.SetGameJoypadMaps(MAP_STYLE_1,ACTION_MENU_STICK_PRESS, _360_JOY_BUTTON_LTHUMB);
|
|
InputManager.SetGameJoypadMaps(MAP_STYLE_1,ACTION_MENU_OTHER_STICK_PRESS, _360_JOY_BUTTON_RTHUMB);
|
|
InputManager.SetGameJoypadMaps(MAP_STYLE_1,ACTION_MENU_OTHER_STICK_UP, _360_JOY_BUTTON_RSTICK_UP);
|
|
InputManager.SetGameJoypadMaps(MAP_STYLE_1,ACTION_MENU_OTHER_STICK_DOWN, _360_JOY_BUTTON_RSTICK_DOWN);
|
|
InputManager.SetGameJoypadMaps(MAP_STYLE_1,ACTION_MENU_OTHER_STICK_LEFT, _360_JOY_BUTTON_RSTICK_LEFT);
|
|
InputManager.SetGameJoypadMaps(MAP_STYLE_1,ACTION_MENU_OTHER_STICK_RIGHT, _360_JOY_BUTTON_RSTICK_RIGHT);
|
|
|
|
InputManager.SetGameJoypadMaps(MAP_STYLE_1,MINECRAFT_ACTION_JUMP, _360_JOY_BUTTON_RB);
|
|
InputManager.SetGameJoypadMaps(MAP_STYLE_1,MINECRAFT_ACTION_FORWARD, _360_JOY_BUTTON_LSTICK_UP);
|
|
InputManager.SetGameJoypadMaps(MAP_STYLE_1,MINECRAFT_ACTION_BACKWARD, _360_JOY_BUTTON_LSTICK_DOWN);
|
|
InputManager.SetGameJoypadMaps(MAP_STYLE_1,MINECRAFT_ACTION_LEFT, _360_JOY_BUTTON_LSTICK_LEFT);
|
|
InputManager.SetGameJoypadMaps(MAP_STYLE_1,MINECRAFT_ACTION_RIGHT, _360_JOY_BUTTON_LSTICK_RIGHT);
|
|
InputManager.SetGameJoypadMaps(MAP_STYLE_1,MINECRAFT_ACTION_LOOK_LEFT, _360_JOY_BUTTON_RSTICK_LEFT);
|
|
InputManager.SetGameJoypadMaps(MAP_STYLE_1,MINECRAFT_ACTION_LOOK_RIGHT, _360_JOY_BUTTON_RSTICK_RIGHT);
|
|
InputManager.SetGameJoypadMaps(MAP_STYLE_1,MINECRAFT_ACTION_LOOK_UP, _360_JOY_BUTTON_RSTICK_UP);
|
|
InputManager.SetGameJoypadMaps(MAP_STYLE_1,MINECRAFT_ACTION_LOOK_DOWN, _360_JOY_BUTTON_RSTICK_DOWN);
|
|
InputManager.SetGameJoypadMaps(MAP_STYLE_1,MINECRAFT_ACTION_USE, _360_JOY_BUTTON_RT);
|
|
InputManager.SetGameJoypadMaps(MAP_STYLE_1,MINECRAFT_ACTION_ACTION, _360_JOY_BUTTON_LT);
|
|
InputManager.SetGameJoypadMaps(MAP_STYLE_1,MINECRAFT_ACTION_RIGHT_SCROLL, _360_JOY_BUTTON_DPAD_RIGHT);
|
|
InputManager.SetGameJoypadMaps(MAP_STYLE_1,MINECRAFT_ACTION_LEFT_SCROLL, _360_JOY_BUTTON_DPAD_LEFT);
|
|
InputManager.SetGameJoypadMaps(MAP_STYLE_1,MINECRAFT_ACTION_INVENTORY, _360_JOY_BUTTON_Y);
|
|
InputManager.SetGameJoypadMaps(MAP_STYLE_1,MINECRAFT_ACTION_PAUSEMENU, _360_JOY_BUTTON_START);
|
|
InputManager.SetGameJoypadMaps(MAP_STYLE_1,MINECRAFT_ACTION_DROP, _360_JOY_BUTTON_B);
|
|
InputManager.SetGameJoypadMaps(MAP_STYLE_1,MINECRAFT_ACTION_SNEAK_TOGGLE, _360_JOY_BUTTON_LTHUMB);
|
|
InputManager.SetGameJoypadMaps(MAP_STYLE_1,MINECRAFT_ACTION_CRAFTING, _360_JOY_BUTTON_X);
|
|
InputManager.SetGameJoypadMaps(MAP_STYLE_1,MINECRAFT_ACTION_RENDER_THIRD_PERSON, _360_JOY_BUTTON_RTHUMB);
|
|
InputManager.SetGameJoypadMaps(MAP_STYLE_1,MINECRAFT_ACTION_GAME_INFO, _360_JOY_BUTTON_BACK);
|
|
|
|
InputManager.SetGameJoypadMaps(MAP_STYLE_1,MINECRAFT_ACTION_DPAD_LEFT, _360_JOY_BUTTON_DPAD_LEFT);
|
|
InputManager.SetGameJoypadMaps(MAP_STYLE_1,MINECRAFT_ACTION_DPAD_RIGHT, _360_JOY_BUTTON_DPAD_RIGHT);
|
|
InputManager.SetGameJoypadMaps(MAP_STYLE_1,MINECRAFT_ACTION_DPAD_UP, _360_JOY_BUTTON_DPAD_UP);
|
|
InputManager.SetGameJoypadMaps(MAP_STYLE_1,MINECRAFT_ACTION_DPAD_DOWN, _360_JOY_BUTTON_DPAD_DOWN);
|
|
|
|
InputManager.SetGameJoypadMaps(MAP_STYLE_2,ACTION_MENU_A, _360_JOY_BUTTON_A);
|
|
InputManager.SetGameJoypadMaps(MAP_STYLE_2,ACTION_MENU_B, _360_JOY_BUTTON_B);
|
|
InputManager.SetGameJoypadMaps(MAP_STYLE_2,ACTION_MENU_X, _360_JOY_BUTTON_X);
|
|
InputManager.SetGameJoypadMaps(MAP_STYLE_2,ACTION_MENU_Y, _360_JOY_BUTTON_Y);
|
|
InputManager.SetGameJoypadMaps(MAP_STYLE_2,ACTION_MENU_OK, _360_JOY_BUTTON_A);
|
|
InputManager.SetGameJoypadMaps(MAP_STYLE_2,ACTION_MENU_CANCEL, _360_JOY_BUTTON_B);
|
|
InputManager.SetGameJoypadMaps(MAP_STYLE_2,ACTION_MENU_UP, _360_JOY_BUTTON_DPAD_UP | _360_JOY_BUTTON_LSTICK_UP);
|
|
InputManager.SetGameJoypadMaps(MAP_STYLE_2,ACTION_MENU_DOWN, _360_JOY_BUTTON_DPAD_DOWN | _360_JOY_BUTTON_LSTICK_DOWN);
|
|
InputManager.SetGameJoypadMaps(MAP_STYLE_2,ACTION_MENU_LEFT, _360_JOY_BUTTON_DPAD_LEFT | _360_JOY_BUTTON_LSTICK_LEFT);
|
|
InputManager.SetGameJoypadMaps(MAP_STYLE_2,ACTION_MENU_RIGHT, _360_JOY_BUTTON_DPAD_RIGHT | _360_JOY_BUTTON_LSTICK_RIGHT);
|
|
InputManager.SetGameJoypadMaps(MAP_STYLE_2,ACTION_MENU_PAGEUP, _360_JOY_BUTTON_DPAD_UP | _360_JOY_BUTTON_LB);
|
|
InputManager.SetGameJoypadMaps(MAP_STYLE_2,ACTION_MENU_PAGEDOWN, _360_JOY_BUTTON_RT);
|
|
InputManager.SetGameJoypadMaps(MAP_STYLE_2,ACTION_MENU_RIGHT_SCROLL, _360_JOY_BUTTON_RB);
|
|
InputManager.SetGameJoypadMaps(MAP_STYLE_2,ACTION_MENU_LEFT_SCROLL, _360_JOY_BUTTON_LB);
|
|
|
|
InputManager.SetGameJoypadMaps(MAP_STYLE_2,MINECRAFT_ACTION_JUMP, _360_JOY_BUTTON_LT);
|
|
InputManager.SetGameJoypadMaps(MAP_STYLE_2,MINECRAFT_ACTION_FORWARD, _360_JOY_BUTTON_LSTICK_UP);
|
|
InputManager.SetGameJoypadMaps(MAP_STYLE_2,MINECRAFT_ACTION_BACKWARD, _360_JOY_BUTTON_LSTICK_DOWN);
|
|
InputManager.SetGameJoypadMaps(MAP_STYLE_2,MINECRAFT_ACTION_LEFT, _360_JOY_BUTTON_LSTICK_LEFT);
|
|
InputManager.SetGameJoypadMaps(MAP_STYLE_2,MINECRAFT_ACTION_RIGHT, _360_JOY_BUTTON_LSTICK_RIGHT);
|
|
InputManager.SetGameJoypadMaps(MAP_STYLE_2,MINECRAFT_ACTION_LOOK_LEFT, _360_JOY_BUTTON_RSTICK_LEFT);
|
|
InputManager.SetGameJoypadMaps(MAP_STYLE_2,MINECRAFT_ACTION_LOOK_RIGHT, _360_JOY_BUTTON_RSTICK_RIGHT);
|
|
InputManager.SetGameJoypadMaps(MAP_STYLE_2,MINECRAFT_ACTION_LOOK_UP, _360_JOY_BUTTON_RSTICK_UP);
|
|
InputManager.SetGameJoypadMaps(MAP_STYLE_2,MINECRAFT_ACTION_LOOK_DOWN, _360_JOY_BUTTON_RSTICK_DOWN);
|
|
InputManager.SetGameJoypadMaps(MAP_STYLE_2,MINECRAFT_ACTION_USE, _360_JOY_BUTTON_RT);
|
|
InputManager.SetGameJoypadMaps(MAP_STYLE_2,MINECRAFT_ACTION_ACTION, _360_JOY_BUTTON_A);
|
|
InputManager.SetGameJoypadMaps(MAP_STYLE_2,MINECRAFT_ACTION_RIGHT_SCROLL, _360_JOY_BUTTON_DPAD_RIGHT);
|
|
InputManager.SetGameJoypadMaps(MAP_STYLE_2,MINECRAFT_ACTION_LEFT_SCROLL, _360_JOY_BUTTON_DPAD_LEFT);
|
|
InputManager.SetGameJoypadMaps(MAP_STYLE_2,MINECRAFT_ACTION_INVENTORY, _360_JOY_BUTTON_Y);
|
|
InputManager.SetGameJoypadMaps(MAP_STYLE_2,MINECRAFT_ACTION_PAUSEMENU, _360_JOY_BUTTON_START);
|
|
InputManager.SetGameJoypadMaps(MAP_STYLE_2,MINECRAFT_ACTION_DROP, _360_JOY_BUTTON_B);
|
|
InputManager.SetGameJoypadMaps(MAP_STYLE_2,MINECRAFT_ACTION_SNEAK_TOGGLE, _360_JOY_BUTTON_LB);
|
|
InputManager.SetGameJoypadMaps(MAP_STYLE_2,MINECRAFT_ACTION_CRAFTING, _360_JOY_BUTTON_X);
|
|
InputManager.SetGameJoypadMaps(MAP_STYLE_2,MINECRAFT_ACTION_RENDER_THIRD_PERSON, _360_JOY_BUTTON_LTHUMB);
|
|
InputManager.SetGameJoypadMaps(MAP_STYLE_2,MINECRAFT_ACTION_GAME_INFO, _360_JOY_BUTTON_BACK);
|
|
InputManager.SetGameJoypadMaps(MAP_STYLE_2,ACTION_MENU_PAUSEMENU, _360_JOY_BUTTON_START);
|
|
|
|
InputManager.SetGameJoypadMaps(MAP_STYLE_2,ACTION_MENU_STICK_PRESS, _360_JOY_BUTTON_LTHUMB);
|
|
InputManager.SetGameJoypadMaps(MAP_STYLE_2,ACTION_MENU_OTHER_STICK_PRESS, _360_JOY_BUTTON_RTHUMB);
|
|
InputManager.SetGameJoypadMaps(MAP_STYLE_2,ACTION_MENU_OTHER_STICK_UP, _360_JOY_BUTTON_RSTICK_UP);
|
|
InputManager.SetGameJoypadMaps(MAP_STYLE_2,ACTION_MENU_OTHER_STICK_DOWN, _360_JOY_BUTTON_RSTICK_DOWN);
|
|
InputManager.SetGameJoypadMaps(MAP_STYLE_2,ACTION_MENU_OTHER_STICK_LEFT, _360_JOY_BUTTON_RSTICK_LEFT);
|
|
InputManager.SetGameJoypadMaps(MAP_STYLE_2,ACTION_MENU_OTHER_STICK_RIGHT, _360_JOY_BUTTON_RSTICK_RIGHT);
|
|
|
|
InputManager.SetGameJoypadMaps(MAP_STYLE_2,MINECRAFT_ACTION_DPAD_LEFT, _360_JOY_BUTTON_DPAD_LEFT);
|
|
InputManager.SetGameJoypadMaps(MAP_STYLE_2,MINECRAFT_ACTION_DPAD_RIGHT, _360_JOY_BUTTON_DPAD_RIGHT);
|
|
InputManager.SetGameJoypadMaps(MAP_STYLE_2,MINECRAFT_ACTION_DPAD_UP, _360_JOY_BUTTON_DPAD_UP);
|
|
InputManager.SetGameJoypadMaps(MAP_STYLE_2,MINECRAFT_ACTION_DPAD_DOWN, _360_JOY_BUTTON_DPAD_DOWN);
|
|
}
|
|
|
|
#if 0
|
|
HRESULT InitD3D( IDirect3DDevice9 **ppDevice,
|
|
D3DPRESENT_PARAMETERS *pd3dPP )
|
|
{
|
|
IDirect3D9 *pD3D;
|
|
|
|
pD3D = Direct3DCreate9( D3D_SDK_VERSION );
|
|
|
|
// Set up the structure used to create the D3DDevice
|
|
// Using a permanent 1280x720 backbuffer now no matter what the actual video resolution.right Have also disabled letterboxing,
|
|
// which would letterbox a 1280x720 output if it detected a 4:3 video source - we're doing an anamorphic squash in this
|
|
// mode so don't need this functionality.
|
|
|
|
ZeroMemory( pd3dPP, sizeof(D3DPRESENT_PARAMETERS) );
|
|
XVIDEO_MODE VideoMode;
|
|
XGetVideoMode( &VideoMode );
|
|
g_bWidescreen = VideoMode.fIsWideScreen;
|
|
pd3dPP->BackBufferWidth = 1280;
|
|
pd3dPP->BackBufferHeight = 720;
|
|
pd3dPP->BackBufferFormat = D3DFMT_A8R8G8B8;
|
|
pd3dPP->BackBufferCount = 1;
|
|
pd3dPP->EnableAutoDepthStencil = TRUE;
|
|
pd3dPP->AutoDepthStencilFormat = D3DFMT_D24S8;
|
|
pd3dPP->SwapEffect = D3DSWAPEFFECT_DISCARD;
|
|
pd3dPP->PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
|
|
//pd3dPP->Flags = D3DPRESENTFLAG_NO_LETTERBOX;
|
|
//ERR[D3D]: Can't set D3DPRESENTFLAG_NO_LETTERBOX when wide-screen is enabled
|
|
// in the launcher/dashboard.
|
|
if(g_bWidescreen)
|
|
pd3dPP->Flags=0;
|
|
else
|
|
pd3dPP->Flags = D3DPRESENTFLAG_NO_LETTERBOX;
|
|
|
|
// Create the device.
|
|
return pD3D->CreateDevice(
|
|
0,
|
|
D3DDEVTYPE_HAL,
|
|
nullptr,
|
|
D3DCREATE_HARDWARE_VERTEXPROCESSING|D3DCREATE_BUFFER_2_FRAMES,
|
|
pd3dPP,
|
|
ppDevice );
|
|
}
|
|
#endif
|
|
//#define MEMORY_TRACKING
|
|
|
|
#ifdef MEMORY_TRACKING
|
|
void ResetMem();
|
|
void DumpMem();
|
|
void MemPixStuff();
|
|
#else
|
|
void MemSect(int sect)
|
|
{
|
|
}
|
|
#endif
|
|
|
|
HINSTANCE g_hInst = nullptr;
|
|
HWND g_hWnd = nullptr;
|
|
D3D_DRIVER_TYPE g_driverType = D3D_DRIVER_TYPE_NULL;
|
|
D3D_FEATURE_LEVEL g_featureLevel = D3D_FEATURE_LEVEL_11_0;
|
|
ID3D11Device* g_pd3dDevice = nullptr;
|
|
ID3D11DeviceContext* g_pImmediateContext = nullptr;
|
|
IDXGISwapChain* g_pSwapChain = nullptr;
|
|
bool g_bVSync = false;
|
|
static bool g_bPendingExclusiveFullscreen = false;
|
|
static bool g_bPendingExclusiveFullscreenValue = false;
|
|
|
|
// Captures the D3D11 back buffer and saves it as a PNG screenshot.
|
|
// Returns true on success and sets outFilename to the saved filename.
|
|
static bool TakeScreenshot(wstring& outFilename)
|
|
{
|
|
if (!g_pSwapChain || !g_pd3dDevice || !g_pImmediateContext)
|
|
return false;
|
|
|
|
ID3D11Texture2D* pBackBuffer = nullptr;
|
|
HRESULT hr = g_pSwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (void**)&pBackBuffer);
|
|
if (FAILED(hr))
|
|
return false;
|
|
|
|
D3D11_TEXTURE2D_DESC desc;
|
|
pBackBuffer->GetDesc(&desc);
|
|
desc.Usage = D3D11_USAGE_STAGING;
|
|
desc.BindFlags = 0;
|
|
desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
|
|
desc.MiscFlags = 0;
|
|
|
|
bool success = false;
|
|
ID3D11Texture2D* pStaging = nullptr;
|
|
hr = g_pd3dDevice->CreateTexture2D(&desc, nullptr, &pStaging);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
g_pImmediateContext->CopyResource(pStaging, pBackBuffer);
|
|
|
|
wchar_t exePath[MAX_PATH];
|
|
GetModuleFileNameW(NULL, exePath, MAX_PATH);
|
|
wchar_t* lastSlash = wcsrchr(exePath, L'\\');
|
|
if (lastSlash) *(lastSlash + 1) = L'\0';
|
|
wstring screenshotDirPath = wstring(exePath) + L"screenshots";
|
|
CreateDirectoryW(screenshotDirPath.c_str(), NULL);
|
|
|
|
SYSTEMTIME st;
|
|
GetLocalTime(&st);
|
|
wchar_t filename[128];
|
|
swprintf_s(filename, L"%04d-%02d-%02d_%02d.%02d.%02d.png",
|
|
st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond);
|
|
wstring screenshotPath = screenshotDirPath + L"\\" + filename;
|
|
|
|
D3D11_MAPPED_SUBRESOURCE mapped;
|
|
hr = g_pImmediateContext->Map(pStaging, 0, D3D11_MAP_READ, 0, &mapped);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
unsigned char* rgba = new unsigned char[desc.Width * desc.Height * 4];
|
|
for (UINT row = 0; row < desc.Height; row++)
|
|
{
|
|
unsigned char* src = (unsigned char*)mapped.pData + row * mapped.RowPitch;
|
|
unsigned char* dst = rgba + row * desc.Width * 4;
|
|
memcpy(dst, src, desc.Width * 4);
|
|
for (UINT x = 0; x < desc.Width; x++)
|
|
dst[x * 4 + 3] = 0xFF;
|
|
}
|
|
g_pImmediateContext->Unmap(pStaging, 0);
|
|
|
|
string narrowPath(screenshotPath.begin(), screenshotPath.end());
|
|
int writeResult = stbi_write_png(narrowPath.c_str(), desc.Width, desc.Height, 4, rgba, desc.Width * 4);
|
|
delete[] rgba;
|
|
|
|
if (writeResult)
|
|
{
|
|
outFilename = filename;
|
|
success = true;
|
|
}
|
|
}
|
|
pStaging->Release();
|
|
}
|
|
pBackBuffer->Release();
|
|
return success;
|
|
}
|
|
|
|
ID3D11RenderTargetView* g_pRenderTargetView = nullptr;
|
|
ID3D11DepthStencilView* g_pDepthStencilView = nullptr;
|
|
ID3D11Texture2D* g_pDepthStencilBuffer = nullptr;
|
|
static const float kClearColorWhite[4] = { 1.0f, 1.0f, 1.0f, 1.0f };
|
|
static const float kClearColorBlack[4] = { 0.0f, 0.0f, 0.0f, 1.0f };
|
|
|
|
// True when the swap chain is in DXGI exclusive fullscreen. Lets ResizeD3D
|
|
// skip its destroy-and-recreate path, which would break exclusive ownership.
|
|
static bool g_bDxgiExclusiveFullscreen = false;
|
|
|
|
//
|
|
// FUNCTION: WndProc(HWND, UINT, WPARAM, LPARAM)
|
|
//
|
|
// PURPOSE: Processes messages for the main window.
|
|
//
|
|
// WM_COMMAND - process the application menu
|
|
// WM_PAINT - Paint the main window
|
|
// WM_DESTROY - post a quit message and return
|
|
// WM_SIZE - handle resizing logic to support Any Aspect Ratio
|
|
//
|
|
//
|
|
static bool ResizeD3D(int newW, int newH); // forward declaration
|
|
static bool g_bInSizeMove = false; // true while the user is dragging the window border
|
|
static int g_pendingResizeW = 0; // deferred resize dimensions
|
|
static int g_pendingResizeH = 0;
|
|
|
|
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
int wmId, wmEvent;
|
|
PAINTSTRUCT ps;
|
|
HDC hdc;
|
|
|
|
switch (message)
|
|
{
|
|
case WM_COMMAND:
|
|
wmId = LOWORD(wParam);
|
|
wmEvent = HIWORD(wParam);
|
|
// Parse the menu selections:
|
|
switch (wmId)
|
|
{
|
|
case IDM_EXIT:
|
|
DestroyWindow(hWnd);
|
|
break;
|
|
|
|
default:
|
|
return DefWindowProcW(hWnd, message, wParam, lParam);
|
|
}
|
|
break;
|
|
case WM_PAINT:
|
|
hdc = BeginPaint(hWnd, &ps);
|
|
// TODO: Add any drawing code here...
|
|
EndPaint(hWnd, &ps);
|
|
break;
|
|
case WM_DESTROY:
|
|
PostQuitMessage(0);
|
|
break;
|
|
|
|
case WM_KILLFOCUS:
|
|
g_KBMInput.ClearAllState();
|
|
g_KBMInput.SetWindowFocused(false);
|
|
if (g_KBMInput.IsMouseGrabbed())
|
|
g_KBMInput.SetMouseGrabbed(false);
|
|
break;
|
|
|
|
case WM_SETFOCUS:
|
|
g_KBMInput.SetWindowFocused(true);
|
|
break;
|
|
|
|
case WM_CHAR:
|
|
// Buffer typed characters so UIScene_Keyboard can dispatch them to the Iggy Flash player
|
|
if (wParam >= 0x20 || wParam == 0x08 || wParam == 0x0D) // printable chars + backspace + enter
|
|
g_KBMInput.OnChar(static_cast<wchar_t>(wParam));
|
|
break;
|
|
|
|
case WM_KEYDOWN:
|
|
case WM_SYSKEYDOWN:
|
|
{
|
|
int vk = static_cast<int>(wParam);
|
|
if ((lParam & 0x40000000) && vk != VK_LEFT && vk != VK_RIGHT && vk != VK_BACK)
|
|
break;
|
|
#ifdef _WINDOWS64
|
|
const Minecraft* pm = Minecraft::GetInstance();
|
|
ChatScreen* chat = pm && pm->screen ? dynamic_cast<ChatScreen*>(pm->screen) : nullptr;
|
|
if (chat)
|
|
{
|
|
if (vk == 'V' && (GetKeyState(VK_CONTROL) & 0x8000))
|
|
{ chat->handlePasteRequest(); break; }
|
|
if ((vk == VK_UP || vk == VK_DOWN) && !(lParam & 0x40000000))
|
|
{ if (vk == VK_UP) chat->handleHistoryUp(); else chat->handleHistoryDown(); break; }
|
|
if (vk >= '1' && vk <= '9') // Prevent hotkey conflicts
|
|
break;
|
|
if (vk == VK_SHIFT)
|
|
break;
|
|
}
|
|
#endif
|
|
if (vk == VK_SHIFT)
|
|
vk = (MapVirtualKey((lParam >> 16) & 0xFF, MAPVK_VSC_TO_VK_EX) == VK_RSHIFT) ? VK_RSHIFT : VK_LSHIFT;
|
|
else if (vk == VK_CONTROL)
|
|
vk = (lParam & (1 << 24)) ? VK_RCONTROL : VK_LCONTROL;
|
|
else if (vk == VK_MENU)
|
|
vk = (lParam & (1 << 24)) ? VK_RMENU : VK_LMENU;
|
|
g_KBMInput.OnKeyDown(vk);
|
|
return DefWindowProcW(hWnd, message, wParam, lParam);
|
|
}
|
|
case WM_KEYUP:
|
|
case WM_SYSKEYUP:
|
|
{
|
|
int vk = static_cast<int>(wParam);
|
|
if (vk == VK_SHIFT)
|
|
vk = (MapVirtualKey((lParam >> 16) & 0xFF, MAPVK_VSC_TO_VK_EX) == VK_RSHIFT) ? VK_RSHIFT : VK_LSHIFT;
|
|
else if (vk == VK_CONTROL)
|
|
vk = (lParam & (1 << 24)) ? VK_RCONTROL : VK_LCONTROL;
|
|
else if (vk == VK_MENU)
|
|
vk = (lParam & (1 << 24)) ? VK_RMENU : VK_LMENU;
|
|
g_KBMInput.OnKeyUp(vk);
|
|
break;
|
|
}
|
|
|
|
case WM_LBUTTONDOWN:
|
|
g_KBMInput.OnMouseButtonDown(KeyboardMouseInput::MOUSE_LEFT);
|
|
break;
|
|
case WM_LBUTTONUP:
|
|
g_KBMInput.OnMouseButtonUp(KeyboardMouseInput::MOUSE_LEFT);
|
|
break;
|
|
case WM_RBUTTONDOWN:
|
|
g_KBMInput.OnMouseButtonDown(KeyboardMouseInput::MOUSE_RIGHT);
|
|
break;
|
|
case WM_RBUTTONUP:
|
|
g_KBMInput.OnMouseButtonUp(KeyboardMouseInput::MOUSE_RIGHT);
|
|
break;
|
|
case WM_MBUTTONDOWN:
|
|
g_KBMInput.OnMouseButtonDown(KeyboardMouseInput::MOUSE_MIDDLE);
|
|
break;
|
|
case WM_MBUTTONUP:
|
|
g_KBMInput.OnMouseButtonUp(KeyboardMouseInput::MOUSE_MIDDLE);
|
|
break;
|
|
|
|
case WM_MOUSEMOVE:
|
|
g_KBMInput.OnMouseMove(LOWORD(lParam), HIWORD(lParam));
|
|
break;
|
|
|
|
case WM_MOUSEWHEEL:
|
|
g_KBMInput.OnMouseWheel(GET_WHEEL_DELTA_WPARAM(wParam));
|
|
break;
|
|
|
|
case WM_INPUT:
|
|
{
|
|
UINT dwSize = 0;
|
|
GetRawInputData((HRAWINPUT)lParam, RID_INPUT, nullptr, &dwSize, sizeof(RAWINPUTHEADER));
|
|
if (dwSize > 0 && dwSize <= 256)
|
|
{
|
|
BYTE rawBuffer[256];
|
|
if (GetRawInputData((HRAWINPUT)lParam, RID_INPUT, rawBuffer, &dwSize, sizeof(RAWINPUTHEADER)) == dwSize)
|
|
{
|
|
const RAWINPUT* raw = (RAWINPUT*)rawBuffer;
|
|
if (raw->header.dwType == RIM_TYPEMOUSE)
|
|
{
|
|
g_KBMInput.OnRawMouseDelta(raw->data.mouse.lLastX, raw->data.mouse.lLastY);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case WM_ENTERSIZEMOVE:
|
|
g_bInSizeMove = true;
|
|
break;
|
|
|
|
case WM_EXITSIZEMOVE:
|
|
g_bInSizeMove = false;
|
|
if (g_pendingResizeW > 0 && g_pendingResizeH > 0)
|
|
{
|
|
// g_rScreenWidth/Height updated inside ResizeD3D to backbuffer dims
|
|
ResizeD3D(g_pendingResizeW, g_pendingResizeH);
|
|
g_pendingResizeW = 0;
|
|
g_pendingResizeH = 0;
|
|
}
|
|
break;
|
|
|
|
case WM_SIZE:
|
|
{
|
|
int newW = LOWORD(lParam);
|
|
int newH = HIWORD(lParam);
|
|
if (newW > 0 && newH > 0)
|
|
{
|
|
if (g_bInSizeMove)
|
|
{
|
|
// Just store the latest size, resize when dragging ends
|
|
g_pendingResizeW = newW;
|
|
g_pendingResizeH = newH;
|
|
}
|
|
else
|
|
{
|
|
// Immediate resize (maximize, programmatic resize, etc.)
|
|
// g_rScreenWidth/Height updated inside ResizeD3D to backbuffer dims
|
|
ResizeD3D(newW, newH);
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
return DefWindowProcW(hWnd, message, wParam, lParam);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
//
|
|
// FUNCTION: MyRegisterClass()
|
|
//
|
|
// PURPOSE: Registers the window class.
|
|
//
|
|
ATOM MyRegisterClass(HINSTANCE hInstance)
|
|
{
|
|
WNDCLASSEXW wcex;
|
|
|
|
wcex.cbSize = sizeof(WNDCLASSEXW);
|
|
|
|
wcex.style = CS_HREDRAW | CS_VREDRAW;
|
|
wcex.lpfnWndProc = WndProc;
|
|
wcex.cbClsExtra = 0;
|
|
wcex.cbWndExtra = 0;
|
|
wcex.hInstance = hInstance;
|
|
wcex.hIcon = LoadIconW(hInstance, L"Minecraft");
|
|
wcex.hCursor = LoadCursor(nullptr, IDC_ARROW);
|
|
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
|
|
wcex.lpszMenuName = L"Minecraft";
|
|
wcex.lpszClassName = L"MinecraftClass";
|
|
wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_MINECRAFTWINDOWS));
|
|
|
|
return RegisterClassExW(&wcex);
|
|
}
|
|
|
|
//
|
|
// FUNCTION: InitInstance(HINSTANCE, int)
|
|
//
|
|
// PURPOSE: Saves instance handle and creates main window
|
|
//
|
|
// COMMENTS:
|
|
//
|
|
// In this function, we save the instance handle in a global variable and
|
|
// create and display the main program window.
|
|
//
|
|
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
|
|
{
|
|
g_hInst = hInstance; // Store instance handle in our global variable
|
|
|
|
RECT wr = {0, 0, g_rScreenWidth, g_rScreenHeight}; // set the size, but not the position
|
|
AdjustWindowRect(&wr, WS_OVERLAPPEDWINDOW, FALSE); // adjust the size
|
|
|
|
g_hWnd = CreateWindowW( L"MinecraftClass",
|
|
L"Minecraft",
|
|
WS_OVERLAPPEDWINDOW,
|
|
CW_USEDEFAULT,
|
|
0,
|
|
wr.right - wr.left, // width of the window
|
|
wr.bottom - wr.top, // height of the window
|
|
nullptr,
|
|
nullptr,
|
|
hInstance,
|
|
nullptr);
|
|
|
|
if (!g_hWnd)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
ShowWindow(g_hWnd, (nCmdShow != SW_HIDE) ? SW_SHOWMAXIMIZED : nCmdShow);
|
|
UpdateWindow(g_hWnd);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
// 4J Stu - These functions are referenced from the Windows Input library
|
|
void ClearGlobalText()
|
|
{
|
|
// clear the global text
|
|
memset(chGlobalText,0,256);
|
|
memset(ui16GlobalText,0,512);
|
|
}
|
|
|
|
uint16_t *GetGlobalText()
|
|
{
|
|
//copy the ch text to ui16
|
|
char * pchBuffer=(char *)ui16GlobalText;
|
|
for(int i=0;i<256;i++)
|
|
{
|
|
pchBuffer[i*2]=chGlobalText[i];
|
|
}
|
|
return ui16GlobalText;
|
|
}
|
|
void SeedEditBox()
|
|
{
|
|
DialogBox(hMyInst, MAKEINTRESOURCE(IDD_SEED),
|
|
g_hWnd, reinterpret_cast<DLGPROC>(DlgProc));
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
LRESULT CALLBACK DlgProc(HWND hWndDlg, UINT Msg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
switch(Msg)
|
|
{
|
|
case WM_INITDIALOG:
|
|
return TRUE;
|
|
|
|
case WM_COMMAND:
|
|
switch(wParam)
|
|
{
|
|
case IDOK:
|
|
// Set the text
|
|
GetDlgItemText(hWndDlg,IDC_EDIT,chGlobalText,256);
|
|
EndDialog(hWndDlg, 0);
|
|
return TRUE;
|
|
}
|
|
break;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------
|
|
// Create Direct3D device and swap chain
|
|
//--------------------------------------------------------------------------------------
|
|
HRESULT InitDevice()
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
RECT rc;
|
|
GetClientRect( g_hWnd, &rc );
|
|
UINT width = rc.right - rc.left;
|
|
UINT height = rc.bottom - rc.top;
|
|
//app.DebugPrintf("width: %d, height: %d\n", width, height);
|
|
width = g_rScreenWidth;
|
|
height = g_rScreenHeight;
|
|
//app.DebugPrintf("width: %d, height: %d\n", width, height);
|
|
|
|
UINT createDeviceFlags = 0;
|
|
#ifdef _DEBUG
|
|
createDeviceFlags |= D3D11_CREATE_DEVICE_DEBUG;
|
|
#endif
|
|
|
|
D3D_DRIVER_TYPE driverTypes[] =
|
|
{
|
|
D3D_DRIVER_TYPE_HARDWARE,
|
|
D3D_DRIVER_TYPE_WARP,
|
|
D3D_DRIVER_TYPE_REFERENCE,
|
|
};
|
|
UINT numDriverTypes = ARRAYSIZE( driverTypes );
|
|
|
|
D3D_FEATURE_LEVEL featureLevels[] =
|
|
{
|
|
D3D_FEATURE_LEVEL_11_0,
|
|
D3D_FEATURE_LEVEL_10_1,
|
|
D3D_FEATURE_LEVEL_10_0,
|
|
};
|
|
UINT numFeatureLevels = ARRAYSIZE( featureLevels );
|
|
|
|
// Use the legacy bitblt DISCARD swap model (SwapEffect left as default 0).
|
|
// DXGI_SWAP_EFFECT_FLIP_DISCARD gives lower latency and tearing support, but
|
|
// takes exclusive ownership of the HWND — which makes window resize via
|
|
// CreateSwapChain fail with E_ACCESSDENIED and ResizeBuffers fail with
|
|
// DXGI_ERROR_INVALID_CALL (the closed-source 4J Renderer holds hidden
|
|
// backbuffer refs we can't release). Bitblt DISCARD has no HWND lock, so
|
|
// the "destroy old, create new" resize path in ResizeD3D() works cleanly.
|
|
// VSync toggle still works via the SyncInterval parameter on Present().
|
|
// RefreshRate=0/0 so DXGI matches the current display mode. Hardcoding a
|
|
// rate would force a mode switch on SetFullscreenState, which can produce
|
|
// "input signal out of range" errors on high-refresh monitors.
|
|
DXGI_SWAP_CHAIN_DESC sd;
|
|
ZeroMemory( &sd, sizeof( sd ) );
|
|
sd.BufferCount = 1;
|
|
sd.BufferDesc.Width = width;
|
|
sd.BufferDesc.Height = height;
|
|
sd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
|
|
sd.BufferDesc.RefreshRate.Numerator = 0;
|
|
sd.BufferDesc.RefreshRate.Denominator = 0;
|
|
sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT | DXGI_USAGE_SHADER_INPUT;
|
|
sd.OutputWindow = g_hWnd;
|
|
sd.SampleDesc.Count = 1;
|
|
sd.SampleDesc.Quality = 0;
|
|
sd.Windowed = TRUE;
|
|
|
|
for( UINT driverTypeIndex = 0; driverTypeIndex < numDriverTypes; driverTypeIndex++ )
|
|
{
|
|
g_driverType = driverTypes[driverTypeIndex];
|
|
hr = D3D11CreateDeviceAndSwapChain( nullptr, g_driverType, nullptr, createDeviceFlags, featureLevels, numFeatureLevels,
|
|
D3D11_SDK_VERSION, &sd, &g_pSwapChain, &g_pd3dDevice, &g_featureLevel, &g_pImmediateContext );
|
|
if( HRESULT_SUCCEEDED( hr ) )
|
|
break;
|
|
}
|
|
if( FAILED( hr ) )
|
|
return hr;
|
|
|
|
// Create a render target view
|
|
ID3D11Texture2D* pBackBuffer = nullptr;
|
|
hr = g_pSwapChain->GetBuffer( 0, __uuidof( ID3D11Texture2D ), ( LPVOID* )&pBackBuffer );
|
|
if( FAILED( hr ) )
|
|
return hr;
|
|
|
|
// Create a depth stencil buffer
|
|
D3D11_TEXTURE2D_DESC descDepth;
|
|
ZeroMemory(&descDepth, sizeof(descDepth));
|
|
|
|
descDepth.Width = width;
|
|
descDepth.Height = height;
|
|
descDepth.MipLevels = 1;
|
|
descDepth.ArraySize = 1;
|
|
descDepth.Format = DXGI_FORMAT_D24_UNORM_S8_UINT;
|
|
descDepth.SampleDesc.Count = 1;
|
|
descDepth.SampleDesc.Quality = 0;
|
|
descDepth.Usage = D3D11_USAGE_DEFAULT;
|
|
descDepth.BindFlags = D3D11_BIND_DEPTH_STENCIL;
|
|
descDepth.CPUAccessFlags = 0;
|
|
descDepth.MiscFlags = 0;
|
|
hr = g_pd3dDevice->CreateTexture2D(&descDepth, nullptr, &g_pDepthStencilBuffer);
|
|
|
|
D3D11_DEPTH_STENCIL_VIEW_DESC descDSView;
|
|
ZeroMemory(&descDSView, sizeof(descDSView));
|
|
descDSView.Format = DXGI_FORMAT_D24_UNORM_S8_UINT;
|
|
descDSView.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D;
|
|
descDSView.Texture2D.MipSlice = 0;
|
|
|
|
hr = g_pd3dDevice->CreateDepthStencilView(g_pDepthStencilBuffer, &descDSView, &g_pDepthStencilView);
|
|
|
|
hr = g_pd3dDevice->CreateRenderTargetView( pBackBuffer, nullptr, &g_pRenderTargetView );
|
|
pBackBuffer->Release();
|
|
if( FAILED( hr ) )
|
|
return hr;
|
|
|
|
g_pImmediateContext->OMSetRenderTargets( 1, &g_pRenderTargetView, g_pDepthStencilView );
|
|
|
|
// Setup the viewport
|
|
D3D11_VIEWPORT vp;
|
|
vp.Width = static_cast<FLOAT>(width);
|
|
vp.Height = static_cast<FLOAT>(height);
|
|
vp.MinDepth = 0.0f;
|
|
vp.MaxDepth = 1.0f;
|
|
vp.TopLeftX = 0;
|
|
vp.TopLeftY = 0;
|
|
g_pImmediateContext->RSSetViewports( 1, &vp );
|
|
|
|
RenderManager.Initialise(g_pd3dDevice, g_pSwapChain);
|
|
|
|
PostProcesser::GetInstance().Init();
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------
|
|
// Render the frame
|
|
//--------------------------------------------------------------------------------------
|
|
void Render()
|
|
{
|
|
// Just clear the backbuffer
|
|
const float ClearColor[4] = { 0.0f, 0.125f, 0.3f, 1.0f }; //red,green,blue,alpha
|
|
|
|
g_pImmediateContext->ClearRenderTargetView( g_pRenderTargetView, ClearColor );
|
|
g_pSwapChain->Present(0, 0);
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------
|
|
// Rebuild D3D11 resources after a window resize
|
|
//--------------------------------------------------------------------------------------
|
|
static bool ResizeD3D(int newW, int newH)
|
|
{
|
|
if (newW <= 0 || newH <= 0) return false;
|
|
if (!g_pSwapChain) return false;
|
|
if (!g_bResizeReady) return false;
|
|
// In exclusive fullscreen the swap chain must not be recreated.
|
|
if (g_bDxgiExclusiveFullscreen)
|
|
return false;
|
|
|
|
int bbW = newW;
|
|
int bbH = newH;
|
|
|
|
// InternalRenderManager member offsets (from decompiled Renderer.h):
|
|
// 0x10 m_pDevice (ID3D11Device*)
|
|
// 0x18 m_pDeviceContext (ID3D11DeviceContext*)
|
|
// 0x20 m_pSwapChain (IDXGISwapChain*)
|
|
// 0x28 renderTargetView (ID3D11RenderTargetView*) — backbuffer RTV
|
|
// 0x50 renderTargetShaderResourceView (ID3D11ShaderResourceView*)
|
|
// 0x98 depthStencilView (ID3D11DepthStencilView*)
|
|
// 0x5138 backBufferWidth (DWORD) — used by StartFrame() for viewport
|
|
// 0x513C backBufferHeight (DWORD) — used by StartFrame() for viewport
|
|
//
|
|
// Strategy: destroy old swap chain, create new one, patch Renderer's internal
|
|
// pointers directly. This avoids both ResizeBuffers (outstanding ref issues)
|
|
// and Initialise() (which wipes the texture table via memset).
|
|
// The Renderer's old RTV/SRV/DSV are intentionally NOT released — they become
|
|
// orphaned with the old swap chain. Tiny leak, but avoids fighting unknown refs.
|
|
char* pRM = (char*)&InternalRenderManager;
|
|
ID3D11RenderTargetView** ppRM_RTV = (ID3D11RenderTargetView**)(pRM + 0x28);
|
|
ID3D11ShaderResourceView** ppRM_SRV = (ID3D11ShaderResourceView**)(pRM + 0x50);
|
|
ID3D11DepthStencilView** ppRM_DSV = (ID3D11DepthStencilView**)(pRM + 0x98);
|
|
IDXGISwapChain** ppRM_SC = (IDXGISwapChain**)(pRM + 0x20);
|
|
DWORD* pRM_BBWidth = (DWORD*)(pRM + 0x5138);
|
|
DWORD* pRM_BBHeight = (DWORD*)(pRM + 0x513C);
|
|
|
|
// Verify offsets by checking device and swap chain pointers
|
|
ID3D11Device** ppRM_Device = (ID3D11Device**)(pRM + 0x10);
|
|
if (*ppRM_Device != g_pd3dDevice || *ppRM_SC != g_pSwapChain)
|
|
{
|
|
app.DebugPrintf("[RESIZE] ERROR: RenderManager offset verification failed! "
|
|
"device=%p (expected %p) swapchain=%p (expected %p)\n",
|
|
*ppRM_Device, g_pd3dDevice, *ppRM_SC, g_pSwapChain);
|
|
return false;
|
|
}
|
|
|
|
// Cross-check backbuffer dimension offsets against swap chain desc
|
|
DXGI_SWAP_CHAIN_DESC oldScDesc;
|
|
g_pSwapChain->GetDesc(&oldScDesc);
|
|
bool bbDimsValid = (*pRM_BBWidth == oldScDesc.BufferDesc.Width &&
|
|
*pRM_BBHeight == oldScDesc.BufferDesc.Height);
|
|
if (!bbDimsValid)
|
|
{
|
|
app.DebugPrintf("[RESIZE] WARNING: backBuffer dim offsets wrong: "
|
|
"stored=%ux%u, swapchain=%ux%u\n",
|
|
*pRM_BBWidth, *pRM_BBHeight, oldScDesc.BufferDesc.Width, oldScDesc.BufferDesc.Height);
|
|
}
|
|
|
|
RenderManager.Suspend();
|
|
while (!RenderManager.Suspended()) { Sleep(1); }
|
|
|
|
PostProcesser::GetInstance().Cleanup();
|
|
|
|
g_pImmediateContext->ClearState();
|
|
g_pImmediateContext->Flush();
|
|
|
|
// Release OUR views and depth buffer
|
|
if (g_pRenderTargetView) { g_pRenderTargetView->Release(); g_pRenderTargetView = NULL; }
|
|
if (g_pDepthStencilView) { g_pDepthStencilView->Release(); g_pDepthStencilView = NULL; }
|
|
if (g_pDepthStencilBuffer) { g_pDepthStencilBuffer->Release(); g_pDepthStencilBuffer = NULL; }
|
|
|
|
gdraw_D3D11_PreReset();
|
|
|
|
// Get IDXGIFactory from the existing device BEFORE destroying the old swap
|
|
// chain. If anything fails before we have a new swap chain, we abort
|
|
// without destroying the old one — leaving the Renderer in a valid
|
|
// (old-size) state.
|
|
IDXGISwapChain* pOldSwapChain = g_pSwapChain;
|
|
bool success = false;
|
|
HRESULT hr;
|
|
|
|
IDXGIDevice* dxgiDevice = NULL;
|
|
IDXGIAdapter* dxgiAdapter = NULL;
|
|
IDXGIFactory* dxgiFactory = NULL;
|
|
hr = g_pd3dDevice->QueryInterface(__uuidof(IDXGIDevice), (void**)&dxgiDevice);
|
|
if (FAILED(hr)) goto postReset;
|
|
hr = dxgiDevice->GetParent(__uuidof(IDXGIAdapter), (void**)&dxgiAdapter);
|
|
if (FAILED(hr)) { dxgiDevice->Release(); goto postReset; }
|
|
hr = dxgiAdapter->GetParent(__uuidof(IDXGIFactory), (void**)&dxgiFactory);
|
|
dxgiAdapter->Release();
|
|
dxgiDevice->Release();
|
|
if (FAILED(hr)) goto postReset;
|
|
|
|
// Create a brand-new swap chain at the target size and swap it in.
|
|
// Must use the SAME swap-chain config as InitDevice (legacy bitblt
|
|
// DISCARD model), otherwise DXGI may return E_ACCESSDENIED. The
|
|
// Renderer's old RTV/SRV/DSV are intentionally NOT released here — they
|
|
// become orphaned with the old swap chain (tiny leak, but avoids
|
|
// fighting unknown refs inside the closed-source Renderer library).
|
|
{
|
|
DXGI_SWAP_CHAIN_DESC sd = {};
|
|
sd.BufferCount = 1;
|
|
sd.BufferDesc.Width = bbW;
|
|
sd.BufferDesc.Height = bbH;
|
|
sd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
|
|
// RefreshRate=0/0 matches InitDevice; see comment there.
|
|
sd.BufferDesc.RefreshRate.Numerator = 0;
|
|
sd.BufferDesc.RefreshRate.Denominator = 0;
|
|
sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT | DXGI_USAGE_SHADER_INPUT;
|
|
sd.OutputWindow = g_hWnd;
|
|
sd.SampleDesc.Count = 1;
|
|
sd.SampleDesc.Quality = 0;
|
|
sd.Windowed = TRUE;
|
|
|
|
IDXGISwapChain* pNewSwapChain = NULL;
|
|
hr = dxgiFactory->CreateSwapChain(g_pd3dDevice, &sd, &pNewSwapChain);
|
|
dxgiFactory->Release();
|
|
if (FAILED(hr) || pNewSwapChain == NULL)
|
|
{
|
|
app.DebugPrintf("[RESIZE] CreateSwapChain FAILED hr=0x%08X — keeping old swap chain\n", (unsigned)hr);
|
|
goto postReset;
|
|
}
|
|
|
|
// New swap chain created successfully — NOW destroy the old one.
|
|
pOldSwapChain->Release();
|
|
g_pSwapChain = pNewSwapChain;
|
|
}
|
|
|
|
// Patch Renderer's swap chain pointer to the new raw swap chain.
|
|
*ppRM_SC = g_pSwapChain;
|
|
|
|
// Create render target views from new backbuffer
|
|
{
|
|
ID3D11Texture2D* pBackBuffer = NULL;
|
|
hr = g_pSwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (LPVOID*)&pBackBuffer);
|
|
if (FAILED(hr)) goto postReset;
|
|
|
|
// Our RTV
|
|
hr = g_pd3dDevice->CreateRenderTargetView(pBackBuffer, NULL, &g_pRenderTargetView);
|
|
if (FAILED(hr)) { pBackBuffer->Release(); goto postReset; }
|
|
|
|
// Renderer's internal RTV (offset 0x28)
|
|
hr = g_pd3dDevice->CreateRenderTargetView(pBackBuffer, NULL, ppRM_RTV);
|
|
if (FAILED(hr)) { pBackBuffer->Release(); goto postReset; }
|
|
|
|
// Renderer's SRV: separate texture matching backbuffer dims (used by CaptureThumbnail)
|
|
D3D11_TEXTURE2D_DESC backDesc = {};
|
|
pBackBuffer->GetDesc(&backDesc);
|
|
pBackBuffer->Release();
|
|
|
|
D3D11_TEXTURE2D_DESC srvDesc = backDesc;
|
|
srvDesc.BindFlags = D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE;
|
|
ID3D11Texture2D* srvTexture = NULL;
|
|
hr = g_pd3dDevice->CreateTexture2D(&srvDesc, NULL, &srvTexture);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = g_pd3dDevice->CreateShaderResourceView(srvTexture, NULL, ppRM_SRV);
|
|
srvTexture->Release();
|
|
}
|
|
if (FAILED(hr)) goto postReset;
|
|
}
|
|
|
|
// Recreate depth stencil at backbuffer size
|
|
{
|
|
D3D11_TEXTURE2D_DESC descDepth = {};
|
|
descDepth.Width = bbW;
|
|
descDepth.Height = bbH;
|
|
descDepth.MipLevels = 1;
|
|
descDepth.ArraySize = 1;
|
|
descDepth.Format = DXGI_FORMAT_D24_UNORM_S8_UINT;
|
|
descDepth.SampleDesc.Count = 1;
|
|
descDepth.SampleDesc.Quality = 0;
|
|
descDepth.Usage = D3D11_USAGE_DEFAULT;
|
|
descDepth.BindFlags = D3D11_BIND_DEPTH_STENCIL;
|
|
hr = g_pd3dDevice->CreateTexture2D(&descDepth, NULL, &g_pDepthStencilBuffer);
|
|
if (FAILED(hr)) goto postReset;
|
|
|
|
D3D11_DEPTH_STENCIL_VIEW_DESC descDSView = {};
|
|
descDSView.Format = DXGI_FORMAT_D24_UNORM_S8_UINT;
|
|
descDSView.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D;
|
|
hr = g_pd3dDevice->CreateDepthStencilView(g_pDepthStencilBuffer, &descDSView, &g_pDepthStencilView);
|
|
if (FAILED(hr)) goto postReset;
|
|
}
|
|
|
|
// Patch Renderer's DSV (AddRef because both we and the Renderer reference it)
|
|
g_pDepthStencilView->AddRef();
|
|
*ppRM_DSV = g_pDepthStencilView;
|
|
|
|
// Update Renderer's cached backbuffer dimensions (StartFrame uses these for viewport)
|
|
if (bbDimsValid)
|
|
{
|
|
*pRM_BBWidth = (DWORD)bbW;
|
|
*pRM_BBHeight = (DWORD)bbH;
|
|
}
|
|
|
|
// Rebind render targets and viewport
|
|
g_pImmediateContext->OMSetRenderTargets(1, &g_pRenderTargetView, g_pDepthStencilView);
|
|
{
|
|
D3D11_VIEWPORT vp = {};
|
|
vp.Width = (FLOAT)bbW;
|
|
vp.Height = (FLOAT)bbH;
|
|
vp.MinDepth = 0.0f;
|
|
vp.MaxDepth = 1.0f;
|
|
g_pImmediateContext->RSSetViewports(1, &vp);
|
|
}
|
|
|
|
ui.updateRenderTargets(g_pRenderTargetView, g_pDepthStencilView);
|
|
ui.updateScreenSize(bbW, bbH);
|
|
|
|
// Track actual backbuffer dimensions for the rest of the engine
|
|
g_rScreenWidth = bbW;
|
|
g_rScreenHeight = bbH;
|
|
|
|
success = true;
|
|
|
|
postReset:
|
|
if (!success && g_pSwapChain != NULL)
|
|
{
|
|
// Failure recovery: recreate our views from whatever swap chain survived
|
|
// so ui.m_pRenderTargetView / m_pDepthStencilView don't dangle.
|
|
DXGI_SWAP_CHAIN_DESC recoveryDesc;
|
|
g_pSwapChain->GetDesc(&recoveryDesc);
|
|
int recW = (int)recoveryDesc.BufferDesc.Width;
|
|
int recH = (int)recoveryDesc.BufferDesc.Height;
|
|
|
|
if (g_pRenderTargetView == NULL)
|
|
{
|
|
ID3D11Texture2D* pBB = NULL;
|
|
if (SUCCEEDED(g_pSwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (LPVOID*)&pBB)))
|
|
{
|
|
g_pd3dDevice->CreateRenderTargetView(pBB, NULL, &g_pRenderTargetView);
|
|
pBB->Release();
|
|
}
|
|
}
|
|
if (g_pDepthStencilView == NULL)
|
|
{
|
|
D3D11_TEXTURE2D_DESC dd = {};
|
|
dd.Width = recW; dd.Height = recH; dd.MipLevels = 1; dd.ArraySize = 1;
|
|
dd.Format = DXGI_FORMAT_D24_UNORM_S8_UINT;
|
|
dd.SampleDesc.Count = 1; dd.Usage = D3D11_USAGE_DEFAULT;
|
|
dd.BindFlags = D3D11_BIND_DEPTH_STENCIL;
|
|
if (g_pDepthStencilBuffer == NULL)
|
|
g_pd3dDevice->CreateTexture2D(&dd, NULL, &g_pDepthStencilBuffer);
|
|
if (g_pDepthStencilBuffer != NULL)
|
|
{
|
|
D3D11_DEPTH_STENCIL_VIEW_DESC dsvd = {};
|
|
dsvd.Format = DXGI_FORMAT_D24_UNORM_S8_UINT;
|
|
dsvd.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D;
|
|
g_pd3dDevice->CreateDepthStencilView(g_pDepthStencilBuffer, &dsvd, &g_pDepthStencilView);
|
|
}
|
|
}
|
|
if (g_pRenderTargetView != NULL)
|
|
g_pImmediateContext->OMSetRenderTargets(1, &g_pRenderTargetView, g_pDepthStencilView);
|
|
|
|
ui.updateRenderTargets(g_pRenderTargetView, g_pDepthStencilView);
|
|
|
|
// If the surviving swap chain is the OLD one, dims are unchanged.
|
|
// If it's the NEW one (partial failure after swap), update to new dims.
|
|
if (g_pSwapChain != pOldSwapChain)
|
|
{
|
|
g_rScreenWidth = recW;
|
|
g_rScreenHeight = recH;
|
|
ui.updateScreenSize(recW, recH);
|
|
}
|
|
|
|
app.DebugPrintf("[RESIZE] FAILED but recovered views at %dx%d\n", g_rScreenWidth, g_rScreenHeight);
|
|
}
|
|
|
|
gdraw_D3D11_PostReset();
|
|
gdraw_D3D11_SetRendertargetSize(g_rScreenWidth, g_rScreenHeight);
|
|
if (success)
|
|
IggyFlushInstalledFonts();
|
|
RenderManager.Resume();
|
|
|
|
if (success)
|
|
PostProcesser::GetInstance().Init();
|
|
|
|
return success;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------
|
|
// Toggle borderless fullscreen
|
|
//--------------------------------------------------------------------------------------
|
|
void ToggleFullscreen()
|
|
{
|
|
const DWORD dwStyle = GetWindowLong(g_hWnd, GWL_STYLE);
|
|
if (!g_isFullscreen)
|
|
{
|
|
MONITORINFO mi = { sizeof(mi) };
|
|
if (GetWindowPlacement(g_hWnd, &g_wpPrev) &&
|
|
GetMonitorInfo(MonitorFromWindow(g_hWnd, MONITOR_DEFAULTTOPRIMARY), &mi))
|
|
{
|
|
SetWindowLong(g_hWnd, GWL_STYLE, dwStyle & ~WS_OVERLAPPEDWINDOW);
|
|
SetWindowPos(g_hWnd, HWND_TOP,
|
|
mi.rcMonitor.left, mi.rcMonitor.top,
|
|
mi.rcMonitor.right - mi.rcMonitor.left,
|
|
mi.rcMonitor.bottom - mi.rcMonitor.top,
|
|
SWP_NOOWNERZORDER | SWP_FRAMECHANGED);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
SetWindowLong(g_hWnd, GWL_STYLE, dwStyle | WS_OVERLAPPEDWINDOW);
|
|
SetWindowPlacement(g_hWnd, &g_wpPrev);
|
|
SetWindowPos(g_hWnd, nullptr, 0, 0, 0, 0,
|
|
SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOOWNERZORDER | SWP_FRAMECHANGED);
|
|
}
|
|
g_isFullscreen = !g_isFullscreen;
|
|
SaveFullscreenOption(g_isFullscreen);
|
|
|
|
if (g_KBMInput.IsWindowFocused())
|
|
g_KBMInput.SetWindowFocused(true);
|
|
}
|
|
|
|
// Called from UI thread — defers the actual transition to the main game loop
|
|
void SetExclusiveFullscreen(bool enabled)
|
|
{
|
|
if (enabled == g_isFullscreen)
|
|
return;
|
|
g_bPendingExclusiveFullscreen = true;
|
|
g_bPendingExclusiveFullscreenValue = enabled;
|
|
}
|
|
|
|
// Enter or leave true DXGI exclusive fullscreen. With our bitblt swap chain,
|
|
// Present(SyncInterval=0) in exclusive mode produces real screen tearing via
|
|
// direct scanout (DWM is out of the pipeline). Flip mode with ALLOW_TEARING
|
|
// would also work but is blocked by the 4J Renderer's deferred context refs
|
|
// on the backbuffer, which DXGI's ResizeBuffers cannot release.
|
|
static void ApplyExclusiveFullscreen(bool enabled)
|
|
{
|
|
if (!g_pSwapChain)
|
|
return;
|
|
|
|
LONG styleBefore = GetWindowLong(g_hWnd, GWL_STYLE);
|
|
|
|
if (enabled)
|
|
{
|
|
// Grow the window to cover the monitor first. This fires WM_SIZE which
|
|
// runs ResizeD3D and recreates the backbuffer at monitor-native size.
|
|
// Otherwise a small windowed backbuffer would enter exclusive fullscreen
|
|
// at that smaller size and DXGI would scale it to fill the monitor,
|
|
// producing a filtered / washed-out look.
|
|
HMONITOR hMon = MonitorFromWindow(g_hWnd, MONITOR_DEFAULTTOPRIMARY);
|
|
MONITORINFO mi = {};
|
|
mi.cbSize = sizeof(mi);
|
|
if (GetMonitorInfo(hMon, &mi))
|
|
{
|
|
int monW = mi.rcMonitor.right - mi.rcMonitor.left;
|
|
int monH = mi.rcMonitor.bottom - mi.rcMonitor.top;
|
|
SetWindowLong(g_hWnd, GWL_STYLE, (styleBefore & ~WS_OVERLAPPEDWINDOW) | WS_VISIBLE);
|
|
SetWindowPos(g_hWnd, HWND_TOP,
|
|
mi.rcMonitor.left, mi.rcMonitor.top, monW, monH,
|
|
SWP_NOOWNERZORDER | SWP_FRAMECHANGED);
|
|
|
|
// ResizeTarget pins the display mode to the backbuffer size with
|
|
// no scaling. Microsoft's pattern is ResizeTarget then
|
|
// SetFullscreenState then ResizeTarget again (see below).
|
|
DXGI_MODE_DESC targetMode = {};
|
|
targetMode.Width = monW;
|
|
targetMode.Height = monH;
|
|
targetMode.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
|
|
targetMode.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
|
|
targetMode.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
|
|
g_pSwapChain->ResizeTarget(&targetMode);
|
|
}
|
|
}
|
|
|
|
HRESULT hr = g_pSwapChain->SetFullscreenState(enabled ? TRUE : FALSE, nullptr);
|
|
if (FAILED(hr))
|
|
return;
|
|
|
|
g_bDxgiExclusiveFullscreen = enabled;
|
|
|
|
if (enabled)
|
|
{
|
|
// Explicitly declare sRGB. Default for R8G8B8A8_UNORM but some drivers
|
|
// behave differently if the color space is never set.
|
|
IDXGISwapChain3* pSwapChain3 = nullptr;
|
|
if (SUCCEEDED(g_pSwapChain->QueryInterface(__uuidof(IDXGISwapChain3), (void**)&pSwapChain3)) && pSwapChain3)
|
|
{
|
|
UINT colorSpaceSupport = 0;
|
|
pSwapChain3->CheckColorSpaceSupport(DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709, &colorSpaceSupport);
|
|
if (colorSpaceSupport & DXGI_SWAP_CHAIN_COLOR_SPACE_SUPPORT_FLAG_PRESENT)
|
|
pSwapChain3->SetColorSpace1(DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709);
|
|
pSwapChain3->Release();
|
|
}
|
|
|
|
// Second ResizeTarget per Microsoft's recommendation to make the mode stick.
|
|
HMONITOR hMon2 = MonitorFromWindow(g_hWnd, MONITOR_DEFAULTTOPRIMARY);
|
|
MONITORINFO mi2 = {};
|
|
mi2.cbSize = sizeof(mi2);
|
|
if (GetMonitorInfo(hMon2, &mi2))
|
|
{
|
|
DXGI_MODE_DESC targetMode2 = {};
|
|
targetMode2.Width = mi2.rcMonitor.right - mi2.rcMonitor.left;
|
|
targetMode2.Height = mi2.rcMonitor.bottom - mi2.rcMonitor.top;
|
|
targetMode2.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
|
|
targetMode2.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
|
|
targetMode2.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
|
|
g_pSwapChain->ResizeTarget(&targetMode2);
|
|
}
|
|
g_isFullscreen = true;
|
|
}
|
|
else
|
|
{
|
|
// Force a real decorated windowed state on exit. DXGI would otherwise
|
|
// restore whatever state the window had before SetFullscreenState,
|
|
// which may still be borderless.
|
|
SetWindowLong(g_hWnd, GWL_STYLE, WS_OVERLAPPEDWINDOW | WS_VISIBLE);
|
|
const int w = 1280, h = 720;
|
|
const int sw = GetSystemMetrics(SM_CXSCREEN);
|
|
const int sh = GetSystemMetrics(SM_CYSCREEN);
|
|
SetWindowPos(g_hWnd, HWND_TOP, (sw - w) / 2, (sh - h) / 2, w, h,
|
|
SWP_NOOWNERZORDER | SWP_FRAMECHANGED);
|
|
g_isFullscreen = false;
|
|
}
|
|
}
|
|
|
|
//--------------------------------------------------------------------------------------
|
|
// Clean up the objects we've created
|
|
//--------------------------------------------------------------------------------------
|
|
void CleanupDevice()
|
|
{
|
|
if( g_pImmediateContext ) g_pImmediateContext->ClearState();
|
|
|
|
if( g_pDepthStencilView ) g_pDepthStencilView->Release();
|
|
if( g_pDepthStencilBuffer ) g_pDepthStencilBuffer->Release();
|
|
if( g_pRenderTargetView ) g_pRenderTargetView->Release();
|
|
if( g_pSwapChain ) g_pSwapChain->Release();
|
|
if( g_pImmediateContext ) g_pImmediateContext->Release();
|
|
if( g_pd3dDevice ) g_pd3dDevice->Release();
|
|
}
|
|
|
|
static Minecraft* InitialiseMinecraftRuntime()
|
|
{
|
|
app.loadMediaArchive();
|
|
|
|
RenderManager.Initialise(g_pd3dDevice, g_pSwapChain);
|
|
|
|
app.loadStringTable();
|
|
ui.init(g_pd3dDevice, g_pImmediateContext, g_pRenderTargetView, g_pDepthStencilView, g_rScreenWidth, g_rScreenHeight);
|
|
|
|
InputManager.Initialise(1, 3, MINECRAFT_ACTION_MAX, ACTION_MAX_MENU);
|
|
g_KBMInput.Init();
|
|
DefineActions();
|
|
InputManager.SetJoypadMapVal(0, 0);
|
|
InputManager.SetKeyRepeatRate(0.3f, 0.2f);
|
|
|
|
ProfileManager.Initialise(TITLEID_MINECRAFT,
|
|
app.m_dwOfferID,
|
|
PROFILE_VERSION_10,
|
|
NUM_PROFILE_VALUES,
|
|
NUM_PROFILE_SETTINGS,
|
|
dwProfileSettingsA,
|
|
app.GAME_DEFINED_PROFILE_DATA_BYTES * XUSER_MAX_COUNT,
|
|
&app.uiGameDefinedDataChangedBitmask
|
|
);
|
|
ProfileManager.SetDefaultOptionsCallback(&CConsoleMinecraftApp::DefaultOptionsCallback, (LPVOID)&app);
|
|
|
|
g_NetworkManager.Initialise();
|
|
|
|
for (int i = 0; i < MINECRAFT_NET_MAX_PLAYERS; i++)
|
|
{
|
|
IQNet::m_player[i].m_smallId = static_cast<BYTE>(i);
|
|
IQNet::m_player[i].m_isRemote = false;
|
|
IQNet::m_player[i].m_isHostPlayer = (i == 0);
|
|
swprintf_s(IQNet::m_player[i].m_gamertag, 32, L"Player%d", i);
|
|
}
|
|
wcscpy_s(IQNet::m_player[0].m_gamertag, 32, g_Win64UsernameW);
|
|
|
|
WinsockNetLayer::Initialize();
|
|
|
|
ProfileManager.SetDebugFullOverride(true);
|
|
|
|
Tesselator::CreateNewThreadStorage(1024 * 1024);
|
|
AABB::CreateNewThreadStorage();
|
|
Vec3::CreateNewThreadStorage();
|
|
IntCache::CreateNewThreadStorage();
|
|
Compression::CreateNewThreadStorage();
|
|
OldChunkStorage::CreateNewThreadStorage();
|
|
Level::enableLightingCache();
|
|
Tile::CreateNewThreadStorage();
|
|
|
|
Minecraft::main();
|
|
Minecraft* pMinecraft = Minecraft::GetInstance();
|
|
if (pMinecraft == nullptr)
|
|
return nullptr;
|
|
|
|
app.InitGameSettings();
|
|
app.InitialiseTips();
|
|
|
|
return pMinecraft;
|
|
}
|
|
|
|
int APIENTRY _tWinMain(_In_ HINSTANCE hInstance,
|
|
_In_opt_ HINSTANCE hPrevInstance,
|
|
_In_ LPTSTR lpCmdLine,
|
|
_In_ int nCmdShow)
|
|
{
|
|
UNREFERENCED_PARAMETER(hPrevInstance);
|
|
UNREFERENCED_PARAMETER(lpCmdLine);
|
|
|
|
// 4J-Win64: set CWD to exe dir so asset paths resolve correctly
|
|
{
|
|
char szExeDir[MAX_PATH] = {};
|
|
GetModuleFileNameA(nullptr, szExeDir, MAX_PATH);
|
|
char *pSlash = strrchr(szExeDir, '\\');
|
|
if (pSlash) { *(pSlash + 1) = '\0'; SetCurrentDirectoryA(szExeDir); }
|
|
}
|
|
|
|
// Declare DPI awareness so GetSystemMetrics returns physical pixels
|
|
SetProcessDPIAware();
|
|
// Use the native monitor resolution for the window and swap chain,
|
|
// but keep g_iScreenWidth/Height at 1920x1080 for logical resolution
|
|
// (SWF selection, ortho projection, game logic). The real window
|
|
// dimensions are tracked by g_rScreenWidth/g_rScreenHeight.
|
|
g_rScreenWidth = GetSystemMetrics(SM_CXSCREEN);
|
|
g_rScreenHeight = GetSystemMetrics(SM_CYSCREEN);
|
|
|
|
// Load username from username.txt
|
|
char exePath[MAX_PATH] = {};
|
|
GetModuleFileNameA(nullptr, exePath, MAX_PATH);
|
|
char *lastSlash = strrchr(exePath, '\\');
|
|
if (lastSlash)
|
|
{
|
|
*(lastSlash + 1) = '\0';
|
|
}
|
|
|
|
char filePath[MAX_PATH] = {};
|
|
_snprintf_s(filePath, sizeof(filePath), _TRUNCATE, "%susername.txt", exePath);
|
|
|
|
FILE *f = nullptr;
|
|
if (fopen_s(&f, filePath, "r") == 0 && f)
|
|
{
|
|
char buf[128] = {};
|
|
if (fgets(buf, sizeof(buf), f))
|
|
{
|
|
int len = static_cast<int>(strlen(buf));
|
|
while (len > 0 && (buf[len - 1] == '\n' || buf[len - 1] == '\r' || buf[len - 1] == ' '))
|
|
{
|
|
buf[--len] = '\0';
|
|
}
|
|
|
|
if (len > 0)
|
|
{
|
|
strncpy_s(g_Win64Username, sizeof(g_Win64Username), buf, _TRUNCATE);
|
|
}
|
|
}
|
|
fclose(f);
|
|
}
|
|
|
|
// Load stuff from launch options, including username
|
|
const Win64LaunchOptions launchOptions = ParseLaunchOptions();
|
|
ApplyScreenMode(launchOptions.screenMode);
|
|
|
|
// Ensure uid.dat exists from startup (before any multiplayer/login path).
|
|
Win64Xuid::ResolvePersistentXuid();
|
|
|
|
// If no username, let's fall back
|
|
if (g_Win64Username[0] == 0)
|
|
{
|
|
// Default username will be "Player"
|
|
strncpy_s(g_Win64Username, sizeof(g_Win64Username), "Player", _TRUNCATE);
|
|
}
|
|
|
|
MultiByteToWideChar(CP_ACP, 0, g_Win64Username, -1, g_Win64UsernameW, 17);
|
|
|
|
// convert servers.txt to servers.db
|
|
if (GetFileAttributesA("servers.txt") != INVALID_FILE_ATTRIBUTES &&
|
|
GetFileAttributesA("servers.db") == INVALID_FILE_ATTRIBUTES)
|
|
{
|
|
FILE* txtFile = nullptr;
|
|
if (fopen_s(&txtFile, "servers.txt", "r") == 0 && txtFile)
|
|
{
|
|
struct MigEntry { std::string ip; uint16_t port; std::string name; };
|
|
std::vector<MigEntry> migEntries;
|
|
char line[512];
|
|
|
|
while (fgets(line, sizeof(line), txtFile))
|
|
{
|
|
int l = (int)strlen(line);
|
|
while (l > 0 && (line[l - 1] == '\n' || line[l - 1] == '\r' || line[l - 1] == ' '))
|
|
line[--l] = '\0';
|
|
if (l == 0) continue;
|
|
|
|
std::string srvIP = line;
|
|
|
|
if (!fgets(line, sizeof(line), txtFile)) break;
|
|
l = (int)strlen(line);
|
|
while (l > 0 && (line[l - 1] == '\n' || line[l - 1] == '\r' || line[l - 1] == ' '))
|
|
line[--l] = '\0';
|
|
uint16_t srvPort = (uint16_t)atoi(line);
|
|
|
|
std::string srvName;
|
|
if (fgets(line, sizeof(line), txtFile))
|
|
{
|
|
l = (int)strlen(line);
|
|
while (l > 0 && (line[l - 1] == '\n' || line[l - 1] == '\r' || line[l - 1] == ' '))
|
|
line[--l] = '\0';
|
|
srvName = line;
|
|
}
|
|
|
|
if (!srvIP.empty() && srvPort > 0)
|
|
migEntries.push_back({srvIP, srvPort, srvName});
|
|
}
|
|
fclose(txtFile);
|
|
|
|
if (!migEntries.empty())
|
|
{
|
|
FILE* dbFile = nullptr;
|
|
if (fopen_s(&dbFile, "servers.db", "wb") == 0 && dbFile)
|
|
{
|
|
fwrite("MCSV", 1, 4, dbFile);
|
|
uint32_t ver = 1;
|
|
uint32_t cnt = (uint32_t)migEntries.size();
|
|
fwrite(&ver, sizeof(uint32_t), 1, dbFile);
|
|
fwrite(&cnt, sizeof(uint32_t), 1, dbFile);
|
|
for (size_t i = 0; i < migEntries.size(); i++)
|
|
{
|
|
uint16_t ipLen = (uint16_t)migEntries[i].ip.length();
|
|
fwrite(&ipLen, sizeof(uint16_t), 1, dbFile);
|
|
fwrite(migEntries[i].ip.c_str(), 1, ipLen, dbFile);
|
|
fwrite(&migEntries[i].port, sizeof(uint16_t), 1, dbFile);
|
|
uint16_t nameLen = (uint16_t)migEntries[i].name.length();
|
|
fwrite(&nameLen, sizeof(uint16_t), 1, dbFile);
|
|
fwrite(migEntries[i].name.c_str(), 1, nameLen, dbFile);
|
|
}
|
|
fclose(dbFile);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Initialize global strings
|
|
MyRegisterClass(hInstance);
|
|
|
|
// Perform application initialization:
|
|
if (!InitInstance (hInstance, nCmdShow))
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
hMyInst=hInstance;
|
|
|
|
if( FAILED( InitDevice() ) )
|
|
{
|
|
CleanupDevice();
|
|
return 0;
|
|
}
|
|
|
|
// Restore fullscreen state from previous session. Route through the
|
|
// deferred exclusive fullscreen path so the main loop applies it on the
|
|
// first tick (safer than transitioning during init).
|
|
if ((LoadFullscreenOption() && !g_isFullscreen) || launchOptions.fullscreen)
|
|
{
|
|
g_bPendingExclusiveFullscreen = true;
|
|
g_bPendingExclusiveFullscreenValue = true;
|
|
}
|
|
|
|
#if 0
|
|
// Main message loop
|
|
MSG msg = {0};
|
|
while( WM_QUIT != msg.message )
|
|
{
|
|
if( PeekMessage( &msg, nullptr, 0, 0, PM_REMOVE ) )
|
|
{
|
|
TranslateMessage( &msg );
|
|
DispatchMessage( &msg );
|
|
}
|
|
else
|
|
{
|
|
Render();
|
|
}
|
|
}
|
|
|
|
return (int) msg.wParam;
|
|
#endif
|
|
|
|
static bool bTrialTimerDisplayed=true;
|
|
|
|
#ifdef MEMORY_TRACKING
|
|
ResetMem();
|
|
MEMORYSTATUS memStat;
|
|
GlobalMemoryStatus(&memStat);
|
|
printf("RESETMEM start: Avail. phys %d\n",memStat.dwAvailPhys/(1024*1024));
|
|
#endif
|
|
|
|
#if 0
|
|
// Initialize D3D
|
|
hr = InitD3D( &pDevice, &d3dpp );
|
|
g_pD3DDevice = pDevice;
|
|
if( FAILED(hr) )
|
|
{
|
|
app.DebugPrintf
|
|
( "Failed initializing D3D.\n" );
|
|
return -1;
|
|
}
|
|
|
|
// Initialize the application, assuming sharing of the d3d interface.
|
|
hr = app.InitShared( pDevice, &d3dpp,
|
|
XuiPNGTextureLoader );
|
|
|
|
if ( FAILED(hr) )
|
|
{
|
|
app.DebugPrintf
|
|
( "Failed initializing application.\n" );
|
|
|
|
return -1;
|
|
}
|
|
|
|
#endif
|
|
Minecraft *pMinecraft = InitialiseMinecraftRuntime();
|
|
if (pMinecraft == nullptr)
|
|
{
|
|
CleanupDevice();
|
|
return 1;
|
|
}
|
|
g_bResizeReady = true;
|
|
|
|
//app.TemporaryCreateGameStart();
|
|
|
|
//Sleep(10000);
|
|
#if 0
|
|
// Intro loop ?
|
|
while(app.IntroRunning())
|
|
{
|
|
ProfileManager.Tick();
|
|
// Tick XUI
|
|
app.RunFrame();
|
|
|
|
// 4J : WESTY : Added to ensure we always have clear background for intro.
|
|
RenderManager.SetClearColour(D3DCOLOR_RGBA(0,0,0,255));
|
|
RenderManager.Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
|
|
|
// Render XUI
|
|
hr = app.Render();
|
|
|
|
// Present the frame.
|
|
RenderManager.Present();
|
|
|
|
// Update XUI Timers
|
|
hr = XuiTimersRun();
|
|
}
|
|
#endif
|
|
MSG msg = {0};
|
|
while( WM_QUIT != msg.message && !app.m_bShutdown)
|
|
{
|
|
g_KBMInput.Tick();
|
|
|
|
while( PeekMessage( &msg, nullptr, 0, 0, PM_REMOVE ) )
|
|
{
|
|
TranslateMessage( &msg );
|
|
DispatchMessage( &msg );
|
|
if (msg.message == WM_QUIT) break;
|
|
}
|
|
if (msg.message == WM_QUIT) break;
|
|
|
|
// When the window is minimized (e.g. "Show Desktop"), skip rendering entirely
|
|
// to avoid pegging the GPU at 100% presenting to a non-visible swap chain.
|
|
if (IsIconic(g_hWnd))
|
|
{
|
|
Sleep(100);
|
|
continue;
|
|
}
|
|
|
|
const float* clearColor = app.GetGameStarted() ? kClearColorBlack : kClearColorWhite;
|
|
RenderManager.SetClearColour(clearColor);
|
|
RenderManager.StartFrame();
|
|
if (!app.GetGameStarted())
|
|
{
|
|
RenderManager.SetClearColour(kClearColorWhite); // set intro scene background to white
|
|
RenderManager.Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
|
}
|
|
#if 0
|
|
if(pMinecraft->soundEngine->isStreamingWavebankReady() &&
|
|
!pMinecraft->soundEngine->isPlayingStreamingGameMusic() &&
|
|
!pMinecraft->soundEngine->isPlayingStreamingCDMusic() )
|
|
{
|
|
// play some music in the menus
|
|
pMinecraft->soundEngine->playStreaming(L"", 0, 0, 0, 0, 0, false);
|
|
}
|
|
#endif
|
|
|
|
// static bool bPlay=false;
|
|
// if(bPlay)
|
|
// {
|
|
// bPlay=false;
|
|
// app.audio.PlaySound();
|
|
// }
|
|
|
|
app.UpdateTime();
|
|
PIXBeginNamedEvent(0,"Input manager tick");
|
|
InputManager.Tick();
|
|
|
|
// Detect KBM vs controller input mode
|
|
if (InputManager.IsPadConnected(0))
|
|
{
|
|
const bool controllerUsed = InputManager.ButtonPressed(0) ||
|
|
InputManager.GetJoypadStick_LX(0, false) != 0.0f ||
|
|
InputManager.GetJoypadStick_LY(0, false) != 0.0f ||
|
|
InputManager.GetJoypadStick_RX(0, false) != 0.0f ||
|
|
InputManager.GetJoypadStick_RY(0, false) != 0.0f;
|
|
|
|
if (controllerUsed)
|
|
g_KBMInput.SetKBMActive(false);
|
|
else if (g_KBMInput.HasAnyInput())
|
|
g_KBMInput.SetKBMActive(true);
|
|
}
|
|
else
|
|
{
|
|
g_KBMInput.SetKBMActive(true);
|
|
}
|
|
|
|
if (!g_KBMInput.IsMouseGrabbed())
|
|
{
|
|
if (!g_KBMInput.IsKBMActive())
|
|
g_KBMInput.SetCursorHiddenForUI(true);
|
|
else if (!g_KBMInput.IsScreenCursorHidden())
|
|
g_KBMInput.SetCursorHiddenForUI(false);
|
|
}
|
|
|
|
PIXEndNamedEvent();
|
|
PIXBeginNamedEvent(0,"Profile manager tick");
|
|
// ProfileManager.Tick();
|
|
PIXEndNamedEvent();
|
|
PIXBeginNamedEvent(0,"Storage manager tick");
|
|
StorageManager.Tick();
|
|
PIXEndNamedEvent();
|
|
PIXBeginNamedEvent(0,"Render manager tick");
|
|
RenderManager.Tick();
|
|
PIXEndNamedEvent();
|
|
|
|
// Tick the social networking manager.
|
|
PIXBeginNamedEvent(0,"Social network manager tick");
|
|
// CSocialManager::Instance()->Tick();
|
|
PIXEndNamedEvent();
|
|
|
|
// Tick sentient.
|
|
PIXBeginNamedEvent(0,"Sentient tick");
|
|
MemSect(37);
|
|
// SentientManager.Tick();
|
|
MemSect(0);
|
|
PIXEndNamedEvent();
|
|
|
|
PIXBeginNamedEvent(0,"Network manager do work #1");
|
|
g_NetworkManager.DoWork();
|
|
PIXEndNamedEvent();
|
|
|
|
// LeaderboardManager::Instance()->Tick();
|
|
// Render game graphics.
|
|
if(app.GetGameStarted())
|
|
{
|
|
pMinecraft->applyFrameMouseLook(); // Per-frame mouse look (before ticks + render)
|
|
pMinecraft->run_middle();
|
|
app.SetAppPaused( g_NetworkManager.IsLocalGame() && g_NetworkManager.GetPlayerCount() == 1 && ui.IsPauseMenuDisplayed(ProfileManager.GetPrimaryPad()) );
|
|
}
|
|
else
|
|
{
|
|
MemSect(28);
|
|
pMinecraft->soundEngine->tick(nullptr, 0.0f);
|
|
MemSect(0);
|
|
pMinecraft->textures->tick(true,false);
|
|
IntCache::Reset();
|
|
if( app.GetReallyChangingSessionType() )
|
|
{
|
|
pMinecraft->tickAllConnections(); // Added to stop timing out when we are waiting after converting to an offline game
|
|
}
|
|
}
|
|
|
|
pMinecraft->soundEngine->playMusicTick();
|
|
|
|
#ifdef MEMORY_TRACKING
|
|
static bool bResetMemTrack = false;
|
|
static bool bDumpMemTrack = false;
|
|
|
|
MemPixStuff();
|
|
|
|
if( bResetMemTrack )
|
|
{
|
|
ResetMem();
|
|
MEMORYSTATUS memStat;
|
|
GlobalMemoryStatus(&memStat);
|
|
printf("RESETMEM: Avail. phys %d\n",memStat.dwAvailPhys/(1024*1024));
|
|
bResetMemTrack = false;
|
|
}
|
|
|
|
if( bDumpMemTrack )
|
|
{
|
|
DumpMem();
|
|
bDumpMemTrack = false;
|
|
MEMORYSTATUS memStat;
|
|
GlobalMemoryStatus(&memStat);
|
|
printf("DUMPMEM: Avail. phys %d\n",memStat.dwAvailPhys/(1024*1024));
|
|
printf("Renderer used: %d\n",RenderManager.CBuffSize(-1));
|
|
}
|
|
#endif
|
|
#if 0
|
|
static bool bDumpTextureUsage = false;
|
|
if( bDumpTextureUsage )
|
|
{
|
|
RenderManager.TextureGetStats();
|
|
bDumpTextureUsage = false;
|
|
}
|
|
#endif
|
|
ui.tick();
|
|
ui.render();
|
|
|
|
pMinecraft->gameRenderer->ApplyGammaPostProcess();
|
|
|
|
#if 0
|
|
app.HandleButtonPresses();
|
|
|
|
// store the minecraft renderstates, and re-set them after the xui render
|
|
GetRenderAndSamplerStates(pDevice,RenderStateA,SamplerStateA);
|
|
|
|
// Tick XUI
|
|
PIXBeginNamedEvent(0,"Xui running");
|
|
app.RunFrame();
|
|
PIXEndNamedEvent();
|
|
|
|
// Render XUI
|
|
|
|
PIXBeginNamedEvent(0,"XUI render");
|
|
MemSect(7);
|
|
hr = app.Render();
|
|
MemSect(0);
|
|
GetRenderAndSamplerStates(pDevice,RenderStateA2,SamplerStateA2);
|
|
PIXEndNamedEvent();
|
|
|
|
for(int i=0;i<8;i++)
|
|
{
|
|
if(RenderStateA2[i]!=RenderStateA[i])
|
|
{
|
|
//printf("Reseting RenderStateA[%d] after a XUI render\n",i);
|
|
pDevice->SetRenderState(RenderStateModes[i],RenderStateA[i]);
|
|
}
|
|
}
|
|
for(int i=0;i<5;i++)
|
|
{
|
|
if(SamplerStateA2[i]!=SamplerStateA[i])
|
|
{
|
|
//printf("Reseting SamplerStateA[%d] after a XUI render\n",i);
|
|
pDevice->SetSamplerState(0,SamplerStateModes[i],SamplerStateA[i]);
|
|
}
|
|
}
|
|
|
|
RenderManager.Set_matrixDirty();
|
|
#endif
|
|
// Present the frame. RenderManager.Present() hardcodes SyncInterval=1,
|
|
// so when VSync is off we bypass it for uncapped frames. In DXGI
|
|
// exclusive fullscreen this produces real tearing via direct scanout.
|
|
if (!g_bVSync && g_pSwapChain)
|
|
{
|
|
HRESULT hrPresent = g_pSwapChain->Present(0, 0);
|
|
// If the direct Present fails (e.g. during fullscreen transition),
|
|
// fall back to the library's VSync'd Present for this frame.
|
|
if (FAILED(hrPresent))
|
|
RenderManager.Present();
|
|
}
|
|
else
|
|
{
|
|
RenderManager.Present();
|
|
}
|
|
|
|
ui.CheckMenuDisplayed();
|
|
|
|
// Update mouse grab: grab when in-game and no menu is open
|
|
{
|
|
static bool altToggleSuppressCapture = false;
|
|
const bool shouldCapture = app.GetGameStarted() && !ui.GetMenuDisplayed(0) && pMinecraft->screen == nullptr;
|
|
// Left Alt key toggles capture on/off for debugging
|
|
if (g_KBMInput.IsKeyPressed(VK_LMENU) || g_KBMInput.IsKeyPressed(VK_RMENU))
|
|
{
|
|
if (g_KBMInput.IsMouseGrabbed()) { g_KBMInput.SetMouseGrabbed(false); altToggleSuppressCapture = true; }
|
|
else if (shouldCapture) { g_KBMInput.SetMouseGrabbed(true); altToggleSuppressCapture = false; }
|
|
}
|
|
else if (!shouldCapture)
|
|
{
|
|
if (g_KBMInput.IsMouseGrabbed()) g_KBMInput.SetMouseGrabbed(false);
|
|
altToggleSuppressCapture = false;
|
|
}
|
|
else if (shouldCapture && !g_KBMInput.IsMouseGrabbed() && GetFocus() == g_hWnd && !altToggleSuppressCapture)
|
|
{
|
|
g_KBMInput.SetMouseGrabbed(true);
|
|
}
|
|
}
|
|
|
|
// F2 takes a screenshot (works in any context)
|
|
if (g_KBMInput.IsKeyPressed(KeyboardMouseInput::KEY_SCREENSHOT))
|
|
{
|
|
wstring filename;
|
|
if (TakeScreenshot(filename))
|
|
{
|
|
if (pMinecraft->gui && pMinecraft->player)
|
|
{
|
|
wstring msg = L"Saved screenshot to " + filename;
|
|
pMinecraft->gui->addMessage(msg, ProfileManager.GetPrimaryPad());
|
|
}
|
|
}
|
|
}
|
|
|
|
// F1 toggles the HUD
|
|
if (g_KBMInput.IsKeyPressed(KeyboardMouseInput::KEY_TOGGLE_HUD))
|
|
{
|
|
const int primaryPad = ProfileManager.GetPrimaryPad();
|
|
const unsigned char displayHud = app.GetGameSettings(primaryPad, eGameSetting_DisplayHUD);
|
|
app.SetGameSettings(primaryPad, eGameSetting_DisplayHUD, displayHud ? 0 : 1);
|
|
app.SetGameSettings(primaryPad, eGameSetting_DisplayHand, displayHud ? 0 : 1);
|
|
}
|
|
|
|
// F3 toggles onscreen debug info
|
|
if (g_KBMInput.IsKeyPressed(KeyboardMouseInput::KEY_DEBUG_INFO)) f3ComboUsed = false;
|
|
|
|
// f3 combo
|
|
if (g_KBMInput.IsKeyDown(KeyboardMouseInput::KEY_DEBUG_INFO))
|
|
{
|
|
switch (g_KBMInput.GetPressedKey())
|
|
{
|
|
// advanced tooltips
|
|
case 'H':
|
|
if (pMinecraft->options && app.GetGameStarted())
|
|
{
|
|
pMinecraft->options->advancedTooltips = !pMinecraft->options->advancedTooltips;
|
|
pMinecraft->options->save();
|
|
|
|
const wstring msg = wstring(L"Advanced tooltips: ") + (pMinecraft->options->advancedTooltips ? L"shown" : L"hidden");
|
|
const int primaryPad = ProfileManager.GetPrimaryPad();
|
|
if (pMinecraft->gui) pMinecraft->gui->addMessage(msg, primaryPad);
|
|
|
|
f3ComboUsed = true;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
// no combo
|
|
if (g_KBMInput.IsKeyReleased(KeyboardMouseInput::KEY_DEBUG_INFO) && !f3ComboUsed)
|
|
if (pMinecraft->options)
|
|
pMinecraft->options->renderDebug = !pMinecraft->options->renderDebug;
|
|
|
|
|
|
|
|
#ifdef _DEBUG_MENUS_ENABLED
|
|
// F6 Open debug console
|
|
if (g_KBMInput.IsKeyPressed(KeyboardMouseInput::KEY_DEBUG_CONSOLE))
|
|
{
|
|
static bool s_debugConsole = false;
|
|
s_debugConsole = !s_debugConsole;
|
|
ui.ShowUIDebugConsole(s_debugConsole);
|
|
}
|
|
#endif
|
|
|
|
// toggle fullscreen (DXGI exclusive via ApplyExclusiveFullscreen)
|
|
if (g_KBMInput.IsKeyPressed(KeyboardMouseInput::KEY_FULLSCREEN))
|
|
{
|
|
ApplyExclusiveFullscreen(!g_bDxgiExclusiveFullscreen);
|
|
app.SetGameSettings(ProfileManager.GetPrimaryPad(), eGameSetting_ExclusiveFullscreen, g_bDxgiExclusiveFullscreen ? 1 : 0);
|
|
}
|
|
|
|
// Apply deferred exclusive fullscreen toggle
|
|
if (g_bPendingExclusiveFullscreen)
|
|
{
|
|
g_bPendingExclusiveFullscreen = false;
|
|
ApplyExclusiveFullscreen(g_bPendingExclusiveFullscreenValue);
|
|
}
|
|
|
|
// TAB opens game info menu. - Vvis :3 - Updated by detectiveren
|
|
if (g_KBMInput.IsKeyPressed(KeyboardMouseInput::KEY_HOST_SETTINGS) && !ui.GetMenuDisplayed(0))
|
|
{
|
|
if (Minecraft* pMinecraft = Minecraft::GetInstance())
|
|
{
|
|
{
|
|
ui.NavigateToScene(0, eUIScene_InGameInfoMenu);
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
// Open chat
|
|
if (g_KBMInput.IsKeyPressed(KeyboardMouseInput::KEY_CHAT) && app.GetGameStarted() && !ui.GetMenuDisplayed(0) && pMinecraft->screen == NULL)
|
|
{
|
|
g_KBMInput.ClearCharBuffer();
|
|
pMinecraft->setScreen(new ChatScreen());
|
|
SetFocus(g_hWnd);
|
|
}
|
|
|
|
#if 0
|
|
// has the game defined profile data been changed (by a profile load)
|
|
if(app.uiGameDefinedDataChangedBitmask!=0)
|
|
{
|
|
void *pData;
|
|
for(int i=0;i<XUSER_MAX_COUNT;i++)
|
|
{
|
|
if(app.uiGameDefinedDataChangedBitmask&(1<<i))
|
|
{\
|
|
// It has - game needs to update its values with the data from the profile
|
|
pData=ProfileManager.GetGameDefinedProfileData(i);
|
|
// reset the changed flag
|
|
app.ClearGameSettingsChangedFlag(i);
|
|
app.DebugPrintf("*** - APPLYING GAME SETTINGS CHANGE for pad %d\n",i);
|
|
app.ApplyGameSettingsChanged(i);
|
|
|
|
#ifdef _DEBUG_MENUS_ENABLED
|
|
if(app.DebugSettingsOn())
|
|
{
|
|
app.ActionDebugMask(i);
|
|
}
|
|
else
|
|
{
|
|
// force debug mask off
|
|
app.ActionDebugMask(i,true);
|
|
}
|
|
#endif
|
|
// clear the stats first - there could have beena signout and sign back in in the menus
|
|
// need to clear the player stats - can't assume it'll be done in setlevel - we may not be in the game
|
|
pMinecraft->stats[ i ]->clear();
|
|
pMinecraft->stats[i]->parse(pData);
|
|
}
|
|
}
|
|
|
|
// Check to see if we can post to social networks.
|
|
CSocialManager::Instance()->RefreshPostingCapability();
|
|
|
|
// clear the flag
|
|
app.uiGameDefinedDataChangedBitmask=0;
|
|
|
|
// Check if any profile write are needed
|
|
app.CheckGameSettingsChanged();
|
|
}
|
|
PIXEndNamedEvent();
|
|
app.TickDLCOffersRetrieved();
|
|
app.TickTMSPPFilesRetrieved();
|
|
|
|
PIXBeginNamedEvent(0,"Network manager do work #2");
|
|
g_NetworkManager.DoWork();
|
|
PIXEndNamedEvent();
|
|
|
|
PIXBeginNamedEvent(0,"Misc extra xui");
|
|
// Update XUI Timers
|
|
hr = XuiTimersRun();
|
|
|
|
#endif
|
|
// Any threading type things to deal with from the xui side?
|
|
app.HandleXuiActions();
|
|
|
|
#if 0
|
|
PIXEndNamedEvent();
|
|
#endif
|
|
|
|
// 4J-PB - Update the trial timer display if we are in the trial version
|
|
if(!ProfileManager.IsFullVersion())
|
|
{
|
|
// display the trial timer
|
|
if(app.GetGameStarted())
|
|
{
|
|
// 4J-PB - if the game is paused, add the elapsed time to the trial timer count so it doesn't tick down
|
|
if(app.IsAppPaused())
|
|
{
|
|
app.UpdateTrialPausedTimer();
|
|
}
|
|
ui.UpdateTrialTimer(ProfileManager.GetPrimaryPad());
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// need to turn off the trial timer if it was on , and we've unlocked the full version
|
|
if(bTrialTimerDisplayed)
|
|
{
|
|
ui.ShowTrialTimer(false);
|
|
bTrialTimerDisplayed=false;
|
|
}
|
|
}
|
|
|
|
// Fix for #7318 - Title crashes after short soak in the leaderboards menu
|
|
// A memory leak was caused because the icon renderer kept creating new Vec3's because the pool wasn't reset
|
|
Vec3::resetPool();
|
|
}
|
|
|
|
// Free resources, unregister custom classes, and exit.
|
|
// app.Uninit();
|
|
g_pd3dDevice->Release();
|
|
}
|
|
|
|
#ifdef MEMORY_TRACKING
|
|
|
|
int totalAllocGen = 0;
|
|
unordered_map<int,int> allocCounts;
|
|
bool trackEnable = false;
|
|
bool trackStarted = false;
|
|
volatile size_t sizeCheckMin = 1160;
|
|
volatile size_t sizeCheckMax = 1160;
|
|
volatile int sectCheck = 48;
|
|
CRITICAL_SECTION memCS;
|
|
DWORD tlsIdx;
|
|
|
|
LPVOID XMemAlloc(SIZE_T dwSize, DWORD dwAllocAttributes)
|
|
{
|
|
if( !trackStarted )
|
|
{
|
|
void *p = XMemAllocDefault(dwSize,dwAllocAttributes);
|
|
size_t realSize = XMemSizeDefault(p, dwAllocAttributes);
|
|
totalAllocGen += realSize;
|
|
return p;
|
|
}
|
|
|
|
EnterCriticalSection(&memCS);
|
|
|
|
void *p=XMemAllocDefault(dwSize + 16,dwAllocAttributes);
|
|
size_t realSize = XMemSizeDefault(p,dwAllocAttributes) - 16;
|
|
|
|
if( trackEnable )
|
|
{
|
|
#if 1
|
|
int sect = ((int) TlsGetValue(tlsIdx)) & 0x3f;
|
|
*(((unsigned char *)p)+realSize) = sect;
|
|
|
|
if( ( realSize >= sizeCheckMin ) && ( realSize <= sizeCheckMax ) && ( ( sect == sectCheck ) || ( sectCheck == -1 ) ) )
|
|
{
|
|
app.DebugPrintf("Found one\n");
|
|
}
|
|
#endif
|
|
|
|
if( p )
|
|
{
|
|
totalAllocGen += realSize;
|
|
trackEnable = false;
|
|
int key = ( sect << 26 ) | realSize;
|
|
int oldCount = allocCounts[key];
|
|
allocCounts[key] = oldCount + 1;
|
|
|
|
trackEnable = true;
|
|
}
|
|
}
|
|
|
|
LeaveCriticalSection(&memCS);
|
|
|
|
return p;
|
|
}
|
|
|
|
void* operator new (size_t size)
|
|
{
|
|
return (unsigned char *)XMemAlloc(size,MAKE_XALLOC_ATTRIBUTES(0,FALSE,TRUE,FALSE,0,XALLOC_PHYSICAL_ALIGNMENT_DEFAULT,XALLOC_MEMPROTECT_READWRITE,FALSE,XALLOC_MEMTYPE_HEAP));
|
|
}
|
|
|
|
void operator delete (void *p)
|
|
{
|
|
XMemFree(p,MAKE_XALLOC_ATTRIBUTES(0,FALSE,TRUE,FALSE,0,XALLOC_PHYSICAL_ALIGNMENT_DEFAULT,XALLOC_MEMPROTECT_READWRITE,FALSE,XALLOC_MEMTYPE_HEAP));
|
|
}
|
|
|
|
void WINAPI XMemFree(PVOID pAddress, DWORD dwAllocAttributes)
|
|
{
|
|
bool special = false;
|
|
if( dwAllocAttributes == 0 )
|
|
{
|
|
dwAllocAttributes = MAKE_XALLOC_ATTRIBUTES(0,FALSE,TRUE,FALSE,0,XALLOC_PHYSICAL_ALIGNMENT_DEFAULT,XALLOC_MEMPROTECT_READWRITE,FALSE,XALLOC_MEMTYPE_HEAP);
|
|
special = true;
|
|
}
|
|
if(!trackStarted )
|
|
{
|
|
size_t realSize = XMemSizeDefault(pAddress, dwAllocAttributes);
|
|
XMemFreeDefault(pAddress, dwAllocAttributes);
|
|
totalAllocGen -= realSize;
|
|
return;
|
|
}
|
|
EnterCriticalSection(&memCS);
|
|
if( pAddress )
|
|
{
|
|
size_t realSize = XMemSizeDefault(pAddress, dwAllocAttributes) - 16;
|
|
|
|
if(trackEnable)
|
|
{
|
|
int sect = *(((unsigned char *)pAddress)+realSize);
|
|
totalAllocGen -= realSize;
|
|
trackEnable = false;
|
|
int key = ( sect << 26 ) | realSize;
|
|
int oldCount = allocCounts[key];
|
|
allocCounts[key] = oldCount - 1;
|
|
trackEnable = true;
|
|
}
|
|
XMemFreeDefault(pAddress, dwAllocAttributes);
|
|
}
|
|
LeaveCriticalSection(&memCS);
|
|
}
|
|
|
|
SIZE_T WINAPI XMemSize(
|
|
PVOID pAddress,
|
|
DWORD dwAllocAttributes
|
|
)
|
|
{
|
|
if( trackStarted )
|
|
{
|
|
return XMemSizeDefault(pAddress, dwAllocAttributes) - 16;
|
|
}
|
|
else
|
|
{
|
|
return XMemSizeDefault(pAddress, dwAllocAttributes);
|
|
}
|
|
}
|
|
|
|
void DumpMem()
|
|
{
|
|
int totalLeak = 0;
|
|
for( auto it = allocCounts.begin(); it != allocCounts.end(); it++ )
|
|
{
|
|
if(it->second > 0 )
|
|
{
|
|
app.DebugPrintf("%d %d %d %d\n",( it->first >> 26 ) & 0x3f,it->first & 0x03ffffff, it->second, (it->first & 0x03ffffff) * it->second);
|
|
totalLeak += ( it->first & 0x03ffffff ) * it->second;
|
|
}
|
|
}
|
|
app.DebugPrintf("Total %d\n",totalLeak);
|
|
}
|
|
|
|
void ResetMem()
|
|
{
|
|
if( !trackStarted )
|
|
{
|
|
trackEnable = true;
|
|
trackStarted = true;
|
|
totalAllocGen = 0;
|
|
InitializeCriticalSection(&memCS);
|
|
tlsIdx = TlsAlloc();
|
|
}
|
|
EnterCriticalSection(&memCS);
|
|
trackEnable = false;
|
|
allocCounts.clear();
|
|
trackEnable = true;
|
|
LeaveCriticalSection(&memCS);
|
|
}
|
|
|
|
void MemSect(int section)
|
|
{
|
|
unsigned int value = (unsigned int)TlsGetValue(tlsIdx);
|
|
if( section == 0 ) // pop
|
|
{
|
|
value = (value >> 6) & 0x03ffffff;
|
|
}
|
|
else
|
|
{
|
|
value = (value << 6) | section;
|
|
}
|
|
TlsSetValue(tlsIdx, (LPVOID)value);
|
|
}
|
|
|
|
void MemPixStuff()
|
|
{
|
|
const int MAX_SECT = 46;
|
|
|
|
int totals[MAX_SECT] = {0};
|
|
|
|
for( auto it = allocCounts.begin(); it != allocCounts.end(); it++ )
|
|
{
|
|
if(it->second > 0 )
|
|
{
|
|
int sect = ( it->first >> 26 ) & 0x3f;
|
|
int bytes = it->first & 0x03ffffff;
|
|
totals[sect] += bytes * it->second;
|
|
}
|
|
}
|
|
|
|
unsigned int allSectsTotal = 0;
|
|
for( int i = 0; i < MAX_SECT; i++ )
|
|
{
|
|
allSectsTotal += totals[i];
|
|
PIXAddNamedCounter(((float)totals[i])/1024.0f,"MemSect%d",i);
|
|
}
|
|
|
|
PIXAddNamedCounter(((float)allSectsTotal)/(4096.0f),"MemSect total pages");
|
|
}
|
|
|
|
#endif
|