Files
noggit-red/src/noggit/application/NoggitApplication.cpp
2024-09-04 03:04:09 +02:00

272 lines
9.7 KiB
C++
Executable File

#include <noggit/application/NoggitApplication.hpp>
#include <noggit/project/ApplicationProject.h>
#include <noggit/Log.h>
#include <chrono>
#include <future>
#include <thread>
#include <QDateTime>
#include <QMessageBox>
#include <QString>
namespace
{
std::atomic_bool success = false;
void opengl_context_creation_stuck_failsafe()
{
for (int i = 0; i < 50; ++i)
{
std::this_thread::sleep_for(std::chrono::milliseconds(100));
if (success.load())
{
return;
}
}
LogError << "OpenGL Context creation failed (timeout), closing..." << std::endl;
std::terminate();
}
}
namespace Noggit::Application
{
void NoggitApplication::initalize(int argc, char* argv[], std::vector<bool> Parser)
{
InitLogging();
Command = Parser;
QLocale locale = QLocale(QLocale::English);
QString dateTimeText = locale.toString(QDateTime::currentDateTime(), "dd MMMM yyyy hh:mm:ss");
Log << "Start time : " << dateTimeText.toStdString() << std::endl;
//Locate application relative path
Log << "Noggit Studio - " << STRPRODUCTVER << std::endl;
Log << "Build Date : " << __DATE__ ", " __TIME__ << std::endl;
auto applicationLocation = std::filesystem::path(argv[0]);
Log << "Noggit Application Path: " << applicationLocation << std::endl;
auto applicationExecutionLocation = std::filesystem::current_path();
Log << "Noggit Execution Path: " << applicationExecutionLocation << std::endl;
if (applicationLocation.remove_filename().is_relative())
{
std::filesystem::current_path(std::filesystem::current_path() / applicationLocation);
}
else
{
std::filesystem::current_path(applicationLocation);
}
auto applicationCurrentPath = std::filesystem::current_path();
Log << "Noggit Relative Path: " << applicationCurrentPath << std::endl;
//Locate application configuration file
auto nogginConfigurationPath = applicationCurrentPath / "noggit.json";
if(!std::filesystem::exists(nogginConfigurationPath))
{
//Create Default config file
Log << "Noggit Configuration File Not Found! Creating New File: " << nogginConfigurationPath << std::endl;
auto configurationFileStream = QFile(QString::fromStdString(nogginConfigurationPath.generic_string()));
auto configurationFileWriter = NoggitApplicationConfigurationWriter();
configurationFileWriter.PersistDefaultConfigurationState(configurationFileStream);
configurationFileStream.close();
}
//Read config file
auto configurationFileStream = QFile(QString::fromStdString( nogginConfigurationPath.generic_string()));
auto configurationFileReader = NoggitApplicationConfigurationReader();
auto applicationConfiguration = configurationFileReader.ReadConfigurationState(configurationFileStream);
configurationFileStream.close();
Log << "Noggit Configuration File Loaded! Creating New File: " << nogginConfigurationPath << std::endl;
auto noggitProjectPath = applicationConfiguration.ApplicationProjectPath;
if (!std::filesystem::exists(noggitProjectPath))
{
std::filesystem::create_directory(noggitProjectPath);
// Log << "Noggit Project Folder Not Loaded! Creating..." << std::endl;
}
auto listFilePath = applicationConfiguration.ApplicationListFilePath;
if (!std::filesystem::exists(listFilePath))
{
// LogError << "Unable to find listfile! please reinstall Noggit Red, or download from wow.tools" << std::endl;
}
Log << "Listfile found! : " << listFilePath << std::endl;
auto databaseDefinitionPath = applicationConfiguration.ApplicationDatabaseDefinitionsPath;
if (!std::filesystem::exists(databaseDefinitionPath))
{
LogError << "Unable to find database definitions! please reinstall Noggit Red, or download from wow.tools" << std::endl;
}
Log << "Database Definitions found! : " << databaseDefinitionPath << std::endl;
// Check MSVC redistribuable version
const QString registryPath = "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\";
// Visual C++ 2015 (MSVC++ 14.0)
// Visual C++ 2017 (MSVC++ 14.1)
// Visual C++ 2019 (MSVC++ 14.2)
// Visual C++ 2022 (MSVC++ 14.3)
const QStringList versions = {
"14.0", // MSVC 14.0 Visual Studio 2015
// "15.0", // MSVC 14.1 Visual Studio 2017
// "16.0", // MSVC 14.2 Visual Studio 2019
// "17.0" // MSVC 14.3 Visual Studio 2022
};
// confirmed crashes with v14.30.30704.00 and v14.36.32532.00
const int required_version = 37;
bool redist_found = false;
foreach (const QString & version, versions) {
QString keyPath = registryPath + version + "\\VC\\Runtimes\\x64";
QSettings settings(keyPath, QSettings::NativeFormat);
if (settings.contains("Installed")) {
bool installed = settings.value("Installed").toBool();
if (installed) {
QString versionNumber = settings.value("Version").toString();
// LogDebug << "Minor version : " << minorVersion << std::endl;
LogDebug << "Found MSVC " << version.toStdString() << " Redistributable Version: " << versionNumber.toStdString() << std::endl;
int minorVersion = settings.value("Minor").toInt();
if (minorVersion < required_version)
{
{
QMessageBox msgBox;
msgBox.setIcon(QMessageBox::Critical);
msgBox.setWindowTitle("Outdated Redistributable");
msgBox.setTextFormat(Qt::RichText); //this is what makes the links clickable
QString message = "Your Microsoft Visual C++ Redistributable x64 is outdated. "
"Please update it to the latest version to continue running this application.<br>"
"You can download it from the <a href=\"https://learn.microsoft.com/en-us/cpp/windows/latest-supported-vc-redist?view=msvc-170\">official website (x64)</a>.<br>"
"Direct Download Link : <a href=\"https://learn.microsoft.com/en-us/cpp/windows/latest-supported-vc-redist?view=msvc-170\">https://aka.ms/vs/17/release/vc_redist.x64.exe</a>";
msgBox.setText(message);
msgBox.setStandardButtons(QMessageBox::Ok);
msgBox.exec();
}
// throw std::runtime_error("Installed Microsoft Visual C++ Redistributable version : " + versionNumber.toStdString() + " is too old."
// + "Minimum required is 14.31"
// + "Update at https://aka.ms/vs/17/release/vc_redist.x64.exe or search \"Microsoft Visual C++ Redistributable x64\"");
}
redist_found = true;
}
}
}
if (!redist_found)
{
LogDebug << "No Redistribuable MSVC version 14.xx found" << std::endl;
}
// Initialize OpenGL
QSurfaceFormat format;
format.setRenderableType(QSurfaceFormat::OpenGL);
format.setVersion(4, 1); // will automatically set to the highest version available
format.setProfile(QSurfaceFormat::CoreProfile);
format.setSwapBehavior(applicationConfiguration.GraphicsConfiguration.SwapChainDepth); // default is TripleBuffer
QSettings app_settings;
bool vsync = app_settings.value("vsync", false).toBool();
format.setSwapInterval(vsync ? 1 : applicationConfiguration.GraphicsConfiguration.SwapChainInternal);
// TODO. old config files used 16 so just ignore them, could implement a version check of the config file to update it
format.setDepthBufferSize(24); // applicationConfiguration.GraphicsConfiguration.DepthBufferSize
auto deflt = format.depthBufferSize();
bool doAntiAliasing = app_settings.value("anti_aliasing", false).toBool();
format.setSamples(doAntiAliasing ? 4 : applicationConfiguration.GraphicsConfiguration.SamplesCount); // default is 0, no AA
// context creation seems to get stuck sometimes, this ensure the app is killed
// otherwise it's wasting cpu resources and is annoying when developping
auto failsafe = std::async(&opengl_context_creation_stuck_failsafe);
QSurfaceFormat::setDefaultFormat(format);
QOpenGLContext context;
context.create();
QOffscreenSurface surface;
surface.create();
context.makeCurrent(&surface);
success = true;
OpenGL::context::scoped_setter const _(::gl, &context);
GLint majVers = 0, minVers = 0;
glGetIntegerv(GL_MAJOR_VERSION, &majVers);
glGetIntegerv(GL_MINOR_VERSION, &minVers);
if (majVers != 4)
{
LogError << "Default GL major version is not 4" << std::endl;
}
else if (minVers < 1) // noggit required 4.1
{
LogError << "Default GL minor version is less than 1" << std::endl;
}
QOpenGLVersionProfile profile = QOpenGLVersionProfile(format);
LogDebug << "GL: Version: " << gl.getString(GL_VERSION) << std::endl;
LogDebug << "GL: Vendor: " << gl.getString(GL_VENDOR) << std::endl;
LogDebug << "GL: Renderer: " << gl.getString(GL_RENDERER) << std::endl;
if (!profile.isValid())
{
LogError << "OpenGL version profile is not valid." << std::endl;
throw std::runtime_error(
"OpenGL version profile is not valid.");
}
_application_configuration = std::make_shared<Noggit::Application::NoggitApplicationConfiguration>(applicationConfiguration);
//All of the below should be Project Initalisation
srand(::time(nullptr));
// TODO : thread count setting
// AsyncLoader::setup(NoggitSettings.value("async_thread_count", 3).toInt());
AsyncLoader::setup(3);
}
std::shared_ptr<Noggit::Application::NoggitApplicationConfiguration> NoggitApplication::getConfiguration()
{
return _application_configuration;
}
void NoggitApplication::terminationHandler()
{
std::string const reason{ ::util::exception_to_string(std::current_exception()) };
if (qApp)
{
QMessageBox::critical(nullptr
, "std::terminate"
, QString::fromStdString(reason)
, QMessageBox::Close
, QMessageBox::Close
);
}
LogError << "std::terminate: " << reason << std::endl;
}
bool NoggitApplication::GetCommand(int index)
{
if (index >= 0 && index < Command.size())
return Command[index];
return false;
}
}