mirror of
https://github.com/thunderbrewhq/thunderbrew
synced 2025-11-02 09:16:03 +03:00
346 lines
12 KiB
C++
346 lines
12 KiB
C++
#include "console/Device.hpp"
|
|
#include "client/CmdLine.hpp"
|
|
#include "os/Gui.hpp"
|
|
#include "console/CVar.hpp"
|
|
#include "console/Console.hpp"
|
|
#include "console/Detect.hpp"
|
|
#include "console/Gx.hpp"
|
|
#include "console/cvar/Gx.hpp"
|
|
#include "os/Input.hpp"
|
|
#include "gx/CGxFormat.hpp"
|
|
#include "gx/Device.hpp"
|
|
#include "gx/Types.hpp"
|
|
#include "console/command/Commands.hpp"
|
|
#include "db/Startup_Strings.hpp"
|
|
#include <storm/String.hpp>
|
|
#include <tempest/Vector.hpp>
|
|
#include <cstdio>
|
|
#include <cstring>
|
|
|
|
CVar* s_cvHwDetect;
|
|
DefaultSettings s_defaults;
|
|
Hardware s_hardware;
|
|
bool s_hardwareDetected;
|
|
bool s_hwChanged;
|
|
bool s_hwDetect;
|
|
TSGrowableArray<CGxMonitorMode> s_gxMonitorModes;
|
|
CGxDevice* s_device;
|
|
char s_windowTitle[256];
|
|
CGxFormat s_requestedFormat;
|
|
CGxFormat s_fallbackFormat = { 0, { 640, 480 }, CGxFormat::Fmt_Rgb565, CGxFormat::Fmt_Ds160, 60, true, true, false, true, true, false };
|
|
CGxFormat s_lastGoodFormat;
|
|
CGxFormat s_desktopFormat = { 0, { 800, 600 }, CGxFormat::Fmt_Rgb565, CGxFormat::Fmt_Ds24X, 60, true, true, false, true, true, false };
|
|
|
|
uint32_t s_FormatTobpp[4] = {
|
|
16,
|
|
32,
|
|
32,
|
|
32
|
|
};
|
|
|
|
void OnGxStereoChanged() {
|
|
// ???
|
|
}
|
|
|
|
void ValidateFormatMonitor(CGxFormat& fmt) {
|
|
static C2iVector standardSizes[] = {
|
|
{ 1600, 1200 },
|
|
{ 1280, 1024 },
|
|
{ 1280, 960 },
|
|
{ 1152, 864 },
|
|
{ 1024, 768 },
|
|
{ 800, 600 },
|
|
{ 640, 480 }
|
|
};
|
|
|
|
auto fmtbpp = s_FormatTobpp[fmt.colorFormat];
|
|
|
|
int32_t lowRate = 9999;
|
|
|
|
int32_t i = 0;
|
|
while (i < s_gxMonitorModes.Count()) {
|
|
auto& size = s_gxMonitorModes[i].size;
|
|
|
|
if (fmt.size.x == size.x && fmt.size.y == size.y && fmtbpp == s_gxMonitorModes[i].bpp) {
|
|
uint32_t refreshRate = s_gxMonitorModes[i].refreshRate;
|
|
if (refreshRate < lowRate) {
|
|
lowRate = refreshRate;
|
|
}
|
|
if (fmt.refreshRate == refreshRate) {
|
|
return;
|
|
}
|
|
}
|
|
|
|
i++;
|
|
}
|
|
|
|
auto rate = lowRate;
|
|
if (lowRate == 9999) {
|
|
GxLog("ValidateFormatMonitor(): unable to find monitor refresh");
|
|
rate = 60;
|
|
}
|
|
|
|
GxLog("ValidateFormatMonitor(): invalid refresh rate %d, set to %d", fmt.refreshRate, rate);
|
|
fmt.refreshRate = rate;
|
|
}
|
|
|
|
void ConsoleDeviceStereoInitialize() {
|
|
s_cvGxStereoConvergence = CVar::Register(
|
|
"gxStereoConvergence",
|
|
"Set stereoscopic rendering convergence depth",
|
|
0x1,
|
|
"1",
|
|
CVGxStereoConvergenceCallback,
|
|
GRAPHICS,
|
|
false,
|
|
nullptr,
|
|
false
|
|
);
|
|
s_cvGxStereoSeparation = CVar::Register(
|
|
"gxStereoSeparation",
|
|
"Set stereoscopic rendering separation percentage",
|
|
0x1,
|
|
"25",
|
|
CVGxStereoSeparationCallback,
|
|
GRAPHICS,
|
|
false,
|
|
nullptr,
|
|
false
|
|
);
|
|
|
|
// g_theGxDevicePtr->AddStereoChangedCallback(nullsub_3);
|
|
GxAddStereoChangedCallback(OnGxStereoChanged);
|
|
}
|
|
|
|
void ConsoleDeviceInitialize(const char* title) {
|
|
GxLogOpen();
|
|
|
|
s_cvHwDetect = CVar::Register(
|
|
"hwDetect",
|
|
"do hardware detection",
|
|
0x1,
|
|
"1",
|
|
nullptr,
|
|
GRAPHICS,
|
|
false,
|
|
nullptr,
|
|
false
|
|
);
|
|
|
|
ConsoleDetectDetectHardware(s_hardware, s_hwChanged);
|
|
s_hardwareDetected = true;
|
|
|
|
if (CmdLineGetBool(CMD_HW_DETECT) == 1 || s_cvHwDetect->GetInt() != 0) {
|
|
s_hwDetect = true;
|
|
s_cvHwDetect->Set("0", true, false, false, true);
|
|
} else {
|
|
s_hwDetect = false;
|
|
}
|
|
|
|
ConsoleAccessSetEnabled(CmdLineGetBool(CMD_CONSOLE) == 1);
|
|
|
|
ConsoleDetectSetDefaultsFormat(s_defaults, s_hardware);
|
|
|
|
RegisterGxCVars();
|
|
|
|
ConsoleCommandRegister("gxRestart", CCGxRestart, GRAPHICS, nullptr);
|
|
|
|
GxAdapterMonitorModes(s_gxMonitorModes);
|
|
ValidateFormatMonitor(s_fallbackFormat);
|
|
|
|
CGxMonitorMode mode;
|
|
mode.size = { 0, 0 };
|
|
if (GxAdapterDesktopMode(mode)) {
|
|
s_desktopFormat.size = mode.size;
|
|
s_desktopFormat.colorFormat = mode.bpp > 16 ? CGxFormat::Fmt_ArgbX888 : CGxFormat::Fmt_Rgb565;
|
|
s_desktopFormat.refreshRate = mode.refreshRate;
|
|
}
|
|
GxLog("ConsoleDeviceInitialize(): hwDetect = %d, hwChanged = %d", s_hwDetect, s_hwChanged);
|
|
|
|
if (CmdLineGetBool(CMD_RES_800x600)) {
|
|
s_requestedFormat.size = { 800, 600 };
|
|
} else if (CmdLineGetBool(CMD_RES_1024x768)) {
|
|
s_requestedFormat.size = { 1024, 768 };
|
|
} else if (CmdLineGetBool(CMD_RES_1280x960)) {
|
|
s_requestedFormat.size = { 1280, 960 };
|
|
} else if (CmdLineGetBool(CMD_RES_1280x1024)) {
|
|
s_requestedFormat.size = { 1280, 1024 };
|
|
} else if (CmdLineGetBool(CMD_RES_1600x1200)) {
|
|
s_requestedFormat.size = { 1600, 1200 };
|
|
}
|
|
|
|
// TODO: fixed function rendering!!!
|
|
if (s_cvFixedFunction->GetInt()) {
|
|
// TODO: IMPORTANT: figure out what these are called
|
|
s_requestedFormat.unk48 = 0;
|
|
s_requestedFormat.unk38 = 0;
|
|
}
|
|
|
|
if (s_hwDetect || s_hwChanged) {
|
|
ConsoleDetectSetDefaults(s_defaults, s_hardware);
|
|
s_cvFixedFunction->Set("0", true, false, false, true);
|
|
memcpy(&s_requestedFormat, s_defaults.format, sizeof(CGxFormat));
|
|
s_requestedFormat.window = s_cvGxWindow->GetInt() != 0;
|
|
s_requestedFormat.maximize = s_cvGxMaximize->GetInt() != 0;
|
|
SetGxCVars(s_requestedFormat);
|
|
}
|
|
|
|
auto gxApi = GxDefaultApi();
|
|
auto cvGxApi = CVar::Lookup("gxApi");
|
|
if (cvGxApi) {
|
|
auto requestedGxApi = cvGxApi->GetString();
|
|
for (auto api = GxApi_OpenGl; api < GxApis_Last; api = static_cast<EGxApi>(static_cast<int32_t>(api) + 1)) {
|
|
if (GxApiSupported(api) && !SStrCmpI(requestedGxApi, g_gxApiNames[api], STORM_MAX_STR)) {
|
|
gxApi = api;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (CmdLineGetBool(CMD_OPENGL) && GxApiSupported(GxApi_OpenGl)) {
|
|
gxApi = GxApi_OpenGl;
|
|
}
|
|
if (CmdLineGetBool(CMD_D3D) && GxApiSupported(GxApi_D3d9)) {
|
|
gxApi = GxApi_D3d9;
|
|
}
|
|
if (CmdLineGetBool(CMD_D3D9EX) && GxApiSupported(GxApi_D3d9Ex)) {
|
|
gxApi = GxApi_D3d9Ex;
|
|
}
|
|
|
|
s_requestedFormat.fixLag = s_cvGxFixLag->GetInt() != 0;
|
|
s_requestedFormat.hwTnL = CmdLineGetBool(CMD_SW_TNL) == 0;
|
|
bool window = s_cvGxWindow->GetInt() != 0;
|
|
if (CmdLineGetBool(CMD_FULL_SCREEN)) {
|
|
window = false;
|
|
} else if (CmdLineGetBool(CMD_WINDOWED)) {
|
|
window = true;
|
|
}
|
|
s_requestedFormat.window = window;
|
|
s_desktopFormat.window = window;
|
|
|
|
bool bVar1 = false;
|
|
CGxFormat apiFormat = s_requestedFormat;
|
|
ValidateFormatMonitor(apiFormat);
|
|
s_device = GxDevCreate(gxApi, OsWindowProc, apiFormat);
|
|
while (!s_device) {
|
|
if (apiFormat.sampleCount < 2) {
|
|
auto colorFormat = apiFormat.colorFormat;
|
|
if (colorFormat <= CGxFormat::Fmt_Rgb565) {
|
|
if (bVar1) {
|
|
GxLog("ConsoleDeviceInitialize(): no output device available!");
|
|
auto titleRecord = g_Startup_StringsDB.GetRecord(MSG_TITLE_WOW);
|
|
auto title = titleRecord ? titleRecord->m_message : "World of Warcraft";
|
|
const char* message;
|
|
if (gxApi == GxApi_D3d9 || gxApi == GxApi_D3d9Ex) {
|
|
auto messageRecord = g_Startup_StringsDB.GetRecord(MSG_GX_INIT_FAILED_D3D);
|
|
message = messageRecord ? messageRecord->m_message : "World of Warcraft was unable to start up 3D acceleration. Please make sure DirectX 9.0c is installed and your video drivers are up-to-date.";
|
|
} else {
|
|
auto messageRecord = g_Startup_StringsDB.GetRecord(MSG_GX_INIT_FAILED);
|
|
message = messageRecord ? messageRecord->m_message : "World of Warcraft was unable to start up 3D acceleration.";
|
|
}
|
|
OsGuiMessageBox(nullptr, 0, message, title);
|
|
GxLogClose();
|
|
exit(0);
|
|
}
|
|
|
|
apiFormat = s_desktopFormat;
|
|
bVar1 = true;
|
|
} else if (apiFormat.depthFormat <= CGxFormat::Fmt_Ds160) {
|
|
apiFormat.colorFormat = static_cast<CGxFormat::Format>(static_cast<int32_t>(apiFormat.colorFormat - 1));
|
|
apiFormat.depthFormat = colorFormat != CGxFormat::Fmt_ArgbX888 ? CGxFormat::Fmt_Ds320 : CGxFormat::Fmt_Ds160;
|
|
} else {
|
|
apiFormat.depthFormat = static_cast<CGxFormat::Format>(static_cast<int32_t>(apiFormat.depthFormat - 1));
|
|
}
|
|
} else {
|
|
apiFormat.sampleCount = std::max(apiFormat.sampleCount - 2, static_cast<uint32_t>(1));
|
|
}
|
|
|
|
ValidateFormatMonitor(apiFormat);
|
|
s_device = GxDevCreate(gxApi, OsWindowProc, apiFormat);
|
|
}
|
|
memcpy(&s_requestedFormat, &apiFormat, sizeof(CGxFormat));
|
|
memcpy(&s_lastGoodFormat, &apiFormat, sizeof(CGxFormat));
|
|
|
|
SetGxCVars(apiFormat);
|
|
|
|
if (GxCaps().m_numTmus < 2) {
|
|
GxDevDestroy(s_device);
|
|
GxLog("ConsoleDeviceInitialize(): output device does not have dual TMUs!");
|
|
auto titleRecord = g_Startup_StringsDB.GetRecord(MSG_TITLE_WOW);
|
|
auto title = titleRecord ? titleRecord->m_message : "World of Warcraft";
|
|
auto messageRecord = g_Startup_StringsDB.GetRecord(MSG_HW_UNSUPPORTED);
|
|
auto message = messageRecord ? messageRecord->m_message : "Your 3D accelerator card is not supported by World of Warcraft. Please install a 3D acceler ator card with dual-TMU support.";
|
|
OsGuiMessageBox(nullptr, 0, message, title);
|
|
GxLogClose();
|
|
exit(0);
|
|
}
|
|
|
|
if (!GxCaps().m_numStreams) {
|
|
GxDevDestroy(s_device);
|
|
GxLog("ConsoleDeviceInitialize(): output device has 0 streams");
|
|
auto titleRecord = g_Startup_StringsDB.GetRecord(MSG_TITLE_WOW);
|
|
auto title = titleRecord ? titleRecord->m_message : "World of Warcraft";
|
|
auto messageRecord = g_Startup_StringsDB.GetRecord(MSG_HW_UNSUPPORTED);
|
|
auto message = messageRecord ? messageRecord->m_message : "Your 3D accelerator card is not supported by World of Warcraft. Please install a 3D acceler ator card with dual-TMU support.";
|
|
OsGuiMessageBox(nullptr, 0, message, title);
|
|
GxLogClose();
|
|
exit(0);
|
|
}
|
|
|
|
switch (GxDevApi()) {
|
|
case GxApi_OpenGl:
|
|
case GxApi_GLL:
|
|
case GxApi_GLSDL:
|
|
ConsoleGxOverride(s_hardware.videoHw->m_oglOverrides);
|
|
break;
|
|
case GxApi_D3d9:
|
|
case GxApi_D3d9Ex:
|
|
ConsoleGxOverride(s_hardware.videoHw->m_d3DOverrides);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
ConsoleGxOverride(CmdLineGetString(CMD_GX_OVERRIDE));
|
|
for (auto override = GxOverride_PixelShader; override < GxOverrides_Last; override = static_cast<EGxOverride>(static_cast<int32_t>(override) + 1)) {
|
|
if (s_consoleGxOverrideSet[override]) {
|
|
GxDevOverride(override, s_consoleGxOverrideVal[override]);
|
|
}
|
|
}
|
|
|
|
OsGuiSetGxWindow(GxDevWindow());
|
|
if (!title) {
|
|
title = "";
|
|
}
|
|
SStrCopy(s_windowTitle, title, sizeof(s_windowTitle));
|
|
auto gxWindow = GxDevWindow();
|
|
if (gxWindow) {
|
|
OsGuiSetWindowTitle(gxWindow, s_windowTitle);
|
|
}
|
|
if (s_hwDetect || s_hwChanged) {
|
|
// TODO: IMPORTANT: find out what the real name is
|
|
s_defaults.unk19 = GxCaps().m_shaderTargets[GxSh_Pixel] != 0;
|
|
}
|
|
|
|
char videoOptionsVersion[32];
|
|
SStrPrintf(videoOptionsVersion, sizeof(videoOptionsVersion), "%d", 3);
|
|
|
|
s_cvVideoOptionsVersion->Set(videoOptionsVersion, true, false, false, true);
|
|
|
|
ConsoleDeviceStereoInitialize();
|
|
|
|
// TODO
|
|
// OsSetSleepInBackground(1);
|
|
// OsSetBackgroundSleepMs(250);
|
|
}
|
|
|
|
bool ConsoleDeviceExists() {
|
|
return s_device != nullptr;
|
|
}
|
|
|
|
void ConsoleDeviceDestroy() {
|
|
GxRemoveStereoChangedCallback(OnGxStereoChanged);
|
|
s_cvVideoOptionsVersion->Update();
|
|
GxDevDestroy(s_device);
|
|
s_device = nullptr;
|
|
GxLogClose();
|
|
}
|