diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7d688877..64c447e5 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -66,7 +66,7 @@ jobs: sudo apt-get update sudo apt-get install -y \ libx11-dev libxext-dev libxrandr-dev libxrender-dev libxfixes-dev libxi-dev libxinerama-dev \ - libxcursor-dev libwayland-dev libxkbcommon-dev wayland-protocols libgl1-mesa-dev libglew-dev qt6-base-dev \ + libxcursor-dev libwayland-dev libxkbcommon-dev wayland-protocols libgl1-mesa-dev qt6-base-dev \ libasound2-dev - name: Install macOS dependencies (brew) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 68b1866b..09801e70 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -50,7 +50,7 @@ jobs: sudo apt update sudo apt install -y \ libx11-dev libxext-dev libxrandr-dev libxrender-dev libxfixes-dev libxi-dev libxinerama-dev \ - libxcursor-dev libwayland-dev libxkbcommon-dev wayland-protocols libgl1-mesa-dev libglew-dev qt6-base-dev \ + libxcursor-dev libwayland-dev libxkbcommon-dev wayland-protocols libgl1-mesa-dev qt6-base-dev \ libasound2-dev - name: Install macOS dependencies (brew) diff --git a/CMakeLists.txt b/CMakeLists.txt index adb8600a..d77ce732 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -525,7 +525,7 @@ endif() if (ISLE_BUILD_CONFIG) find_package(Qt6 REQUIRED COMPONENTS Core Widgets) qt_standard_project_setup() - qt_add_executable(config WIN32 + qt_add_executable(isle-config WIN32 LEGO1/mxdirectx/mxdirectxinfo.cpp LEGO1/mxdirectx/legodxinfo.cpp CONFIG/config.cpp @@ -535,22 +535,22 @@ if (ISLE_BUILD_CONFIG) CONFIG/res/config.rc CONFIG/res/config.qrc ) - target_link_libraries(config PRIVATE Qt6::Core Qt6::Widgets) - set_property(TARGET config PROPERTY AUTOMOC ON) - set_property(TARGET config PROPERTY AUTORCC ON) - set_property(TARGET config PROPERTY AUTOUIC ON) - set_property(TARGET config PROPERTY AUTOUIC_SEARCH_PATHS "${CMAKE_CURRENT_SOURCE_DIR}/CONFIG/res") - list(APPEND isle_targets config) - target_compile_definitions(config PRIVATE _AFXDLL MXDIRECTX_FOR_CONFIG) - target_include_directories(config PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/LEGO1") - target_include_directories(config PUBLIC "$") + target_link_libraries(isle-config PRIVATE Qt6::Core Qt6::Widgets) + set_property(TARGET isle-config PROPERTY AUTOMOC ON) + set_property(TARGET isle-config PROPERTY AUTORCC ON) + set_property(TARGET isle-config PROPERTY AUTOUIC ON) + set_property(TARGET isle-config PROPERTY AUTOUIC_SEARCH_PATHS "${CMAKE_CURRENT_SOURCE_DIR}/CONFIG/res") + list(APPEND isle_targets isle-config) + target_compile_definitions(isle-config PRIVATE _AFXDLL MXDIRECTX_FOR_CONFIG) + target_include_directories(isle-config PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/LEGO1") + target_include_directories(isle-config PUBLIC "$") if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 14) - target_link_libraries(config PRIVATE DirectX5::DirectX5) + target_link_libraries(isle-config PRIVATE DirectX5::DirectX5) endif() - target_compile_definitions(config PRIVATE DIRECT3D_VERSION=0x500) - target_link_libraries(config PRIVATE SDL3::SDL3 Isle::iniparser) + target_compile_definitions(isle-config PRIVATE DIRECT3D_VERSION=0x500) + target_link_libraries(isle-config PRIVATE SDL3::SDL3 Isle::iniparser) if (NOT ISLE_MINIWIN) - target_link_libraries(config PRIVATE ddraw dxguid) + target_link_libraries(isle-config PRIVATE ddraw dxguid) endif() endif() @@ -564,8 +564,8 @@ if (MSVC) if (TARGET isle) target_compile_definitions(isle PRIVATE "_CRT_SECURE_NO_WARNINGS") endif() - if (TARGET config) - target_compile_definitions(config PRIVATE "_CRT_SECURE_NO_WARNINGS") + if (TARGET isle-config) + target_compile_definitions(isle-config PRIVATE "_CRT_SECURE_NO_WARNINGS") endif() endif() # Visual Studio 2017 version 15.7 needs "/Zc:__cplusplus" for __cplusplus @@ -574,8 +574,8 @@ if (MSVC) if (TARGET isle) target_compile_options(isle PRIVATE "-Zc:__cplusplus") endif() - if (TARGET config) - target_compile_options(config PRIVATE "-Zc:__cplusplus") + if (TARGET isle-config) + target_compile_options(isle-config PRIVATE "-Zc:__cplusplus") endif() endif() endif() @@ -633,7 +633,7 @@ install(TARGETS isle ${install_extra_targets} LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}" ) if (ISLE_BUILD_CONFIG) - install(TARGETS config + install(TARGETS isle-config RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}" ) endif() diff --git a/CONFIG/MainDlg.cpp b/CONFIG/MainDlg.cpp index 46a2efe8..e2c526f6 100644 --- a/CONFIG/MainDlg.cpp +++ b/CONFIG/MainDlg.cpp @@ -11,6 +11,8 @@ #include "res/resource.h" #include +#include +#include #include #include @@ -56,18 +58,16 @@ CMainDialog::CMainDialog(QWidget* pParent) : QDialog(pParent) connect(m_ui->musicCheckBox, &QCheckBox::toggled, this, &CMainDialog::OnCheckboxMusic); connect(m_ui->sound3DCheckBox, &QCheckBox::toggled, this, &CMainDialog::OnCheckbox3DSound); connect(m_ui->joystickCheckBox, &QCheckBox::toggled, this, &CMainDialog::OnCheckboxJoystick); + connect(m_ui->fullscreenCheckBox, &QCheckBox::toggled, this, &CMainDialog::OnCheckboxFullscreen); connect(m_ui->okButton, &QPushButton::clicked, this, &CMainDialog::accept); connect(m_ui->cancelButton, &QPushButton::clicked, this, &CMainDialog::reject); + connect(m_ui->launchButton, &QPushButton::clicked, this, &CMainDialog::launch); - connect(m_ui->diskPathOpen, &QPushButton::clicked, this, &CMainDialog::SelectDiskPathDialog); - connect(m_ui->cdPathOpen, &QPushButton::clicked, this, &CMainDialog::SelectCDPathDialog); - connect(m_ui->mediaPathOpen, &QPushButton::clicked, this, &CMainDialog::SelectMediaPathDialog); + connect(m_ui->dataPathOpen, &QPushButton::clicked, this, &CMainDialog::SelectDataPathDialog); connect(m_ui->savePathOpen, &QPushButton::clicked, this, &CMainDialog::SelectSavePathDialog); - connect(m_ui->diskPath, &QLineEdit::textEdited, this, &CMainDialog::DiskPathEdited); - connect(m_ui->cdPath, &QLineEdit::textEdited, this, &CMainDialog::CDPathEdited); - connect(m_ui->mediaPath, &QLineEdit::textEdited, this, &CMainDialog::MediaPathEdited); - connect(m_ui->savePath, &QLineEdit::textEdited, this, &CMainDialog::SavePathEdited); + connect(m_ui->dataPath, &QLineEdit::editingFinished, this, &CMainDialog::DataPathEdited); + connect(m_ui->savePath, &QLineEdit::editingFinished, this, &CMainDialog::SavePathEdited); connect(m_ui->maxLoDSlider, &QSlider::valueChanged, this, &CMainDialog::MaxLoDChanged); connect(m_ui->maxActorsSlider, &QSlider::valueChanged, this, &CMainDialog::MaxActorsChanged); @@ -158,6 +158,30 @@ void CMainDialog::accept() QDialog::accept(); } +void CMainDialog::launch() +{ + if (m_modified) { + currentConfigApp->WriteRegisterSettings(); + } + + QDir::setCurrent(QCoreApplication::applicationDirPath()); + + QMessageBox msgBox = QMessageBox( + QMessageBox::Warning, + QString("Error!"), + QString("Unable to locate isle executable!"), + QMessageBox::Close + ); + + if (!QProcess::startDetached("./isle")) { // Check in isle-config directory + if (!QProcess::startDetached("isle")) { // Check in $PATH + msgBox.exec(); + } + } + + QDialog::accept(); +} + // FUNCTION: CONFIG 0x00404360 void CMainDialog::UpdateInterface() { @@ -187,9 +211,8 @@ void CMainDialog::UpdateInterface() } m_ui->joystickCheckBox->setChecked(currentConfigApp->m_use_joystick); m_ui->musicCheckBox->setChecked(currentConfigApp->m_music); - m_ui->diskPath->setText(QString::fromStdString(currentConfigApp->m_base_path)); - m_ui->cdPath->setText(QString::fromStdString(currentConfigApp->m_cd_path)); - m_ui->mediaPath->setText(QString::fromStdString(currentConfigApp->m_media_path)); + m_ui->fullscreenCheckBox->setChecked(currentConfigApp->m_full_screen); + m_ui->dataPath->setText(QString::fromStdString(currentConfigApp->m_cd_path)); m_ui->savePath->setText(QString::fromStdString(currentConfigApp->m_save_path)); } @@ -266,54 +289,33 @@ void CMainDialog::OnCheckboxMusic(bool checked) UpdateInterface(); } -void CMainDialog::SelectDiskPathDialog() +void CMainDialog::OnCheckboxFullscreen(bool checked) { - QString disk_path = QString::fromStdString(currentConfigApp->m_base_path); - disk_path = QFileDialog::getExistingDirectory( - this, - tr("Open Directory"), - disk_path, - QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks - ); - - if (disk_path.toStdString() != "") { - currentConfigApp->m_base_path = disk_path.toStdString(); - m_modified = true; - UpdateInterface(); - } + currentConfigApp->m_full_screen = checked; + m_modified = true; + UpdateInterface(); } -void CMainDialog::SelectCDPathDialog() +void CMainDialog::SelectDataPathDialog() { - QString cd_path = QString::fromStdString(currentConfigApp->m_cd_path); - cd_path = QFileDialog::getExistingDirectory( + QString data_path = QString::fromStdString(currentConfigApp->m_cd_path); + data_path = QFileDialog::getExistingDirectory( this, tr("Open Directory"), - cd_path, + data_path, QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks ); - if (cd_path.toStdString() != "") { - currentConfigApp->m_cd_path = cd_path.toStdString(); - m_modified = true; - UpdateInterface(); - } -} + QDir data_dir = QDir(data_path); -void CMainDialog::SelectMediaPathDialog() -{ - QString media_path = QString::fromStdString(currentConfigApp->m_media_path); - media_path = QFileDialog::getExistingDirectory( - this, - tr("Open Directory"), - media_path, - QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks - ); - if (media_path.toStdString() != "") { - currentConfigApp->m_media_path = media_path.toStdString(); + if (data_dir.exists()) { + currentConfigApp->m_cd_path = data_dir.absolutePath().toStdString(); + data_dir.cd(QString("DATA")); + data_dir.cd(QString("disk")); + currentConfigApp->m_base_path = data_dir.absolutePath().toStdString(); m_modified = true; - UpdateInterface(); } + UpdateInterface(); } void CMainDialog::SelectSavePathDialog() @@ -326,38 +328,39 @@ void CMainDialog::SelectSavePathDialog() QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks ); - if (save_path.toStdString() != "") { - currentConfigApp->m_save_path = save_path.toStdString(); + QDir save_dir = QDir(save_path); + + if (save_dir.exists()) { + currentConfigApp->m_save_path = save_dir.absolutePath().toStdString(); m_modified = true; - UpdateInterface(); } -} - -void CMainDialog::DiskPathEdited(const QString& text) -{ - currentConfigApp->m_base_path = text.toStdString(); - m_modified = true; UpdateInterface(); } -void CMainDialog::CDPathEdited(const QString& text) +void CMainDialog::DataPathEdited() { - currentConfigApp->m_cd_path = text.toStdString(); - m_modified = true; + QDir data_dir = QDir(m_ui->dataPath->text()); + + if (data_dir.exists()) { + currentConfigApp->m_cd_path = data_dir.absolutePath().toStdString(); + data_dir.cd(QString("DATA")); + data_dir.cd(QString("disk")); + currentConfigApp->m_base_path = data_dir.absolutePath().toStdString(); + m_modified = true; + } + UpdateInterface(); } -void CMainDialog::MediaPathEdited(const QString& text) +void CMainDialog::SavePathEdited() { - currentConfigApp->m_media_path = text.toStdString(); - m_modified = true; - UpdateInterface(); -} -void CMainDialog::SavePathEdited(const QString& text) -{ - currentConfigApp->m_save_path = text.toStdString(); - m_modified = true; + QDir save_dir = QDir(m_ui->savePath->text()); + + if (save_dir.exists()) { + currentConfigApp->m_save_path = save_dir.absolutePath().toStdString(); + m_modified = true; + } UpdateInterface(); } diff --git a/CONFIG/MainDlg.h b/CONFIG/MainDlg.h index b441248d..372a1156 100644 --- a/CONFIG/MainDlg.h +++ b/CONFIG/MainDlg.h @@ -42,16 +42,14 @@ private slots: void OnRadiobuttonTextureHighQuality(bool checked); void OnCheckboxJoystick(bool checked); void OnCheckboxMusic(bool checked); + void OnCheckboxFullscreen(bool checked); void accept() override; void reject() override; - void SelectDiskPathDialog(); - void SelectCDPathDialog(); - void SelectMediaPathDialog(); + void launch(); + void SelectDataPathDialog(); void SelectSavePathDialog(); - void DiskPathEdited(const QString& text); - void CDPathEdited(const QString& text); - void MediaPathEdited(const QString& text); - void SavePathEdited(const QString& text); + void DataPathEdited(); + void SavePathEdited(); void MaxLoDChanged(int value); void MaxActorsChanged(int value); }; diff --git a/CONFIG/config.cpp b/CONFIG/config.cpp index 31e7032b..bd38e669 100644 --- a/CONFIG/config.cpp +++ b/CONFIG/config.cpp @@ -141,7 +141,6 @@ bool CConfigApp::ReadRegisterSettings() } m_base_path = iniparser_getstring(dict, "isle:diskpath", m_base_path.c_str()); m_cd_path = iniparser_getstring(dict, "isle:cdpath", m_cd_path.c_str()); - m_media_path = iniparser_getstring(dict, "isle:mediapath", m_media_path.c_str()); m_save_path = iniparser_getstring(dict, "isle:savepath", m_save_path.c_str()); m_display_bit_depth = iniparser_getint(dict, "isle:Display Bit Depth", -1); m_flip_surfaces = iniparser_getboolean(dict, "isle:Flip Surfaces", m_flip_surfaces); @@ -166,10 +165,6 @@ bool CConfigApp::ValidateSettings() { BOOL is_modified = FALSE; - if (!IsPrimaryDriver() && !m_full_screen) { - m_full_screen = TRUE; - is_modified = TRUE; - } if (IsDeviceInBasicRGBMode()) { if (m_3d_video_ram) { m_3d_video_ram = FALSE; @@ -203,10 +198,6 @@ bool CConfigApp::ValidateSettings() m_3d_video_ram = TRUE; is_modified = TRUE; } - if (!m_full_screen) { - m_full_screen = TRUE; - is_modified = TRUE; - } } if ((m_display_bit_depth != 8 && m_display_bit_depth != 16) && (m_display_bit_depth != 0 || m_full_screen)) { m_display_bit_depth = 16; @@ -302,7 +293,6 @@ void CConfigApp::WriteRegisterSettings() const } iniparser_set(dict, "isle:diskpath", m_base_path.c_str()); iniparser_set(dict, "isle:cdpath", m_cd_path.c_str()); - iniparser_set(dict, "isle:mediapath", m_media_path.c_str()); iniparser_set(dict, "isle:savepath", m_save_path.c_str()); SetIniInt(dict, "isle:Display Bit Depth", m_display_bit_depth); diff --git a/CONFIG/config.h b/CONFIG/config.h index 276dc755..a621655a 100644 --- a/CONFIG/config.h +++ b/CONFIG/config.h @@ -77,7 +77,6 @@ class CConfigApp { std::string m_iniPath; std::string m_base_path; std::string m_cd_path; - std::string m_media_path; std::string m_save_path; float m_max_lod; int m_max_actors; diff --git a/CONFIG/res/maindialog.ui b/CONFIG/res/maindialog.ui index ac69f782..c2760e7c 100644 --- a/CONFIG/res/maindialog.ui +++ b/CONFIG/res/maindialog.ui @@ -7,7 +7,7 @@ 0 0 575 - 650 + 600 @@ -44,6 +44,9 @@ 16777215 + + Jaws. + @@ -76,13 +79,7 @@ 0 - - - - - - - + @@ -101,68 +98,8 @@ - - - - - 0 - 0 - - - - - 55 - 16777215 - - - - Open - - - - - - - - 0 - 0 - - - - - 55 - 16777215 - - - - Open - - - - - - - - 0 - 0 - - - - CD Path: - - - Qt::PlainText - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - + 0 @@ -180,26 +117,7 @@ - - - - - 0 - 0 - - - - Disk Path: - - - Qt::PlainText - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - + @@ -218,8 +136,22 @@ - - + + + + Path to the game data files. Set this to the CD image root. + + + + + + + Folder where save files are kept. + + + + + 0 @@ -227,7 +159,7 @@ - Media Path: + Data Path: Qt::PlainText @@ -237,9 +169,6 @@ - - - @@ -266,6 +195,9 @@ 120 + + Set 3D model detail level. + Island Model Quality @@ -345,6 +277,9 @@ + + Set texture detail level. + Island Texture Quality @@ -422,16 +357,13 @@ - - - - 0 - - - 0 - + + + + Enable 3D positional audio effects. + 3D Sound @@ -439,6 +371,9 @@ + + Enable in-game background music. + Music @@ -446,11 +381,24 @@ + + Enable joystick and gamepad support for LEGO Island. + Use Joystick + + + + Toggle fullscreen display mode. + + + Fullscreen + + + @@ -462,6 +410,9 @@ 225 + + 3D graphics device used to render the game. + @@ -557,8 +508,11 @@ + + Save configuration and close the config tool. + - OK + Save and Exit true @@ -566,9 +520,22 @@ - + + + Save configuration and launch LEGO Island. + - Cancel + Save and Launch + + + + + + + Discard changed settings and close the config tool. + + + Exit without saving @@ -581,12 +548,8 @@ - diskPath - diskPathOpen - cdPath - cdPathOpen - mediaPath - mediaPathOpen + dataPath + dataPathOpen savePath savePathOpen textureQualityFastRadioButton diff --git a/ISLE/emscripten/libwasmfs_fetch.js.patch b/ISLE/emscripten/libwasmfs_fetch.js.patch index 6c598e3f..de8fab60 100644 --- a/ISLE/emscripten/libwasmfs_fetch.js.patch +++ b/ISLE/emscripten/libwasmfs_fetch.js.patch @@ -1,5 +1,5 @@ diff --git a/src/lib/libwasmfs_fetch.js b/src/lib/libwasmfs_fetch.js -index e8c9f7e21..5c3a3dfbe 100644 +index e8c9f7e21..caf1971d2 100644 --- a/src/lib/libwasmfs_fetch.js +++ b/src/lib/libwasmfs_fetch.js @@ -38,36 +38,7 @@ addToLibrary({ @@ -49,7 +49,7 @@ index e8c9f7e21..5c3a3dfbe 100644 allPresent = false; break; } -@@ -90,16 +61,36 @@ addToLibrary({ +@@ -90,16 +61,37 @@ addToLibrary({ // one request for all the chunks we need, rather than one // request per chunk. var start = firstChunk * chunkSize; @@ -66,8 +66,10 @@ index e8c9f7e21..5c3a3dfbe 100644 if (!response.ok) { throw response; } +- var bytes = await response['bytes'](); + - var bytes = await response['bytes'](); ++ const buffer = await response.arrayBuffer(); ++ const bytes = new Uint8Array(buffer); + if (!(file in wasmFS$JSMemoryRanges)) { + var size = Math.max( + parseInt(response.headers.get('Content-Range').split('/')[1], 10), @@ -87,7 +89,21 @@ index e8c9f7e21..5c3a3dfbe 100644 return Promise.resolve(); } -@@ -164,6 +155,21 @@ addToLibrary({ +@@ -156,14 +148,31 @@ addToLibrary({ + return readLength; + }, + getSize: async (file) => { +- try { +- await getFileRange(file, 0, 0); +- } catch (failedResponse) { +- return 0; ++ if (!(file in wasmFS$JSMemoryRanges)) { ++ try { ++ await getFileRange(file, undefined, undefined); ++ } catch (failedResponse) { ++ return 0; ++ } + } return wasmFS$JSMemoryRanges[file].size; }, }; diff --git a/ISLE/isleapp.cpp b/ISLE/isleapp.cpp index d1d1ec69..e700d5b2 100644 --- a/ISLE/isleapp.cpp +++ b/ISLE/isleapp.cpp @@ -96,11 +96,7 @@ IsleApp::IsleApp() m_cdPath = NULL; m_deviceId = NULL; m_savePath = NULL; -#ifdef __EMSCRIPTEN__ - m_fullScreen = FALSE; -#else m_fullScreen = TRUE; -#endif m_flipSurfaces = FALSE; m_backBuffersInVram = TRUE; m_using8bit = FALSE; @@ -140,6 +136,7 @@ IsleApp::IsleApp() m_iniPath = NULL; m_maxLod = RealtimeView::GetUserMaxLOD(); m_maxAllowedExtras = m_islandQuality <= 1 ? 10 : 20; + m_transitionType = MxTransitionManager::e_mosaic; } // FUNCTION: ISLE 0x4011a0 @@ -394,6 +391,7 @@ SDL_AppResult SDL_AppEvent(void* appstate, SDL_Event* event) #endif switch (event->type) { + case SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED: case SDL_EVENT_MOUSE_MOTION: case SDL_EVENT_MOUSE_BUTTON_DOWN: case SDL_EVENT_MOUSE_BUTTON_UP: @@ -658,6 +656,8 @@ MxResult IsleApp::SetupWindow() SDL_SetStringProperty(props, SDL_PROP_WINDOW_CREATE_TITLE_STRING, WINDOW_TITLE); #ifdef MINIWIN SDL_SetBooleanProperty(props, SDL_PROP_WINDOW_CREATE_OPENGL_BOOLEAN, true); + SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); + SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24); #endif window = SDL_CreateWindowWithProperties(props); @@ -701,6 +701,7 @@ MxResult IsleApp::SetupWindow() return FAILURE; } + DetectGameVersion(); GameState()->SerializePlayersInfo(LegoStorage::c_read); GameState()->SerializeScoreHistory(LegoStorage::c_read); @@ -723,6 +724,7 @@ MxResult IsleApp::SetupWindow() LegoBuildingManager::configureLegoBuildingManager(m_islandQuality); LegoROI::configureLegoROI(iVar10); LegoAnimationManager::configureLegoAnimationManager(m_maxAllowedExtras); + MxTransitionManager::configureMxTransitionManager(m_transitionType); RealtimeView::SetUserMaxLOD(m_maxLod); if (LegoOmni::GetInstance()) { if (LegoOmni::GetInstance()->GetInputManager()) { @@ -821,6 +823,7 @@ bool IsleApp::LoadConfig() SDL_snprintf(buf, sizeof(buf), "%f", m_maxLod); iniparser_set(dict, "isle:Max LOD", buf); iniparser_set(dict, "isle:Max Allowed Extras", SDL_itoa(m_maxAllowedExtras, buf, 10)); + iniparser_set(dict, "isle:Transition Type", SDL_itoa(m_transitionType, buf, 10)); iniparser_dump_ini(dict, iniFP); SDL_LogInfo(SDL_LOG_CATEGORY_APPLICATION, "New config written at '%s'", iniConfig); @@ -850,7 +853,13 @@ bool IsleApp::LoadConfig() strcpy(m_mediaPath, mediaPath); m_flipSurfaces = iniparser_getboolean(dict, "isle:Flip Surfaces", m_flipSurfaces); + +#ifdef __EMSCRIPTEN__ + m_fullScreen = FALSE; +#else m_fullScreen = iniparser_getboolean(dict, "isle:Full Screen", m_fullScreen); +#endif + m_wideViewAngle = iniparser_getboolean(dict, "isle:Wide View Angle", m_wideViewAngle); m_use3dSound = iniparser_getboolean(dict, "isle:3DSound", m_use3dSound); m_useMusic = iniparser_getboolean(dict, "isle:Music", m_useMusic); @@ -877,6 +886,8 @@ bool IsleApp::LoadConfig() m_islandTexture = iniparser_getint(dict, "isle:Island Texture", m_islandTexture); m_maxLod = iniparser_getdouble(dict, "isle:Max LOD", m_maxLod); m_maxAllowedExtras = iniparser_getint(dict, "isle:Max Allowed Extras", m_maxAllowedExtras); + m_transitionType = + (MxTransitionManager::TransitionType) iniparser_getint(dict, "isle:Transition Type", m_transitionType); const char* deviceId = iniparser_getstring(dict, "isle:3D Device ID", NULL); if (deviceId != NULL) { @@ -909,7 +920,7 @@ inline bool IsleApp::Tick() static MxLong g_lastFrameTime = 0; // GLOBAL: ISLE 0x4101bc - static MxS32 g_startupDelay = 200; + static MxS32 g_startupDelay = 1; if (IsleDebug_Paused() && IsleDebug_StepModeEnabled()) { IsleDebug_SetPaused(false); @@ -1096,6 +1107,34 @@ MxResult IsleApp::VerifyFilesystem() return SUCCESS; } +void IsleApp::DetectGameVersion() +{ + const char* file = "/lego/scripts/infocntr/infomain.si"; + SDL_PathInfo info; + bool success = false; + + MxString path = MxString(m_hdPath) + file; + path.MapPathToFilesystem(); + if (!(success = SDL_GetPathInfo(path.GetData(), &info))) { + path = MxString(m_cdPath) + file; + path.MapPathToFilesystem(); + success = SDL_GetPathInfo(path.GetData(), &info); + } + + assert(success); + + // File sizes of INFOMAIN.SI in English 1.0 and Japanese 1.0 + Lego()->SetVersion10(info.size == 58130432 || info.size == 57737216); + + if (Lego()->IsVersion10()) { + SDL_Log("Detected game version 1.0"); + SDL_SetWindowTitle(reinterpret_cast(m_windowHandle), "Lego Island"); + } + else { + SDL_Log("Detected game version 1.1"); + } +} + IDirect3DRMMiniwinDevice* GetD3DRMMiniwinDevice() { LegoVideoManager* videoManager = LegoOmni::GetInstance()->GetVideoManager(); diff --git a/ISLE/isleapp.h b/ISLE/isleapp.h index d76a291b..dd7bfdb1 100644 --- a/ISLE/isleapp.h +++ b/ISLE/isleapp.h @@ -3,6 +3,7 @@ #include "lego1_export.h" #include "legoutils.h" +#include "mxtransitionmanager.h" #include "mxtypes.h" #include "mxvideoparam.h" @@ -56,6 +57,7 @@ class IsleApp { MxResult ParseArguments(int argc, char** argv); MxResult VerifyFilesystem(); + void DetectGameVersion(); private: char* m_hdPath; // 0x00 @@ -90,6 +92,7 @@ class IsleApp { char* m_iniPath; MxFloat m_maxLod; MxU32 m_maxAllowedExtras; + MxTransitionManager::TransitionType m_transitionType; }; extern IsleApp* g_isle; diff --git a/LEGO1/lego/legoomni/include/ambulance.h b/LEGO1/lego/legoomni/include/ambulance.h index 97e6ba38..cb6a396a 100644 --- a/LEGO1/lego/legoomni/include/ambulance.h +++ b/LEGO1/lego/legoomni/include/ambulance.h @@ -11,6 +11,12 @@ class MxEndActionNotificationParam; // SIZE 0x24 class AmbulanceMissionState : public LegoState { public: + enum { + e_ready = 0, + e_enteredAmbulance = 1, + e_prepareAmbulance = 2, + }; + AmbulanceMissionState(); // FUNCTION: LEGO1 0x10037440 @@ -125,18 +131,18 @@ class AmbulanceMissionState : public LegoState { // SYNTHETIC: LEGO1 0x100376c0 // AmbulanceMissionState::`scalar deleting destructor' - undefined4 m_unk0x08; // 0x08 - MxLong m_startTime; // 0x0c - MxS16 m_peScore; // 0x10 - MxS16 m_maScore; // 0x12 - MxS16 m_paScore; // 0x14 - MxS16 m_niScore; // 0x16 - MxS16 m_laScore; // 0x18 - MxS16 m_peHighScore; // 0x1a - MxS16 m_maHighScore; // 0x1c - MxS16 m_paHighScore; // 0x1e - MxS16 m_niHighScore; // 0x20 - MxS16 m_laHighScore; // 0x22 + MxU32 m_state; // 0x08 + MxLong m_startTime; // 0x0c + MxS16 m_peScore; // 0x10 + MxS16 m_maScore; // 0x12 + MxS16 m_paScore; // 0x14 + MxS16 m_niScore; // 0x16 + MxS16 m_laScore; // 0x18 + MxS16 m_peHighScore; // 0x1a + MxS16 m_maHighScore; // 0x1c + MxS16 m_paHighScore; // 0x1e + MxS16 m_niHighScore; // 0x20 + MxS16 m_laHighScore; // 0x22 }; // VTABLE: LEGO1 0x100d71a8 @@ -177,15 +183,21 @@ class Ambulance : public IslePathActor { virtual MxLong HandleEndAction(MxEndActionNotificationParam& p_param); // vtable+0xf4 void CreateState(); - void FUN_10036e60(); + void Init(); void ActivateSceneActions(); void StopActions(); - void FUN_10037250(); + void Reset(); // SYNTHETIC: LEGO1 0x10036130 // Ambulance::`scalar deleting destructor' private: + enum { + e_none = 0, + e_waiting = 1, + e_finished = 3, + }; + void PlayAnimation(IsleScript::Script p_objectId); void PlayFinalAnimation(IsleScript::Script p_objectId); void StopAction(IsleScript::Script p_objectId); @@ -196,9 +208,9 @@ class Ambulance : public IslePathActor { AmbulanceMissionState* m_state; // 0x164 MxS16 m_unk0x168; // 0x168 MxS16 m_actorId; // 0x16a - MxS16 m_unk0x16c; // 0x16c - MxS16 m_unk0x16e; // 0x16e - MxS16 m_unk0x170; // 0x170 + MxS16 m_atPoliceTask; // 0x16c + MxS16 m_atBeachTask; // 0x16e + MxS16 m_taskState; // 0x170 MxS16 m_unk0x172; // 0x172 IsleScript::Script m_lastAction; // 0x174 IsleScript::Script m_lastAnimation; // 0x178 diff --git a/LEGO1/lego/legoomni/include/hospital.h b/LEGO1/lego/legoomni/include/hospital.h index 8629c2c2..be198776 100644 --- a/LEGO1/lego/legoomni/include/hospital.h +++ b/LEGO1/lego/legoomni/include/hospital.h @@ -123,7 +123,7 @@ class Hospital : public LegoWorld { MxLong m_copLedAnimTimer; // 0x11c MxLong m_pizzaLedAnimTimer; // 0x120 MxLong m_time; // 0x124 - undefined m_unk0x128; // 0x128 + MxBool m_exited; // 0x128 }; #endif // HOSPITAL_H diff --git a/LEGO1/lego/legoomni/include/legoanimpresenter.h b/LEGO1/lego/legoomni/include/legoanimpresenter.h index 85917cbc..a3d6cd60 100644 --- a/LEGO1/lego/legoomni/include/legoanimpresenter.h +++ b/LEGO1/lego/legoomni/include/legoanimpresenter.h @@ -121,7 +121,7 @@ class LegoAnimPresenter : public MxVideoPresenter { void SubstituteVariables(); void FUN_1006b900(LegoAnim* p_anim, MxLong p_time, Matrix4* p_matrix); void FUN_1006b9a0(LegoAnim* p_anim, MxLong p_time, Matrix4* p_matrix); - void FUN_1006c8a0(MxBool p_bool); + void SetDisabled(MxBool p_disabled); LegoAnim* m_anim; // 0x64 LegoROI** m_roiMap; // 0x68 diff --git a/LEGO1/lego/legoomni/include/legobuildingmanager.h b/LEGO1/lego/legoomni/include/legobuildingmanager.h index 5dd83221..4d27695c 100644 --- a/LEGO1/lego/legoomni/include/legobuildingmanager.h +++ b/LEGO1/lego/legoomni/include/legobuildingmanager.h @@ -79,7 +79,7 @@ class LegoBuildingManager : public MxCore { MxBool SwitchMove(LegoEntity* p_entity); MxBool SwitchMood(LegoEntity* p_entity); MxU32 GetAnimationId(LegoEntity* p_entity); - MxU32 GetSoundId(LegoEntity* p_entity, MxBool p_state); + MxU32 GetSoundId(LegoEntity* p_entity, MxBool p_basedOnMood); MxBool DecrementCounter(LegoEntity* p_entity); MxBool DecrementCounter(MxS32 p_index); MxBool DecrementCounter(LegoBuildingInfo* p_data); diff --git a/LEGO1/lego/legoomni/include/legocharactermanager.h b/LEGO1/lego/legoomni/include/legocharactermanager.h index 2f9d9551..9b4c5313 100644 --- a/LEGO1/lego/legoomni/include/legocharactermanager.h +++ b/LEGO1/lego/legoomni/include/legocharactermanager.h @@ -88,7 +88,7 @@ class LegoCharacterManager { MxBool SwitchMove(LegoROI* p_roi); MxBool SwitchMood(LegoROI* p_roi); MxU32 GetAnimationId(LegoROI* p_roi); - MxU32 GetSoundId(LegoROI* p_roi, MxBool p_und); + MxU32 GetSoundId(LegoROI* p_roi, MxBool p_basedOnMood); MxU8 GetMood(LegoROI* p_roi); LegoROI* CreateAutoROI(const char* p_name, const char* p_lodName, MxBool p_createEntity); MxResult UpdateBoundingSphereAndBox(LegoROI* p_roi); diff --git a/LEGO1/lego/legoomni/include/legoentity.h b/LEGO1/lego/legoomni/include/legoentity.h index eecf6867..a6d9d9ee 100644 --- a/LEGO1/lego/legoomni/include/legoentity.h +++ b/LEGO1/lego/legoomni/include/legoentity.h @@ -28,7 +28,7 @@ class LegoEntity : public MxEntity { }; enum { - c_altBit1 = 0x01 + c_disabled = 0x01 }; LegoEntity() { Init(); } @@ -68,13 +68,13 @@ class LegoEntity : public MxEntity { // FUNCTION: BETA10 0x10013260 virtual void SetWorldSpeed(MxFloat p_worldSpeed) { m_worldSpeed = p_worldSpeed; } // vtable+0x30 - virtual void ClickSound(MxBool p_und); // vtable+0x34 - virtual void ClickAnimation(); // vtable+0x38 - virtual void SwitchVariant(); // vtable+0x3c - virtual void SwitchSound(); // vtable+0x40 - virtual void SwitchMove(); // vtable+0x44 - virtual void SwitchColor(LegoROI* p_roi); // vtable+0x48 - virtual void SwitchMood(); // vtable+0x4c + virtual void ClickSound(MxBool p_basedOnMood); // vtable+0x34 + virtual void ClickAnimation(); // vtable+0x38 + virtual void SwitchVariant(); // vtable+0x3c + virtual void SwitchSound(); // vtable+0x40 + virtual void SwitchMove(); // vtable+0x44 + virtual void SwitchColor(LegoROI* p_roi); // vtable+0x48 + virtual void SwitchMood(); // vtable+0x4c void FUN_10010c30(); void SetType(MxU8 p_type); @@ -83,7 +83,7 @@ class LegoEntity : public MxEntity { Mx3DPointFloat GetWorldUp(); Mx3DPointFloat GetWorldPosition(); - MxBool GetUnknown0x10IsSet(MxU8 p_flag) { return m_unk0x10 & p_flag; } + MxBool IsInteraction(MxU8 p_flag) { return m_interaction & p_flag; } MxBool GetFlagsIsSet(MxU8 p_flag) { return m_flags & p_flag; } MxU8 GetFlags() { return m_flags; } @@ -101,14 +101,14 @@ class LegoEntity : public MxEntity { void SetFlags(MxU8 p_flags) { m_flags = p_flags; } void SetFlag(MxU8 p_flag) { m_flags |= p_flag; } void ClearFlag(MxU8 p_flag) { m_flags &= ~p_flag; } - void SetUnknown0x10Flag(MxU8 p_flag) { m_unk0x10 |= p_flag; } - void ClearUnknown0x10Flag(MxU8 p_flag) { m_unk0x10 &= ~p_flag; } + void SetInteractionFlag(MxU8 p_flag) { m_interaction |= p_flag; } + void ClearInteractionFlag(MxU8 p_flag) { m_interaction &= ~p_flag; } protected: void Init(); void SetWorld(); - MxU8 m_unk0x10; // 0x10 + MxU8 m_interaction; // 0x10 MxU8 m_flags; // 0x11 Mx3DPointFloat m_worldLocation; // 0x14 Mx3DPointFloat m_worldDirection; // 0x28 diff --git a/LEGO1/lego/legoomni/include/legomain.h b/LEGO1/lego/legoomni/include/legomain.h index fa9a91c5..c27be280 100644 --- a/LEGO1/lego/legoomni/include/legomain.h +++ b/LEGO1/lego/legoomni/include/legomain.h @@ -200,6 +200,9 @@ class LegoOmni : public MxOmni { SDL_PushEvent(&event); } + void SetVersion10(MxBool p_version10) { m_version10 = p_version10; } + MxBool IsVersion10() { return m_version10; } + // SYNTHETIC: LEGO1 0x10058b30 // LegoOmni::`scalar deleting destructor' @@ -221,6 +224,7 @@ class LegoOmni : public MxOmni { MxDSAction m_action; // 0xa0 MxBackgroundAudioManager* m_bkgAudioManager; // 0x134 MxTransitionManager* m_transitionManager; // 0x138 + MxBool m_version10; public: MxBool m_unk0x13c; // 0x13c diff --git a/LEGO1/lego/legoomni/include/legopathactor.h b/LEGO1/lego/legoomni/include/legopathactor.h index 6566c6fb..8df0e9db 100644 --- a/LEGO1/lego/legoomni/include/legopathactor.h +++ b/LEGO1/lego/legoomni/include/legopathactor.h @@ -13,7 +13,7 @@ struct LegoPathEdgeContainer; struct LegoOrientedEdge; class LegoWEEdge; -extern MxLong g_unk0x100f3308; +extern MxLong g_timeLastHitSoundPlayed; extern const char* g_strHIT_WALL_SOUND; // VTABLE: LEGO1 0x100d6e28 diff --git a/LEGO1/lego/legoomni/include/legoplantmanager.h b/LEGO1/lego/legoomni/include/legoplantmanager.h index 1e17d6f4..3cdb5105 100644 --- a/LEGO1/lego/legoomni/include/legoplantmanager.h +++ b/LEGO1/lego/legoomni/include/legoplantmanager.h @@ -49,12 +49,12 @@ class LEGO1_EXPORT LegoPlantManager : public MxCore { MxBool SwitchMove(LegoEntity* p_entity); MxBool SwitchMood(LegoEntity* p_entity); MxU32 GetAnimationId(LegoEntity* p_entity); - MxU32 GetSoundId(LegoEntity* p_entity, MxBool p_state); + MxU32 GetSoundId(LegoEntity* p_entity, MxBool p_basedOnMood); LegoPlantInfo* GetInfoArray(MxS32& p_length); LegoEntity* CreatePlant(MxS32 p_index, LegoWorld* p_world, LegoOmni::World p_worldId); MxBool DecrementCounter(LegoEntity* p_entity); void ScheduleAnimation(LegoEntity* p_entity, MxLong p_length); - MxResult FUN_10026410(); + MxResult DetermineBoundaries(); void ClearCounters(); void SetInitialCounters(); @@ -77,11 +77,11 @@ class LEGO1_EXPORT LegoPlantManager : public MxCore { static MxS32 g_maxMove[4]; static MxU32 g_maxSound; - LegoOmni::World m_worldId; // 0x08 - undefined m_unk0x0c; // 0x0c - AnimEntry* m_entries[5]; // 0x10 - MxS8 m_numEntries; // 0x24 - LegoWorld* m_world; // 0x28 + LegoOmni::World m_worldId; // 0x08 + MxBool m_boundariesDetermined; // 0x0c + AnimEntry* m_entries[5]; // 0x10 + MxS8 m_numEntries; // 0x24 + LegoWorld* m_world; // 0x28 friend class DebugViewer; }; diff --git a/LEGO1/lego/legoomni/include/legoracers.h b/LEGO1/lego/legoomni/include/legoracers.h index 76d1071d..3c8ffe07 100644 --- a/LEGO1/lego/legoomni/include/legoracers.h +++ b/LEGO1/lego/legoomni/include/legoracers.h @@ -144,10 +144,10 @@ class LegoRaceCar : public LegoCarRaceActor, public LegoRaceMap { MxResult VTable0x9c() override; // vtable+0x9c virtual void SetMaxLinearVelocity(float p_maxLinearVelocity); - virtual void FUN_10012ff0(float p_param); + virtual void KickCamera(float p_param); virtual MxU32 HandleSkeletonKicks(float p_param1); - static void FUN_10012de0(); + static void InitYouCantStopSound(); static void InitSoundIndices(); // SYNTHETIC: LEGO1 0x10014240 @@ -155,7 +155,7 @@ class LegoRaceCar : public LegoCarRaceActor, public LegoRaceMap { private: undefined m_userState; // 0x54 - float m_unk0x58; // 0x58 + float m_kickStart; // 0x58 Mx3DPointFloat m_unk0x5c; // 0x5c // Names verified by BETA10 0x100cb4a9 diff --git a/LEGO1/lego/legoomni/include/legoracespecial.h b/LEGO1/lego/legoomni/include/legoracespecial.h index fab200aa..fa9dd51d 100644 --- a/LEGO1/lego/legoomni/include/legoracespecial.h +++ b/LEGO1/lego/legoomni/include/legoracespecial.h @@ -44,8 +44,11 @@ class LegoCarRaceActor : public virtual LegoRaceActor { Vector3& p_v3 ) override; // vtable+0x6c void Animate(float p_time) override; // vtable+0x70 - void SwitchBoundary(LegoPathBoundary*& p_boundary, LegoOrientedEdge*& p_edge, float& p_unk0xe4) - override; // vtable+0x98 + void SwitchBoundary( + LegoPathBoundary*& p_boundary, + LegoOrientedEdge*& p_edge, + float& p_unk0xe4 + ) override; // vtable+0x98 MxResult VTable0x9c() override; // vtable+0x9c // LegoCarRaceActor vtable @@ -83,7 +86,7 @@ class LegoCarRaceActor : public virtual LegoRaceActor { protected: MxFloat m_unk0x08; // 0x08 - MxU8 m_unk0x0c; // 0x0c + MxU8 m_animState; // 0x0c // Could be a multiplier for the maximum speed when going straight MxFloat m_unk0x10; // 0x10 diff --git a/LEGO1/lego/legoomni/include/mxtransitionmanager.h b/LEGO1/lego/legoomni/include/mxtransitionmanager.h index 50b80055..dd9dc9ed 100644 --- a/LEGO1/lego/legoomni/include/mxtransitionmanager.h +++ b/LEGO1/lego/legoomni/include/mxtransitionmanager.h @@ -55,6 +55,8 @@ class MxTransitionManager : public MxCore { TransitionType GetTransitionType() { return m_mode; } + LEGO1_EXPORT static void configureMxTransitionManager(TransitionType p_transitionManagerConfig); + // SYNTHETIC: LEGO1 0x1004b9e0 // MxTransitionManager::`scalar deleting destructor' diff --git a/LEGO1/lego/legoomni/src/actors/ambulance.cpp b/LEGO1/lego/legoomni/src/actors/ambulance.cpp index c4bded70..ff87c657 100644 --- a/LEGO1/lego/legoomni/src/actors/ambulance.cpp +++ b/LEGO1/lego/legoomni/src/actors/ambulance.cpp @@ -40,9 +40,9 @@ Ambulance::Ambulance() m_state = NULL; m_unk0x168 = 0; m_actorId = -1; - m_unk0x16c = 0; - m_unk0x16e = 0; - m_unk0x170 = 0; + m_atPoliceTask = 0; + m_atBeachTask = 0; + m_taskState = Ambulance::e_none; m_lastAction = IsleScript::c_noneIsle; m_unk0x172 = 0; m_lastAnimation = IsleScript::c_noneIsle; @@ -73,7 +73,7 @@ MxResult Ambulance::Create(MxDSAction& p_dsAction) m_state = (AmbulanceMissionState*) GameState()->GetState("AmbulanceMissionState"); if (!m_state) { m_state = new AmbulanceMissionState(); - m_state->m_unk0x08 = 0; + m_state->m_state = AmbulanceMissionState::e_ready; GameState()->RegisterState(m_state); } } @@ -173,25 +173,25 @@ MxLong Ambulance::HandleEndAction(MxEndActionNotificationParam& p_param) m_lastAction = IsleScript::c_noneIsle; } else if (objectId == IsleScript::c_hho027en_RunAnim) { - m_state->m_unk0x08 = 1; + m_state->m_state = AmbulanceMissionState::e_enteredAmbulance; CurrentWorld()->PlaceActor(UserActor()); HandleClick(); m_unk0x172 = 0; TickleManager()->RegisterClient(this, 40000); } else if (objectId == IsleScript::c_hpz047pe_RunAnim || objectId == IsleScript::c_hpz048pe_RunAnim || objectId == IsleScript::c_hpz049bd_RunAnim || objectId == IsleScript::c_hpz053pa_RunAnim) { - if (m_unk0x170 == 3) { + if (m_taskState == Ambulance::e_finished) { PlayAnimation(IsleScript::c_hpz055pa_RunAnim); - m_unk0x170 = 0; + m_taskState = Ambulance::e_none; } else { PlayAnimation(IsleScript::c_hpz053pa_RunAnim); } } else if (objectId == IsleScript::c_hpz050bd_RunAnim || objectId == IsleScript::c_hpz052ma_RunAnim) { - if (m_unk0x170 == 3) { + if (m_taskState == Ambulance::e_finished) { PlayAnimation(IsleScript::c_hpz057ma_RunAnim); - m_unk0x170 = 0; + m_taskState = Ambulance::e_none; } else { PlayAnimation(IsleScript::c_hpz052ma_RunAnim); @@ -204,18 +204,18 @@ MxLong Ambulance::HandleEndAction(MxEndActionNotificationParam& p_param) m_unk0x172 = 0; TickleManager()->RegisterClient(this, 40000); - if (m_unk0x16c != 0) { + if (m_atPoliceTask != 0) { StopActions(); } } else if (objectId == IsleScript::c_hps116bd_RunAnim || objectId == IsleScript::c_hps118re_RunAnim) { - if (objectId == IsleScript::c_hps116bd_RunAnim && m_unk0x170 != 3) { + if (objectId == IsleScript::c_hps116bd_RunAnim && m_taskState != Ambulance::e_finished) { PlayAction(IsleScript::c_Avo923In_PlayWav); } - if (m_unk0x170 == 3) { + if (m_taskState == Ambulance::e_finished) { PlayAnimation(IsleScript::c_hps117bd_RunAnim); - m_unk0x170 = 0; + m_taskState = Ambulance::e_none; } else { PlayAnimation(IsleScript::c_hps118re_RunAnim); @@ -228,12 +228,12 @@ MxLong Ambulance::HandleEndAction(MxEndActionNotificationParam& p_param) m_unk0x172 = 0; TickleManager()->RegisterClient(this, 40000); - if (m_unk0x16e != 0) { + if (m_atBeachTask != 0) { StopActions(); } } else if (objectId == IsleScript::c_hho142cl_RunAnim || objectId == IsleScript::c_hho143cl_RunAnim || objectId == IsleScript::c_hho144cl_RunAnim) { - FUN_10037250(); + Reset(); } } @@ -244,18 +244,18 @@ MxLong Ambulance::HandleEndAction(MxEndActionNotificationParam& p_param) // FUNCTION: BETA10 0x100230bf MxLong Ambulance::HandleButtonDown(LegoControlManagerNotificationParam& p_param) { - if (m_unk0x170 == 1) { + if (m_taskState == Ambulance::e_waiting) { LegoROI* roi = PickROI(p_param.GetX(), p_param.GetY()); if (roi != NULL && !SDL_strcasecmp(roi->GetName(), "ps-gate")) { - m_unk0x170 = 3; + m_taskState = Ambulance::e_finished; return 1; } roi = PickRootROI(p_param.GetX(), p_param.GetY()); if (roi != NULL && !SDL_strcasecmp(roi->GetName(), "gd")) { - m_unk0x170 = 3; + m_taskState = Ambulance::e_finished; return 1; } } @@ -273,9 +273,9 @@ MxLong Ambulance::HandlePathStruct(LegoPathStructNotificationParam& p_param) } if (p_param.GetTrigger() == LegoPathStruct::c_camAnim && p_param.GetData() == 0x0b) { - if (m_unk0x16e != 0) { - if (m_unk0x16c != 0) { - m_state->m_unk0x08 = 2; + if (m_atBeachTask != 0) { + if (m_atPoliceTask != 0) { + m_state->m_state = AmbulanceMissionState::e_prepareAmbulance; if (m_lastAction != IsleScript::c_noneIsle) { InvokeAction(Extra::e_stop, *g_isleScript, m_lastAction, NULL); @@ -300,7 +300,7 @@ MxLong Ambulance::HandlePathStruct(LegoPathStructNotificationParam& p_param) return 0; } - if (m_unk0x16e != 0) { + if (m_atBeachTask != 0) { if (m_lastAction != IsleScript::c_noneIsle) { InvokeAction(Extra::e_stop, *g_isleScript, m_lastAction, NULL); } @@ -310,7 +310,7 @@ MxLong Ambulance::HandlePathStruct(LegoPathStructNotificationParam& p_param) } } - if (m_unk0x16c != 0) { + if (m_atPoliceTask != 0) { if (m_lastAction != IsleScript::c_noneIsle) { InvokeAction(Extra::e_stop, *g_isleScript, m_lastAction, NULL); } @@ -318,9 +318,9 @@ MxLong Ambulance::HandlePathStruct(LegoPathStructNotificationParam& p_param) PlayAction(IsleScript::c_Avo915In_PlayWav); } } - else if (p_param.GetTrigger() == LegoPathStruct::c_s && p_param.GetData() == 0x131 && m_unk0x16e == 0) { - m_unk0x16e = 1; - m_unk0x170 = 1; + else if (p_param.GetTrigger() == LegoPathStruct::c_s && p_param.GetData() == 0x131 && m_atBeachTask == 0) { + m_atBeachTask = 1; + m_taskState = Ambulance::e_waiting; if (m_lastAction != IsleScript::c_noneIsle) { InvokeAction(Extra::e_stop, *g_isleScript, m_lastAction, NULL); @@ -348,9 +348,9 @@ MxLong Ambulance::HandlePathStruct(LegoPathStructNotificationParam& p_param) break; } } - else if (p_param.GetTrigger() == LegoPathStruct::c_camAnim && (p_param.GetData() == 0x22 || p_param.GetData() == 0x23 || p_param.GetData() == 0x24) && m_unk0x16c == 0) { - m_unk0x16c = 1; - m_unk0x170 = 1; + else if (p_param.GetTrigger() == LegoPathStruct::c_camAnim && (p_param.GetData() == 0x22 || p_param.GetData() == 0x23 || p_param.GetData() == 0x24) && m_atPoliceTask == 0) { + m_atPoliceTask = 1; + m_taskState = Ambulance::e_waiting; if (m_lastAction != IsleScript::c_noneIsle) { InvokeAction(Extra::e_stop, *g_isleScript, m_lastAction, NULL); @@ -371,7 +371,7 @@ MxLong Ambulance::HandleClick() return 1; } - if (m_state->m_unk0x08 == 2) { + if (m_state->m_state == AmbulanceMissionState::e_prepareAmbulance) { return 1; } @@ -390,7 +390,7 @@ MxLong Ambulance::HandleClick() InvokeAction(Extra::e_start, *g_isleScript, IsleScript::c_AmbulanceDashboard, NULL); ControlManager()->Register(this); - if (m_state->m_unk0x08 == 1) { + if (m_state->m_state == AmbulanceMissionState::e_enteredAmbulance) { SpawnPlayer(LegoGameState::e_hospitalExited, TRUE, 0); m_state->m_startTime = Timer()->GetTime(); InvokeAction(Extra::e_start, *g_isleScript, IsleScript::c_pns018rd_RunAnim, NULL); @@ -401,9 +401,9 @@ MxLong Ambulance::HandleClick() // FUNCTION: LEGO1 0x10036e60 // FUNCTION: BETA10 0x100236bb -void Ambulance::FUN_10036e60() +void Ambulance::Init() { - m_state->m_unk0x08 = 2; + m_state->m_state = AmbulanceMissionState::e_prepareAmbulance; PlayAnimation(IsleScript::c_hho027en_RunAnim); m_lastAction = IsleScript::c_noneIsle; m_lastAnimation = IsleScript::c_noneIsle; @@ -414,7 +414,7 @@ void Ambulance::Exit() { GameState()->m_currentArea = LegoGameState::e_hospitalExterior; StopActions(); - FUN_10037250(); + Reset(); Leave(); } @@ -470,11 +470,11 @@ void Ambulance::ActivateSceneActions() { PlayMusic(JukeboxScript::c_Hospital_Music); - if (m_state->m_unk0x08 == 1) { - m_state->m_unk0x08 = 0; + if (m_state->m_state == AmbulanceMissionState::e_enteredAmbulance) { + m_state->m_state = AmbulanceMissionState::e_ready; PlayAction(IsleScript::c_ham033cl_PlayWav); } - else if (m_unk0x16c != 0 && m_unk0x16e != 0) { + else if (m_atPoliceTask != 0 && m_atBeachTask != 0) { IsleScript::Script objectId; switch (SDL_rand(2)) { @@ -574,14 +574,14 @@ void Ambulance::StopActions() } // FUNCTION: LEGO1 0x10037250 -void Ambulance::FUN_10037250() +void Ambulance::Reset() { StopAction(m_lastAction); BackgroundAudioManager()->RaiseVolume(); ((Act1State*) GameState()->GetState("Act1State"))->m_unk0x018 = 0; - m_state->m_unk0x08 = 0; - m_unk0x16e = 0; - m_unk0x16c = 0; + m_state->m_state = AmbulanceMissionState::e_ready; + m_atBeachTask = 0; + m_atPoliceTask = 0; g_isleFlags |= Isle::c_playMusic; AnimationManager()->EnableCamAnims(TRUE); AnimationManager()->FUN_1005f6d0(TRUE); @@ -629,7 +629,7 @@ void Ambulance::PlayAction(IsleScript::Script p_objectId) // FUNCTION: LEGO1 0x100373a0 AmbulanceMissionState::AmbulanceMissionState() { - m_unk0x08 = 0; + m_state = AmbulanceMissionState::e_ready; m_startTime = 0; m_peScore = 0; m_maScore = 0; diff --git a/LEGO1/lego/legoomni/src/build/legocarbuild.cpp b/LEGO1/lego/legoomni/src/build/legocarbuild.cpp index e69415f6..fa0be996 100644 --- a/LEGO1/lego/legoomni/src/build/legocarbuild.cpp +++ b/LEGO1/lego/legoomni/src/build/legocarbuild.cpp @@ -488,7 +488,7 @@ void LegoCarBuild::FUN_100236d0() m_unk0x110 = NULL; m_unk0x100 = 0; - if (m_animPresenter->AllPartsPlaced()) { + if (m_animPresenter->AllPartsPlaced() && !Lego()->IsVersion10()) { // Note the code duplication with LEGO1 0x10025ee0 switch (m_carId) { case 1: diff --git a/LEGO1/lego/legoomni/src/common/legobuildingmanager.cpp b/LEGO1/lego/legoomni/src/common/legobuildingmanager.cpp index d46b8a49..8dae5d61 100644 --- a/LEGO1/lego/legoomni/src/common/legobuildingmanager.cpp +++ b/LEGO1/lego/legoomni/src/common/legobuildingmanager.cpp @@ -199,10 +199,10 @@ LegoBuildingInfo g_buildingInfoInit[16] = { MxU32 LegoBuildingManager::g_maxSound = 6; // GLOBAL: LEGO1 0x100f373c -MxU32 g_unk0x100f373c = 0x3c; +MxU32 g_buildingSoundIdOffset = 0x3c; // GLOBAL: LEGO1 0x100f3740 -MxU32 g_unk0x100f3740 = 0x42; +MxU32 g_buildingSoundIdMoodOffset = 0x42; // clang-format off // GLOBAL: LEGO1 0x100f3788 @@ -227,6 +227,8 @@ LegoBuildingInfo g_buildingInfo[16]; // GLOBAL: LEGO1 0x100f3748 MxS32 LegoBuildingManager::g_maxMove[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 3, 3, 0}; +#define HAUS1_INDEX 12 + // FUNCTION: LEGO1 0x1002f8b0 void LegoBuildingManager::configureLegoBuildingManager(MxS32 p_buildingManagerConfig) { @@ -392,6 +394,9 @@ MxResult LegoBuildingManager::Read(LegoStorage* p_storage) m_nextVariant = 0; } + // Bugfix: allow Pepper to change variant building after save game load + g_buildingInfo[HAUS1_INDEX].m_variant = g_buildingInfoVariants[m_nextVariant]; + result = SUCCESS; done: @@ -461,7 +466,7 @@ MxBool LegoBuildingManager::SwitchVariant(LegoEntity* p_entity) roi->SetVisibility(FALSE); info->m_variant = g_buildingInfoVariants[m_nextVariant]; - CreateBuilding(12, CurrentWorld()); + CreateBuilding(HAUS1_INDEX, CurrentWorld()); if (info->m_entity != NULL) { info->m_entity->GetROI()->SetVisibility(TRUE); @@ -548,7 +553,7 @@ MxU32 LegoBuildingManager::GetAnimationId(LegoEntity* p_entity) // FUNCTION: LEGO1 0x1002ff40 // FUNCTION: BETA10 0x10064398 -MxU32 LegoBuildingManager::GetSoundId(LegoEntity* p_entity, MxBool p_state) +MxU32 LegoBuildingManager::GetSoundId(LegoEntity* p_entity, MxBool p_basedOnMood) { LegoBuildingInfo* info = GetInfo(p_entity); @@ -556,12 +561,12 @@ MxU32 LegoBuildingManager::GetSoundId(LegoEntity* p_entity, MxBool p_state) return 0; } - if (p_state) { - return info->m_mood + g_unk0x100f3740; + if (p_basedOnMood) { + return info->m_mood + g_buildingSoundIdMoodOffset; } if (info != NULL) { - return info->m_sound + g_unk0x100f373c; + return info->m_sound + g_buildingSoundIdOffset; } return 0; diff --git a/LEGO1/lego/legoomni/src/common/legocharactermanager.cpp b/LEGO1/lego/legoomni/src/common/legocharactermanager.cpp index 6510dcb3..adf442eb 100644 --- a/LEGO1/lego/legoomni/src/common/legocharactermanager.cpp +++ b/LEGO1/lego/legoomni/src/common/legocharactermanager.cpp @@ -39,10 +39,10 @@ MxU32 g_characterAnimationId = 10; char* LegoCharacterManager::g_customizeAnimFile = NULL; // GLOBAL: LEGO1 0x100fc4d8 -MxU32 g_soundIdOffset = 50; +MxU32 g_characterSoundIdOffset = 50; // GLOBAL: LEGO1 0x100fc4dc -MxU32 g_soundIdMoodOffset = 66; +MxU32 g_characterSoundIdMoodOffset = 66; // GLOBAL: LEGO1 0x100fc4e8 MxU32 g_headTextureCounter = 0; @@ -636,7 +636,7 @@ MxBool LegoCharacterManager::SetHeadTexture(LegoROI* p_roi, LegoTextureInfo* p_t LegoLOD* clone = lod->Clone(renderer); if (p_texture != NULL) { - clone->FUN_100aad70(p_texture); + clone->UpdateTextureInfo(p_texture); } dupLodList->PushBack(clone); @@ -933,16 +933,16 @@ MxU32 LegoCharacterManager::GetAnimationId(LegoROI* p_roi) // FUNCTION: LEGO1 0x10085140 // FUNCTION: BETA10 0x10076855 -MxU32 LegoCharacterManager::GetSoundId(LegoROI* p_roi, MxBool p_und) +MxU32 LegoCharacterManager::GetSoundId(LegoROI* p_roi, MxBool p_basedOnMood) { LegoActorInfo* info = GetActorInfo(p_roi); - if (p_und) { - return info->m_mood + g_soundIdMoodOffset; + if (p_basedOnMood) { + return info->m_mood + g_characterSoundIdMoodOffset; } if (info != NULL) { - return info->m_sound + g_soundIdOffset; + return info->m_sound + g_characterSoundIdOffset; } else { return 0; diff --git a/LEGO1/lego/legoomni/src/common/legoplantmanager.cpp b/LEGO1/lego/legoomni/src/common/legoplantmanager.cpp index 1444571f..a67f7e08 100644 --- a/LEGO1/lego/legoomni/src/common/legoplantmanager.cpp +++ b/LEGO1/lego/legoomni/src/common/legoplantmanager.cpp @@ -40,10 +40,10 @@ MxU8 g_counters[] = {1, 2, 2, 3}; MxU32 LegoPlantManager::g_maxSound = 8; // GLOBAL: LEGO1 0x100f3160 -MxU32 g_unk0x100f3160 = 56; +MxU32 g_plantSoundIdOffset = 56; // GLOBAL: LEGO1 0x100f3164 -MxU32 g_unk0x100f3164 = 66; +MxU32 g_plantSoundIdMoodOffset = 66; // GLOBAL: LEGO1 0x100f3168 MxS32 LegoPlantManager::g_maxMove[4] = {3, 3, 3, 3}; @@ -83,7 +83,7 @@ void LegoPlantManager::Init() } m_worldId = LegoOmni::e_undefined; - m_unk0x0c = 0; + m_boundariesDetermined = FALSE; m_numEntries = 0; } @@ -98,7 +98,7 @@ void LegoPlantManager::LoadWorldInfo(LegoOmni::World p_worldId) CreatePlant(i, world, p_worldId); } - m_unk0x0c = 0; + m_boundariesDetermined = FALSE; } // FUNCTION: LEGO1 0x100263a0 @@ -119,12 +119,12 @@ void LegoPlantManager::Reset(LegoOmni::World p_worldId) } m_worldId = LegoOmni::e_undefined; - m_unk0x0c = 0; + m_boundariesDetermined = FALSE; } // FUNCTION: LEGO1 0x10026410 // FUNCTION: BETA10 0x100c50e9 -MxResult LegoPlantManager::FUN_10026410() +MxResult LegoPlantManager::DetermineBoundaries() { // similar to LegoBuildingManager::FUN_10030630() @@ -192,7 +192,7 @@ MxResult LegoPlantManager::FUN_10026410() } } - m_unk0x0c = TRUE; + m_boundariesDetermined = TRUE; return SUCCESS; } @@ -200,8 +200,8 @@ MxResult LegoPlantManager::FUN_10026410() // FUNCTION: BETA10 0x100c55e0 LegoPlantInfo* LegoPlantManager::GetInfoArray(MxS32& p_length) { - if (!m_unk0x0c) { - FUN_10026410(); + if (!m_boundariesDetermined) { + DetermineBoundaries(); } p_length = sizeOfArray(g_plantInfo); @@ -214,7 +214,7 @@ LegoEntity* LegoPlantManager::CreatePlant(MxS32 p_index, LegoWorld* p_world, Leg { LegoEntity* entity = NULL; - if (p_index < sizeOfArray(g_plantInfo)) { + if (p_worldId != LegoOmni::e_undefined && p_index < sizeOfArray(g_plantInfo)) { MxU32 world = 1 << (MxU8) p_worldId; if (g_plantInfo[p_index].m_worlds & world && g_plantInfo[p_index].m_counter != 0) { @@ -514,16 +514,16 @@ MxU32 LegoPlantManager::GetAnimationId(LegoEntity* p_entity) // FUNCTION: LEGO1 0x10026ba0 // FUNCTION: BETA10 0x100c61ba -MxU32 LegoPlantManager::GetSoundId(LegoEntity* p_entity, MxBool p_state) +MxU32 LegoPlantManager::GetSoundId(LegoEntity* p_entity, MxBool p_basedOnMood) { LegoPlantInfo* info = GetInfo(p_entity); - if (p_state) { - return (info->m_mood & 1) + g_unk0x100f3164; + if (p_basedOnMood) { + return (info->m_mood & 1) + g_plantSoundIdMoodOffset; } if (info != NULL) { - return info->m_sound + g_unk0x100f3160; + return info->m_sound + g_plantSoundIdOffset; } return 0; diff --git a/LEGO1/lego/legoomni/src/common/legotextureinfo.cpp b/LEGO1/lego/legoomni/src/common/legotextureinfo.cpp index 46dad6dc..eb639d84 100644 --- a/LEGO1/lego/legoomni/src/common/legotextureinfo.cpp +++ b/LEGO1/lego/legoomni/src/common/legotextureinfo.cpp @@ -83,7 +83,7 @@ LegoTextureInfo* LegoTextureInfo::Create(const char* p_name, LegoTexture* p_text memset(&desc, 0, sizeof(desc)); desc.dwSize = sizeof(desc); - if (textureInfo->m_surface->Lock(NULL, &desc, DDLOCK_SURFACEMEMORYPTR, NULL) != DD_OK) { + if (textureInfo->m_surface->Lock(NULL, &desc, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WRITEONLY, NULL) != DD_OK) { goto done; } @@ -193,7 +193,7 @@ LegoResult LegoTextureInfo::LoadBits(const LegoU8* p_bits) memset(&desc, 0, sizeof(desc)); desc.dwSize = sizeof(desc); - if (m_surface->Lock(NULL, &desc, DDLOCK_SURFACEMEMORYPTR, NULL) == DD_OK) { + if (m_surface->Lock(NULL, &desc, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WRITEONLY, NULL) == DD_OK) { MxU8* surface = (MxU8*) desc.lpSurface; const LegoU8* bits = p_bits; diff --git a/LEGO1/lego/legoomni/src/common/legoutils.cpp b/LEGO1/lego/legoomni/src/common/legoutils.cpp index 26948049..9d3f3c7d 100644 --- a/LEGO1/lego/legoomni/src/common/legoutils.cpp +++ b/LEGO1/lego/legoomni/src/common/legoutils.cpp @@ -708,7 +708,7 @@ void WriteDefaultTexture(LegoStorage* p_storage, const char* p_name) memset(&desc, 0, sizeof(desc)); desc.dwSize = sizeof(desc); - if (surface->Lock(NULL, &desc, DDLOCK_SURFACEMEMORYPTR, NULL) == DD_OK) { + if (surface->Lock(NULL, &desc, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WRITEONLY, NULL) == DD_OK) { LegoImage* image = new LegoImage(desc.dwWidth, desc.dwHeight); if (image != NULL) { diff --git a/LEGO1/lego/legoomni/src/common/mxtransitionmanager.cpp b/LEGO1/lego/legoomni/src/common/mxtransitionmanager.cpp index 6cd73584..d54563ab 100644 --- a/LEGO1/lego/legoomni/src/common/mxtransitionmanager.cpp +++ b/LEGO1/lego/legoomni/src/common/mxtransitionmanager.cpp @@ -16,6 +16,8 @@ DECOMP_SIZE_ASSERT(MxTransitionManager, 0x900) +MxTransitionManager::TransitionType g_transitionManagerConfig = MxTransitionManager::e_mosaic; + // GLOBAL: LEGO1 0x100f4378 RECT g_fullScreenRect = {0, 0, 640, 480}; @@ -105,7 +107,7 @@ MxResult MxTransitionManager::StartTransition( backgroundAudioManager->Stop(); } - m_mode = p_animationType; + m_mode = g_transitionManagerConfig; m_copyFlags.m_bit0 = p_doCopy; @@ -210,10 +212,10 @@ void MxTransitionManager::DissolveTransition() memset(&ddsd, 0, sizeof(ddsd)); ddsd.dwSize = sizeof(ddsd); - HRESULT res = m_ddSurface->Lock(NULL, &ddsd, DDLOCK_WAIT, NULL); + HRESULT res = m_ddSurface->Lock(NULL, &ddsd, DDLOCK_WAIT | DDLOCK_WRITEONLY, NULL); if (res == DDERR_SURFACELOST) { m_ddSurface->Restore(); - res = m_ddSurface->Lock(NULL, &ddsd, DDLOCK_WAIT, NULL); + res = m_ddSurface->Lock(NULL, &ddsd, DDLOCK_WAIT | DDLOCK_WRITEONLY, NULL); } if (res == DD_OK) { @@ -402,10 +404,10 @@ void MxTransitionManager::WipeDownTransition() memset(&ddsd, 0, sizeof(ddsd)); ddsd.dwSize = sizeof(ddsd); - HRESULT res = m_ddSurface->Lock(NULL, &ddsd, DDLOCK_WAIT, NULL); + HRESULT res = m_ddSurface->Lock(NULL, &ddsd, DDLOCK_WAIT | DDLOCK_WRITEONLY, NULL); if (res == DDERR_SURFACELOST) { m_ddSurface->Restore(); - res = m_ddSurface->Lock(NULL, &ddsd, DDLOCK_WAIT, NULL); + res = m_ddSurface->Lock(NULL, &ddsd, DDLOCK_WAIT | DDLOCK_WRITEONLY, NULL); } if (res == DD_OK) { @@ -439,10 +441,10 @@ void MxTransitionManager::WindowsTransition() memset(&ddsd, 0, sizeof(ddsd)); ddsd.dwSize = sizeof(ddsd); - HRESULT res = m_ddSurface->Lock(NULL, &ddsd, DDLOCK_WAIT, NULL); + HRESULT res = m_ddSurface->Lock(NULL, &ddsd, DDLOCK_WAIT | DDLOCK_WRITEONLY, NULL); if (res == DDERR_SURFACELOST) { m_ddSurface->Restore(); - res = m_ddSurface->Lock(NULL, &ddsd, DDLOCK_WAIT, NULL); + res = m_ddSurface->Lock(NULL, &ddsd, DDLOCK_WAIT | DDLOCK_WRITEONLY, NULL); } if (res == DD_OK) { @@ -483,10 +485,10 @@ void MxTransitionManager::BrokenTransition() memset(&ddsd, 0, sizeof(ddsd)); ddsd.dwSize = sizeof(ddsd); - HRESULT res = m_ddSurface->Lock(NULL, &ddsd, DDLOCK_WAIT, NULL); + HRESULT res = m_ddSurface->Lock(NULL, &ddsd, DDLOCK_WAIT | DDLOCK_WRITEONLY, NULL); if (res == DDERR_SURFACELOST) { m_ddSurface->Restore(); - res = m_ddSurface->Lock(NULL, &ddsd, DDLOCK_WAIT, NULL); + res = m_ddSurface->Lock(NULL, &ddsd, DDLOCK_WAIT | DDLOCK_WRITEONLY, NULL); } if (res == DD_OK) { @@ -632,3 +634,8 @@ void MxTransitionManager::SetupCopyRect(LPDDSURFACEDESC p_ddsc) ); } } + +void MxTransitionManager::configureMxTransitionManager(TransitionType p_transitionManagerConfig) +{ + g_transitionManagerConfig = p_transitionManagerConfig; +} diff --git a/LEGO1/lego/legoomni/src/entity/legoactor.cpp b/LEGO1/lego/legoomni/src/entity/legoactor.cpp index 34ba9fb8..477bf529 100644 --- a/LEGO1/lego/legoomni/src/entity/legoactor.cpp +++ b/LEGO1/lego/legoomni/src/entity/legoactor.cpp @@ -20,7 +20,7 @@ LegoActor::LegoActor() m_frequencyFactor = 0.0f; m_sound = NULL; m_unk0x70 = 0.0f; - m_unk0x10 = 0; + m_interaction = 0; m_actorId = 0; } diff --git a/LEGO1/lego/legoomni/src/entity/legoentity.cpp b/LEGO1/lego/legoomni/src/entity/legoentity.cpp index 148d4c16..cce17c18 100644 --- a/LEGO1/lego/legoomni/src/entity/legoentity.cpp +++ b/LEGO1/lego/legoomni/src/entity/legoentity.cpp @@ -31,7 +31,7 @@ void LegoEntity::Init() m_roi = NULL; m_cameraFlag = FALSE; m_siFile = NULL; - m_unk0x10 = 0; + m_interaction = 0; m_flags = 0; m_actionType = Extra::ActionType::e_unknown; m_targetEntityId = -1; @@ -266,23 +266,23 @@ void LegoEntity::ParseAction(char* p_extra) // FUNCTION: LEGO1 0x10010f10 // FUNCTION: BETA10 0x1007ee87 -void LegoEntity::ClickSound(MxBool p_und) +void LegoEntity::ClickSound(MxBool p_basedOnMood) { - if (!GetUnknown0x10IsSet(c_altBit1)) { + if (!IsInteraction(c_disabled)) { MxU32 objectId = 0; const char* name = m_roi->GetName(); switch (m_type) { case e_actor: - objectId = CharacterManager()->GetSoundId(m_roi, p_und); + objectId = CharacterManager()->GetSoundId(m_roi, p_basedOnMood); break; case e_unk1: break; case e_plant: - objectId = PlantManager()->GetSoundId(this, p_und); + objectId = PlantManager()->GetSoundId(this, p_basedOnMood); break; case e_building: - objectId = BuildingManager()->GetSoundId(this, p_und); + objectId = BuildingManager()->GetSoundId(this, p_basedOnMood); break; } @@ -300,7 +300,7 @@ void LegoEntity::ClickSound(MxBool p_und) // FUNCTION: BETA10 0x1007f062 void LegoEntity::ClickAnimation() { - if (!GetUnknown0x10IsSet(c_altBit1)) { + if (!IsInteraction(c_disabled)) { MxU32 objectId = 0; MxDSAction action; const char* name = m_roi->GetName(); @@ -332,7 +332,7 @@ void LegoEntity::ClickAnimation() action.SetObjectId(objectId); action.AppendExtra(strlen(extra) + 1, extra); LegoOmni::GetInstance()->GetAnimationManager()->StartEntityAction(action, this); - m_unk0x10 |= c_altBit1; + m_interaction |= c_disabled; } } } diff --git a/LEGO1/lego/legoomni/src/entity/legonavcontroller.cpp b/LEGO1/lego/legoomni/src/entity/legonavcontroller.cpp index 407fa3cb..4308717a 100644 --- a/LEGO1/lego/legoomni/src/entity/legonavcontroller.cpp +++ b/LEGO1/lego/legoomni/src/entity/legonavcontroller.cpp @@ -697,7 +697,7 @@ MxLong LegoNavController::Notify(MxParam& p_param) for (MxS32 i = 0; i < numPlants; i++) { LegoEntity* entity = plantMgr->CreatePlant(i, NULL, LegoOmni::e_act1); - if (entity != NULL && !entity->GetUnknown0x10IsSet(LegoEntity::c_altBit1)) { + if (entity != NULL && !entity->IsInteraction(LegoEntity::c_disabled)) { LegoROI* roi = entity->GetROI(); if (roi != NULL && roi->GetVisibility()) { diff --git a/LEGO1/lego/legoomni/src/main/legomain.cpp b/LEGO1/lego/legoomni/src/main/legomain.cpp index 3b99f0b5..1695e1c3 100644 --- a/LEGO1/lego/legoomni/src/main/legomain.cpp +++ b/LEGO1/lego/legoomni/src/main/legomain.cpp @@ -76,6 +76,7 @@ void LegoOmni::Init() m_bkgAudioManager = NULL; m_unk0x13c = TRUE; m_transitionManager = NULL; + m_version10 = FALSE; } // FUNCTION: LEGO1 0x10058c30 diff --git a/LEGO1/lego/legoomni/src/paths/legopathactor.cpp b/LEGO1/lego/legoomni/src/paths/legopathactor.cpp index adf3390a..c9ce7c6c 100644 --- a/LEGO1/lego/legoomni/src/paths/legopathactor.cpp +++ b/LEGO1/lego/legoomni/src/paths/legopathactor.cpp @@ -37,7 +37,7 @@ const char* g_strHIT_WALL_SOUND = "HIT_WALL_SOUND"; // GLOBAL: LEGO1 0x100f3308 // GLOBAL: BETA10 0x101f1e1c -MxLong g_unk0x100f3308 = 0; +MxLong g_timeLastHitSoundPlayed = 0; // FUNCTION: LEGO1 0x1002d700 // FUNCTION: BETA10 0x100ae6e0 @@ -292,8 +292,8 @@ MxS32 LegoPathActor::VTable0x8c(float p_time, Matrix4& p_transform) if (m_boundary == oldBoundary) { MxLong time = Timer()->GetTime(); - if (time - g_unk0x100f3308 > 1000) { - g_unk0x100f3308 = time; + if (time - g_timeLastHitSoundPlayed > 1000) { + g_timeLastHitSoundPlayed = time; const char* var = VariableTable()->GetVariable(g_strHIT_WALL_SOUND); if (var && var[0] != 0) { diff --git a/LEGO1/lego/legoomni/src/race/carrace.cpp b/LEGO1/lego/legoomni/src/race/carrace.cpp index 988584c5..97ae49b8 100644 --- a/LEGO1/lego/legoomni/src/race/carrace.cpp +++ b/LEGO1/lego/legoomni/src/race/carrace.cpp @@ -246,7 +246,7 @@ MxLong CarRace::HandlePathStruct(LegoPathStructNotificationParam& p_param) VariableTable()->SetVariable(g_strHIT_WALL_SOUND, ""); NavController()->SetDeadZone(NavController()->GetDefaultDeadZone()); NavController()->SetTrackDefault(1); - LegoRaceCar::FUN_10012de0(); + LegoRaceCar::InitYouCantStopSound(); m_raceState->m_unk0x28 = 2; RaceState::Entry* raceState = m_raceState->GetState(GameState()->GetActorId()); @@ -348,7 +348,7 @@ MxLong CarRace::HandleClick(LegoEventNotificationParam& p_param) VariableTable()->SetVariable(g_strHIT_WALL_SOUND, ""); NavController()->SetDeadZone(NavController()->GetDefaultDeadZone()); NavController()->SetTrackDefault(1); - LegoRaceCar::FUN_10012de0(); + LegoRaceCar::InitYouCantStopSound(); m_destLocation = LegoGameState::e_infomain; TransitionManager()->StartTransition(MxTransitionManager::e_mosaic, 50, FALSE, FALSE); GameState()->GetBackgroundColor()->SetValue("reset"); @@ -360,7 +360,7 @@ MxLong CarRace::HandleClick(LegoEventNotificationParam& p_param) VariableTable()->SetVariable(g_strHIT_WALL_SOUND, ""); NavController()->SetDeadZone(NavController()->GetDefaultDeadZone()); NavController()->SetTrackDefault(1); - LegoRaceCar::FUN_10012de0(); + LegoRaceCar::InitYouCantStopSound(); m_destLocation = LegoGameState::e_carraceExterior; TransitionManager()->StartTransition(MxTransitionManager::e_mosaic, 50, FALSE, FALSE); GameState()->GetBackgroundColor()->SetValue("reset"); @@ -424,7 +424,7 @@ MxBool CarRace::Escape() NavController()->SetDeadZone(NavController()->GetDefaultDeadZone()); NavController()->SetTrackDefault(1); - LegoRaceCar::FUN_10012de0(); + LegoRaceCar::InitYouCantStopSound(); GameState()->GetBackgroundColor()->SetValue("reset"); m_destLocation = LegoGameState::e_infomain; diff --git a/LEGO1/lego/legoomni/src/race/jetskirace.cpp b/LEGO1/lego/legoomni/src/race/jetskirace.cpp index 042090db..b520f8f3 100644 --- a/LEGO1/lego/legoomni/src/race/jetskirace.cpp +++ b/LEGO1/lego/legoomni/src/race/jetskirace.cpp @@ -132,7 +132,7 @@ MxLong JetskiRace::HandleClick(LegoEventNotificationParam& p_param) m_act1State->m_unk0x018 = 0; VariableTable()->SetVariable(g_raceState, ""); VariableTable()->SetVariable(g_strHIT_WALL_SOUND, ""); - LegoRaceCar::FUN_10012de0(); + LegoRaceCar::InitYouCantStopSound(); m_destLocation = LegoGameState::e_jetraceExterior; TransitionManager()->StartTransition(MxTransitionManager::e_mosaic, 50, FALSE, FALSE); break; @@ -140,7 +140,7 @@ MxLong JetskiRace::HandleClick(LegoEventNotificationParam& p_param) m_act1State->m_unk0x018 = 0; VariableTable()->SetVariable(g_raceState, ""); VariableTable()->SetVariable(g_strHIT_WALL_SOUND, ""); - LegoRaceCar::FUN_10012de0(); + LegoRaceCar::InitYouCantStopSound(); m_destLocation = LegoGameState::e_infomain; result = 1; TransitionManager()->StartTransition(MxTransitionManager::e_mosaic, 50, FALSE, FALSE); @@ -193,7 +193,7 @@ MxLong JetskiRace::HandlePathStruct(LegoPathStructNotificationParam& p_param) VariableTable()->SetVariable(g_raceState, ""); VariableTable()->SetVariable(g_strHIT_WALL_SOUND, ""); - LegoRaceCar::FUN_10012de0(); + LegoRaceCar::InitYouCantStopSound(); m_raceState->m_unk0x28 = 2; RaceState::Entry* raceStateEntry = m_raceState->GetState(GameState()->GetActorId()); @@ -294,6 +294,6 @@ MxBool JetskiRace::Escape() VariableTable()->SetVariable(g_raceState, ""); VariableTable()->SetVariable(g_strHIT_WALL_SOUND, ""); m_destLocation = LegoGameState::e_infomain; - LegoRaceCar::FUN_10012de0(); + LegoRaceCar::InitYouCantStopSound(); return TRUE; } diff --git a/LEGO1/lego/legoomni/src/race/legoraceactor.cpp b/LEGO1/lego/legoomni/src/race/legoraceactor.cpp index 965ba326..f005d996 100644 --- a/LEGO1/lego/legoomni/src/race/legoraceactor.cpp +++ b/LEGO1/lego/legoomni/src/race/legoraceactor.cpp @@ -31,8 +31,8 @@ MxS32 LegoRaceActor::VTable0x68(Vector3& p_v1, Vector3& p_v2, Vector3& p_v3) if (m_userNavFlag && result) { MxLong time = Timer()->GetTime(); - if (time - g_unk0x100f3308 > 1000) { - g_unk0x100f3308 = time; + if (time - g_timeLastHitSoundPlayed > 1000) { + g_timeLastHitSoundPlayed = time; const char* soundKey = VariableTable()->GetVariable(g_strHIT_ACTOR_SOUND); if (soundKey && *soundKey) { diff --git a/LEGO1/lego/legoomni/src/race/legoracers.cpp b/LEGO1/lego/legoomni/src/race/legoracers.cpp index 0cffed0c..4aeaced0 100644 --- a/LEGO1/lego/legoomni/src/race/legoracers.cpp +++ b/LEGO1/lego/legoomni/src/race/legoracers.cpp @@ -178,7 +178,7 @@ LegoRaceCar::LegoRaceCar() m_skelKick1Anim = 0; m_skelKick2Anim = 0; m_unk0x5c.Clear(); - m_unk0x58 = 0; + m_kickStart = 0; m_kick1B = 0; m_kick2B = 0; NotificationManager()->Register(this); @@ -201,10 +201,10 @@ MxLong LegoRaceCar::Notify(MxParam& p_param) // Initialized at LEGO1 0x10012db0 // GLOBAL: LEGO1 0x10102af0 // GLOBAL: BETA10 0x102114c0 -Mx3DPointFloat g_unk0x10102af0 = Mx3DPointFloat(0.0f, 2.0f, 0.0f); +Mx3DPointFloat g_hitOffset = Mx3DPointFloat(0.0f, 2.0f, 0.0f); // FUNCTION: LEGO1 0x10012de0 -void LegoRaceCar::FUN_10012de0() +void LegoRaceCar::InitYouCantStopSound() { // Init to TRUE so we don't play "you can't stop in the middle of the race!" before the player ever moves g_playedYouCantStopSound = TRUE; @@ -229,7 +229,7 @@ void LegoRaceCar::InitSoundIndices() void LegoRaceCar::SetWorldSpeed(MxFloat p_worldSpeed) { if (!m_userNavFlag) { - if (!LegoCarRaceActor::m_unk0x0c) { + if (!LegoCarRaceActor::m_animState) { m_maxLinearVel = p_worldSpeed; } LegoAnimActor::SetWorldSpeed(p_worldSpeed); @@ -244,7 +244,7 @@ void LegoRaceCar::SetWorldSpeed(MxFloat p_worldSpeed) void LegoRaceCar::SetMaxLinearVelocity(float p_maxLinearVelocity) { if (p_maxLinearVelocity < 0) { - LegoCarRaceActor::m_unk0x0c = 2; + LegoCarRaceActor::m_animState = 2; m_maxLinearVel = 0; SetWorldSpeed(0); } @@ -299,7 +299,7 @@ void LegoRaceCar::ParseAction(char* p_extra) // FUNCTION: LEGO1 0x10012ff0 // FUNCTION: BETA10 0x100cb60e -void LegoRaceCar::FUN_10012ff0(float p_param) +void LegoRaceCar::KickCamera(float p_param) { LegoAnimActorStruct* a; // called `a` in BETA10 float deltaTime; @@ -315,7 +315,7 @@ void LegoRaceCar::FUN_10012ff0(float p_param) assert(a && a->GetAnimTreePtr() && a->GetAnimTreePtr()->GetCamAnim()); if (a->GetAnimTreePtr()) { - deltaTime = p_param - m_unk0x58; + deltaTime = p_param - m_kickStart; if (a->GetDuration() <= deltaTime || deltaTime < 0.0) { if (m_userState == LEGORACECAR_KICK1) { @@ -390,7 +390,7 @@ MxU32 LegoRaceCar::HandleSkeletonKicks(float p_param1) return FALSE; } - m_unk0x58 = p_param1; + m_kickStart = p_param1; SoundManager()->GetCacheSoundManager()->Play(g_soundSkel3, NULL, FALSE); return TRUE; @@ -401,7 +401,7 @@ MxU32 LegoRaceCar::HandleSkeletonKicks(float p_param1) void LegoRaceCar::Animate(float p_time) { if (m_userNavFlag && (m_userState == LEGORACECAR_KICK1 || m_userState == LEGORACECAR_KICK2)) { - FUN_10012ff0(p_time); + KickCamera(p_time); return; } @@ -413,7 +413,7 @@ void LegoRaceCar::Animate(float p_time) } } - if (LegoCarRaceActor::m_unk0x0c == 1) { + if (LegoCarRaceActor::m_animState == 1) { FUN_1005d4b0(); if (!m_userNavFlag) { @@ -471,7 +471,7 @@ MxResult LegoRaceCar::HitActor(LegoPathActor* p_actor, MxBool p_bool) assert(roi); matr = roi->GetLocal2World(); - Vector3(matr[3]) += g_unk0x10102af0; + Vector3(matr[3]) += g_hitOffset; roi->SetLocal2World(matr); p_actor->SetActorState(c_two); @@ -516,7 +516,7 @@ MxResult LegoRaceCar::HitActor(LegoPathActor* p_actor, MxBool p_bool) if (soundKey) { SoundManager()->GetCacheSoundManager()->Play(soundKey, NULL, FALSE); - g_timeLastRaceCarSoundPlayed = g_unk0x100f3308 = time; + g_timeLastRaceCarSoundPlayed = g_timeLastHitSoundPlayed = time; } } @@ -582,7 +582,7 @@ void LegoJetski::InitSoundIndices() void LegoJetski::SetWorldSpeed(MxFloat p_worldSpeed) { if (!m_userNavFlag) { - if (!LegoCarRaceActor::m_unk0x0c) { + if (!LegoCarRaceActor::m_animState) { m_maxLinearVel = p_worldSpeed; } LegoAnimActor::SetWorldSpeed(p_worldSpeed); @@ -597,7 +597,7 @@ void LegoJetski::SetWorldSpeed(MxFloat p_worldSpeed) void LegoJetski::FUN_100136f0(float p_worldSpeed) { if (p_worldSpeed < 0) { - LegoCarRaceActor::m_unk0x0c = 2; + LegoCarRaceActor::m_animState = 2; m_maxLinearVel = 0; SetWorldSpeed(0); } @@ -612,7 +612,7 @@ void LegoJetski::Animate(float p_time) { LegoJetskiRaceActor::Animate(p_time); - if (LegoCarRaceActor::m_unk0x0c == 1) { + if (LegoCarRaceActor::m_animState == 1) { FUN_1005d4b0(); if (!m_userNavFlag) { @@ -685,7 +685,7 @@ MxResult LegoJetski::HitActor(LegoPathActor* p_actor, MxBool p_bool) LegoROI* roi = p_actor->GetROI(); matr = roi->GetLocal2World(); - Vector3(matr[3]) += g_unk0x10102af0; + Vector3(matr[3]) += g_hitOffset; roi->SetLocal2World(matr); p_actor->SetActorState(c_two); @@ -714,7 +714,7 @@ MxResult LegoJetski::HitActor(LegoPathActor* p_actor, MxBool p_bool) if (soundKey) { SoundManager()->GetCacheSoundManager()->Play(soundKey, NULL, FALSE); - g_timeLastJetskiSoundPlayed = g_unk0x100f3308 = time; + g_timeLastJetskiSoundPlayed = g_timeLastHitSoundPlayed = time; } } diff --git a/LEGO1/lego/legoomni/src/race/legoracespecial.cpp b/LEGO1/lego/legoomni/src/race/legoracespecial.cpp index 935c3406..7fe58c71 100644 --- a/LEGO1/lego/legoomni/src/race/legoracespecial.cpp +++ b/LEGO1/lego/legoomni/src/race/legoracespecial.cpp @@ -45,7 +45,7 @@ LegoCarRaceActor::LegoCarRaceActor() { m_unk0x08 = 1.0f; m_unk0x70 = 0.0f; - m_unk0x0c = 0; + m_animState = 0; m_maxLinearVel = 0.0f; m_frequencyFactor = 1.0f; m_unk0x1c = 0; @@ -224,18 +224,18 @@ void LegoCarRaceActor::SwitchBoundary(LegoPathBoundary*& p_boundary, LegoOriente // FUNCTION: BETA10 0x100cdbae void LegoCarRaceActor::Animate(float p_time) { - // m_unk0x0c is not an MxBool, there are places where it is set to 2 or higher - if (m_unk0x0c == 0) { + // m_animState is not an MxBool, there are places where it is set to 2 or higher + if (m_animState == 0) { const char* value = VariableTable()->GetVariable(g_raceState); if (SDL_strcasecmp(value, g_racing) == 0) { - m_unk0x0c = 1; + m_animState = 1; m_lastTime = p_time - 1.0f; m_unk0x1c = p_time; } } - if (m_unk0x0c == 1) { + if (m_animState == 1) { LegoAnimActor::Animate(p_time); } } @@ -399,10 +399,10 @@ MxS32 LegoJetskiRaceActor::VTable0x1c(LegoPathBoundary* p_boundary, LegoEdge* p_ // FUNCTION: LEGO1 0x10081550 void LegoJetskiRaceActor::Animate(float p_time) { - if (m_unk0x0c == 0) { + if (m_animState == 0) { const LegoChar* raceState = VariableTable()->GetVariable(g_raceState); if (!SDL_strcasecmp(raceState, g_racing)) { - m_unk0x0c = 1; + m_animState = 1; m_lastTime = p_time - 1.0f; m_unk0x1c = p_time; } @@ -411,7 +411,7 @@ void LegoJetskiRaceActor::Animate(float p_time) } } - if (m_unk0x0c == 1) { + if (m_animState == 1) { LegoAnimActor::Animate(p_time); } } diff --git a/LEGO1/lego/legoomni/src/video/legoanimpresenter.cpp b/LEGO1/lego/legoomni/src/video/legoanimpresenter.cpp index 28642bab..c49b766e 100644 --- a/LEGO1/lego/legoomni/src/video/legoanimpresenter.cpp +++ b/LEGO1/lego/legoomni/src/video/legoanimpresenter.cpp @@ -793,7 +793,7 @@ void LegoAnimPresenter::StartingTickle() } FUN_10069b10(); - FUN_1006c8a0(TRUE); + SetDisabled(TRUE); if (m_unk0x78 == NULL) { if (fabs(m_action->GetDirection()[0]) >= 0.00000047683716F || @@ -1093,7 +1093,7 @@ void LegoAnimPresenter::EndAction() } } - FUN_1006c8a0(FALSE); + SetDisabled(FALSE); FUN_1006ab70(); VTable0x90(); @@ -1154,18 +1154,18 @@ void LegoAnimPresenter::VTable0x90() } // FUNCTION: LEGO1 0x1006c8a0 -void LegoAnimPresenter::FUN_1006c8a0(MxBool p_bool) +void LegoAnimPresenter::SetDisabled(MxBool p_disabled) { if (m_roiMapSize != 0 && m_roiMap != NULL) { for (MxU32 i = 1; i <= m_roiMapSize; i++) { LegoEntity* entity = m_roiMap[i]->GetEntity(); if (entity != NULL) { - if (p_bool) { - entity->SetUnknown0x10Flag(LegoEntity::c_altBit1); + if (p_disabled) { + entity->SetInteractionFlag(LegoEntity::c_disabled); } else { - entity->ClearUnknown0x10Flag(LegoEntity::c_altBit1); + entity->ClearInteractionFlag(LegoEntity::c_disabled); } } } diff --git a/LEGO1/lego/legoomni/src/worlds/hospital.cpp b/LEGO1/lego/legoomni/src/worlds/hospital.cpp index 66d22168..4a8fa8ac 100644 --- a/LEGO1/lego/legoomni/src/worlds/hospital.cpp +++ b/LEGO1/lego/legoomni/src/worlds/hospital.cpp @@ -48,7 +48,7 @@ Hospital::Hospital() m_flashingLeds = 0; m_copLedAnimTimer = 0; m_pizzaLedAnimTimer = 0; - m_unk0x128 = 0; + m_exited = FALSE; NotificationManager()->Register(this); } @@ -369,8 +369,8 @@ MxLong Hospital::HandleEndAction(MxEndActionNotificationParam& p_param) act1State = (Act1State*) GameState()->GetState("Act1State"); act1State->SetUnknown18(9); case HospitalState::e_exitToFront: - if (m_unk0x128 == 0) { - m_unk0x128 = 1; + if (m_exited == FALSE) { + m_exited = TRUE; m_destLocation = LegoGameState::e_hospitalExited; DeleteObjects(&m_atomId, HospitalScript::c_hho002cl_RunAnim, HospitalScript::c_hho006cl_RunAnim); @@ -378,8 +378,8 @@ MxLong Hospital::HandleEndAction(MxEndActionNotificationParam& p_param) } break; case HospitalState::e_exitToInfocenter: - if (m_unk0x128 == 0) { - m_unk0x128 = 1; + if (m_exited == FALSE) { + m_exited = TRUE; m_destLocation = LegoGameState::e_infomain; DeleteObjects(&m_atomId, HospitalScript::c_hho002cl_RunAnim, HospitalScript::c_hho006cl_RunAnim); @@ -412,8 +412,8 @@ MxLong Hospital::HandleButtonDown(LegoControlManagerNotificationParam& p_param) m_interactionMode = 3; if (m_hospitalState->m_state == HospitalState::e_explainQuestShort) { - if (m_unk0x128 == 0) { - m_unk0x128 = 1; + if (m_exited == FALSE) { + m_exited = TRUE; TickleManager()->UnregisterClient(this); @@ -568,8 +568,8 @@ MxBool Hospital::HandleControl(LegoControlManagerNotificationParam& p_param) m_currentAction = HospitalScript::c_hho016cl_RunAnim; m_setWithCurrentAction = 1; } - else if (m_unk0x128 == 0) { - m_unk0x128 = 1; + else if (m_exited == FALSE) { + m_exited = TRUE; m_hospitalState->m_state = HospitalState::e_exitImmediately; m_destLocation = LegoGameState::e_infomain; @@ -589,8 +589,8 @@ MxBool Hospital::HandleControl(LegoControlManagerNotificationParam& p_param) m_currentAction = HospitalScript::c_hho016cl_RunAnim; m_setWithCurrentAction = 1; } - else if (m_unk0x128 == 0) { - m_unk0x128 = 1; + else if (m_exited == FALSE) { + m_exited = TRUE; m_hospitalState->m_state = HospitalState::e_exitImmediately; m_destLocation = LegoGameState::e_hospitalExited; diff --git a/LEGO1/lego/legoomni/src/worlds/infocenter.cpp b/LEGO1/lego/legoomni/src/worlds/infocenter.cpp index f9bfb4eb..c007dc96 100644 --- a/LEGO1/lego/legoomni/src/worlds/infocenter.cpp +++ b/LEGO1/lego/legoomni/src/worlds/infocenter.cpp @@ -306,29 +306,32 @@ MxLong Infocenter::HandleEndAction(MxEndActionNotificationParam& p_param) if (!m_unk0x1d4) { PlayMusic(JukeboxScript::c_InformationCenter_Music); - GameState()->SetActor(m_selectedCharacter); - switch (m_selectedCharacter) { - case e_pepper: - PlayAction(InfomainScript::c_avo901in_RunAnim); - break; - case e_mama: - PlayAction(InfomainScript::c_avo902in_RunAnim); - break; - case e_papa: - PlayAction(InfomainScript::c_avo903in_RunAnim); - break; - case e_nick: - PlayAction(InfomainScript::c_avo904in_RunAnim); - break; - case e_laura: - PlayAction(InfomainScript::c_avo905in_RunAnim); - break; - default: - break; + if (!Lego()->IsVersion10()) { + GameState()->SetActor(m_selectedCharacter); + + switch (m_selectedCharacter) { + case e_pepper: + PlayAction(InfomainScript::c_avo901in_RunAnim); + break; + case e_mama: + PlayAction(InfomainScript::c_avo902in_RunAnim); + break; + case e_papa: + PlayAction(InfomainScript::c_avo903in_RunAnim); + break; + case e_nick: + PlayAction(InfomainScript::c_avo904in_RunAnim); + break; + case e_laura: + PlayAction(InfomainScript::c_avo905in_RunAnim); + break; + default: + break; + } + + UpdateFrameHot(TRUE); } - - UpdateFrameHot(TRUE); } } @@ -338,7 +341,7 @@ MxLong Infocenter::HandleEndAction(MxEndActionNotificationParam& p_param) return result; } - if (action->GetObjectId() == InfomainScript::c_iicx26in_RunAnim) { + if (action->GetObjectId() == InfomainScript::c_iicx26in_RunAnim - Lego()->IsVersion10()) { ControlManager()->FUN_100293c0(InfomainScript::c_BigInfo_Ctl, action->GetAtomId().GetInternal(), 0); m_unk0x1d6 = 0; } @@ -478,7 +481,7 @@ void Infocenter::ReadyWorld() InfomainScript::Script script = m_infocenterState->GetNextReturnDialogue(); PlayAction(script); - if (script == InfomainScript::c_iicx26in_RunAnim) { + if (script == InfomainScript::c_iicx26in_RunAnim - Lego()->IsVersion10()) { m_unk0x1d6 = 1; } @@ -1186,13 +1189,13 @@ MxLong Infocenter::HandleNotification0(MxNotificationParam& p_param) m_currentInfomainScript == InfomainScript::c_Pepper_All_Movie || m_currentInfomainScript == InfomainScript::c_Nick_All_Movie || m_currentInfomainScript == InfomainScript::c_Laura_All_Movie || - m_currentInfomainScript == InfomainScript::c_iic007ra_PlayWav || - m_currentInfomainScript == InfomainScript::c_ijs002ra_PlayWav || - m_currentInfomainScript == InfomainScript::c_irt001ra_PlayWav || - m_currentInfomainScript == InfomainScript::c_ipz006ra_PlayWav || - m_currentInfomainScript == InfomainScript::c_igs004ra_PlayWav || - m_currentInfomainScript == InfomainScript::c_iho003ra_PlayWav || - m_currentInfomainScript == InfomainScript::c_ips005ra_PlayWav) { + m_currentInfomainScript == InfomainScript::c_iic007ra_PlayWav - Lego()->IsVersion10() || + m_currentInfomainScript == InfomainScript::c_ijs002ra_PlayWav - Lego()->IsVersion10() || + m_currentInfomainScript == InfomainScript::c_irt001ra_PlayWav - Lego()->IsVersion10() || + m_currentInfomainScript == InfomainScript::c_ipz006ra_PlayWav - Lego()->IsVersion10() || + m_currentInfomainScript == InfomainScript::c_igs004ra_PlayWav - Lego()->IsVersion10() || + m_currentInfomainScript == InfomainScript::c_iho003ra_PlayWav - Lego()->IsVersion10() || + m_currentInfomainScript == InfomainScript::c_ips005ra_PlayWav - Lego()->IsVersion10()) { StopCurrentAction(); } } @@ -1506,6 +1509,17 @@ void Infocenter::StopCredits() // FUNCTION: BETA10 0x1002ee8c void Infocenter::PlayAction(InfomainScript::Script p_script) { + if (Lego()->IsVersion10()) { + if (p_script == InfomainScript::c_iicx18in_RunAnim) { + // Alternative dialogue after signing in (1.0 version) + p_script = InfomainScript::c_iic016in_RunAnim; + } + else if (p_script > InfomainScript::c_iicx18in_RunAnim) { + // Shift all other actions by 1 + p_script = (InfomainScript::Script)((int) p_script - 1); + } + } + MxDSAction action; action.SetObjectId(p_script); action.SetAtomId(*g_infomainScript); diff --git a/LEGO1/lego/legoomni/src/worlds/isle.cpp b/LEGO1/lego/legoomni/src/worlds/isle.cpp index 4d2c5b29..8c35e1f1 100644 --- a/LEGO1/lego/legoomni/src/worlds/isle.cpp +++ b/LEGO1/lego/legoomni/src/worlds/isle.cpp @@ -810,7 +810,7 @@ void Isle::Enable(MxBool p_enable) AnimationManager()->EnableCamAnims(FALSE); g_isleFlags &= ~c_playMusic; - m_ambulance->FUN_10036e60(); + m_ambulance->Init(); break; case 11: m_act1state->m_unk0x018 = 0; @@ -1209,7 +1209,7 @@ MxBool Isle::Escape() case 10: if (UserActor() != NULL && !UserActor()->IsA("Ambulance")) { m_ambulance->StopActions(); - m_ambulance->FUN_10037250(); + m_ambulance->Reset(); } break; } @@ -1250,7 +1250,7 @@ void Isle::FUN_10033350() if (m_act1state->m_unk0x018 == 10) { if (UserActor() != NULL && !UserActor()->IsA("Ambulance")) { m_ambulance->StopActions(); - m_ambulance->FUN_10037250(); + m_ambulance->Reset(); } } diff --git a/LEGO1/lego/legoomni/src/worlds/score.cpp b/LEGO1/lego/legoomni/src/worlds/score.cpp index ebeca836..69b4305a 100644 --- a/LEGO1/lego/legoomni/src/worlds/score.cpp +++ b/LEGO1/lego/legoomni/src/worlds/score.cpp @@ -254,7 +254,7 @@ void Score::Paint() memset(&desc, 0, sizeof(desc)); desc.dwSize = sizeof(desc); - HRESULT result = cube->m_surface->Lock(NULL, &desc, DDLOCK_SURFACEMEMORYPTR, NULL); + HRESULT result = cube->m_surface->Lock(NULL, &desc, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WRITEONLY, NULL); if (result == DD_OK) { if (desc.lPitch != desc.dwWidth) { cube->m_surface->Unlock(desc.lpSurface); diff --git a/LEGO1/lego/sources/3dmanager/lego3dview.cpp b/LEGO1/lego/sources/3dmanager/lego3dview.cpp index 0a4779a4..1cc272e1 100644 --- a/LEGO1/lego/sources/3dmanager/lego3dview.cpp +++ b/LEGO1/lego/sources/3dmanager/lego3dview.cpp @@ -154,7 +154,7 @@ double Lego3DView::Render(double p_und) } // FUNCTION: LEGO1 0x100ab2b0 -ViewROI* Lego3DView::Pick(unsigned int x, unsigned int y) +ViewROI* Lego3DView::Pick(int x, int y) { return m_pViewManager->Pick(GetView(), x, y); } diff --git a/LEGO1/lego/sources/3dmanager/lego3dview.h b/LEGO1/lego/sources/3dmanager/lego3dview.h index baec8f43..4441b85e 100644 --- a/LEGO1/lego/sources/3dmanager/lego3dview.h +++ b/LEGO1/lego/sources/3dmanager/lego3dview.h @@ -27,7 +27,7 @@ class Lego3DView : public LegoView1 { double Render(double p_und); - ViewROI* Pick(unsigned int x, unsigned int y); + ViewROI* Pick(int x, int y); ViewROI* GetPointOfView(); ViewManager* GetViewManager(); diff --git a/LEGO1/lego/sources/misc/legocontainer.cpp b/LEGO1/lego/sources/misc/legocontainer.cpp index 6928a5c3..98836d6a 100644 --- a/LEGO1/lego/sources/misc/legocontainer.cpp +++ b/LEGO1/lego/sources/misc/legocontainer.cpp @@ -22,7 +22,7 @@ LegoTextureInfo* LegoTextureContainer::GetCached(LegoTextureInfo* p_textureInfo) memset(&desc, 0, sizeof(desc)); desc.dwSize = sizeof(desc); - if (p_textureInfo->m_surface->Lock(NULL, &desc, DDLOCK_SURFACEMEMORYPTR, NULL) == DD_OK) { + if (p_textureInfo->m_surface->Lock(NULL, &desc, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WRITEONLY, NULL) == DD_OK) { width = desc.dwWidth; height = desc.dwHeight; p_textureInfo->m_surface->Unlock(desc.lpSurface); @@ -35,7 +35,7 @@ LegoTextureInfo* LegoTextureContainer::GetCached(LegoTextureInfo* p_textureInfo) memset(&newDesc, 0, sizeof(newDesc)); newDesc.dwSize = sizeof(newDesc); - if (surface->Lock(NULL, &newDesc, DDLOCK_SURFACEMEMORYPTR, NULL) == DD_OK) { + if (surface->Lock(NULL, &newDesc, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WRITEONLY, NULL) == DD_OK) { BOOL und = FALSE; if (newDesc.dwWidth == width && newDesc.dwHeight == height) { und = TRUE; diff --git a/LEGO1/lego/sources/roi/legolod.cpp b/LEGO1/lego/sources/roi/legolod.cpp index 2e0df088..94eef6ff 100644 --- a/LEGO1/lego/sources/roi/legolod.cpp +++ b/LEGO1/lego/sources/roi/legolod.cpp @@ -353,7 +353,7 @@ LegoResult LegoLOD::SetTextureInfo(LegoTextureInfo* p_textureInfo) } // FUNCTION: LEGO1 0x100aad70 -LegoResult LegoLOD::FUN_100aad70(LegoTextureInfo* p_textureInfo) +LegoResult LegoLOD::UpdateTextureInfo(LegoTextureInfo* p_textureInfo) { for (LegoU32 i = m_meshOffset; i < m_numMeshes; i++) { if (m_melems[i].m_textured) { diff --git a/LEGO1/lego/sources/roi/legolod.h b/LEGO1/lego/sources/roi/legolod.h index 114e377b..e787d377 100644 --- a/LEGO1/lego/sources/roi/legolod.h +++ b/LEGO1/lego/sources/roi/legolod.h @@ -31,7 +31,7 @@ class LegoLOD : public ViewLOD { LegoLOD* Clone(Tgl::Renderer* p_renderer); LegoResult SetColor(LegoFloat p_red, LegoFloat p_green, LegoFloat p_blue, LegoFloat p_alpha); LegoResult SetTextureInfo(LegoTextureInfo* p_textureInfo); - LegoResult FUN_100aad70(LegoTextureInfo* p_textureInfo); + LegoResult UpdateTextureInfo(LegoTextureInfo* p_textureInfo); void ClearMeshOffset(); LegoResult GetTextureInfo(LegoTextureInfo*& p_textureInfo); diff --git a/LEGO1/mxdirectx/mxdirect3d.cpp b/LEGO1/mxdirectx/mxdirect3d.cpp index 9ce37cf5..d6043a2c 100644 --- a/LEGO1/mxdirectx/mxdirect3d.cpp +++ b/LEGO1/mxdirectx/mxdirect3d.cpp @@ -174,7 +174,7 @@ BOOL MxDirect3D::D3DSetMode() memset(&desc, 0, sizeof(desc)); desc.dwSize = sizeof(desc); - if (backBuffer->Lock(NULL, &desc, DDLOCK_WAIT, NULL) == DD_OK) { + if (backBuffer->Lock(NULL, &desc, DDLOCK_WAIT | DDLOCK_WRITEONLY, NULL) == DD_OK) { unsigned char* surface = (unsigned char*) desc.lpSurface; for (int i = 0; i < mode.height; i++) { @@ -192,7 +192,7 @@ BOOL MxDirect3D::D3DSetMode() memset(&desc, 0, sizeof(desc)); desc.dwSize = sizeof(desc); - if (frontBuffer->Lock(NULL, &desc, DDLOCK_WAIT, NULL) == DD_OK) { + if (frontBuffer->Lock(NULL, &desc, DDLOCK_WAIT | DDLOCK_WRITEONLY, NULL) == DD_OK) { unsigned char* surface = (unsigned char*) desc.lpSurface; for (int i = 0; i < mode.height; i++) { diff --git a/LEGO1/mxdirectx/mxdirectdraw.cpp b/LEGO1/mxdirectx/mxdirectdraw.cpp index 6f3dfd78..104b6836 100644 --- a/LEGO1/mxdirectx/mxdirectdraw.cpp +++ b/LEGO1/mxdirectx/mxdirectdraw.cpp @@ -539,10 +539,10 @@ void MxDirectDraw::ClearBackBuffers() memset(&ddsd, 0, sizeof(ddsd)); ddsd.dwSize = sizeof(ddsd); - result = m_pBackBuffer->Lock(NULL, &ddsd, DDLOCK_WAIT, NULL); + result = m_pBackBuffer->Lock(NULL, &ddsd, DDLOCK_WAIT | DDLOCK_WRITEONLY, NULL); if (result == DDERR_SURFACELOST) { m_pBackBuffer->Restore(); - result = m_pBackBuffer->Lock(NULL, &ddsd, DDLOCK_WAIT, NULL); + result = m_pBackBuffer->Lock(NULL, &ddsd, DDLOCK_WAIT | DDLOCK_WRITEONLY, NULL); } if (result != DD_OK) { diff --git a/LEGO1/omni/include/mxstring.h b/LEGO1/omni/include/mxstring.h index eaa58181..b4b25262 100644 --- a/LEGO1/omni/include/mxstring.h +++ b/LEGO1/omni/include/mxstring.h @@ -20,10 +20,10 @@ class MxString : public MxCore { void ToLowerCase(); void MapPathToFilesystem() { MapPathToFilesystem(m_data); } - MxString& operator=(const MxString& p_str); - const MxString& operator=(const char* p_str); - MxString operator+(const MxString& p_str) const; - MxString operator+(const char* p_str) const; + LEGO1_EXPORT MxString& operator=(const MxString& p_str); + LEGO1_EXPORT const MxString& operator=(const char* p_str); + LEGO1_EXPORT MxString operator+(const MxString& p_str) const; + LEGO1_EXPORT MxString operator+(const char* p_str) const; LEGO1_EXPORT MxString& operator+=(const char* p_str); static void CharSwap(char* p_a, char* p_b); diff --git a/LEGO1/omni/src/audio/mxsoundmanager.cpp b/LEGO1/omni/src/audio/mxsoundmanager.cpp index afb9b21e..f865ebf0 100644 --- a/LEGO1/omni/src/audio/mxsoundmanager.cpp +++ b/LEGO1/omni/src/audio/mxsoundmanager.cpp @@ -9,6 +9,8 @@ #include "mxticklethread.h" #include "mxwavepresenter.h" +#include + DECOMP_SIZE_ASSERT(MxSoundManager, 0x3c); // GLOBAL LEGO1 0x10101420 @@ -98,12 +100,17 @@ MxResult MxSoundManager::Create(MxU32 p_frequencyMS, MxBool p_createThread) spec.format = SDL_AUDIO_F32; spec.channels = ma_engine_get_channels(m_engine); - if ((m_stream = SDL_OpenAudioDeviceStream(SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK, &spec, &AudioStreamCallback, this)) == + if ((m_stream = SDL_OpenAudioDeviceStream(SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK, &spec, &AudioStreamCallback, this)) != NULL) { - goto done; + SDL_ResumeAudioDevice(SDL_GetAudioStreamDevice(m_stream)); + } + else { + SDL_LogError( + SDL_LOG_CATEGORY_APPLICATION, + "Failed to open default audio device for playback: %s", + SDL_GetError() + ); } - - SDL_ResumeAudioDevice(SDL_GetAudioStreamDevice(m_stream)); if (p_createThread) { m_thread = new MxTickleThread(this, p_frequencyMS); diff --git a/LEGO1/omni/src/video/mxdisplaysurface.cpp b/LEGO1/omni/src/video/mxdisplaysurface.cpp index 9b7d321e..6c93a0e7 100644 --- a/LEGO1/omni/src/video/mxdisplaysurface.cpp +++ b/LEGO1/omni/src/video/mxdisplaysurface.cpp @@ -402,10 +402,10 @@ void MxDisplaySurface::VTable0x28( memset(&ddsd, 0, sizeof(ddsd)); ddsd.dwSize = sizeof(ddsd); - HRESULT hr = m_ddSurface2->Lock(NULL, &ddsd, DDLOCK_WAIT, NULL); + HRESULT hr = m_ddSurface2->Lock(NULL, &ddsd, DDLOCK_WAIT | DDLOCK_WRITEONLY, NULL); if (hr == DDERR_SURFACELOST) { m_ddSurface2->Restore(); - hr = m_ddSurface2->Lock(NULL, &ddsd, DDLOCK_WAIT, NULL); + hr = m_ddSurface2->Lock(NULL, &ddsd, DDLOCK_WAIT | DDLOCK_WRITEONLY, NULL); } if (hr != DD_OK) { @@ -514,10 +514,10 @@ void MxDisplaySurface::VTable0x30( memset(&ddsd, 0, sizeof(ddsd)); ddsd.dwSize = sizeof(ddsd); - HRESULT hr = m_ddSurface2->Lock(NULL, &ddsd, DDLOCK_WAIT, NULL); + HRESULT hr = m_ddSurface2->Lock(NULL, &ddsd, DDLOCK_WAIT | DDLOCK_WRITEONLY, NULL); if (hr == DDERR_SURFACELOST) { m_ddSurface2->Restore(); - hr = m_ddSurface2->Lock(NULL, &ddsd, DDLOCK_WAIT, NULL); + hr = m_ddSurface2->Lock(NULL, &ddsd, DDLOCK_WAIT | DDLOCK_WRITEONLY, NULL); } if (hr != DD_OK) { @@ -726,11 +726,11 @@ void MxDisplaySurface::VTable0x34(MxU8* p_pixels, MxS32 p_bpp, MxS32 p_width, Mx memset(&surfaceDesc, 0, sizeof(surfaceDesc)); surfaceDesc.dwSize = sizeof(surfaceDesc); - HRESULT result = m_ddSurface2->Lock(NULL, &surfaceDesc, DDLOCK_WAIT, NULL); + HRESULT result = m_ddSurface2->Lock(NULL, &surfaceDesc, DDLOCK_WAIT | DDLOCK_WRITEONLY, NULL); if (result == DDERR_SURFACELOST) { m_ddSurface2->Restore(); - result = m_ddSurface2->Lock(NULL, &surfaceDesc, DDLOCK_WAIT, NULL); + result = m_ddSurface2->Lock(NULL, &surfaceDesc, DDLOCK_WAIT | DDLOCK_WRITEONLY, NULL); } if (result == DD_OK) { @@ -784,7 +784,7 @@ void MxDisplaySurface::Display(MxS32 p_left, MxS32 p_top, MxS32 p_left2, MxS32 p DDSURFACEDESC ddsd; memset(&ddsd, 0, sizeof(ddsd)); ddsd.dwSize = sizeof(ddsd); - if (m_ddSurface2->Lock(NULL, &ddsd, DDLOCK_WAIT, NULL) == DD_OK) { + if (m_ddSurface2->Lock(NULL, &ddsd, DDLOCK_WAIT | DDLOCK_WRITEONLY, NULL) == DD_OK) { MxU8* surface = (MxU8*) ddsd.lpSurface; MxS32 height = m_videoParam.GetRect().GetHeight(); @@ -891,7 +891,7 @@ LPDIRECTDRAWSURFACE MxDisplaySurface::VTable0x44( memset(&ddsd, 0, sizeof(ddsd)); ddsd.dwSize = sizeof(ddsd); - if (surface->Lock(NULL, &ddsd, DDLOCK_WAIT, 0) != DD_OK) { + if (surface->Lock(NULL, &ddsd, DDLOCK_WAIT | DDLOCK_WRITEONLY, 0) != DD_OK) { surface->Release(); surface = NULL; } @@ -1067,7 +1067,7 @@ LPDIRECTDRAWSURFACE MxDisplaySurface::CreateCursorSurface() memset(&ddsd, 0, sizeof(ddsd)); ddsd.dwSize = sizeof(ddsd); - if (newSurface->Lock(NULL, &ddsd, DDLOCK_WAIT, NULL) != DD_OK) { + if (newSurface->Lock(NULL, &ddsd, DDLOCK_WAIT | DDLOCK_WRITEONLY, NULL) != DD_OK) { goto done; } else { diff --git a/LEGO1/tgl/d3drm/impl.h b/LEGO1/tgl/d3drm/impl.h index 5dccba8b..4c834521 100644 --- a/LEGO1/tgl/d3drm/impl.h +++ b/LEGO1/tgl/d3drm/impl.h @@ -252,8 +252,8 @@ class ViewImpl : public View { Result TransformWorldToScreen(const float world[3], float screen[4]) override; Result TransformScreenToWorld(const float screen[4], float world[3]) override; Result Pick( - unsigned int x, - unsigned int y, + int x, + int y, const Group** ppGroupsToPickFrom, int groupsToPickFromCount, const Group**& rppPickedGroups, @@ -277,8 +277,8 @@ class ViewImpl : public View { Result SetCamera(const CameraImpl& rCamera); Result Render(const GroupImpl& rScene); Result Pick( - unsigned int x, - unsigned int y, + int x, + int y, const GroupImpl** ppGroupsToPickFrom, int groupsToPickFromCount, const Group**& rppPickedGroups, diff --git a/LEGO1/tgl/d3drm/view.cpp b/LEGO1/tgl/d3drm/view.cpp index 4a000178..92e5e107 100644 --- a/LEGO1/tgl/d3drm/view.cpp +++ b/LEGO1/tgl/d3drm/view.cpp @@ -495,8 +495,8 @@ Result ViewImpl::ForceUpdate(unsigned int x, unsigned int y, unsigned int width, // FUNCTION: BETA10 0x101710f0 inline Result ViewImpl::Pick( - unsigned int x, - unsigned int y, + int x, + int y, const GroupImpl** ppGroupsToPickFrom, int groupsToPickFromCount, const Group**& rppPickedGroups, @@ -519,8 +519,8 @@ inline Result ViewImpl::Pick( // FUNCTION: LEGO1 0x100a30c0 // FUNCTION: BETA10 0x1016ee10 Result ViewImpl::Pick( - unsigned int x, - unsigned int y, + int x, + int y, const Group** ppGroupsToPickFrom, int groupsToPickFromCount, const Group**& rppPickedGroups, diff --git a/LEGO1/tgl/tgl.h b/LEGO1/tgl/tgl.h index aabe6c96..2f8ab645 100644 --- a/LEGO1/tgl/tgl.h +++ b/LEGO1/tgl/tgl.h @@ -257,8 +257,8 @@ class View : public Object { // output parameter // size of rppPickedGroups virtual Result Pick( - unsigned int x, - unsigned int y, + int x, + int y, const Group** ppGroupsToPickFrom, int groupsToPickFromCount, const Group**& rppPickedGroups, diff --git a/LEGO1/viewmanager/viewmanager.cpp b/LEGO1/viewmanager/viewmanager.cpp index 721ec247..9ec2da58 100644 --- a/LEGO1/viewmanager/viewmanager.cpp +++ b/LEGO1/viewmanager/viewmanager.cpp @@ -499,7 +499,7 @@ float ViewManager::ProjectedSize(const BoundingSphere& p_bounding_sphere) } // FUNCTION: LEGO1 0x100a6e00 -ViewROI* ViewManager::Pick(Tgl::View* p_view, unsigned int x, unsigned int y) +ViewROI* ViewManager::Pick(Tgl::View* p_view, int x, int y) { LPDIRECT3DRMPICKEDARRAY picked = NULL; ViewROI* result = NULL; diff --git a/LEGO1/viewmanager/viewmanager.h b/LEGO1/viewmanager/viewmanager.h index 2fdb9afb..ee068658 100644 --- a/LEGO1/viewmanager/viewmanager.h +++ b/LEGO1/viewmanager/viewmanager.h @@ -33,7 +33,7 @@ class ViewManager { void RemoveROIDetailFromScene(ViewROI* p_roi); void SetPOVSource(const OrientableROI* point_of_view); float ProjectedSize(const BoundingSphere& p_bounding_sphere); - ViewROI* Pick(Tgl::View* p_view, unsigned int x, unsigned int y); + ViewROI* Pick(Tgl::View* p_view, int x, int y); void SetResolution(int width, int height); void SetFrustrum(float fov, float front, float back); inline void ManageVisibilityAndDetailRecursively(ViewROI* p_from, int p_lodLevel); diff --git a/miniwin/CMakeLists.txt b/miniwin/CMakeLists.txt index 5017f456..508e685d 100644 --- a/miniwin/CMakeLists.txt +++ b/miniwin/CMakeLists.txt @@ -27,15 +27,21 @@ add_library(miniwin STATIC EXCLUDE_FROM_ALL src/d3drm/backends/software/renderer.cpp ) +target_compile_definitions(miniwin PRIVATE + $<$:DEBUG> +) + find_package(OpenGL) -find_package(GLEW) -if(OpenGL_FOUND AND GLEW_FOUND) - message(STATUS "Found OpenGL and GLEW: enabling OpenGL 1.x renderer") - target_sources(miniwin PRIVATE src/d3drm/backends/opengl1/renderer.cpp) +if(OpenGL_FOUND) + message(STATUS "Found OpenGL: enabling OpenGL 1.x renderer") + target_sources(miniwin PRIVATE + src/d3drm/backends/opengl1/actual.cpp + src/d3drm/backends/opengl1/renderer.cpp + ) target_compile_definitions(miniwin PRIVATE USE_OPENGL1) - target_link_libraries(miniwin PRIVATE OpenGL::GL GLEW::GLEW) + target_link_libraries(miniwin PRIVATE OpenGL::GL) else() - message(STATUS "🧩 OpenGL 1.x support not enabled — needs OpenGL and GLEW") + message(STATUS "🧩 OpenGL 1.x support not enabled — needs OpenGL") endif() find_library(OPENGL_ES2_LIBRARY NAMES GLESv2) diff --git a/miniwin/include/miniwin/ddraw.h b/miniwin/include/miniwin/ddraw.h index 55a95f8f..1e3fd17f 100644 --- a/miniwin/include/miniwin/ddraw.h +++ b/miniwin/include/miniwin/ddraw.h @@ -159,12 +159,15 @@ enum class DDBltFastFlags : uint32_t { }; ENABLE_BITMASK_OPERATORS(DDBltFastFlags) -#define DDLOCK_WAIT DDLockFlags::WAIT #define DDLOCK_SURFACEMEMORYPTR DDLockFlags::SURFACEMEMORYPTR +#define DDLOCK_WAIT DDLockFlags::WAIT +#define DDLOCK_WRITEONLY DDLockFlags::WRITEONLY enum class DDLockFlags : uint32_t { - SURFACEMEMORYPTR, - WAIT, + SURFACEMEMORYPTR = 0, + WAIT = 1 << 0, + WRITEONLY = 1 << 5, }; +ENABLE_BITMASK_OPERATORS(DDLockFlags) #define DDSCL_FULLSCREEN DDSCLFlags::FULLSCREEN #define DDSCL_ALLOWREBOOT DDSCLFlags::ALLOWREBOOT diff --git a/miniwin/src/d3drm/backends/directx9/actual.cpp b/miniwin/src/d3drm/backends/directx9/actual.cpp index 30a3360c..33dc2864 100644 --- a/miniwin/src/d3drm/backends/directx9/actual.cpp +++ b/miniwin/src/d3drm/backends/directx9/actual.cpp @@ -11,19 +11,22 @@ static LPDIRECT3D9 g_d3d; static LPDIRECT3DDEVICE9 g_device; static HWND g_hwnd; -static LPDIRECT3DTEXTURE9 g_renderTargetTex; -static LPDIRECT3DSURFACE9 g_renderTargetSurf; -static LPDIRECT3DSURFACE9 g_oldRenderTarget; -static int m_width; -static int m_height; -static std::vector m_lights; -static Matrix4x4 m_projection; +static int g_width; +static int g_height; +static int g_virtualWidth; +static int g_virtualHeight; +static bool g_hasScene = false; +static std::vector g_lights; +static Matrix4x4 g_projection; +static ViewportTransform g_viewportTransform; bool Actual_Initialize(void* hwnd, int width, int height) { g_hwnd = (HWND) hwnd; - m_width = width; - m_height = height; + g_width = width; + g_height = height; + g_virtualWidth = width; + g_virtualHeight = height; g_d3d = Direct3DCreate9(D3D_SDK_VERSION); if (!g_d3d) { return false; @@ -52,45 +55,17 @@ bool Actual_Initialize(void* hwnd, int width, int height) return false; } - hr = g_device->CreateTexture( - width, - height, - 1, - D3DUSAGE_RENDERTARGET, - D3DFMT_A8R8G8B8, - D3DPOOL_DEFAULT, - &g_renderTargetTex, - nullptr - ); if (FAILED(hr)) { g_device->Release(); g_d3d->Release(); return false; } - hr = g_renderTargetTex->GetSurfaceLevel(0, &g_renderTargetSurf); - if (FAILED(hr)) { - g_renderTargetTex->Release(); - g_device->Release(); - g_d3d->Release(); - return false; - } - - g_device->SetFVF(D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_TEX1); - return true; } void Actual_Shutdown() { - if (g_renderTargetSurf) { - g_renderTargetSurf->Release(); - g_renderTargetSurf = nullptr; - } - if (g_renderTargetTex) { - g_renderTargetTex->Release(); - g_renderTargetTex = nullptr; - } if (g_device) { g_device->Release(); g_device = nullptr; @@ -103,12 +78,12 @@ void Actual_Shutdown() void Actual_PushLights(const BridgeSceneLight* lightsArray, size_t count) { - m_lights.assign(lightsArray, lightsArray + count); + g_lights.assign(lightsArray, lightsArray + count); } void Actual_SetProjection(const Matrix4x4* projection, float front, float back) { - memcpy(&m_projection, projection, sizeof(Matrix4x4)); + memcpy(&g_projection, projection, sizeof(Matrix4x4)); } IDirect3DTexture9* UploadSurfaceToD3DTexture(SDL_Surface* surface) @@ -188,18 +163,71 @@ void UploadMeshBuffers( cache.ibo->Unlock(); } -constexpr float PI = 3.14159265358979323846f; - -void SetupLights() +void Actual_Resize(int width, int height, const ViewportTransform& viewportTransform) { + g_width = width; + g_height = height; + g_viewportTransform = viewportTransform; + + D3DPRESENT_PARAMETERS pp = {}; + pp.Windowed = TRUE; + pp.SwapEffect = D3DSWAPEFFECT_DISCARD; + pp.hDeviceWindow = g_hwnd; + pp.BackBufferFormat = D3DFMT_A8R8G8B8; + pp.BackBufferWidth = width; + pp.BackBufferHeight = height; + pp.EnableAutoDepthStencil = TRUE; + pp.AutoDepthStencilFormat = D3DFMT_D24S8; + g_device->Reset(&pp); +} + +void StartScene() +{ + if (g_hasScene) { + return; + } + g_device->BeginScene(); + g_hasScene = true; +} + +void Actual_Clear(float r, float g, float b) +{ + StartScene(); + + g_device->Clear( + 0, + nullptr, + D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, + D3DCOLOR_ARGB(255, static_cast(r * 255), static_cast(g * 255), static_cast(b * 255)), + 1.0f, + 0 + ); +} + +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif + +uint32_t Actual_BeginFrame() +{ + StartScene(); + g_device->SetRenderState(D3DRS_LIGHTING, TRUE); + g_device->SetRenderState(D3DRS_ZENABLE, D3DZB_TRUE); + g_device->SetRenderState(D3DRS_ZWRITEENABLE, TRUE); + g_device->SetRenderState(D3DRS_ZFUNC, D3DCMP_LESSEQUAL); + + g_device->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); + g_device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); + g_device->SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_NONE); + for (DWORD i = 0; i < 8; ++i) { g_device->LightEnable(i, FALSE); } DWORD lightIdx = 0; - for (const auto& l : m_lights) { + for (const auto& l : g_lights) { if (lightIdx >= 8) { break; } @@ -235,30 +263,16 @@ void SetupLights() } light.Falloff = 1.0f; - light.Phi = PI; - light.Theta = PI / 2; + light.Phi = M_PI; + light.Theta = M_PI / 2; if (SUCCEEDED(g_device->SetLight(lightIdx, &light))) { g_device->LightEnable(lightIdx, TRUE); } ++lightIdx; } -} -uint32_t Actual_BeginFrame() -{ - g_device->GetRenderTarget(0, &g_oldRenderTarget); - g_device->SetRenderTarget(0, g_renderTargetSurf); - - g_device->Clear(0, nullptr, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_ARGB(0, 0, 0, 0), 1.0f, 0); - - g_device->SetRenderState(D3DRS_ZENABLE, D3DZB_TRUE); - g_device->SetRenderState(D3DRS_ZWRITEENABLE, TRUE); - g_device->SetRenderState(D3DRS_ZFUNC, D3DCMP_LESSEQUAL); - - g_device->BeginScene(); - - SetupLights(); + g_device->SetFVF(D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_TEX1); return D3D_OK; } @@ -286,15 +300,19 @@ D3DMATRIX ToD3DMATRIX(const Matrix4x4& in) void Actual_SubmitDraw( const D3D9MeshCacheEntry* mesh, const Matrix4x4* modelViewMatrix, + const Matrix4x4* worldMatrix, + const Matrix4x4* viewMatrix, const Matrix3x3* normalMatrix, const Appearance* appearance, IDirect3DTexture9* texture ) { - D3DMATRIX worldView = ToD3DMATRIX(*modelViewMatrix); - g_device->SetTransform(D3DTS_WORLD, &worldView); - D3DMATRIX proj = ToD3DMATRIX(m_projection); + D3DMATRIX proj = ToD3DMATRIX(g_projection); g_device->SetTransform(D3DTS_PROJECTION, &proj); + D3DMATRIX view = ToD3DMATRIX(*viewMatrix); + g_device->SetTransform(D3DTS_VIEW, &view); + D3DMATRIX world = ToD3DMATRIX(*worldMatrix); + g_device->SetTransform(D3DTS_WORLD, &world); D3DMATERIAL9 mat = {}; mat.Diffuse.r = appearance->color.r / 255.0f; @@ -342,44 +360,149 @@ void Actual_SubmitDraw( g_device->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, 0, 0, mesh->vertexCount, 0, mesh->indexCount / 3); } -uint32_t Actual_FinalizeFrame(void* pixels, int pitch) +uint32_t Actual_Flip() { g_device->EndScene(); - - g_device->SetRenderTarget(0, g_oldRenderTarget); - g_oldRenderTarget->Release(); - - LPDIRECT3DSURFACE9 sysMemSurf; - HRESULT hr = - g_device - ->CreateOffscreenPlainSurface(m_width, m_height, D3DFMT_A8R8G8B8, D3DPOOL_SYSTEMMEM, &sysMemSurf, nullptr); - if (FAILED(hr)) { - return hr; - } - - hr = g_device->GetRenderTargetData(g_renderTargetSurf, sysMemSurf); - if (FAILED(hr)) { - sysMemSurf->Release(); - return hr; - } - - D3DLOCKED_RECT lockedRect; - hr = sysMemSurf->LockRect(&lockedRect, nullptr, D3DLOCK_READONLY); - if (FAILED(hr)) { - sysMemSurf->Release(); - return hr; - } - - BYTE* src = static_cast(lockedRect.pBits); - BYTE* dst = static_cast(pixels); - int copyWidth = m_width * 4; - - for (int y = 0; y < m_height; y++) { - memcpy(dst + y * pitch, src + y * lockedRect.Pitch, copyWidth); - } - - sysMemSurf->UnlockRect(); - sysMemSurf->Release(); - - return hr; + g_hasScene = false; + return g_device->Present(nullptr, nullptr, nullptr, nullptr); +} + +void Actual_Draw2DImage(IDirect3DTexture9* texture, const SDL_Rect& srcRect, const SDL_Rect& dstRect) +{ + StartScene(); + + float left = -g_viewportTransform.offsetX / g_viewportTransform.scale; + float right = (g_width - g_viewportTransform.offsetX) / g_viewportTransform.scale; + float top = -g_viewportTransform.offsetY / g_viewportTransform.scale; + float bottom = (g_height - g_viewportTransform.offsetY) / g_viewportTransform.scale; + + auto virtualToScreenX = [&](float x) { return ((x - left) / (right - left)) * g_width; }; + auto virtualToScreenY = [&](float y) { return ((y - top) / (bottom - top)) * g_height; }; + + float x1_virtual = static_cast(dstRect.x); + float y1_virtual = static_cast(dstRect.y); + float x2_virtual = x1_virtual + dstRect.w; + float y2_virtual = y1_virtual + dstRect.h; + + float x1 = virtualToScreenX(x1_virtual); + float y1 = virtualToScreenY(y1_virtual); + float x2 = virtualToScreenX(x2_virtual); + float y2 = virtualToScreenY(y2_virtual); + + D3DMATRIX identity = + {1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}; + g_device->SetTransform(D3DTS_PROJECTION, &identity); + g_device->SetTransform(D3DTS_VIEW, &identity); + g_device->SetTransform(D3DTS_WORLD, &identity); + + g_device->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); + g_device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_POINT); + + g_device->SetRenderState(D3DRS_ZENABLE, FALSE); + g_device->SetRenderState(D3DRS_ZWRITEENABLE, FALSE); + g_device->SetRenderState(D3DRS_LIGHTING, FALSE); + g_device->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE); + g_device->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA); + g_device->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA); + + g_device->SetTexture(0, texture); + g_device->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE); + g_device->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE); + g_device->SetTextureStageState(0, D3DTSS_COLORARG2, D3DTA_DIFFUSE); + + D3DSURFACE_DESC texDesc; + texture->GetLevelDesc(0, &texDesc); + float texW = static_cast(texDesc.Width); + float texH = static_cast(texDesc.Height); + + float u1 = static_cast(srcRect.x) / texW; + float v1 = static_cast(srcRect.y) / texH; + float u2 = static_cast(srcRect.x + srcRect.w) / texW; + float v2 = static_cast(srcRect.y + srcRect.h) / texH; + + struct Vertex { + float x, y, z, rhw; + float u, v; + }; + + Vertex quad[4] = { + {x1, y1, 0.0f, 1.0f, u1, v1}, + {x2, y1, 0.0f, 1.0f, u2, v1}, + {x2, y2, 0.0f, 1.0f, u2, v2}, + {x1, y2, 0.0f, 1.0f, u1, v2}, + }; + + g_device->SetFVF(D3DFVF_XYZRHW | D3DFVF_TEX1); + g_device->DrawPrimitiveUP(D3DPT_TRIANGLEFAN, 2, quad, sizeof(Vertex)); +} + +uint32_t Actual_Download(SDL_Surface* target) +{ + IDirect3DSurface9* backBuffer; + HRESULT hr = g_device->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &backBuffer); + if (FAILED(hr)) { + return hr; + } + + IDirect3DSurface9* sysMemSurface; + hr = g_device->CreateOffscreenPlainSurface( + g_width, + g_height, + D3DFMT_A8R8G8B8, + D3DPOOL_SYSTEMMEM, + &sysMemSurface, + nullptr + ); + if (FAILED(hr)) { + backBuffer->Release(); + return hr; + } + + hr = g_device->GetRenderTargetData(backBuffer, sysMemSurface); + backBuffer->Release(); + if (FAILED(hr)) { + sysMemSurface->Release(); + return hr; + } + + D3DLOCKED_RECT locked; + hr = sysMemSurface->LockRect(&locked, nullptr, D3DLOCK_READONLY); + if (FAILED(hr)) { + sysMemSurface->Release(); + return hr; + } + + SDL_Surface* srcSurface = + SDL_CreateSurfaceFrom(g_width, g_height, SDL_PIXELFORMAT_ARGB8888, locked.pBits, locked.Pitch); + if (!srcSurface) { + sysMemSurface->UnlockRect(); + sysMemSurface->Release(); + return E_FAIL; + } + + float srcAspect = static_cast(g_width) / g_height; + float dstAspect = static_cast(target->w) / target->h; + + SDL_Rect srcRect; + if (srcAspect > dstAspect) { + int cropWidth = static_cast(g_height * dstAspect); + srcRect = {(g_width - cropWidth) / 2, 0, cropWidth, g_height}; + } + else { + int cropHeight = static_cast(g_width / dstAspect); + srcRect = {0, (g_height - cropHeight) / 2, g_width, cropHeight}; + } + + if (SDL_BlitSurfaceScaled(srcSurface, &srcRect, target, nullptr, SDL_SCALEMODE_NEAREST)) { + SDL_DestroySurface(srcSurface); + sysMemSurface->UnlockRect(); + sysMemSurface->Release(); + return E_FAIL; + } + + SDL_DestroySurface(srcSurface); + sysMemSurface->UnlockRect(); + sysMemSurface->Release(); + + return D3D_OK; } diff --git a/miniwin/src/d3drm/backends/directx9/actual.h b/miniwin/src/d3drm/backends/directx9/actual.h index 9080878d..e3369ec9 100644 --- a/miniwin/src/d3drm/backends/directx9/actual.h +++ b/miniwin/src/d3drm/backends/directx9/actual.h @@ -69,8 +69,14 @@ void Actual_EnableTransparency(); void Actual_SubmitDraw( const D3D9MeshCacheEntry* mesh, const Matrix4x4* modelViewMatrix, + const Matrix4x4* worldMatrix, + const Matrix4x4* viewMatrix, const Matrix3x3* normalMatrix, const Appearance* appearance, IDirect3DTexture9* texture ); -uint32_t Actual_FinalizeFrame(void* pixels, int pitch); +void Actual_Resize(int width, int height, const ViewportTransform& viewportTransform); +void Actual_Clear(float r, float g, float b); +uint32_t Actual_Flip(); +void Actual_Draw2DImage(IDirect3DTexture9* texture, const SDL_Rect& srcRect, const SDL_Rect& dstRect); +uint32_t Actual_Download(SDL_Surface* target); diff --git a/miniwin/src/d3drm/backends/directx9/renderer.cpp b/miniwin/src/d3drm/backends/directx9/renderer.cpp index f0207041..574939f5 100644 --- a/miniwin/src/d3drm/backends/directx9/renderer.cpp +++ b/miniwin/src/d3drm/backends/directx9/renderer.cpp @@ -20,14 +20,18 @@ Direct3DRMRenderer* DirectX9Renderer::Create(DWORD width, DWORD height) return new DirectX9Renderer(width, height); } -DirectX9Renderer::DirectX9Renderer(DWORD width, DWORD height) : m_width(width), m_height(height) +DirectX9Renderer::DirectX9Renderer(DWORD width, DWORD height) { + m_width = width; + m_height = height; + m_virtualWidth = width; + m_virtualHeight = height; Actual_Initialize( SDL_GetPointerProperty(SDL_GetWindowProperties(DDWindow), SDL_PROP_WINDOW_WIN32_HWND_POINTER, NULL), width, height ); - m_renderedImage = SDL_CreateSurface(m_width, m_height, SDL_PIXELFORMAT_ARGB8888); + m_renderedImage = SDL_CreateSurface(m_width, m_height, SDL_PIXELFORMAT_RGBA32); } DirectX9Renderer::~DirectX9Renderer() @@ -212,16 +216,6 @@ Uint32 DirectX9Renderer::GetMeshId(IDirect3DRMMesh* mesh, const MeshGroup* meshG return static_cast(m_meshs.size() - 1); } -DWORD DirectX9Renderer::GetWidth() -{ - return m_width; -} - -DWORD DirectX9Renderer::GetHeight() -{ - return m_height; -} - void DirectX9Renderer::GetDesc(D3DDEVICEDESC* halDesc, D3DDEVICEDESC* helDesc) { halDesc->dcmColorModel = D3DCOLORMODEL::RGB; @@ -253,6 +247,8 @@ void DirectX9Renderer::EnableTransparency() void DirectX9Renderer::SubmitDraw( DWORD meshId, const D3DRMMATRIX4D& modelViewMatrix, + const D3DRMMATRIX4D& worldMatrix, + const D3DRMMATRIX4D& viewMatrix, const Matrix3x3& normalMatrix, const Appearance& appearance ) @@ -261,17 +257,46 @@ void DirectX9Renderer::SubmitDraw( if (appearance.textureId != NO_TEXTURE_ID) { texture = m_textures[appearance.textureId].dxTexture; } - Actual_SubmitDraw(&m_meshs[meshId], &modelViewMatrix, &normalMatrix, &appearance, texture); + Actual_SubmitDraw( + &m_meshs[meshId], + &modelViewMatrix, + &worldMatrix, + &viewMatrix, + &normalMatrix, + &appearance, + texture + ); } HRESULT DirectX9Renderer::FinalizeFrame() { - HRESULT hr = Actual_FinalizeFrame(m_renderedImage->pixels, m_renderedImage->pitch); - if (hr != DD_OK) { - return hr; - } - - // Composite onto SDL backbuffer - SDL_BlitSurface(m_renderedImage, nullptr, DDBackBuffer, nullptr); - return hr; + return DD_OK; +} + +void DirectX9Renderer::Resize(int width, int height, const ViewportTransform& viewportTransform) +{ + m_width = width; + m_height = height; + m_viewportTransform = viewportTransform; + Actual_Resize(width, height, viewportTransform); +} + +void DirectX9Renderer::Clear(float r, float g, float b) +{ + Actual_Clear(r, g, b); +} + +void DirectX9Renderer::Flip() +{ + Actual_Flip(); +} + +void DirectX9Renderer::Draw2DImage(Uint32 textureId, const SDL_Rect& srcRect, const SDL_Rect& dstRect) +{ + Actual_Draw2DImage(m_textures[textureId].dxTexture, srcRect, dstRect); +} + +void DirectX9Renderer::Download(SDL_Surface* target) +{ + Actual_Download(target); } diff --git a/miniwin/src/d3drm/backends/opengl1/actual.cpp b/miniwin/src/d3drm/backends/opengl1/actual.cpp new file mode 100644 index 00000000..e1c56636 --- /dev/null +++ b/miniwin/src/d3drm/backends/opengl1/actual.cpp @@ -0,0 +1,354 @@ +// This file cannot include any minwin headers. + +#include "actual.h" + +#include "structs.h" + +#include +#include +#include +#include +#include + +// GL extension API functions. +bool g_useVBOs; +PFNGLGENBUFFERSPROC mwglGenBuffers; +PFNGLBINDBUFFERPROC mwglBindBuffer; +PFNGLBUFFERDATAPROC mwglBufferData; +PFNGLDELETEBUFFERSPROC mwglDeleteBuffers; + +void GL11_InitState() +{ + glEnable(GL_CULL_FACE); + glCullFace(GL_BACK); + glFrontFace(GL_CW); +} + +void GL11_LoadExtensions() +{ + g_useVBOs = SDL_GL_ExtensionSupported("GL_ARB_vertex_buffer_object"); + + if (g_useVBOs) { + // Load the required GL function pointers. + mwglGenBuffers = (PFNGLGENBUFFERSPROC) SDL_GL_GetProcAddress("glGenBuffersARB"); + mwglBindBuffer = (PFNGLBINDBUFFERPROC) SDL_GL_GetProcAddress("glBindBufferARB"); + mwglBufferData = (PFNGLBUFFERDATAPROC) SDL_GL_GetProcAddress("glBufferDataARB"); + mwglDeleteBuffers = (PFNGLDELETEBUFFERSPROC) SDL_GL_GetProcAddress("glDeleteBuffersARB"); + } +} + +void GL11_DestroyTexture(GLuint texId) +{ + glDeleteTextures(1, &texId); +} + +GLuint GL11_UploadTextureData(void* pixels, int width, int height) +{ + GLuint texId; + glGenTextures(1, &texId); + glBindTexture(GL_TEXTURE_2D, texId); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels); + return texId; +} + +void GL11_UploadMesh(GLMeshCacheEntry& cache, bool hasTexture) +{ + if (g_useVBOs) { + mwglGenBuffers(1, &cache.vboPositions); + mwglBindBuffer(GL_ARRAY_BUFFER_ARB, cache.vboPositions); + mwglBufferData( + GL_ARRAY_BUFFER_ARB, + cache.positions.size() * sizeof(GL11_BridgeVector), + cache.positions.data(), + GL_STATIC_DRAW_ARB + ); + + mwglGenBuffers(1, &cache.vboNormals); + mwglBindBuffer(GL_ARRAY_BUFFER_ARB, cache.vboNormals); + mwglBufferData( + GL_ARRAY_BUFFER_ARB, + cache.normals.size() * sizeof(GL11_BridgeVector), + cache.normals.data(), + GL_STATIC_DRAW_ARB + ); + + if (hasTexture) { + mwglGenBuffers(1, &cache.vboTexcoords); + mwglBindBuffer(GL_ARRAY_BUFFER_ARB, cache.vboTexcoords); + mwglBufferData( + GL_ARRAY_BUFFER_ARB, + cache.texcoords.size() * sizeof(GL11_BridgeTexCoord), + cache.texcoords.data(), + GL_STATIC_DRAW_ARB + ); + } + + mwglGenBuffers(1, &cache.ibo); + mwglBindBuffer(GL_ELEMENT_ARRAY_BUFFER_ARB, cache.ibo); + mwglBufferData( + GL_ELEMENT_ARRAY_BUFFER_ARB, + cache.indices.size() * sizeof(cache.indices[0]), + cache.indices.data(), + GL_STATIC_DRAW_ARB + ); + } +} + +void GL11_DestroyMesh(GLMeshCacheEntry& cache) +{ + if (g_useVBOs) { + mwglDeleteBuffers(1, &cache.vboPositions); + mwglDeleteBuffers(1, &cache.vboNormals); + mwglDeleteBuffers(1, &cache.vboTexcoords); + mwglDeleteBuffers(1, &cache.ibo); + } +} + +void GL11_BeginFrame(const Matrix4x4* projection) +{ + glDisable(GL_BLEND); + glEnable(GL_DEPTH_TEST); + glDepthMask(GL_TRUE); + glEnable(GL_LIGHTING); + glEnable(GL_COLOR_MATERIAL); + glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE); + + // Disable all lights and reset global ambient + for (int i = 0; i < 8; ++i) { + glDisable(GL_LIGHT0 + i); + } + const GLfloat zeroAmbient[4] = {0.f, 0.f, 0.f, 1.f}; + glLightModelfv(GL_LIGHT_MODEL_AMBIENT, zeroAmbient); + glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE); + + // Projection and view + glMatrixMode(GL_PROJECTION); + glLoadMatrixf((const GLfloat*) projection); + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); +} + +void GL11_UploadLight(int lightIdx, GL11_BridgeSceneLight* l) +{ + // Setup light + glMatrixMode(GL_MODELVIEW); + glPushMatrix(); + glLoadIdentity(); + GLenum lightId = GL_LIGHT0 + lightIdx++; + const FColor& c = l->color; + GLfloat col[4] = {c.r, c.g, c.b, c.a}; + const GLfloat zeroAmbient[4] = {0.f, 0.f, 0.f, 1.f}; + + if (l->positional == 0.f && l->directional == 0.f) { + // Ambient light only + glLightfv(lightId, GL_AMBIENT, col); + const GLfloat black[4] = {0.f, 0.f, 0.f, 1.f}; + glLightfv(lightId, GL_DIFFUSE, black); + glLightfv(lightId, GL_SPECULAR, black); + const GLfloat dummyPos[4] = {0.f, 0.f, 1.f, 0.f}; + glLightfv(lightId, GL_POSITION, dummyPos); + } + else { + glLightfv(lightId, GL_AMBIENT, zeroAmbient); + glLightfv(lightId, GL_DIFFUSE, col); + if (l->directional == 1.0f) { + glLightfv(lightId, GL_SPECULAR, col); + } + else { + const GLfloat black[4] = {0.f, 0.f, 0.f, 1.f}; + glLightfv(lightId, GL_SPECULAR, black); + } + + GLfloat pos[4]; + if (l->directional == 1.f) { + pos[0] = -l->direction.x; + pos[1] = -l->direction.y; + pos[2] = -l->direction.z; + pos[3] = 0.f; + } + else { + pos[0] = l->position.x; + pos[1] = l->position.y; + pos[2] = l->position.z; + pos[3] = 1.f; + } + glLightfv(lightId, GL_POSITION, pos); + } + glEnable(lightId); + + glPopMatrix(); +} + +void GL11_EnableTransparency() +{ + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glDepthMask(GL_FALSE); +} + +#define NO_TEXTURE_ID 0xffffffff + +void GL11_SubmitDraw( + GLMeshCacheEntry& mesh, + const Matrix4x4& modelViewMatrix, + const Appearance& appearance, + GLuint texId +) +{ + glLoadMatrixf(&modelViewMatrix[0][0]); + glEnable(GL_NORMALIZE); + + glColor4ub(appearance.color.r, appearance.color.g, appearance.color.b, appearance.color.a); + + if (appearance.shininess != 0.0f) { + GLfloat whiteSpec[] = {1.f, 1.f, 1.f, 1.f}; + glMaterialfv(GL_FRONT, GL_SPECULAR, whiteSpec); + glMaterialf(GL_FRONT, GL_SHININESS, appearance.shininess); + } + else { + GLfloat noSpec[] = {0.0f, 0.0f, 0.0f, 0.0f}; + glMaterialfv(GL_FRONT, GL_SPECULAR, noSpec); + glMaterialf(GL_FRONT, GL_SHININESS, 0.0f); + } + + if (mesh.flat) { + glShadeModel(GL_FLAT); + } + else { + glShadeModel(GL_SMOOTH); + } + + // Bind texture if present + if (appearance.textureId != NO_TEXTURE_ID) { + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glEnable(GL_TEXTURE_2D); + glBindTexture(GL_TEXTURE_2D, texId); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + } + else { + glDisable(GL_TEXTURE_2D); + glDisableClientState(GL_TEXTURE_COORD_ARRAY); + } + + glEnableClientState(GL_VERTEX_ARRAY); + glEnableClientState(GL_NORMAL_ARRAY); + + if (g_useVBOs) { + mwglBindBuffer(GL_ARRAY_BUFFER_ARB, mesh.vboPositions); + glVertexPointer(3, GL_FLOAT, 0, nullptr); + + mwglBindBuffer(GL_ARRAY_BUFFER_ARB, mesh.vboNormals); + glNormalPointer(GL_FLOAT, 0, nullptr); + + if (appearance.textureId != NO_TEXTURE_ID) { + mwglBindBuffer(GL_ARRAY_BUFFER_ARB, mesh.vboTexcoords); + glTexCoordPointer(2, GL_FLOAT, 0, nullptr); + } + + mwglBindBuffer(GL_ELEMENT_ARRAY_BUFFER_ARB, mesh.ibo); + glDrawElements(GL_TRIANGLES, static_cast(mesh.indices.size()), GL_UNSIGNED_SHORT, nullptr); + + mwglBindBuffer(GL_ARRAY_BUFFER_ARB, 0); + mwglBindBuffer(GL_ELEMENT_ARRAY_BUFFER_ARB, 0); + } + else { + glVertexPointer(3, GL_FLOAT, 0, mesh.positions.data()); + glNormalPointer(GL_FLOAT, 0, mesh.normals.data()); + if (appearance.textureId != NO_TEXTURE_ID) { + glTexCoordPointer(2, GL_FLOAT, 0, mesh.texcoords.data()); + } + + glDrawElements(GL_TRIANGLES, static_cast(mesh.indices.size()), GL_UNSIGNED_SHORT, mesh.indices.data()); + } + + glPopMatrix(); +} + +void GL11_Resize(int width, int height) +{ + glViewport(0, 0, width, height); +} + +void GL11_Clear(float r, float g, float b) +{ + glEnable(GL_DEPTH_TEST); + glDepthMask(GL_TRUE); + glClearColor(r, g, b, 1.0f); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); +} + +void GL11_Draw2DImage( + GLuint texId, + const SDL_Rect& srcRect, + const SDL_Rect& dstRect, + float left, + float right, + float bottom, + float top +) +{ + glDisable(GL_DEPTH_TEST); + glDepthMask(GL_FALSE); + + glMatrixMode(GL_PROJECTION); + glPushMatrix(); + glLoadIdentity(); + + glOrtho(left, right, bottom, top, -1, 1); + + glMatrixMode(GL_MODELVIEW); + glPushMatrix(); + glLoadIdentity(); + + glDisable(GL_LIGHTING); + glColor4f(1.0f, 1.0f, 1.0f, 1.0f); + + glEnable(GL_TEXTURE_2D); + glBindTexture(GL_TEXTURE_2D, texId); + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + + GLint boundTexture = 0; + glGetIntegerv(GL_TEXTURE_BINDING_2D, &boundTexture); + + GLfloat texW, texH; + glGetTexLevelParameterfv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &texW); + glGetTexLevelParameterfv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &texH); + + float u1 = srcRect.x / texW; + float v1 = srcRect.y / texH; + float u2 = (srcRect.x + srcRect.w) / texW; + float v2 = (srcRect.y + srcRect.h) / texH; + + float x1 = (float) dstRect.x; + float y1 = (float) dstRect.y; + float x2 = x1 + dstRect.w; + float y2 = y1 + dstRect.h; + + glBegin(GL_QUADS); + glTexCoord2f(u1, v1); + glVertex2f(x1, y1); + glTexCoord2f(u2, v1); + glVertex2f(x2, y1); + glTexCoord2f(u2, v2); + glVertex2f(x2, y2); + glTexCoord2f(u1, v2); + glVertex2f(x1, y2); + glEnd(); + + // Restore state + glMatrixMode(GL_MODELVIEW); + glPopMatrix(); + glMatrixMode(GL_PROJECTION); + glPopMatrix(); +} + +void GL11_Download(SDL_Surface* target) +{ + glFinish(); + glReadPixels(0, 0, target->w, target->h, GL_RGBA, GL_UNSIGNED_BYTE, target->pixels); +} diff --git a/miniwin/src/d3drm/backends/opengl1/actual.h b/miniwin/src/d3drm/backends/opengl1/actual.h new file mode 100644 index 00000000..8a4fb8e8 --- /dev/null +++ b/miniwin/src/d3drm/backends/opengl1/actual.h @@ -0,0 +1,88 @@ +#pragma once + +#include "structs.h" + +#include +#include +#include + +// We don't want to transitively include windows.h, but we need GLuint +typedef unsigned int GLuint; +struct IDirect3DRMTexture; +struct MeshGroup; + +typedef float Matrix4x4[4][4]; + +struct GL11_BridgeVector { + float x, y, z; +}; + +struct GL11_BridgeTexCoord { + float u, v; +}; + +struct GL11_BridgeSceneLight { + FColor color; + GL11_BridgeVector position; + float positional; + GL11_BridgeVector direction; + float directional; +}; + +struct GL11_BridgeSceneVertex { + GL11_BridgeVector position; + GL11_BridgeVector normal; + float tu, tv; +}; + +struct GLTextureCacheEntry { + IDirect3DRMTexture* texture; + Uint32 version; + GLuint glTextureId; +}; + +struct GLMeshCacheEntry { + const MeshGroup* meshGroup; + int version; + bool flat; + + // non-VBO cache + std::vector positions; + std::vector normals; + std::vector texcoords; + std::vector indices; + + // VBO cache + GLuint vboPositions; + GLuint vboNormals; + GLuint vboTexcoords; + GLuint ibo; +}; + +void GL11_InitState(); +void GL11_LoadExtensions(); +void GL11_DestroyTexture(GLuint texId); +GLuint GL11_UploadTextureData(void* pixels, int width, int height); +void GL11_UploadMesh(GLMeshCacheEntry& cache, bool hasTexture); +void GL11_DestroyMesh(GLMeshCacheEntry& cache); +void GL11_BeginFrame(const Matrix4x4* projection); +void GL11_UploadLight(int lightIdx, GL11_BridgeSceneLight* l); +void GL11_EnableTransparency(); +void GL11_SubmitDraw( + GLMeshCacheEntry& mesh, + const Matrix4x4& modelViewMatrix, + const Appearance& appearance, + GLuint texId +); +void GL11_Resize(int width, int height); +void GL11_Clear(float r, float g, float b); +void GL11_Draw2DImage( + GLuint texId, + const SDL_Rect& srcRect, + const SDL_Rect& dstRect, + float left, + float right, + float bottom, + float top +); +void GL11_Download(SDL_Surface* target); diff --git a/miniwin/src/d3drm/backends/opengl1/renderer.cpp b/miniwin/src/d3drm/backends/opengl1/renderer.cpp index 815d854b..a0b84a80 100644 --- a/miniwin/src/d3drm/backends/opengl1/renderer.cpp +++ b/miniwin/src/d3drm/backends/opengl1/renderer.cpp @@ -1,5 +1,4 @@ -#include -// must come after GLEW +#include "actual.h" #include "d3drmrenderer_opengl1.h" #include "ddraw_impl.h" #include "ddsurface_impl.h" @@ -11,21 +10,38 @@ #include #include +static_assert(sizeof(Matrix4x4) == sizeof(D3DRMMATRIX4D), "Matrix4x4 is wrong size"); +static_assert(sizeof(GL11_BridgeVector) == sizeof(D3DVECTOR), "GL11_BridgeVector is wrong size"); +static_assert(sizeof(GL11_BridgeTexCoord) == sizeof(TexCoord), "GL11_BridgeTexCoord is wrong size"); +static_assert(sizeof(GL11_BridgeSceneLight) == sizeof(SceneLight), "GL11_BridgeSceneLight is wrong size"); +static_assert(sizeof(GL11_BridgeSceneVertex) == sizeof(D3DRMVERTEX), "GL11_BridgeSceneVertex is wrong size"); + Direct3DRMRenderer* OpenGL1Renderer::Create(DWORD width, DWORD height) { + // We have to reset the attributes here after having enumerated the + // OpenGL ES 2.0 renderer, or else SDL gets very confused by SDL_GL_DEPTH_SIZE + // call below when on an EGL-based backend, and crashes with EGL_BAD_MATCH. + SDL_GL_ResetAttributes(); + // But ResetAttributes resets it to 16. + SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24); SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_COMPATIBILITY); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 1); - SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 2); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 1); SDL_Window* window = DDWindow; bool testWindow = false; if (!window) { - window = SDL_CreateWindow("OpenGL 1.2 test", width, height, SDL_WINDOW_HIDDEN | SDL_WINDOW_OPENGL); + window = SDL_CreateWindow("OpenGL 1.1 test", width, height, SDL_WINDOW_HIDDEN | SDL_WINDOW_OPENGL); + if (!window) { + SDL_Log("SDL_CreateWindow: %s", SDL_GetError()); + return nullptr; + } testWindow = true; } SDL_GLContext context = SDL_GL_CreateContext(window); if (!context) { + SDL_Log("SDL_GL_CreateContext: %s", SDL_GetError()); if (testWindow) { SDL_DestroyWindow(window); } @@ -33,85 +49,44 @@ Direct3DRMRenderer* OpenGL1Renderer::Create(DWORD width, DWORD height) } if (!SDL_GL_MakeCurrent(window, context)) { - return nullptr; - } - - GLenum err = glewInit(); - if (err != GLEW_OK) { + SDL_Log("SDL_GL_MakeCurrent: %s", SDL_GetError()); if (testWindow) { SDL_DestroyWindow(window); } return nullptr; } - if (!GLEW_EXT_framebuffer_object) { - if (testWindow) { - SDL_DestroyWindow(window); - } - return nullptr; - } - - glEnable(GL_CULL_FACE); - glCullFace(GL_BACK); - glFrontFace(GL_CCW); - - // Setup FBO - GLuint fbo; - glGenFramebuffers(1, &fbo); - glBindFramebuffer(GL_FRAMEBUFFER, fbo); - - // Create color texture - GLuint colorTex; - glGenTextures(1, &colorTex); - glBindTexture(GL_TEXTURE_2D, colorTex); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colorTex, 0); - - // Create depth renderbuffer - GLuint depthRb; - glGenRenderbuffers(1, &depthRb); - glBindRenderbuffer(GL_RENDERBUFFER, depthRb); - glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, width, height); - glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthRb); - - if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { - return nullptr; - } - glBindFramebuffer(GL_FRAMEBUFFER, 0); + GL11_InitState(); if (testWindow) { SDL_DestroyWindow(window); } - return new OpenGL1Renderer(width, height, context, fbo, colorTex, depthRb); + return new OpenGL1Renderer(width, height, context); } -OpenGL1Renderer::OpenGL1Renderer( - DWORD width, - DWORD height, - SDL_GLContext context, - GLuint fbo, - GLuint colorTex, - GLuint depthRb -) - : m_width(width), m_height(height), m_context(context), m_fbo(fbo), m_colorTex(colorTex), m_depthRb(depthRb) +OpenGL1Renderer::OpenGL1Renderer(DWORD width, DWORD height, SDL_GLContext context) : m_context(context) { - m_renderedImage = SDL_CreateSurface(m_width, m_height, SDL_PIXELFORMAT_ABGR8888); - m_useVBOs = GLEW_ARB_vertex_buffer_object; + m_width = width; + m_height = height; + m_virtualWidth = width; + m_virtualHeight = height; + m_renderedImage = SDL_CreateSurface(m_width, m_height, SDL_PIXELFORMAT_RGBA32); + GL11_LoadExtensions(); } OpenGL1Renderer::~OpenGL1Renderer() { SDL_DestroySurface(m_renderedImage); - glDeleteFramebuffers(1, &m_fbo); - glDeleteRenderbuffers(1, &m_depthRb); - glDeleteTextures(1, &m_colorTex); } void OpenGL1Renderer::PushLights(const SceneLight* lightsArray, size_t count) { + if (count > 8) { + SDL_Log("Unsupported number of lights (%d)", static_cast(count)); + count = 8; + } + m_lights.assign(lightsArray, lightsArray + count); } @@ -122,7 +97,6 @@ void OpenGL1Renderer::SetFrustumPlanes(const Plane* frustumPlanes) void OpenGL1Renderer::SetProjection(const D3DRMMATRIX4D& projection, D3DVALUE front, D3DVALUE back) { memcpy(&m_projection, projection, sizeof(D3DRMMATRIX4D)); - m_projection[1][1] *= -1.0f; // OpenGL is upside down } struct TextureDestroyContextGL { @@ -138,7 +112,7 @@ void OpenGL1Renderer::AddTextureDestroyCallback(Uint32 id, IDirect3DRMTexture* t auto* ctx = static_cast(arg); auto& cache = ctx->renderer->m_textures[ctx->textureId]; if (cache.glTextureId != 0) { - glDeleteTextures(1, &cache.glTextureId); + GL11_DestroyTexture(cache.glTextureId); cache.glTextureId = 0; cache.texture = nullptr; } @@ -157,18 +131,14 @@ Uint32 OpenGL1Renderer::GetTextureId(IDirect3DRMTexture* iTexture) auto& tex = m_textures[i]; if (tex.texture == texture) { if (tex.version != texture->m_version) { - glDeleteTextures(1, &tex.glTextureId); - glGenTextures(1, &tex.glTextureId); - glBindTexture(GL_TEXTURE_2D, tex.glTextureId); + GL11_DestroyTexture(tex.glTextureId); - SDL_Surface* surf = SDL_ConvertSurface(surface->m_surface, SDL_PIXELFORMAT_ABGR8888); + SDL_Surface* surf = SDL_ConvertSurface(surface->m_surface, SDL_PIXELFORMAT_RGBA32); if (!surf) { return NO_TEXTURE_ID; } - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, surf->w, surf->h, 0, GL_RGBA, GL_UNSIGNED_BYTE, surf->pixels); + tex.glTextureId = GL11_UploadTextureData(surf->pixels, surf->w, surf->h); SDL_DestroySurface(surf); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); tex.version = texture->m_version; } @@ -177,17 +147,13 @@ Uint32 OpenGL1Renderer::GetTextureId(IDirect3DRMTexture* iTexture) } GLuint texId; - glGenTextures(1, &texId); - glBindTexture(GL_TEXTURE_2D, texId); - SDL_Surface* surf = SDL_ConvertSurface(surface->m_surface, SDL_PIXELFORMAT_ABGR8888); + SDL_Surface* surf = SDL_ConvertSurface(surface->m_surface, SDL_PIXELFORMAT_RGBA32); if (!surf) { return NO_TEXTURE_ID; } - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, surf->w, surf->h, 0, GL_RGBA, GL_UNSIGNED_BYTE, surf->pixels); + texId = GL11_UploadTextureData(surf->pixels, surf->w, surf->h); SDL_DestroySurface(surf); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); for (Uint32 i = 0; i < m_textures.size(); ++i) { auto& tex = m_textures[i]; @@ -234,52 +200,19 @@ GLMeshCacheEntry GLUploadMesh(const MeshGroup& meshGroup, bool useVBOs) if (meshGroup.texture) { cache.texcoords.resize(vertices.size()); std::transform(vertices.begin(), vertices.end(), cache.texcoords.begin(), [](const D3DRMVERTEX& v) { - return v.texCoord; + return GL11_BridgeTexCoord{v.texCoord.u, v.texCoord.v}; }); } cache.positions.resize(vertices.size()); std::transform(vertices.begin(), vertices.end(), cache.positions.begin(), [](const D3DRMVERTEX& v) { - return v.position; + return GL11_BridgeVector{v.position.x, v.position.y, v.position.z}; }); cache.normals.resize(vertices.size()); std::transform(vertices.begin(), vertices.end(), cache.normals.begin(), [](const D3DRMVERTEX& v) { - return v.normal; + return GL11_BridgeVector{v.normal.x, v.normal.y, v.normal.z}; }); - if (useVBOs) { - glGenBuffers(1, &cache.vboPositions); - glBindBuffer(GL_ARRAY_BUFFER, cache.vboPositions); - glBufferData( - GL_ARRAY_BUFFER, - cache.positions.size() * sizeof(D3DVECTOR), - cache.positions.data(), - GL_STATIC_DRAW - ); - - glGenBuffers(1, &cache.vboNormals); - glBindBuffer(GL_ARRAY_BUFFER, cache.vboNormals); - glBufferData(GL_ARRAY_BUFFER, cache.normals.size() * sizeof(D3DVECTOR), cache.normals.data(), GL_STATIC_DRAW); - - if (meshGroup.texture != nullptr) { - glGenBuffers(1, &cache.vboTexcoords); - glBindBuffer(GL_ARRAY_BUFFER, cache.vboTexcoords); - glBufferData( - GL_ARRAY_BUFFER, - cache.texcoords.size() * sizeof(TexCoord), - cache.texcoords.data(), - GL_STATIC_DRAW - ); - } - - glGenBuffers(1, &cache.ibo); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, cache.ibo); - glBufferData( - GL_ELEMENT_ARRAY_BUFFER, - cache.indices.size() * sizeof(cache.indices[0]), - cache.indices.data(), - GL_STATIC_DRAW - ); - } + GL11_UploadMesh(cache, meshGroup.texture != nullptr); return cache; } @@ -297,12 +230,7 @@ void OpenGL1Renderer::AddMeshDestroyCallback(Uint32 id, IDirect3DRMMesh* mesh) auto* ctx = static_cast(arg); auto& cache = ctx->renderer->m_meshs[ctx->id]; cache.meshGroup = nullptr; - if (ctx->renderer->m_useVBOs) { - glDeleteBuffers(1, &cache.vboPositions); - glDeleteBuffers(1, &cache.vboNormals); - glDeleteBuffers(1, &cache.vboTexcoords); - glDeleteBuffers(1, &cache.ibo); - } + GL11_DestroyMesh(cache); delete ctx; }, ctx @@ -337,16 +265,6 @@ Uint32 OpenGL1Renderer::GetMeshId(IDirect3DRMMesh* mesh, const MeshGroup* meshGr return (Uint32) (m_meshs.size() - 1); } -DWORD OpenGL1Renderer::GetWidth() -{ - return m_width; -} - -DWORD OpenGL1Renderer::GetHeight() -{ - return m_height; -} - void OpenGL1Renderer::GetDesc(D3DDEVICEDESC* halDesc, D3DDEVICEDESC* helDesc) { halDesc->dcmColorModel = D3DCOLORMODEL::RGB; @@ -362,191 +280,119 @@ void OpenGL1Renderer::GetDesc(D3DDEVICEDESC* halDesc, D3DDEVICEDESC* helDesc) const char* OpenGL1Renderer::GetName() { - return "OpenGL 1.2 HAL"; + return "OpenGL 1.1 HAL"; } HRESULT OpenGL1Renderer::BeginFrame() { - SDL_GL_MakeCurrent(DDWindow, m_context); - glBindFramebuffer(GL_FRAMEBUFFER, m_fbo); - glViewport(0, 0, m_width, m_height); - - glDisable(GL_BLEND); - glEnable(GL_DEPTH_TEST); - glDepthMask(GL_TRUE); - glEnable(GL_LIGHTING); - glEnable(GL_COLOR_MATERIAL); - glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE); - - glClearColor(0.0f, 0.0f, 0.0f, 0.0f); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - - // Disable all lights and reset global ambient - for (int i = 0; i < 8; ++i) { - glDisable(GL_LIGHT0 + i); - } - const GLfloat zeroAmbient[4] = {0.f, 0.f, 0.f, 1.f}; - glLightModelfv(GL_LIGHT_MODEL_AMBIENT, zeroAmbient); - glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR); - glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE); - - // Setup lights - glMatrixMode(GL_MODELVIEW); - glPushMatrix(); - glLoadIdentity(); + GL11_BeginFrame((Matrix4x4*) &m_projection[0][0]); int lightIdx = 0; for (const auto& l : m_lights) { if (lightIdx > 7) { break; } - GLenum lightId = GL_LIGHT0 + lightIdx++; - const FColor& c = l.color; - GLfloat col[4] = {c.r, c.g, c.b, c.a}; + GL11_UploadLight(lightIdx, (GL11_BridgeSceneLight*) &l); - if (l.positional == 0.f && l.directional == 0.f) { - // Ambient light only - glLightfv(lightId, GL_AMBIENT, col); - const GLfloat black[4] = {0.f, 0.f, 0.f, 1.f}; - glLightfv(lightId, GL_DIFFUSE, black); - glLightfv(lightId, GL_SPECULAR, black); - const GLfloat dummyPos[4] = {0.f, 0.f, 1.f, 0.f}; - glLightfv(lightId, GL_POSITION, dummyPos); - } - else { - glLightfv(lightId, GL_AMBIENT, zeroAmbient); - glLightfv(lightId, GL_DIFFUSE, col); - if (l.directional == 1.0f) { - glLightfv(lightId, GL_SPECULAR, col); - } - else { - const GLfloat black[4] = {0.f, 0.f, 0.f, 1.f}; - glLightfv(lightId, GL_SPECULAR, black); - } - - GLfloat pos[4]; - if (l.directional == 1.f) { - pos[0] = -l.direction.x; - pos[1] = -l.direction.y; - pos[2] = -l.direction.z; - pos[3] = 0.f; - } - else { - pos[0] = l.position.x; - pos[1] = l.position.y; - pos[2] = l.position.z; - pos[3] = 1.f; - } - glLightfv(lightId, GL_POSITION, pos); - } - glEnable(lightId); + lightIdx++; } - glPopMatrix(); - - // Projection and view - glMatrixMode(GL_PROJECTION); - glLoadMatrixf(&m_projection[0][0]); - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); - return DD_OK; } void OpenGL1Renderer::EnableTransparency() { - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glDepthMask(GL_FALSE); + GL11_EnableTransparency(); } void OpenGL1Renderer::SubmitDraw( DWORD meshId, const D3DRMMATRIX4D& modelViewMatrix, + const D3DRMMATRIX4D& worldMatrix, + const D3DRMMATRIX4D& viewMatrix, const Matrix3x3& normalMatrix, const Appearance& appearance ) { auto& mesh = m_meshs[meshId]; - glMatrixMode(GL_MODELVIEW); - glPushMatrix(); - - glLoadMatrixf(&modelViewMatrix[0][0]); - glEnable(GL_NORMALIZE); - - glColor4ub(appearance.color.r, appearance.color.g, appearance.color.b, appearance.color.a); - - if (appearance.shininess != 0.0f) { - GLfloat whiteSpec[] = {1.f, 1.f, 1.f, 1.f}; - glMaterialfv(GL_FRONT, GL_SPECULAR, whiteSpec); - glMaterialf(GL_FRONT, GL_SHININESS, appearance.shininess); - } - else { - GLfloat noSpec[] = {0.0f, 0.0f, 0.0f, 0.0f}; - glMaterialfv(GL_FRONT, GL_SPECULAR, noSpec); - glMaterialf(GL_FRONT, GL_SHININESS, 0.0f); - } - - if (mesh.flat) { - glShadeModel(GL_FLAT); - } - else { - glShadeModel(GL_SMOOTH); - } - // Bind texture if present if (appearance.textureId != NO_TEXTURE_ID) { auto& tex = m_textures[appearance.textureId]; - glEnable(GL_TEXTURE_2D); - glBindTexture(GL_TEXTURE_2D, tex.glTextureId); - glEnableClientState(GL_TEXTURE_COORD_ARRAY); + GL11_SubmitDraw(mesh, modelViewMatrix, appearance, tex.glTextureId); } else { - glDisable(GL_TEXTURE_2D); - glDisableClientState(GL_TEXTURE_COORD_ARRAY); + GL11_SubmitDraw(mesh, modelViewMatrix, appearance, 0); } - - glEnableClientState(GL_VERTEX_ARRAY); - glEnableClientState(GL_NORMAL_ARRAY); - - if (m_useVBOs) { - glBindBuffer(GL_ARRAY_BUFFER, mesh.vboPositions); - glVertexPointer(3, GL_FLOAT, 0, nullptr); - - glBindBuffer(GL_ARRAY_BUFFER, mesh.vboNormals); - glNormalPointer(GL_FLOAT, 0, nullptr); - - if (appearance.textureId != NO_TEXTURE_ID) { - glBindBuffer(GL_ARRAY_BUFFER, mesh.vboTexcoords); - glTexCoordPointer(2, GL_FLOAT, 0, nullptr); - } - - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mesh.ibo); - glDrawElements(GL_TRIANGLES, static_cast(mesh.indices.size()), GL_UNSIGNED_SHORT, nullptr); - - glBindBuffer(GL_ARRAY_BUFFER, 0); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); - } - else { - glVertexPointer(3, GL_FLOAT, 0, mesh.positions.data()); - glNormalPointer(GL_FLOAT, 0, mesh.normals.data()); - if (appearance.textureId != NO_TEXTURE_ID) { - glTexCoordPointer(2, GL_FLOAT, 0, mesh.texcoords.data()); - } - - glDrawElements(GL_TRIANGLES, static_cast(mesh.indices.size()), GL_UNSIGNED_SHORT, mesh.indices.data()); - } - - glPopMatrix(); } HRESULT OpenGL1Renderer::FinalizeFrame() { - glReadPixels(0, 0, m_width, m_height, GL_RGBA, GL_UNSIGNED_BYTE, m_renderedImage->pixels); - glBindFramebuffer(GL_FRAMEBUFFER, 0); - - // Composite onto SDL backbuffer - SDL_BlitSurface(m_renderedImage, nullptr, DDBackBuffer, nullptr); - return DD_OK; } + +void OpenGL1Renderer::Resize(int width, int height, const ViewportTransform& viewportTransform) +{ + m_width = width; + m_height = height; + m_viewportTransform = viewportTransform; + SDL_DestroySurface(m_renderedImage); + m_renderedImage = SDL_CreateSurface(m_width, m_height, SDL_PIXELFORMAT_RGBA32); + GL11_Resize(width, height); +} + +void OpenGL1Renderer::Clear(float r, float g, float b) +{ + m_dirty = true; + GL11_Clear(r, g, b); +} + +void OpenGL1Renderer::Flip() +{ + if (m_dirty) { + SDL_GL_SwapWindow(DDWindow); + m_dirty = false; + } +} + +void OpenGL1Renderer::Draw2DImage(Uint32 textureId, const SDL_Rect& srcRect, const SDL_Rect& dstRect) +{ + m_dirty = true; + + float left = -m_viewportTransform.offsetX / m_viewportTransform.scale; + float right = (m_width - m_viewportTransform.offsetX) / m_viewportTransform.scale; + float top = -m_viewportTransform.offsetY / m_viewportTransform.scale; + float bottom = (m_height - m_viewportTransform.offsetY) / m_viewportTransform.scale; + + GL11_Draw2DImage(m_textures[textureId].glTextureId, srcRect, dstRect, left, right, bottom, top); +} + +void OpenGL1Renderer::Download(SDL_Surface* target) +{ + GL11_Download(m_renderedImage); + + SDL_Rect srcRect = { + static_cast(m_viewportTransform.offsetX), + static_cast(m_viewportTransform.offsetY), + static_cast(target->w * m_viewportTransform.scale), + static_cast(target->h * m_viewportTransform.scale), + }; + + SDL_Surface* bufferClone = SDL_CreateSurface(target->w, target->h, SDL_PIXELFORMAT_RGBA32); + if (!bufferClone) { + SDL_Log("SDL_CreateSurface: %s", SDL_GetError()); + return; + } + + SDL_BlitSurfaceScaled(m_renderedImage, &srcRect, bufferClone, nullptr, SDL_SCALEMODE_NEAREST); + + // Flip image vertically into target + SDL_Rect rowSrc = {0, 0, bufferClone->w, 1}; + SDL_Rect rowDst = {0, 0, bufferClone->w, 1}; + for (int y = 0; y < bufferClone->h; ++y) { + rowSrc.y = y; + rowDst.y = bufferClone->h - 1 - y; + SDL_BlitSurface(bufferClone, &rowSrc, target, &rowDst); + } + + SDL_DestroySurface(bufferClone); +} diff --git a/miniwin/src/d3drm/backends/opengles2/renderer.cpp b/miniwin/src/d3drm/backends/opengles2/renderer.cpp index 94229cc7..9305510a 100644 --- a/miniwin/src/d3drm/backends/opengles2/renderer.cpp +++ b/miniwin/src/d3drm/backends/opengles2/renderer.cpp @@ -30,6 +30,12 @@ struct SceneLightGLES2 { Direct3DRMRenderer* OpenGLES2Renderer::Create(DWORD width, DWORD height) { + // We have to reset the attributes here after having enumerated the + // OpenGL ES 2.0 renderer, or else SDL gets very confused by SDL_GL_DEPTH_SIZE + // call below when on an EGL-based backend, and crashes with EGL_BAD_MATCH. + SDL_GL_ResetAttributes(); + // But ResetAttributes resets it to 16. + SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24); SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0); @@ -50,51 +56,16 @@ Direct3DRMRenderer* OpenGLES2Renderer::Create(DWORD width, DWORD height) } if (!SDL_GL_MakeCurrent(window, context)) { + if (testWindow) { + SDL_DestroyWindow(window); + } return nullptr; } glDepthFunc(GL_LEQUAL); - glEnable(GL_DEPTH_TEST); glEnable(GL_CULL_FACE); glCullFace(GL_BACK); - glFrontFace(GL_CCW); - - // Setup FBO - GLuint fbo; - glGenFramebuffers(1, &fbo); - glBindFramebuffer(GL_FRAMEBUFFER, fbo); - - // Create color texture - GLuint colorTex; - glGenTextures(1, &colorTex); - glBindTexture(GL_TEXTURE_2D, colorTex); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, colorTex, 0); - - // Create depth renderbuffer - GLuint depthRb; - glGenRenderbuffers(1, &depthRb); - glBindRenderbuffer(GL_RENDERBUFFER, depthRb); - const char* extensions = (const char*) glGetString(GL_EXTENSIONS); - if (extensions) { - if (strstr(extensions, "GL_OES_depth24")) { - glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24_OES, width, height); - } - else if (strstr(extensions, "GL_OES_depth32")) { - glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT32_OES, width, height); - } - } - else { - glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, width, height); - } - glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, depthRb); - - if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) { - return nullptr; - } - glBindFramebuffer(GL_FRAMEBUFFER, 0); + glFrontFace(GL_CW); const char* vertexShaderSource = R"( attribute vec3 a_position; @@ -183,6 +154,7 @@ Direct3DRMRenderer* OpenGLES2Renderer::Create(DWORD width, DWORD height) if (u_useTexture != 0) { vec4 texel = texture2D(u_texture, v_texCoord); finalColor.rgb = clamp(texel.rgb * finalColor.rgb, 0.0, 1.0); + finalColor.a = texel.a; } gl_FragColor = finalColor; @@ -206,31 +178,23 @@ Direct3DRMRenderer* OpenGLES2Renderer::Create(DWORD width, DWORD height) SDL_DestroyWindow(window); } - return new OpenGLES2Renderer(width, height, context, fbo, colorTex, depthRb, shaderProgram); + return new OpenGLES2Renderer(width, height, context, shaderProgram); } -OpenGLES2Renderer::OpenGLES2Renderer( - DWORD width, - DWORD height, - SDL_GLContext context, - GLuint fbo, - GLuint colorTex, - GLuint depthRb, - GLuint shaderProgram -) - : m_width(width), m_height(height), m_context(context), m_fbo(fbo), m_colorTex(colorTex), m_depthRb(depthRb), - m_shaderProgram(shaderProgram) +OpenGLES2Renderer::OpenGLES2Renderer(DWORD width, DWORD height, SDL_GLContext context, GLuint shaderProgram) + : m_context(context), m_shaderProgram(shaderProgram) { - m_renderedImage = SDL_CreateSurface(m_width, m_height, SDL_PIXELFORMAT_ABGR8888); + m_width = width; + m_height = height; + m_virtualWidth = width; + m_virtualHeight = height; + m_renderedImage = SDL_CreateSurface(m_width, m_height, SDL_PIXELFORMAT_RGBA32); } OpenGLES2Renderer::~OpenGLES2Renderer() { SDL_DestroySurface(m_renderedImage); - glDeleteFramebuffers(1, &m_fbo); - glDeleteRenderbuffers(1, &m_depthRb); glDeleteProgram(m_shaderProgram); - glDeleteTextures(1, &m_colorTex); } void OpenGLES2Renderer::PushLights(const SceneLight* lightsArray, size_t count) @@ -250,7 +214,6 @@ void OpenGLES2Renderer::SetFrustumPlanes(const Plane* frustumPlanes) void OpenGLES2Renderer::SetProjection(const D3DRMMATRIX4D& projection, D3DVALUE front, D3DVALUE back) { memcpy(&m_projection, projection, sizeof(D3DRMMATRIX4D)); - m_projection[1][1] *= -1.0f; // OpenGL is upside down } struct TextureDestroyContextGLS2 { @@ -289,14 +252,12 @@ Uint32 OpenGLES2Renderer::GetTextureId(IDirect3DRMTexture* iTexture) glGenTextures(1, &tex.glTextureId); glBindTexture(GL_TEXTURE_2D, tex.glTextureId); - SDL_Surface* surf = SDL_ConvertSurface(surface->m_surface, SDL_PIXELFORMAT_ABGR8888); + SDL_Surface* surf = SDL_ConvertSurface(surface->m_surface, SDL_PIXELFORMAT_RGBA32); if (!surf) { return NO_TEXTURE_ID; } glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, surf->w, surf->h, 0, GL_RGBA, GL_UNSIGNED_BYTE, surf->pixels); SDL_DestroySurface(surf); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); tex.version = texture->m_version; } @@ -308,14 +269,11 @@ Uint32 OpenGLES2Renderer::GetTextureId(IDirect3DRMTexture* iTexture) glGenTextures(1, &texId); glBindTexture(GL_TEXTURE_2D, texId); - SDL_Surface* surf = SDL_ConvertSurface(surface->m_surface, SDL_PIXELFORMAT_ABGR8888); + SDL_Surface* surf = SDL_ConvertSurface(surface->m_surface, SDL_PIXELFORMAT_RGBA32); if (!surf) { return NO_TEXTURE_ID; } glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, surf->w, surf->h, 0, GL_RGBA, GL_UNSIGNED_BYTE, surf->pixels); - SDL_DestroySurface(surf); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); for (Uint32 i = 0; i < m_textures.size(); ++i) { auto& tex = m_textures[i]; @@ -323,12 +281,15 @@ Uint32 OpenGLES2Renderer::GetTextureId(IDirect3DRMTexture* iTexture) tex.texture = texture; tex.version = texture->m_version; tex.glTextureId = texId; + tex.width = surf->w; + tex.height = surf->h; AddTextureDestroyCallback(i, texture); return i; } } - m_textures.push_back({texture, texture->m_version, texId}); + m_textures.push_back({texture, texture->m_version, texId, (uint16_t) surf->w, (uint16_t) surf->h}); + SDL_DestroySurface(surf); AddTextureDestroyCallback((Uint32) (m_textures.size() - 1), texture); return (Uint32) (m_textures.size() - 1); } @@ -366,7 +327,6 @@ GLES2MeshCacheEntry GLES2UploadMesh(const MeshGroup& meshGroup) return v.texCoord; }); } - std::vector positions(vertices.size()); std::transform(vertices.begin(), vertices.end(), positions.begin(), [](const D3DRMVERTEX& v) { return v.position; @@ -451,16 +411,6 @@ Uint32 OpenGLES2Renderer::GetMeshId(IDirect3DRMMesh* mesh, const MeshGroup* mesh return (Uint32) (m_meshs.size() - 1); } -DWORD OpenGLES2Renderer::GetWidth() -{ - return m_width; -} - -DWORD OpenGLES2Renderer::GetHeight() -{ - return m_height; -} - void OpenGLES2Renderer::GetDesc(D3DDEVICEDESC* halDesc, D3DDEVICEDESC* helDesc) { halDesc->dcmColorModel = D3DCOLORMODEL::RGB; @@ -490,9 +440,7 @@ const char* OpenGLES2Renderer::GetName() HRESULT OpenGLES2Renderer::BeginFrame() { - SDL_GL_MakeCurrent(DDWindow, m_context); - glBindFramebuffer(GL_FRAMEBUFFER, m_fbo); - glViewport(0, 0, m_width, m_height); + m_dirty = true; glDisable(GL_BLEND); glEnable(GL_DEPTH_TEST); @@ -500,9 +448,6 @@ HRESULT OpenGLES2Renderer::BeginFrame() glUseProgram(m_shaderProgram); - glClearColor(0.0f, 0.0f, 0.0f, 0.0f); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - SceneLightGLES2 lightData[3]; int lightCount = std::min(static_cast(m_lights.size()), 3); @@ -531,7 +476,6 @@ HRESULT OpenGLES2Renderer::BeginFrame() glUniform4fv(glGetUniformLocation(m_shaderProgram, (base + ".direction").c_str()), 1, lightData[i].direction); } glUniform1i(glGetUniformLocation(m_shaderProgram, "u_lightCount"), lightCount); - return DD_OK; } @@ -545,6 +489,8 @@ void OpenGLES2Renderer::EnableTransparency() void OpenGLES2Renderer::SubmitDraw( DWORD meshId, const D3DRMMATRIX4D& modelViewMatrix, + const D3DRMMATRIX4D& worldMatrix, + const D3DRMMATRIX4D& viewMatrix, const Matrix3x3& normalMatrix, const Appearance& appearance ) @@ -570,6 +516,8 @@ void OpenGLES2Renderer::SubmitDraw( glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, m_textures[appearance.textureId].glTextureId); glUniform1i(glGetUniformLocation(m_shaderProgram, "u_texture"), 0); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); } else { glUniform1i(glGetUniformLocation(m_shaderProgram, "u_useTexture"), 0); @@ -606,11 +554,168 @@ HRESULT OpenGLES2Renderer::FinalizeFrame() glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); glUseProgram(0); - glReadPixels(0, 0, m_width, m_height, GL_RGBA, GL_UNSIGNED_BYTE, m_renderedImage->pixels); - glBindFramebuffer(GL_FRAMEBUFFER, 0); - - // Composite onto SDL backbuffer - SDL_BlitSurface(m_renderedImage, nullptr, DDBackBuffer, nullptr); - return DD_OK; } + +void OpenGLES2Renderer::Resize(int width, int height, const ViewportTransform& viewportTransform) +{ + m_width = width; + m_height = height; + m_viewportTransform = viewportTransform; + SDL_DestroySurface(m_renderedImage); + m_renderedImage = SDL_CreateSurface(m_width, m_height, SDL_PIXELFORMAT_RGBA32); + glViewport(0, 0, m_width, m_height); +} + +void OpenGLES2Renderer::Clear(float r, float g, float b) +{ + m_dirty = true; + glEnable(GL_DEPTH_TEST); + glDepthMask(GL_TRUE); + glClearColor(r, g, b, 1.0f); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); +} + +void OpenGLES2Renderer::Flip() +{ + if (m_dirty) { + SDL_GL_SwapWindow(DDWindow); + m_dirty = false; + } +} + +void CreateOrthoMatrix(float left, float right, float bottom, float top, D3DRMMATRIX4D& outMatrix) +{ + float near = -1.0f; + float far = 1.0f; + float rl = right - left; + float tb = top - bottom; + float fn = far - near; + + outMatrix[0][0] = 2.0f / rl; + outMatrix[0][1] = 0.0f; + outMatrix[0][2] = 0.0f; + outMatrix[0][3] = 0.0f; + + outMatrix[1][0] = 0.0f; + outMatrix[1][1] = 2.0f / tb; + outMatrix[1][2] = 0.0f; + outMatrix[1][3] = 0.0f; + + outMatrix[2][0] = 0.0f; + outMatrix[2][1] = 0.0f; + outMatrix[2][2] = -2.0f / fn; + outMatrix[2][3] = 0.0f; + + outMatrix[3][0] = -(right + left) / rl; + outMatrix[3][1] = -(top + bottom) / tb; + outMatrix[3][2] = -(far + near) / fn; + outMatrix[3][3] = 1.0f; +} + +void OpenGLES2Renderer::Draw2DImage(Uint32 textureId, const SDL_Rect& srcRect, const SDL_Rect& dstRect) +{ + m_dirty = true; + + glDisable(GL_DEPTH_TEST); + glDepthMask(GL_FALSE); + + glUseProgram(m_shaderProgram); + + float color[] = {1.0f, 1.0f, 1.0f, 1.0f}; + float blank[] = {0.0f, 0.0f, 0.0f, 0.0f}; + glUniform4fv(glGetUniformLocation(m_shaderProgram, "u_lights[0].color"), 1, color); + glUniform4fv(glGetUniformLocation(m_shaderProgram, "u_lights[0].position"), 1, blank); + glUniform4fv(glGetUniformLocation(m_shaderProgram, "u_lights[0].direction"), 1, blank); + glUniform1i(glGetUniformLocation(m_shaderProgram, "u_lightCount"), 1); + + glUniform4f(glGetUniformLocation(m_shaderProgram, "u_color"), 1.0f, 1.0f, 1.0f, 1.0f); + glUniform1f(glGetUniformLocation(m_shaderProgram, "u_shininess"), 0.0f); + + float left = -m_viewportTransform.offsetX / m_viewportTransform.scale; + float right = (m_width - m_viewportTransform.offsetX) / m_viewportTransform.scale; + float top = -m_viewportTransform.offsetY / m_viewportTransform.scale; + float bottom = (m_height - m_viewportTransform.offsetY) / m_viewportTransform.scale; + + D3DRMMATRIX4D projection; + CreateOrthoMatrix(left, right, bottom, top, projection); + + D3DRMMATRIX4D identity = {{1.f, 0.f, 0.f, 0.f}, {0.f, 1.f, 0.f, 0.f}, {0.f, 0.f, 1.f, 0.f}, {0.f, 0.f, 0.f, 1.f}}; + glUniformMatrix4fv(glGetUniformLocation(m_shaderProgram, "u_modelViewMatrix"), 1, GL_FALSE, &identity[0][0]); + glUniformMatrix3fv(glGetUniformLocation(m_shaderProgram, "u_normalMatrix"), 1, GL_FALSE, &identity[0][0]); + glUniformMatrix4fv(glGetUniformLocation(m_shaderProgram, "u_projectionMatrix"), 1, GL_FALSE, &projection[0][0]); + + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + glActiveTexture(GL_TEXTURE0); + glUniform1i(glGetUniformLocation(m_shaderProgram, "u_useTexture"), 1); + const GLES2TextureCacheEntry& texture = m_textures[textureId]; + glBindTexture(GL_TEXTURE_2D, texture.glTextureId); + glUniform1i(glGetUniformLocation(m_shaderProgram, "u_texture"), 0); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + float texW = texture.width; + float texH = texture.height; + + float u1 = srcRect.x / texW; + float v1 = srcRect.y / texH; + float u2 = (srcRect.x + srcRect.w) / texW; + float v2 = (srcRect.y + srcRect.h) / texH; + + float x1 = static_cast(dstRect.x); + float y1 = static_cast(dstRect.y); + float x2 = x1 + dstRect.w; + float y2 = y1 + dstRect.h; + + GLfloat vertices[] = {x1, y1, u1, v1, x2, y1, u2, v1, x1, y2, u1, v2, x2, y2, u2, v2}; + + GLint posLoc = glGetAttribLocation(m_shaderProgram, "a_position"); + GLint texLoc = glGetAttribLocation(m_shaderProgram, "a_texCoord"); + + glEnableVertexAttribArray(posLoc); + glEnableVertexAttribArray(texLoc); + + glVertexAttribPointer(posLoc, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(GLfloat), vertices); + glVertexAttribPointer(texLoc, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(GLfloat), vertices + 2); + + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); + + glDisableVertexAttribArray(posLoc); + glDisableVertexAttribArray(texLoc); + + glBindTexture(GL_TEXTURE_2D, 0); + glUseProgram(0); +} + +void OpenGLES2Renderer::Download(SDL_Surface* target) +{ + glFinish(); + glReadPixels(0, 0, m_width, m_height, GL_RGBA, GL_UNSIGNED_BYTE, m_renderedImage->pixels); + + SDL_Rect srcRect = { + static_cast(m_viewportTransform.offsetX), + static_cast(m_viewportTransform.offsetY), + static_cast(target->w * m_viewportTransform.scale), + static_cast(target->h * m_viewportTransform.scale), + }; + + SDL_Surface* bufferClone = SDL_CreateSurface(target->w, target->h, SDL_PIXELFORMAT_RGBA32); + if (!bufferClone) { + SDL_Log("SDL_CreateSurface: %s", SDL_GetError()); + return; + } + + SDL_BlitSurfaceScaled(m_renderedImage, &srcRect, bufferClone, nullptr, SDL_SCALEMODE_NEAREST); + + // Flip image vertically into target + SDL_Rect rowSrc = {0, 0, bufferClone->w, 1}; + SDL_Rect rowDst = {0, 0, bufferClone->w, 1}; + for (int y = 0; y < bufferClone->h; ++y) { + rowSrc.y = y; + rowDst.y = bufferClone->h - 1 - y; + SDL_BlitSurface(bufferClone, &rowSrc, target, &rowDst); + } + + SDL_DestroySurface(bufferClone); +} diff --git a/miniwin/src/d3drm/backends/sdl3gpu/renderer.cpp b/miniwin/src/d3drm/backends/sdl3gpu/renderer.cpp index ea182dc2..4ee5a35c 100644 --- a/miniwin/src/d3drm/backends/sdl3gpu/renderer.cpp +++ b/miniwin/src/d3drm/backends/sdl3gpu/renderer.cpp @@ -7,6 +7,7 @@ #include "miniwin.h" #include +#include #include struct ScopedSurface { @@ -91,7 +92,12 @@ struct ScopedShader { void release() { ptr = nullptr; } }; -static SDL_GPUGraphicsPipeline* InitializeGraphicsPipeline(SDL_GPUDevice* device, bool depthWrite) +static SDL_GPUGraphicsPipeline* InitializeGraphicsPipeline( + SDL_GPUDevice* device, + SDL_Window* window, + bool depthTest, + bool depthWrite +) { const SDL_GPUShaderCreateInfo* vertexCreateInfo = GetVertexShaderCode(VertexShaderId::PositionColor, SDL_GetGPUShaderFormats(device)); @@ -141,8 +147,8 @@ static SDL_GPUGraphicsPipeline* InitializeGraphicsPipeline(SDL_GPUDevice* device vertexInputState.num_vertex_attributes = SDL_arraysize(vertexAttrs); SDL_GPUColorTargetDescription colorTargets = {}; - colorTargets.format = SDL_GPU_TEXTUREFORMAT_R8G8B8A8_UNORM; - if (depthWrite) { + colorTargets.format = SDL_GetGPUSwapchainTextureFormat(device, window); + if (depthTest && depthWrite) { colorTargets.blend_state.enable_blend = false; } else { @@ -170,7 +176,7 @@ static SDL_GPUGraphicsPipeline* InitializeGraphicsPipeline(SDL_GPUDevice* device pipelineCreateInfo.rasterizer_state = rasterizerState; pipelineCreateInfo.depth_stencil_state.compare_op = SDL_GPU_COMPAREOP_GREATER; pipelineCreateInfo.depth_stencil_state.write_mask = 0xff; - pipelineCreateInfo.depth_stencil_state.enable_depth_test = true; + pipelineCreateInfo.depth_stencil_state.enable_depth_test = depthTest; pipelineCreateInfo.depth_stencil_state.enable_depth_write = depthWrite; pipelineCreateInfo.depth_stencil_state.enable_stencil_test = false; pipelineCreateInfo.target_info.color_target_descriptions = &colorTargets; @@ -178,16 +184,18 @@ static SDL_GPUGraphicsPipeline* InitializeGraphicsPipeline(SDL_GPUDevice* device pipelineCreateInfo.target_info.depth_stencil_format = SDL_GPU_TEXTUREFORMAT_D32_FLOAT; pipelineCreateInfo.target_info.has_depth_stencil_target = true; - SDL_GPUGraphicsPipeline* pipeline = SDL_CreateGPUGraphicsPipeline(device, &pipelineCreateInfo); - - return pipeline; + return SDL_CreateGPUGraphicsPipeline(device, &pipelineCreateInfo); } Direct3DRMRenderer* Direct3DRMSDL3GPURenderer::Create(DWORD width, DWORD height) { ScopedDevice device{SDL_CreateGPUDevice( SDL_GPU_SHADERFORMAT_SPIRV | SDL_GPU_SHADERFORMAT_DXIL | SDL_GPU_SHADERFORMAT_MSL, +#ifdef DEBUG true, +#else + false, +#endif nullptr )}; if (!device.ptr) { @@ -195,63 +203,63 @@ Direct3DRMRenderer* Direct3DRMSDL3GPURenderer::Create(DWORD width, DWORD height) return nullptr; } - ScopedPipeline opaquePipeline{device.ptr, InitializeGraphicsPipeline(device.ptr, true)}; + SDL_Window* window = DDWindow; + bool testWindow = false; + if (!window) { + window = SDL_CreateWindow("SDL_GPU test", width, height, SDL_WINDOW_HIDDEN); + if (!window) { + SDL_Log("SDL_CreateWindow: %s", SDL_GetError()); + return nullptr; + } + testWindow = true; + } + + if (!SDL_ClaimWindowForGPUDevice(device.ptr, window)) { + SDL_LogError(LOG_CATEGORY_MINIWIN, "SDL_ClaimWindowForGPUDevice: %s", SDL_GetError()); + if (testWindow) { + SDL_DestroyWindow(window); + } + return nullptr; + } + + ScopedPipeline opaquePipeline{device.ptr, InitializeGraphicsPipeline(device.ptr, window, true, true)}; if (!opaquePipeline.ptr) { SDL_LogError(LOG_CATEGORY_MINIWIN, "InitializeGraphicsPipeline for opaquePipeline"); + if (testWindow) { + SDL_DestroyWindow(window); + } return nullptr; } - ScopedPipeline transparentPipeline{device.ptr, InitializeGraphicsPipeline(device.ptr, false)}; + ScopedPipeline transparentPipeline{device.ptr, InitializeGraphicsPipeline(device.ptr, window, true, false)}; if (!transparentPipeline.ptr) { SDL_LogError(LOG_CATEGORY_MINIWIN, "InitializeGraphicsPipeline for transparentPipeline"); + if (testWindow) { + SDL_DestroyWindow(window); + } return nullptr; } - SDL_GPUTextureCreateInfo textureInfo = {}; - textureInfo.type = SDL_GPU_TEXTURETYPE_2D; - textureInfo.format = SDL_GPU_TEXTUREFORMAT_R8G8B8A8_UNORM; - textureInfo.usage = SDL_GPU_TEXTUREUSAGE_COLOR_TARGET; - textureInfo.width = width; - textureInfo.height = height; - textureInfo.layer_count_or_depth = 1; - textureInfo.num_levels = 1; - textureInfo.sample_count = SDL_GPU_SAMPLECOUNT_1; - ScopedTexture transferTexture{device.ptr, SDL_CreateGPUTexture(device.ptr, &textureInfo)}; - if (!transferTexture.ptr) { - SDL_LogError(LOG_CATEGORY_MINIWIN, "SDL_CreateGPUTexture for backbuffer failed (%s)", SDL_GetError()); - return nullptr; - } - - SDL_GPUTextureCreateInfo depthTexInfo = textureInfo; - depthTexInfo.format = SDL_GPU_TEXTUREFORMAT_D32_FLOAT; - depthTexInfo.usage = SDL_GPU_TEXTUREUSAGE_DEPTH_STENCIL_TARGET; - ScopedTexture depthTexture{device.ptr, SDL_CreateGPUTexture(device.ptr, &depthTexInfo)}; - if (!depthTexture.ptr) { - SDL_LogError(LOG_CATEGORY_MINIWIN, "SDL_CreateGPUTexture for depth buffer (%s)", SDL_GetError()); - return nullptr; - } - - // Setup texture GPU-to-CPU transfer - SDL_GPUTransferBufferCreateInfo downloadBufferInfo = {}; - downloadBufferInfo.usage = SDL_GPU_TRANSFERBUFFERUSAGE_DOWNLOAD; - downloadBufferInfo.size = width * height * 4; - ScopedTransferBuffer downloadBuffer{device.ptr, SDL_CreateGPUTransferBuffer(device.ptr, &downloadBufferInfo)}; - if (!downloadBuffer.ptr) { - SDL_LogError( - LOG_CATEGORY_MINIWIN, - "SDL_CreateGPUTransferBuffer filed for download buffer (%s)", - SDL_GetError() - ); + ScopedPipeline uiPipeline{device.ptr, InitializeGraphicsPipeline(device.ptr, window, false, false)}; + if (!uiPipeline.ptr) { + SDL_LogError(LOG_CATEGORY_MINIWIN, "InitializeGraphicsPipeline for uiPipeline"); + if (testWindow) { + SDL_DestroyWindow(window); + } return nullptr; } // Setup texture CPU-to-GPU transfer SDL_GPUTransferBufferCreateInfo uploadBufferInfo = {}; uploadBufferInfo.usage = SDL_GPU_TRANSFERBUFFERUSAGE_UPLOAD; - uploadBufferInfo.size = 256 * 256 * 4; // Largest known game texture + int uploadBufferSize = 640 * 480 * 4; // Largest known game texture + uploadBufferInfo.size = uploadBufferSize; ScopedTransferBuffer uploadBuffer{device.ptr, SDL_CreateGPUTransferBuffer(device.ptr, &uploadBufferInfo)}; if (!uploadBuffer.ptr) { SDL_LogError(LOG_CATEGORY_MINIWIN, "SDL_CreateGPUTransferBuffer filed for upload buffer (%s)", SDL_GetError()); + if (testWindow) { + SDL_DestroyWindow(window); + } return nullptr; } @@ -265,31 +273,54 @@ Direct3DRMRenderer* Direct3DRMSDL3GPURenderer::Create(DWORD width, DWORD height) ScopedSampler sampler{device.ptr, SDL_CreateGPUSampler(device.ptr, &samplerInfo)}; if (!sampler.ptr) { SDL_LogError(LOG_CATEGORY_MINIWIN, "Failed to create sampler: %s", SDL_GetError()); + if (testWindow) { + SDL_DestroyWindow(window); + } return nullptr; } + SDL_GPUSamplerCreateInfo uiSamplerInfo = {}; + uiSamplerInfo.min_filter = SDL_GPU_FILTER_LINEAR; + uiSamplerInfo.mag_filter = SDL_GPU_FILTER_NEAREST; + uiSamplerInfo.mipmap_mode = SDL_GPU_SAMPLERMIPMAPMODE_LINEAR; + uiSamplerInfo.address_mode_u = SDL_GPU_SAMPLERADDRESSMODE_CLAMP_TO_EDGE; + uiSamplerInfo.address_mode_v = SDL_GPU_SAMPLERADDRESSMODE_CLAMP_TO_EDGE; + uiSamplerInfo.address_mode_w = SDL_GPU_SAMPLERADDRESSMODE_CLAMP_TO_EDGE; + ScopedSampler uiSampler{device.ptr, SDL_CreateGPUSampler(device.ptr, &uiSamplerInfo)}; + if (!uiSampler.ptr) { + SDL_LogError(LOG_CATEGORY_MINIWIN, "Failed to create sampler: %s", SDL_GetError()); + if (testWindow) { + SDL_DestroyWindow(window); + } + return nullptr; + } + + if (testWindow) { + SDL_ReleaseWindowFromGPUDevice(device.ptr, window); + SDL_DestroyWindow(window); + } + auto renderer = new Direct3DRMSDL3GPURenderer( width, height, device.ptr, opaquePipeline.ptr, transparentPipeline.ptr, - transferTexture.ptr, - depthTexture.ptr, + uiPipeline.ptr, sampler.ptr, + uiSampler.ptr, uploadBuffer.ptr, - downloadBuffer.ptr + uploadBufferSize ); // Release resources so they don't get cleaned up device.release(); opaquePipeline.release(); transparentPipeline.release(); - transferTexture.release(); - depthTexture.release(); + uiPipeline.release(); sampler.release(); + uiSampler.release(); uploadBuffer.release(); - downloadBuffer.release(); return renderer; } @@ -300,17 +331,21 @@ Direct3DRMSDL3GPURenderer::Direct3DRMSDL3GPURenderer( SDL_GPUDevice* device, SDL_GPUGraphicsPipeline* opaquePipeline, SDL_GPUGraphicsPipeline* transparentPipeline, - SDL_GPUTexture* transferTexture, - SDL_GPUTexture* depthTexture, + SDL_GPUGraphicsPipeline* uiPipeline, SDL_GPUSampler* sampler, + SDL_GPUSampler* uiSampler, SDL_GPUTransferBuffer* uploadBuffer, - SDL_GPUTransferBuffer* downloadBuffer + int uploadBufferSize ) - : m_width(width), m_height(height), m_device(device), m_opaquePipeline(opaquePipeline), - m_transparentPipeline(transparentPipeline), m_transferTexture(transferTexture), m_depthTexture(depthTexture), - m_sampler(sampler), m_uploadBuffer(uploadBuffer), m_downloadBuffer(downloadBuffer) + : m_device(device), m_opaquePipeline(opaquePipeline), m_transparentPipeline(transparentPipeline), + m_uiPipeline(uiPipeline), m_sampler(sampler), m_uiSampler(uiSampler), m_uploadBuffer(uploadBuffer), + m_uploadBufferSize(uploadBufferSize) { - SDL_Surface* dummySurface = SDL_CreateSurface(1, 1, SDL_PIXELFORMAT_ABGR8888); + m_width = width; + m_height = height; + m_virtualWidth = width; + m_virtualHeight = height; + SDL_Surface* dummySurface = SDL_CreateSurface(1, 1, SDL_PIXELFORMAT_RGBA32); if (!dummySurface) { SDL_LogError(LOG_CATEGORY_MINIWIN, "Failed to create surface: %s", SDL_GetError()); return; @@ -324,35 +359,67 @@ Direct3DRMSDL3GPURenderer::Direct3DRMSDL3GPURenderer( SDL_UnlockSurface(dummySurface); m_dummyTexture = CreateTextureFromSurface(dummySurface); + if (!m_dummyTexture) { + SDL_DestroySurface(dummySurface); + SDL_LogError(LOG_CATEGORY_MINIWIN, "Failed to create surface: %s", SDL_GetError()); + return; + } SDL_DestroySurface(dummySurface); + + ViewportTransform viewportTransform = {1.0f, 0.0f, 0.0f}; + Resize(m_width, m_height, viewportTransform); + + m_uiMesh.vertices = { + {{0.0f, 0.0f, 0.0f}, {0, 0, -1}, {0.0f, 0.0f}}, + {{1.0f, 0.0f, 0.0f}, {0, 0, -1}, {1.0f, 0.0f}}, + {{1.0f, 1.0f, 0.0f}, {0, 0, -1}, {1.0f, 1.0f}}, + {{0.0f, 1.0f, 0.0f}, {0, 0, -1}, {0.0f, 1.0f}} + }; + m_uiMesh.indices = {0, 1, 2, 0, 2, 3}; + m_uiMeshCache = UploadMesh(m_uiMesh); } Direct3DRMSDL3GPURenderer::~Direct3DRMSDL3GPURenderer() { - SDL_ReleaseGPUTransferBuffer(m_device, m_downloadBuffer); + SDL_ReleaseGPUBuffer(m_device, m_uiMeshCache.vertexBuffer); + SDL_ReleaseGPUBuffer(m_device, m_uiMeshCache.indexBuffer); + if (DDWindow) { + SDL_ReleaseWindowFromGPUDevice(m_device, DDWindow); + } + if (m_downloadBuffer) { + SDL_ReleaseGPUTransferBuffer(m_device, m_downloadBuffer); + } if (m_uploadBuffer) { SDL_ReleaseGPUTransferBuffer(m_device, m_uploadBuffer); } SDL_ReleaseGPUSampler(m_device, m_sampler); - SDL_ReleaseGPUTexture(m_device, m_dummyTexture); - SDL_ReleaseGPUTexture(m_device, m_depthTexture); - SDL_ReleaseGPUTexture(m_device, m_transferTexture); + SDL_ReleaseGPUSampler(m_device, m_uiSampler); + if (m_dummyTexture) { + SDL_ReleaseGPUTexture(m_device, m_dummyTexture); + } + if (m_depthTexture) { + SDL_ReleaseGPUTexture(m_device, m_depthTexture); + } + if (m_transferTexture) { + SDL_ReleaseGPUTexture(m_device, m_transferTexture); + } SDL_ReleaseGPUGraphicsPipeline(m_device, m_opaquePipeline); SDL_ReleaseGPUGraphicsPipeline(m_device, m_transparentPipeline); + SDL_ReleaseGPUGraphicsPipeline(m_device, m_uiPipeline); if (m_uploadFence) { SDL_ReleaseGPUFence(m_device, m_uploadFence); } SDL_DestroyGPUDevice(m_device); } -void Direct3DRMSDL3GPURenderer::PushLights(const SceneLight* vertices, size_t count) +void Direct3DRMSDL3GPURenderer::PushLights(const SceneLight* lights, size_t count) { if (count > 3) { SDL_LogError(LOG_CATEGORY_MINIWIN, "Unsupported number of lights (%d)", static_cast(count)); count = 3; } int lightCount = std::min(static_cast(count), 3); - memcpy(&m_fragmentShadingData.lights, vertices, sizeof(SceneLight) * lightCount); + memcpy(&m_fragmentShadingData.lights, lights, sizeof(SceneLight) * lightCount); m_fragmentShadingData.lightCount = lightCount; } @@ -364,7 +431,7 @@ void Direct3DRMSDL3GPURenderer::SetProjection(const D3DRMMATRIX4D& projection, D { m_front = front; m_back = back; - memcpy(&m_uniforms.projection, projection, sizeof(D3DRMMATRIX4D)); + memcpy(&m_projection, projection, sizeof(D3DRMMATRIX4D)); } void Direct3DRMSDL3GPURenderer::WaitForPendingUpload() @@ -405,7 +472,7 @@ void Direct3DRMSDL3GPURenderer::AddTextureDestroyCallback(Uint32 id, IDirect3DRM SDL_GPUTexture* Direct3DRMSDL3GPURenderer::CreateTextureFromSurface(SDL_Surface* surface) { - ScopedSurface surf{SDL_ConvertSurface(surface, SDL_PIXELFORMAT_ABGR8888)}; + ScopedSurface surf{SDL_ConvertSurface(surface, SDL_PIXELFORMAT_RGBA32)}; if (!surf.ptr) { SDL_LogError(LOG_CATEGORY_MINIWIN, "SDL_ConvertSurface (%s)", SDL_GetError()); return nullptr; @@ -607,6 +674,7 @@ void Direct3DRMSDL3GPURenderer::AddMeshDestroyCallback(Uint32 id, IDirect3DRMMes auto* ctx = static_cast(arg); auto& cache = ctx->renderer->m_meshs[ctx->id]; SDL_ReleaseGPUBuffer(ctx->renderer->m_device, cache.vertexBuffer); + SDL_ReleaseGPUBuffer(ctx->renderer->m_device, cache.indexBuffer); cache.meshGroup = nullptr; delete ctx; }, @@ -621,6 +689,7 @@ Uint32 Direct3DRMSDL3GPURenderer::GetMeshId(IDirect3DRMMesh* mesh, const MeshGro if (cache.meshGroup == meshGroup) { if (cache.version != meshGroup->version) { SDL_ReleaseGPUBuffer(m_device, cache.vertexBuffer); + SDL_ReleaseGPUBuffer(m_device, cache.indexBuffer); cache = std::move(UploadMesh(*meshGroup)); } return i; @@ -643,16 +712,6 @@ Uint32 Direct3DRMSDL3GPURenderer::GetMeshId(IDirect3DRMMesh* mesh, const MeshGro return (Uint32) (m_meshs.size() - 1); } -DWORD Direct3DRMSDL3GPURenderer::GetWidth() -{ - return m_width; -} - -DWORD Direct3DRMSDL3GPURenderer::GetHeight() -{ - return m_height; -} - void Direct3DRMSDL3GPURenderer::GetDesc(D3DDEVICEDESC* halDesc, D3DDEVICEDESC* helDesc) { halDesc->dcmColorModel = D3DCOLORMODEL::RGB; @@ -708,32 +767,45 @@ SDL_GPUTransferBuffer* Direct3DRMSDL3GPURenderer::GetUploadBuffer(size_t size) return m_uploadBuffer; } -HRESULT Direct3DRMSDL3GPURenderer::BeginFrame() +void Direct3DRMSDL3GPURenderer::StartRenderPass(float r, float g, float b, bool clear) { - if (!DDBackBuffer) { - return DDERR_GENERIC; + m_cmdbuf = SDL_AcquireGPUCommandBuffer(m_device); + if (!m_cmdbuf) { + SDL_LogError( + LOG_CATEGORY_MINIWIN, + "SDL_AcquireGPUCommandBuffer in StartRenderPass failed (%s)", + SDL_GetError() + ); + return; } // Clear color and depth targets SDL_GPUColorTargetInfo colorTargetInfo = {}; colorTargetInfo.texture = m_transferTexture; - colorTargetInfo.clear_color = {0, 0, 0, 0}; - colorTargetInfo.load_op = SDL_GPU_LOADOP_CLEAR; + colorTargetInfo.clear_color = {r, g, b, 1.0f}; + colorTargetInfo.load_op = clear ? SDL_GPU_LOADOP_CLEAR : SDL_GPU_LOADOP_DONT_CARE; SDL_GPUDepthStencilTargetInfo depthStencilTargetInfo = {}; depthStencilTargetInfo.texture = m_depthTexture; depthStencilTargetInfo.clear_depth = 0.0f; - depthStencilTargetInfo.load_op = SDL_GPU_LOADOP_CLEAR; + depthStencilTargetInfo.load_op = clear ? SDL_GPU_LOADOP_CLEAR : SDL_GPU_LOADOP_DONT_CARE; depthStencilTargetInfo.store_op = SDL_GPU_STOREOP_STORE; - m_cmdbuf = SDL_AcquireGPUCommandBuffer(m_device); - if (!m_cmdbuf) { - SDL_LogError(LOG_CATEGORY_MINIWIN, "SDL_AcquireGPUCommandBuffer in BeginFrame failed (%s)", SDL_GetError()); - return DDERR_GENERIC; - } - m_renderPass = SDL_BeginGPURenderPass(m_cmdbuf, &colorTargetInfo, 1, &depthStencilTargetInfo); +} + +void Direct3DRMSDL3GPURenderer::Clear(float r, float g, float b) +{ + StartRenderPass(r, g, b, true); +} + +HRESULT Direct3DRMSDL3GPURenderer::BeginFrame() +{ + if (!m_renderPass) { + StartRenderPass(0, 0, 0, false); + } SDL_BindGPUGraphicsPipeline(m_renderPass, m_opaquePipeline); + memcpy(&m_uniforms.projection, m_projection, sizeof(D3DRMMATRIX4D)); return DD_OK; } @@ -746,6 +818,8 @@ void Direct3DRMSDL3GPURenderer::EnableTransparency() void Direct3DRMSDL3GPURenderer::SubmitDraw( DWORD meshId, const D3DRMMATRIX4D& modelViewMatrix, + const D3DRMMATRIX4D& worldMatrix, + const D3DRMMATRIX4D& viewMatrix, const Matrix3x3& normalMatrix, const Appearance& appearance ) @@ -774,15 +848,210 @@ void Direct3DRMSDL3GPURenderer::SubmitDraw( HRESULT Direct3DRMSDL3GPURenderer::FinalizeFrame() { - SDL_EndGPURenderPass(m_renderPass); - m_renderPass = nullptr; + return DD_OK; +} + +void Direct3DRMSDL3GPURenderer::Resize(int width, int height, const ViewportTransform& viewportTransform) +{ + m_width = width; + m_height = height; + m_viewportTransform = viewportTransform; + + if (!DDWindow) { + return; + } + + if (m_transferTexture) { + SDL_ReleaseGPUTexture(m_device, m_transferTexture); + } + SDL_GPUTextureCreateInfo textureInfo = {}; + textureInfo.type = SDL_GPU_TEXTURETYPE_2D; + textureInfo.format = SDL_GetGPUSwapchainTextureFormat(m_device, DDWindow); + textureInfo.usage = SDL_GPU_TEXTUREUSAGE_COLOR_TARGET | SDL_GPU_TEXTUREUSAGE_SAMPLER; + textureInfo.width = m_width; + textureInfo.height = m_height; + textureInfo.layer_count_or_depth = 1; + textureInfo.num_levels = 1; + textureInfo.sample_count = SDL_GPU_SAMPLECOUNT_1; + m_transferTexture = SDL_CreateGPUTexture(m_device, &textureInfo); + if (!m_transferTexture) { + SDL_LogError(LOG_CATEGORY_MINIWIN, "SDL_CreateGPUTexture for backbuffer failed (%s)", SDL_GetError()); + return; + } + + if (m_depthTexture) { + SDL_ReleaseGPUTexture(m_device, m_depthTexture); + } + SDL_GPUTextureCreateInfo depthTexInfo = textureInfo; + depthTexInfo.format = SDL_GPU_TEXTUREFORMAT_D32_FLOAT; + depthTexInfo.usage = SDL_GPU_TEXTUREUSAGE_DEPTH_STENCIL_TARGET; + m_depthTexture = SDL_CreateGPUTexture(m_device, &depthTexInfo); + if (!m_depthTexture) { + SDL_LogError(LOG_CATEGORY_MINIWIN, "SDL_CreateGPUTexture for depth buffer (%s)", SDL_GetError()); + return; + } + + // Setup texture GPU-to-CPU transfer + SDL_GPUTransferBufferCreateInfo downloadBufferInfo = {}; + downloadBufferInfo.usage = SDL_GPU_TRANSFERBUFFERUSAGE_DOWNLOAD; + downloadBufferInfo.size = + ((m_width - (m_viewportTransform.offsetX * 2)) * (m_height - (m_viewportTransform.offsetY * 2))) * 4; + m_downloadBuffer = SDL_CreateGPUTransferBuffer(m_device, &downloadBufferInfo); + if (!m_downloadBuffer) { + SDL_LogError( + LOG_CATEGORY_MINIWIN, + "SDL_CreateGPUTransferBuffer filed for download buffer (%s)", + SDL_GetError() + ); + return; + } +} + +void Direct3DRMSDL3GPURenderer::Flip() +{ + if (!m_cmdbuf) { + return; + } + if (m_renderPass) { + SDL_EndGPURenderPass(m_renderPass); + m_renderPass = nullptr; + } + + SDL_GPUTexture* swapchainTexture; + if (!SDL_WaitAndAcquireGPUSwapchainTexture(m_cmdbuf, DDWindow, &swapchainTexture, nullptr, nullptr) || + !swapchainTexture) { + SDL_Log("SDL_WaitAndAcquireGPUSwapchainTexture: %s", SDL_GetError()); + return; + } + + SDL_GPUBlitInfo blit = {}; + blit.source.texture = m_transferTexture; + blit.source.w = m_width; + blit.source.h = m_height; + blit.destination.texture = swapchainTexture; + blit.destination.w = m_width; + blit.destination.h = m_height; + blit.load_op = SDL_GPU_LOADOP_DONT_CARE; + blit.flip_mode = SDL_FLIP_NONE; + blit.filter = SDL_GPU_FILTER_NEAREST; + blit.cycle = false; + SDL_BlitGPUTexture(m_cmdbuf, &blit); + SDL_SubmitGPUCommandBuffer(m_cmdbuf); + m_cmdbuf = nullptr; +} + +// TODO use SDL_SetGPUScissor(SDL_GPURenderPass *render_pass, const SDL_Rect *scissor) when srcRect isn't 100% of +// texture + +void Create2DTransformMatrix( + const SDL_Rect& dstRect, + float scale, + float offsetX, + float offsetY, + D3DRMMATRIX4D& outMatrix +) +{ + float x = static_cast(dstRect.x) * scale + offsetX; + float y = static_cast(dstRect.y) * scale + offsetY; + float w = static_cast(dstRect.w) * scale; + float h = static_cast(dstRect.h) * scale; + + D3DVALUE tmp[4][4] = {{w, 0, 0, 0}, {0, h, 0, 0}, {0, 0, 1, 0}, {x, y, 0, 1}}; + memcpy(outMatrix, tmp, sizeof(tmp)); +} + +void CreateOrthographicProjection(float width, float height, D3DRMMATRIX4D& outProj) +{ + D3DVALUE tmp[4][4] = { + {2.0f / width, 0.0f, 0.0f, 0.0f}, + {0.0f, -2.0f / height, 0.0f, 0.0f}, + {0.0f, 0.0f, 1.0f, 0.0f}, + {-1.0f, 1.0f, 0.0f, 1.0f} + }; + memcpy(outProj, tmp, sizeof(tmp)); +} + +void Direct3DRMSDL3GPURenderer::Draw2DImage(Uint32 textureId, const SDL_Rect& srcRect, const SDL_Rect& dstRect) +{ + if (!m_renderPass) { + StartRenderPass(0, 0, 0, false); + } + SDL_BindGPUGraphicsPipeline(m_renderPass, m_uiPipeline); + + const SDL3TextureCache& tex = m_textures[textureId]; + + auto surface = static_cast(tex.texture->m_surface); + float scaleX = static_cast(dstRect.w) / srcRect.w; + float scaleY = static_cast(dstRect.h) / srcRect.h; + SDL_Rect expandedDstRect = { + static_cast(std::round(dstRect.x - srcRect.x * scaleX)), + static_cast(std::round(dstRect.y - srcRect.y * scaleY)), + static_cast(std::round(static_cast(surface->m_surface->w) * scaleX)), + static_cast(std::round(static_cast(surface->m_surface->h) * scaleY)), + }; + + Create2DTransformMatrix( + expandedDstRect, + m_viewportTransform.scale, + m_viewportTransform.offsetX, + m_viewportTransform.offsetY, + m_uniforms.worldViewMatrix + ); + + CreateOrthographicProjection((float) m_width, (float) m_height, m_uniforms.projection); + + SceneLight fullBright = {{1, 1, 1, 1}, {0, 0, 0}, 0, {0, 0, 0}, 0}; + memcpy(&m_fragmentShadingData.lights, &fullBright, sizeof(SceneLight)); + m_fragmentShadingData.lightCount = 1; + m_fragmentShadingData.color = {0xff, 0xff, 0xff, 0xff}; + m_fragmentShadingData.shininess = 0.0f; + m_fragmentShadingData.useTexture = 1; + + SDL_GPUTextureSamplerBinding samplerBinding = {tex.gpuTexture, m_uiSampler}; + SDL_BindGPUFragmentSamplers(m_renderPass, 0, &samplerBinding, 1); + SDL_PushGPUVertexUniformData(m_cmdbuf, 0, &m_uniforms, sizeof(m_uniforms)); + SDL_PushGPUFragmentUniformData(m_cmdbuf, 0, &m_fragmentShadingData, sizeof(m_fragmentShadingData)); + SDL_GPUBufferBinding vertexBufferBinding = {m_uiMeshCache.vertexBuffer}; + SDL_BindGPUVertexBuffers(m_renderPass, 0, &vertexBufferBinding, 1); + SDL_GPUBufferBinding indexBufferBinding = {m_uiMeshCache.indexBuffer}; + SDL_BindGPUIndexBuffer(m_renderPass, &indexBufferBinding, SDL_GPU_INDEXELEMENTSIZE_16BIT); + + SDL_Rect scissor; + scissor.x = static_cast(std::round(dstRect.x * m_viewportTransform.scale + m_viewportTransform.offsetX)); + scissor.y = static_cast(std::round(dstRect.y * m_viewportTransform.scale + m_viewportTransform.offsetY)); + scissor.w = static_cast(std::round(dstRect.w * m_viewportTransform.scale)); + scissor.h = static_cast(std::round(dstRect.h * m_viewportTransform.scale)); + SDL_SetGPUScissor(m_renderPass, &scissor); + + SDL_DrawGPUIndexedPrimitives(m_renderPass, m_uiMeshCache.indexCount, 1, 0, 0, 0); + + SDL_Rect fullViewport = {0, 0, m_width, m_height}; + SDL_SetGPUScissor(m_renderPass, &fullViewport); +} + +void Direct3DRMSDL3GPURenderer::Download(SDL_Surface* target) +{ + if (!m_cmdbuf) { + StartRenderPass(0, 0, 0, false); + } + if (m_renderPass) { + SDL_EndGPURenderPass(m_renderPass); + m_renderPass = nullptr; + } + + const int offsetX = static_cast(m_viewportTransform.offsetX); + const int offsetY = static_cast(m_viewportTransform.offsetY); + const int width = m_width - offsetX * 2; + const int height = m_height - offsetY * 2; - // Download rendered image SDL_GPUTextureRegion region = {}; region.texture = m_transferTexture; - region.w = m_width; - region.h = m_height; + region.x = offsetX; + region.y = offsetY; + region.w = width; + region.h = height; region.d = 1; + SDL_GPUTextureTransferInfo transferInfo = {}; transferInfo.transfer_buffer = m_downloadBuffer; @@ -792,27 +1061,24 @@ HRESULT Direct3DRMSDL3GPURenderer::FinalizeFrame() WaitForPendingUpload(); - // Render the frame SDL_GPUFence* fence = SDL_SubmitGPUCommandBufferAndAcquireFence(m_cmdbuf); m_cmdbuf = nullptr; - if (!fence) { - return DDERR_GENERIC; + + if (!fence || !SDL_WaitForGPUFences(m_device, true, &fence, 1)) { + SDL_ReleaseGPUFence(m_device, fence); + return; } - bool success = SDL_WaitForGPUFences(m_device, true, &fence, 1); SDL_ReleaseGPUFence(m_device, fence); - if (!success) { - return DDERR_GENERIC; - } + void* downloadedData = SDL_MapGPUTransferBuffer(m_device, m_downloadBuffer, false); if (!downloadedData) { - return DDERR_GENERIC; + return; } SDL_Surface* renderedImage = - SDL_CreateSurfaceFrom(m_width, m_height, SDL_PIXELFORMAT_ABGR8888, downloadedData, m_width * 4); - SDL_BlitSurface(renderedImage, nullptr, DDBackBuffer, nullptr); + SDL_CreateSurfaceFrom(width, height, SDL_PIXELFORMAT_ARGB8888, downloadedData, width * 4); + + SDL_BlitSurfaceScaled(renderedImage, nullptr, target, nullptr, SDL_SCALEMODE_NEAREST); SDL_DestroySurface(renderedImage); SDL_UnmapGPUTransferBuffer(m_device, m_downloadBuffer); - - return DD_OK; } diff --git a/miniwin/src/d3drm/backends/sdl3gpu/shaders/generated/SolidColor.frag.h b/miniwin/src/d3drm/backends/sdl3gpu/shaders/generated/SolidColor.frag.h index ae843a2b..ebdbe79d 100644 --- a/miniwin/src/d3drm/backends/sdl3gpu/shaders/generated/SolidColor.frag.h +++ b/miniwin/src/d3drm/backends/sdl3gpu/shaders/generated/SolidColor.frag.h @@ -10,9 +10,9 @@ // DXIL only makes sense on Windows platforms #if defined(SDL_PLATFORM_WINDOWS) -static const Uint8 SolidColor_frag_dxil[6640] = { - 0x44, 0x58, 0x42, 0x43, 0x91, 0x24, 0xbe, 0xd8, 0x43, 0x8d, 0x7f, 0xf4, 0x71, 0x2b, 0x59, 0x98, - 0x2d, 0x7f, 0x8d, 0xac, 0x01, 0x00, 0x00, 0x00, 0xf0, 0x19, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, +static const Uint8 SolidColor_frag_dxil[6648] = { + 0x44, 0x58, 0x42, 0x43, 0xd8, 0xfe, 0x4c, 0xec, 0x17, 0x1b, 0x52, 0xee, 0xf7, 0xc8, 0x8d, 0xcf, + 0x47, 0x0e, 0xfe, 0xb7, 0x01, 0x00, 0x00, 0x00, 0xf8, 0x19, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0xf4, 0x00, 0x00, 0x00, 0x58, 0x01, 0x00, 0x00, 0xc4, 0x02, 0x00, 0x00, 0x94, 0x0c, 0x00, 0x00, 0xb0, 0x0c, 0x00, 0x00, 0x53, 0x46, 0x49, 0x30, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x49, 0x53, 0x47, 0x31, @@ -52,7 +52,7 @@ static const Uint8 SolidColor_frag_dxil[6640] = { 0x03, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x44, 0x10, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x11, 0x03, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x53, 0x54, 0x41, 0x54, 0xc8, 0x09, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, @@ -113,9 +113,9 @@ static const Uint8 SolidColor_frag_dxil[6640] = { 0x8c, 0x09, 0x26, 0x47, 0xc6, 0x04, 0x43, 0x22, 0x4a, 0x60, 0x04, 0xa0, 0x18, 0x8a, 0xa0, 0x24, 0xca, 0xa0, 0x80, 0x05, 0x0a, 0xac, 0x1c, 0x4a, 0xa3, 0x10, 0x0a, 0xa4, 0x80, 0x0a, 0x54, 0xa0, 0x50, 0x05, 0x0a, 0x56, 0xa0, 0x14, 0x0a, 0x57, 0xa0, 0x20, 0xca, 0xa3, 0x06, 0xca, 0x34, 0xa0, - 0x24, 0x07, 0xa8, 0x28, 0x89, 0x11, 0x80, 0x22, 0x28, 0x83, 0x42, 0x28, 0x90, 0x12, 0x29, 0x81, + 0x2c, 0x07, 0xa8, 0x28, 0x89, 0x11, 0x80, 0x22, 0x28, 0x83, 0x42, 0x28, 0x90, 0x12, 0x29, 0x81, 0x1a, 0xa0, 0xad, 0x06, 0x48, 0x9c, 0x01, 0xa0, 0x71, 0x06, 0x80, 0xca, 0x19, 0x00, 0x32, 0x67, - 0x00, 0x08, 0x9d, 0x01, 0xa0, 0x74, 0x2c, 0x09, 0x22, 0x8e, 0xe3, 0x00, 0x8e, 0x03, 0x00, 0x8e, + 0x00, 0x08, 0x9d, 0x01, 0xa0, 0x74, 0x2c, 0x09, 0x22, 0x8e, 0xe3, 0x00, 0x9e, 0x07, 0x00, 0x8e, 0xe3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x79, 0x18, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x1a, 0x03, 0x4c, 0x90, 0x46, 0x02, 0x13, 0xc4, 0x31, 0x20, 0xc3, 0x1b, 0x43, 0x81, 0x93, 0x4b, 0xb3, 0x0b, 0xa3, 0x2b, 0x4b, 0x01, 0x89, 0x71, 0xc1, 0x71, 0x81, 0x71, 0xa1, 0xb9, 0xc1, 0xc9, @@ -213,10 +213,10 @@ static const Uint8 SolidColor_frag_dxil[6640] = { 0xe3, 0x4b, 0x93, 0x13, 0x11, 0x28, 0x35, 0x3d, 0xd4, 0xe4, 0x17, 0xb7, 0x6d, 0x04, 0xcf, 0x70, 0xf9, 0xce, 0xe3, 0x53, 0x0d, 0x10, 0x61, 0x7e, 0x71, 0xdb, 0x06, 0x40, 0x30, 0x00, 0xd2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x41, 0x53, 0x48, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x58, 0x63, 0x6a, 0xf1, 0xca, 0xdc, 0xf6, 0x75, 0x3d, 0x1e, 0x21, 0x9a, 0xb8, 0xa2, 0x91, 0xc3, - 0x44, 0x58, 0x49, 0x4c, 0x38, 0x0d, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x4e, 0x03, 0x00, 0x00, - 0x44, 0x58, 0x49, 0x4c, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x20, 0x0d, 0x00, 0x00, - 0x42, 0x43, 0xc0, 0xde, 0x21, 0x0c, 0x00, 0x00, 0x45, 0x03, 0x00, 0x00, 0x0b, 0x82, 0x20, 0x00, + 0xeb, 0x0f, 0x40, 0x5f, 0x0e, 0x75, 0xec, 0xd9, 0x61, 0x1b, 0x68, 0x81, 0x54, 0xd3, 0xf4, 0x48, + 0x44, 0x58, 0x49, 0x4c, 0x40, 0x0d, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x50, 0x03, 0x00, 0x00, + 0x44, 0x58, 0x49, 0x4c, 0x00, 0x01, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x28, 0x0d, 0x00, 0x00, + 0x42, 0x43, 0xc0, 0xde, 0x21, 0x0c, 0x00, 0x00, 0x47, 0x03, 0x00, 0x00, 0x0b, 0x82, 0x20, 0x00, 0x02, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x07, 0x81, 0x23, 0x91, 0x41, 0xc8, 0x04, 0x49, 0x06, 0x10, 0x32, 0x39, 0x92, 0x01, 0x84, 0x0c, 0x25, 0x05, 0x08, 0x19, 0x1e, 0x04, 0x8b, 0x62, 0x80, 0x18, 0x45, 0x02, 0x42, 0x92, 0x0b, 0x42, 0xc4, 0x10, 0x32, 0x14, 0x38, 0x08, 0x18, 0x4b, @@ -272,7 +272,7 @@ static const Uint8 SolidColor_frag_dxil[6640] = { 0x8c, 0x09, 0x26, 0x47, 0xc6, 0x04, 0x43, 0x22, 0x4a, 0x60, 0x04, 0xa0, 0x20, 0x8a, 0xa1, 0x08, 0x4a, 0xa2, 0x0c, 0x0a, 0x58, 0xa0, 0x1c, 0xca, 0xa3, 0x06, 0xa8, 0x28, 0x89, 0x11, 0x80, 0x22, 0x28, 0x83, 0x42, 0x28, 0x90, 0x12, 0x29, 0x81, 0x1a, 0x20, 0x71, 0x06, 0x80, 0xcc, 0x19, 0x00, - 0x42, 0x67, 0x00, 0x28, 0x1d, 0x4b, 0x82, 0x88, 0xe3, 0x38, 0x80, 0xe3, 0x00, 0x80, 0xe3, 0x38, + 0x42, 0x67, 0x00, 0x28, 0x1d, 0x4b, 0x82, 0x88, 0xe3, 0x38, 0x80, 0xe7, 0x01, 0x80, 0xe3, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x79, 0x18, 0x00, 0x00, 0x7d, 0x00, 0x00, 0x00, 0x1a, 0x03, 0x4c, 0x90, 0x46, 0x02, 0x13, 0xc4, 0x31, 0x20, 0xc3, 0x1b, 0x43, 0x81, 0x93, 0x4b, 0xb3, 0x0b, 0xa3, 0x2b, 0x4b, 0x01, 0x89, 0x71, 0xc1, 0x71, 0x81, 0x71, 0xa1, 0xb9, 0xc1, 0xc9, @@ -336,7 +336,7 @@ static const Uint8 SolidColor_frag_dxil[6640] = { 0x9b, 0x01, 0x34, 0x5c, 0xbe, 0xf3, 0xf8, 0x12, 0xc0, 0x3c, 0x0b, 0xe1, 0x17, 0xb7, 0x6d, 0x02, 0xd5, 0x70, 0xf9, 0xce, 0xe3, 0x4b, 0x93, 0x13, 0x11, 0x28, 0x35, 0x3d, 0xd4, 0xe4, 0x17, 0xb7, 0x6d, 0x04, 0xcf, 0x70, 0xf9, 0xce, 0xe3, 0x53, 0x0d, 0x10, 0x61, 0x7e, 0x71, 0xdb, 0x06, 0x40, - 0x30, 0x00, 0xd2, 0x00, 0x61, 0x20, 0x00, 0x00, 0x64, 0x01, 0x00, 0x00, 0x13, 0x04, 0x52, 0x2c, + 0x30, 0x00, 0xd2, 0x00, 0x61, 0x20, 0x00, 0x00, 0x66, 0x01, 0x00, 0x00, 0x13, 0x04, 0x52, 0x2c, 0x10, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0xb4, 0x8d, 0x00, 0x10, 0x51, 0x78, 0x05, 0x52, 0x30, 0xa5, 0x32, 0x03, 0x50, 0x76, 0x85, 0x50, 0x46, 0x85, 0x54, 0x6e, 0xa5, 0x50, 0x72, 0x25, 0x53, 0xfe, 0x03, 0xe5, 0x42, 0xc3, 0x0c, 0xc0, 0x18, 0x41, 0x48, 0x82, 0x21, 0xde, 0x8d, 0x11, @@ -413,25 +413,26 @@ static const Uint8 SolidColor_frag_dxil[6640] = { 0xc4, 0xe0, 0x00, 0x40, 0x10, 0x0c, 0x9c, 0xd8, 0x58, 0x8b, 0x21, 0x2c, 0x46, 0x13, 0xb8, 0x61, 0xb8, 0x21, 0x68, 0x0d, 0x30, 0x98, 0x65, 0x88, 0xa0, 0x60, 0xc4, 0xe0, 0x01, 0x40, 0x10, 0x0c, 0xa6, 0xd9, 0xb0, 0x0b, 0xb1, 0x08, 0x8b, 0x9d, 0xd0, 0x89, 0xb3, 0x38, 0x0b, 0xd7, 0x70, 0x0d, - 0xb9, 0x38, 0x8b, 0xd1, 0x84, 0x00, 0x18, 0x4d, 0x10, 0x82, 0xd1, 0x84, 0x41, 0xb0, 0x21, 0x91, - 0x8f, 0x0d, 0x89, 0x7c, 0x6c, 0x48, 0xe4, 0x33, 0x62, 0x70, 0x00, 0x20, 0x08, 0x06, 0xce, 0x6e, - 0xd8, 0xc5, 0xa0, 0x16, 0x23, 0x06, 0x07, 0x00, 0x82, 0x60, 0xe0, 0xf0, 0xc6, 0x5d, 0x0c, 0x6b, - 0x31, 0x62, 0x70, 0x00, 0x20, 0x08, 0x06, 0x4e, 0x6f, 0xe0, 0xc5, 0xc0, 0x16, 0x23, 0x06, 0x07, - 0x00, 0x82, 0x60, 0xe0, 0xf8, 0x06, 0x5e, 0x0c, 0x6e, 0x31, 0x62, 0x70, 0x00, 0x20, 0x08, 0x06, - 0xce, 0x6f, 0xe4, 0xc5, 0xf0, 0x16, 0x23, 0x06, 0x07, 0x00, 0x82, 0x60, 0xe0, 0x80, 0x87, 0x5e, - 0x0c, 0x70, 0x31, 0x4b, 0x10, 0x0d, 0x54, 0x0c, 0x06, 0x44, 0x06, 0xcf, 0x40, 0xc5, 0x60, 0x40, - 0x64, 0xf0, 0x0c, 0x54, 0x0c, 0x06, 0x44, 0x06, 0xcf, 0x88, 0x41, 0x02, 0x80, 0x20, 0x18, 0x20, - 0xe7, 0xc1, 0x17, 0xbe, 0xe1, 0x1b, 0xb3, 0x31, 0x8c, 0x18, 0x24, 0x00, 0x08, 0x82, 0x01, 0x72, - 0x1e, 0x7c, 0xe1, 0x1b, 0xbe, 0xd1, 0x1a, 0xc2, 0x88, 0x41, 0x02, 0x80, 0x20, 0x18, 0x20, 0xe7, - 0xc1, 0x17, 0xbe, 0xe1, 0x1b, 0xb2, 0x11, 0x8c, 0x18, 0x24, 0x00, 0x08, 0x82, 0x01, 0x72, 0x1e, - 0x7c, 0xe1, 0x1b, 0xbe, 0x11, 0x1b, 0x6a, 0x30, 0x62, 0x90, 0x00, 0x20, 0x08, 0x06, 0xc8, 0x79, - 0xf0, 0xc5, 0x6f, 0xf8, 0xc6, 0x6c, 0x98, 0x05, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xb9, 0x38, 0x8b, 0xd1, 0x84, 0x00, 0x18, 0x4d, 0x10, 0x82, 0xd1, 0x84, 0x41, 0x18, 0x4d, 0x20, + 0x06, 0x23, 0x14, 0xf9, 0x18, 0xa1, 0xc8, 0xc7, 0x08, 0x45, 0x3e, 0x23, 0x06, 0x07, 0x00, 0x82, + 0x60, 0xe0, 0xf0, 0xc6, 0x5d, 0x0c, 0x6b, 0x31, 0x62, 0x70, 0x00, 0x20, 0x08, 0x06, 0x4e, 0x6f, + 0xe0, 0xc5, 0xc0, 0x16, 0x23, 0x06, 0x07, 0x00, 0x82, 0x60, 0xe0, 0xf8, 0x46, 0x5e, 0x0c, 0x6d, + 0x31, 0x62, 0x70, 0x00, 0x20, 0x08, 0x06, 0xce, 0x6f, 0xe4, 0xc5, 0xf0, 0x16, 0x23, 0x06, 0x07, + 0x00, 0x82, 0x60, 0xe0, 0x80, 0x87, 0x5e, 0x0c, 0x70, 0x31, 0x62, 0x70, 0x00, 0x20, 0x08, 0x06, + 0x4e, 0x78, 0xec, 0xc5, 0x10, 0x17, 0xb3, 0x04, 0xd1, 0x40, 0xc5, 0x60, 0x40, 0x66, 0xf0, 0x0c, + 0x54, 0x0c, 0x06, 0x64, 0x06, 0xcf, 0x40, 0xc5, 0x60, 0x40, 0x66, 0xf0, 0x0c, 0x54, 0x0c, 0x1a, + 0x64, 0x0b, 0xcf, 0x88, 0x41, 0x02, 0x80, 0x20, 0x18, 0x20, 0xe9, 0xe1, 0x17, 0xe0, 0x01, 0x1e, + 0xb5, 0x41, 0x8c, 0x18, 0x24, 0x00, 0x08, 0x82, 0x01, 0x92, 0x1e, 0x7e, 0x01, 0x1e, 0xe0, 0xf1, + 0x1a, 0xc3, 0x88, 0x41, 0x02, 0x80, 0x20, 0x18, 0x20, 0xe9, 0xe1, 0x17, 0xe0, 0x01, 0x1e, 0xb4, + 0x21, 0x8c, 0x18, 0x24, 0x00, 0x08, 0x82, 0x01, 0x92, 0x1e, 0x7e, 0x01, 0x1e, 0xe0, 0x31, 0x1b, + 0xc1, 0x88, 0x41, 0x02, 0x80, 0x20, 0x18, 0x20, 0xe9, 0xe1, 0x17, 0xe1, 0x01, 0x1e, 0xb5, 0x81, + 0x16, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; #endif // MSL only makes sense on Apple platforms #if defined(SDL_PLATFORM_APPLE) -static const Uint8 SolidColor_frag_msl[3333] = { +static const Uint8 SolidColor_frag_msl[3377] = { 0x23, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x20, 0x3c, 0x6d, 0x65, 0x74, 0x61, 0x6c, 0x5f, 0x73, 0x74, 0x64, 0x6c, 0x69, 0x62, 0x3e, 0x0a, 0x23, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x20, 0x3c, 0x73, 0x69, 0x6d, 0x64, 0x2f, 0x73, 0x69, 0x6d, 0x64, 0x2e, 0x68, 0x3e, 0x0a, 0x0a, @@ -620,32 +621,35 @@ static const Uint8 SolidColor_frag_msl[3333] = { 0x78, 0x79, 0x7a, 0x29, 0x20, 0x2b, 0x20, 0x5f, 0x36, 0x32, 0x2c, 0x20, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x33, 0x28, 0x30, 0x2e, 0x30, 0x29, 0x2c, 0x20, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x33, 0x28, 0x31, 0x2e, 0x30, 0x29, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x66, 0x6c, 0x6f, 0x61, 0x74, - 0x33, 0x20, 0x5f, 0x31, 0x36, 0x34, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x28, + 0x34, 0x20, 0x5f, 0x31, 0x37, 0x34, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x28, 0x46, 0x72, 0x61, 0x67, 0x6d, 0x65, 0x6e, 0x74, 0x53, 0x68, 0x61, 0x64, 0x69, 0x6e, 0x67, 0x44, 0x61, 0x74, 0x61, 0x2e, 0x55, 0x73, 0x65, 0x54, 0x65, 0x78, 0x74, 0x75, 0x72, 0x65, 0x20, 0x21, 0x3d, 0x20, 0x30, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x5f, 0x31, 0x36, 0x34, 0x20, 0x3d, 0x20, 0x66, 0x61, 0x73, 0x74, 0x3a, 0x3a, - 0x63, 0x6c, 0x61, 0x6d, 0x70, 0x28, 0x54, 0x65, 0x78, 0x74, 0x75, 0x72, 0x65, 0x2e, 0x73, 0x61, - 0x6d, 0x70, 0x6c, 0x65, 0x28, 0x53, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x72, 0x2c, 0x20, 0x69, 0x6e, - 0x2e, 0x69, 0x6e, 0x5f, 0x76, 0x61, 0x72, 0x5f, 0x54, 0x45, 0x58, 0x43, 0x4f, 0x4f, 0x52, 0x44, - 0x31, 0x29, 0x2e, 0x78, 0x79, 0x7a, 0x20, 0x2a, 0x20, 0x5f, 0x31, 0x35, 0x31, 0x2c, 0x20, 0x66, - 0x6c, 0x6f, 0x61, 0x74, 0x33, 0x28, 0x30, 0x2e, 0x30, 0x29, 0x2c, 0x20, 0x66, 0x6c, 0x6f, 0x61, - 0x74, 0x33, 0x28, 0x31, 0x2e, 0x30, 0x29, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x0a, - 0x20, 0x20, 0x20, 0x20, 0x65, 0x6c, 0x73, 0x65, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x7b, 0x0a, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x5f, 0x31, 0x36, 0x34, 0x20, 0x3d, 0x20, 0x5f, 0x31, - 0x35, 0x31, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6f, 0x75, - 0x74, 0x2e, 0x6f, 0x75, 0x74, 0x5f, 0x76, 0x61, 0x72, 0x5f, 0x53, 0x56, 0x5f, 0x54, 0x61, 0x72, - 0x67, 0x65, 0x74, 0x30, 0x20, 0x3d, 0x20, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x34, 0x28, 0x5f, 0x31, - 0x36, 0x34, 0x2c, 0x20, 0x5f, 0x31, 0x34, 0x36, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6f, - 0x75, 0x74, 0x2e, 0x67, 0x6c, 0x5f, 0x46, 0x72, 0x61, 0x67, 0x44, 0x65, 0x70, 0x74, 0x68, 0x20, - 0x3d, 0x20, 0x67, 0x6c, 0x5f, 0x46, 0x72, 0x61, 0x67, 0x43, 0x6f, 0x6f, 0x72, 0x64, 0x2e, 0x77, - 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x6f, 0x75, 0x74, - 0x3b, 0x0a, 0x7d, 0x0a, 0x0a, + 0x20, 0x20, 0x20, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x34, 0x20, 0x5f, 0x31, 0x36, 0x31, 0x20, 0x3d, + 0x20, 0x54, 0x65, 0x78, 0x74, 0x75, 0x72, 0x65, 0x2e, 0x73, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x28, + 0x53, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x72, 0x2c, 0x20, 0x69, 0x6e, 0x2e, 0x69, 0x6e, 0x5f, 0x76, + 0x61, 0x72, 0x5f, 0x54, 0x45, 0x58, 0x43, 0x4f, 0x4f, 0x52, 0x44, 0x31, 0x29, 0x3b, 0x0a, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x5f, 0x31, 0x37, 0x34, 0x20, 0x3d, 0x20, 0x66, 0x6c, + 0x6f, 0x61, 0x74, 0x34, 0x28, 0x66, 0x61, 0x73, 0x74, 0x3a, 0x3a, 0x63, 0x6c, 0x61, 0x6d, 0x70, + 0x28, 0x5f, 0x31, 0x36, 0x31, 0x2e, 0x78, 0x79, 0x7a, 0x20, 0x2a, 0x20, 0x5f, 0x31, 0x35, 0x31, + 0x2c, 0x20, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x33, 0x28, 0x30, 0x2e, 0x30, 0x29, 0x2c, 0x20, 0x66, + 0x6c, 0x6f, 0x61, 0x74, 0x33, 0x28, 0x31, 0x2e, 0x30, 0x29, 0x29, 0x2c, 0x20, 0x5f, 0x31, 0x36, + 0x31, 0x2e, 0x77, 0x29, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x7d, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x65, 0x6c, 0x73, 0x65, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x5f, 0x31, 0x37, 0x34, 0x20, 0x3d, 0x20, 0x66, 0x6c, 0x6f, 0x61, 0x74, 0x34, + 0x28, 0x5f, 0x31, 0x35, 0x31, 0x2c, 0x20, 0x5f, 0x31, 0x34, 0x36, 0x29, 0x3b, 0x0a, 0x20, 0x20, + 0x20, 0x20, 0x7d, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6f, 0x75, 0x74, 0x2e, 0x6f, 0x75, 0x74, 0x5f, + 0x76, 0x61, 0x72, 0x5f, 0x53, 0x56, 0x5f, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x30, 0x20, 0x3d, + 0x20, 0x5f, 0x31, 0x37, 0x34, 0x3b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6f, 0x75, 0x74, 0x2e, 0x67, + 0x6c, 0x5f, 0x46, 0x72, 0x61, 0x67, 0x44, 0x65, 0x70, 0x74, 0x68, 0x20, 0x3d, 0x20, 0x67, 0x6c, + 0x5f, 0x46, 0x72, 0x61, 0x67, 0x43, 0x6f, 0x6f, 0x72, 0x64, 0x2e, 0x77, 0x3b, 0x0a, 0x20, 0x20, + 0x20, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x6f, 0x75, 0x74, 0x3b, 0x0a, 0x7d, 0x0a, + 0x0a, }; #endif -static const Uint8 SolidColor_frag_spirv[4492] = { - 0x03, 0x02, 0x23, 0x07, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0e, 0x00, 0xab, 0x00, 0x00, 0x00, +static const Uint8 SolidColor_frag_spirv[4616] = { + 0x03, 0x02, 0x23, 0x07, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0e, 0x00, 0xb1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x06, 0x00, 0x01, 0x00, 0x00, 0x00, 0x47, 0x4c, 0x53, 0x4c, 0x2e, 0x73, 0x74, 0x64, 0x2e, 0x34, 0x35, 0x30, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, @@ -902,28 +906,36 @@ static const Uint8 SolidColor_frag_spirv[4492] = { 0x16, 0x00, 0x00, 0x00, 0x99, 0x00, 0x00, 0x00, 0x98, 0x00, 0x00, 0x00, 0xab, 0x00, 0x05, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x9a, 0x00, 0x00, 0x00, 0x99, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, 0xf7, 0x00, 0x03, 0x00, 0x9b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfa, 0x00, 0x04, 0x00, - 0x9a, 0x00, 0x00, 0x00, 0x9c, 0x00, 0x00, 0x00, 0x9b, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, - 0x9c, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x9d, 0x00, 0x00, 0x00, - 0x0d, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x9e, 0x00, 0x00, 0x00, - 0x0f, 0x00, 0x00, 0x00, 0x56, 0x00, 0x05, 0x00, 0x10, 0x00, 0x00, 0x00, 0x9f, 0x00, 0x00, 0x00, - 0x9d, 0x00, 0x00, 0x00, 0x9e, 0x00, 0x00, 0x00, 0x57, 0x00, 0x06, 0x00, 0x27, 0x00, 0x00, 0x00, - 0xa0, 0x00, 0x00, 0x00, 0x9f, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x4f, 0x00, 0x08, 0x00, 0x14, 0x00, 0x00, 0x00, 0xa1, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x00, - 0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x85, 0x00, 0x05, 0x00, 0x14, 0x00, 0x00, 0x00, 0xa2, 0x00, 0x00, 0x00, 0xa1, 0x00, 0x00, 0x00, - 0x97, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x08, 0x00, 0x14, 0x00, 0x00, 0x00, 0xa3, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x00, 0x00, 0xa2, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, - 0x1e, 0x00, 0x00, 0x00, 0xf9, 0x00, 0x02, 0x00, 0x9b, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, - 0x9b, 0x00, 0x00, 0x00, 0xf5, 0x00, 0x07, 0x00, 0x14, 0x00, 0x00, 0x00, 0xa4, 0x00, 0x00, 0x00, - 0x97, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0xa3, 0x00, 0x00, 0x00, 0x9c, 0x00, 0x00, 0x00, - 0x51, 0x00, 0x05, 0x00, 0x12, 0x00, 0x00, 0x00, 0xa5, 0x00, 0x00, 0x00, 0xa4, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x51, 0x00, 0x05, 0x00, 0x12, 0x00, 0x00, 0x00, 0xa6, 0x00, 0x00, 0x00, - 0xa4, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x51, 0x00, 0x05, 0x00, 0x12, 0x00, 0x00, 0x00, - 0xa7, 0x00, 0x00, 0x00, 0xa4, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x50, 0x00, 0x07, 0x00, - 0x27, 0x00, 0x00, 0x00, 0xa8, 0x00, 0x00, 0x00, 0xa5, 0x00, 0x00, 0x00, 0xa6, 0x00, 0x00, 0x00, - 0xa7, 0x00, 0x00, 0x00, 0x92, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x38, 0x00, 0x00, 0x00, - 0xa9, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, - 0x12, 0x00, 0x00, 0x00, 0xaa, 0x00, 0x00, 0x00, 0xa9, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, - 0x07, 0x00, 0x00, 0x00, 0xa8, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x08, 0x00, 0x00, 0x00, - 0xaa, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x01, 0x00, 0x38, 0x00, 0x01, 0x00, + 0x9a, 0x00, 0x00, 0x00, 0x9c, 0x00, 0x00, 0x00, 0x9d, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, + 0x9c, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x9e, 0x00, 0x00, 0x00, + 0x0d, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x9f, 0x00, 0x00, 0x00, + 0x0f, 0x00, 0x00, 0x00, 0x56, 0x00, 0x05, 0x00, 0x10, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x00, + 0x9e, 0x00, 0x00, 0x00, 0x9f, 0x00, 0x00, 0x00, 0x57, 0x00, 0x06, 0x00, 0x27, 0x00, 0x00, 0x00, + 0xa1, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x4f, 0x00, 0x08, 0x00, 0x14, 0x00, 0x00, 0x00, 0xa2, 0x00, 0x00, 0x00, 0xa1, 0x00, 0x00, 0x00, + 0xa1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x85, 0x00, 0x05, 0x00, 0x14, 0x00, 0x00, 0x00, 0xa3, 0x00, 0x00, 0x00, 0xa2, 0x00, 0x00, 0x00, + 0x97, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x08, 0x00, 0x14, 0x00, 0x00, 0x00, 0xa4, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x00, 0x00, 0xa3, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, + 0x1e, 0x00, 0x00, 0x00, 0x51, 0x00, 0x05, 0x00, 0x12, 0x00, 0x00, 0x00, 0xa5, 0x00, 0x00, 0x00, + 0xa1, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x51, 0x00, 0x05, 0x00, 0x12, 0x00, 0x00, 0x00, + 0xa6, 0x00, 0x00, 0x00, 0xa4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x51, 0x00, 0x05, 0x00, + 0x12, 0x00, 0x00, 0x00, 0xa7, 0x00, 0x00, 0x00, 0xa4, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x51, 0x00, 0x05, 0x00, 0x12, 0x00, 0x00, 0x00, 0xa8, 0x00, 0x00, 0x00, 0xa4, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x50, 0x00, 0x07, 0x00, 0x27, 0x00, 0x00, 0x00, 0xa9, 0x00, 0x00, 0x00, + 0xa6, 0x00, 0x00, 0x00, 0xa7, 0x00, 0x00, 0x00, 0xa8, 0x00, 0x00, 0x00, 0xa5, 0x00, 0x00, 0x00, + 0xf9, 0x00, 0x02, 0x00, 0x9b, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x02, 0x00, 0x9d, 0x00, 0x00, 0x00, + 0x51, 0x00, 0x05, 0x00, 0x12, 0x00, 0x00, 0x00, 0xaa, 0x00, 0x00, 0x00, 0x97, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x51, 0x00, 0x05, 0x00, 0x12, 0x00, 0x00, 0x00, 0xab, 0x00, 0x00, 0x00, + 0x97, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x51, 0x00, 0x05, 0x00, 0x12, 0x00, 0x00, 0x00, + 0xac, 0x00, 0x00, 0x00, 0x97, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x50, 0x00, 0x07, 0x00, + 0x27, 0x00, 0x00, 0x00, 0xad, 0x00, 0x00, 0x00, 0xaa, 0x00, 0x00, 0x00, 0xab, 0x00, 0x00, 0x00, + 0xac, 0x00, 0x00, 0x00, 0x92, 0x00, 0x00, 0x00, 0xf9, 0x00, 0x02, 0x00, 0x9b, 0x00, 0x00, 0x00, + 0xf8, 0x00, 0x02, 0x00, 0x9b, 0x00, 0x00, 0x00, 0xf5, 0x00, 0x07, 0x00, 0x27, 0x00, 0x00, 0x00, + 0xae, 0x00, 0x00, 0x00, 0xa9, 0x00, 0x00, 0x00, 0x9c, 0x00, 0x00, 0x00, 0xad, 0x00, 0x00, 0x00, + 0x9d, 0x00, 0x00, 0x00, 0x41, 0x00, 0x05, 0x00, 0x38, 0x00, 0x00, 0x00, 0xaf, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x04, 0x00, 0x12, 0x00, 0x00, 0x00, + 0xb0, 0x00, 0x00, 0x00, 0xaf, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x07, 0x00, 0x00, 0x00, + 0xae, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x03, 0x00, 0x08, 0x00, 0x00, 0x00, 0xb0, 0x00, 0x00, 0x00, + 0xfd, 0x00, 0x01, 0x00, 0x38, 0x00, 0x01, 0x00, }; diff --git a/miniwin/src/d3drm/backends/sdl3gpu/shaders/src/SolidColor.frag.hlsl b/miniwin/src/d3drm/backends/sdl3gpu/shaders/src/SolidColor.frag.hlsl index 7e9a0c6d..6a6608ba 100644 --- a/miniwin/src/d3drm/backends/sdl3gpu/shaders/src/SolidColor.frag.hlsl +++ b/miniwin/src/d3drm/backends/sdl3gpu/shaders/src/SolidColor.frag.hlsl @@ -72,8 +72,11 @@ FS_Output main(FS_Input input) if (UseTexture != 0) { float4 texel = Texture.Sample(Sampler, input.TexCoord); finalColor = saturate(texel.rgb * finalColor); + output.Color = float4(finalColor, texel.a); + } + else { + output.Color = float4(finalColor, Color.a); } - output.Color = float4(finalColor, Color.a); output.Depth = input.Position.w; return output; } diff --git a/miniwin/src/d3drm/backends/software/renderer.cpp b/miniwin/src/d3drm/backends/software/renderer.cpp index 563821b2..64adc93b 100644 --- a/miniwin/src/d3drm/backends/software/renderer.cpp +++ b/miniwin/src/d3drm/backends/software/renderer.cpp @@ -23,9 +23,22 @@ #include #endif -Direct3DRMSoftwareRenderer::Direct3DRMSoftwareRenderer(DWORD width, DWORD height) : m_width(width), m_height(height) +Direct3DRMSoftwareRenderer::Direct3DRMSoftwareRenderer(DWORD width, DWORD height) { - m_zBuffer.resize(m_width * m_height); + m_virtualWidth = width; + m_virtualHeight = height; + + m_renderer = SDL_CreateRenderer(DDWindow, NULL); + + ViewportTransform viewportTransform = {1.0f, 0.0f, 0.0f}; + Resize(width, height, viewportTransform); +} + +Direct3DRMSoftwareRenderer::~Direct3DRMSoftwareRenderer() +{ + SDL_DestroySurface(m_renderedImage); + SDL_DestroyTexture(m_uploadBuffer); + SDL_DestroyRenderer(m_renderer); } void Direct3DRMSoftwareRenderer::PushLights(const SceneLight* lights, size_t count) @@ -354,8 +367,8 @@ void Direct3DRMSoftwareRenderer::DrawTriangleProjected( c2 = ApplyLighting(v2.position, v2.normal, appearance); } - Uint8* pixels = (Uint8*) DDBackBuffer->pixels; - int pitch = DDBackBuffer->pitch; + Uint8* pixels = (Uint8*) m_renderedImage->pixels; + int pitch = m_renderedImage->pitch; VertexXY verts[3] = { {p0.x, p0.y, p0.z, p0.w, c0, v0.texCoord.u, v0.texCoord.v}, @@ -553,7 +566,7 @@ Uint32 Direct3DRMSoftwareRenderer::GetTextureId(IDirect3DRMTexture* iTexture) if (texRef.version != texture->m_version) { // Update animated textures SDL_DestroySurface(texRef.cached); - texRef.cached = SDL_ConvertSurface(surface->m_surface, DDBackBuffer->format); + texRef.cached = SDL_ConvertSurface(surface->m_surface, m_renderedImage->format); SDL_LockSurface(texRef.cached); texRef.version = texture->m_version; } @@ -561,7 +574,7 @@ Uint32 Direct3DRMSoftwareRenderer::GetTextureId(IDirect3DRMTexture* iTexture) } } - SDL_Surface* convertedRender = SDL_ConvertSurface(surface->m_surface, DDBackBuffer->format); + SDL_Surface* convertedRender = SDL_ConvertSurface(surface->m_surface, m_renderedImage->format); SDL_LockSurface(convertedRender); // Reuse freed slot @@ -651,16 +664,6 @@ Uint32 Direct3DRMSoftwareRenderer::GetMeshId(IDirect3DRMMesh* mesh, const MeshGr return (Uint32) (m_meshs.size() - 1); } -DWORD Direct3DRMSoftwareRenderer::GetWidth() -{ - return m_width; -} - -DWORD Direct3DRMSoftwareRenderer::GetHeight() -{ - return m_height; -} - void Direct3DRMSoftwareRenderer::GetDesc(D3DDEVICEDESC* halDesc, D3DDEVICEDESC* helDesc) { memset(halDesc, 0, sizeof(D3DDEVICEDESC)); @@ -681,13 +684,13 @@ const char* Direct3DRMSoftwareRenderer::GetName() HRESULT Direct3DRMSoftwareRenderer::BeginFrame() { - if (!DDBackBuffer || !SDL_LockSurface(DDBackBuffer)) { + if (!m_renderedImage || !SDL_LockSurface(m_renderedImage)) { return DDERR_GENERIC; } ClearZBuffer(); - m_format = SDL_GetPixelFormatDetails(DDBackBuffer->format); - m_palette = SDL_GetSurfacePalette(DDBackBuffer); + m_format = SDL_GetPixelFormatDetails(m_renderedImage->format); + m_palette = SDL_GetSurfacePalette(m_renderedImage); m_bytesPerPixel = m_format->bits_per_pixel / 8; return DD_OK; @@ -700,6 +703,8 @@ void Direct3DRMSoftwareRenderer::EnableTransparency() void Direct3DRMSoftwareRenderer::SubmitDraw( DWORD meshId, const D3DRMMATRIX4D& modelViewMatrix, + const D3DRMMATRIX4D& worldMatrix, + const D3DRMMATRIX4D& viewMatrix, const Matrix3x3& normalMatrix, const Appearance& appearance ) @@ -731,7 +736,84 @@ void Direct3DRMSoftwareRenderer::SubmitDraw( HRESULT Direct3DRMSoftwareRenderer::FinalizeFrame() { - SDL_UnlockSurface(DDBackBuffer); + SDL_UnlockSurface(m_renderedImage); return DD_OK; } + +void Direct3DRMSoftwareRenderer::Resize(int width, int height, const ViewportTransform& viewportTransform) +{ + m_viewportTransform = viewportTransform; + float aspect = static_cast(width) / height; + float virtualAspect = static_cast(m_virtualWidth) / m_virtualHeight; + + // Cap to virtual canvase for performance + if (aspect > virtualAspect) { + m_height = std::min(height, m_virtualHeight); + m_width = static_cast(m_height * aspect); + } + else { + m_width = std::min(width, m_virtualWidth); + m_height = static_cast(m_width / aspect); + } + + m_viewportTransform.scale = + std::min(static_cast(m_width) / m_virtualWidth, static_cast(m_height) / m_virtualHeight); + + m_viewportTransform.offsetX = (m_width - (m_virtualWidth * m_viewportTransform.scale)) / 2.0f; + m_viewportTransform.offsetY = (m_height - (m_virtualHeight * m_viewportTransform.scale)) / 2.0f; + + if (m_renderedImage) { + SDL_DestroySurface(m_renderedImage); + } + m_renderedImage = SDL_CreateSurface(m_width, m_height, SDL_PIXELFORMAT_RGBA32); + + if (m_uploadBuffer) { + SDL_DestroyTexture(m_uploadBuffer); + } + m_uploadBuffer = + SDL_CreateTexture(m_renderer, SDL_PIXELFORMAT_RGBA32, SDL_TEXTUREACCESS_STREAMING, m_width, m_height); + + m_zBuffer.resize(m_width * m_height); +} + +void Direct3DRMSoftwareRenderer::Clear(float r, float g, float b) +{ + SDL_Rect rect = {0, 0, m_renderedImage->w, m_renderedImage->h}; + const SDL_PixelFormatDetails* details = SDL_GetPixelFormatDetails(m_renderedImage->format); + Uint32 color = SDL_MapRGB(details, m_palette, r * 255, g * 255, b * 255); + SDL_FillSurfaceRect(m_renderedImage, &rect, color); +} + +void Direct3DRMSoftwareRenderer::Flip() +{ + SDL_UpdateTexture(m_uploadBuffer, nullptr, m_renderedImage->pixels, m_renderedImage->pitch); + SDL_RenderTexture(m_renderer, m_uploadBuffer, nullptr, nullptr); + SDL_RenderPresent(m_renderer); +} + +void Direct3DRMSoftwareRenderer::Draw2DImage(Uint32 textureId, const SDL_Rect& srcRect, const SDL_Rect& dstRect) +{ + SDL_Surface* surface = m_textures[textureId].cached; + SDL_UnlockSurface(surface); + SDL_Rect centeredRect = { + static_cast(dstRect.x * m_viewportTransform.scale + m_viewportTransform.offsetX), + static_cast(dstRect.y * m_viewportTransform.scale + m_viewportTransform.offsetY), + static_cast(dstRect.w * m_viewportTransform.scale), + static_cast(dstRect.h * m_viewportTransform.scale), + }; + SDL_BlitSurfaceScaled(surface, &srcRect, m_renderedImage, ¢eredRect, SDL_SCALEMODE_LINEAR); + SDL_LockSurface(surface); +} + +void Direct3DRMSoftwareRenderer::Download(SDL_Surface* target) +{ + SDL_Rect srcRect = { + static_cast(m_viewportTransform.offsetX), + static_cast(m_viewportTransform.offsetY), + static_cast(m_virtualWidth * m_viewportTransform.scale), + static_cast(m_virtualHeight * m_viewportTransform.scale), + }; + + SDL_BlitSurfaceScaled(m_renderedImage, &srcRect, target, nullptr, SDL_SCALEMODE_LINEAR); +} diff --git a/miniwin/src/d3drm/d3drm.cpp b/miniwin/src/d3drm/d3drm.cpp index 01375d8c..e8df37b1 100644 --- a/miniwin/src/d3drm/d3drm.cpp +++ b/miniwin/src/d3drm/d3drm.cpp @@ -127,7 +127,7 @@ HRESULT Direct3DRMImpl::CreateDeviceFromD3D( { auto renderer = static_cast(d3dDevice); *outDevice = static_cast( - new Direct3DRMDevice2Impl(renderer->GetWidth(), renderer->GetHeight(), renderer) + new Direct3DRMDevice2Impl(renderer->GetVirtualWidth(), renderer->GetVirtualHeight(), renderer) ); return DD_OK; } @@ -143,26 +143,25 @@ HRESULT Direct3DRMImpl::CreateDeviceFromSurface( DDSDesc.dwSize = sizeof(DDSURFACEDESC); surface->GetSurfaceDesc(&DDSDesc); - Direct3DRMRenderer* renderer; if (SDL_memcmp(&guid, &SDL3_GPU_GUID, sizeof(GUID)) == 0) { - renderer = Direct3DRMSDL3GPURenderer::Create(DDSDesc.dwWidth, DDSDesc.dwHeight); + DDRenderer = Direct3DRMSDL3GPURenderer::Create(DDSDesc.dwWidth, DDSDesc.dwHeight); } else if (SDL_memcmp(&guid, &SOFTWARE_GUID, sizeof(GUID)) == 0) { - renderer = new Direct3DRMSoftwareRenderer(DDSDesc.dwWidth, DDSDesc.dwHeight); + DDRenderer = new Direct3DRMSoftwareRenderer(DDSDesc.dwWidth, DDSDesc.dwHeight); } #ifdef USE_OPENGLES2 else if (SDL_memcmp(&guid, &OpenGLES2_GUID, sizeof(GUID)) == 0) { - renderer = OpenGLES2Renderer::Create(DDSDesc.dwWidth, DDSDesc.dwHeight); + DDRenderer = OpenGLES2Renderer::Create(DDSDesc.dwWidth, DDSDesc.dwHeight); } #endif #ifdef USE_OPENGL1 else if (SDL_memcmp(&guid, &OpenGL1_GUID, sizeof(GUID)) == 0) { - renderer = OpenGL1Renderer::Create(DDSDesc.dwWidth, DDSDesc.dwHeight); + DDRenderer = OpenGL1Renderer::Create(DDSDesc.dwWidth, DDSDesc.dwHeight); } #endif #ifdef _WIN32 else if (SDL_memcmp(&guid, &DirectX9_GUID, sizeof(GUID)) == 0) { - renderer = DirectX9Renderer::Create(DDSDesc.dwWidth, DDSDesc.dwHeight); + DDRenderer = DirectX9Renderer::Create(DDSDesc.dwWidth, DDSDesc.dwHeight); } #endif else { @@ -170,7 +169,7 @@ HRESULT Direct3DRMImpl::CreateDeviceFromSurface( return E_NOINTERFACE; } *outDevice = - static_cast(new Direct3DRMDevice2Impl(DDSDesc.dwWidth, DDSDesc.dwHeight, renderer)); + static_cast(new Direct3DRMDevice2Impl(DDSDesc.dwWidth, DDSDesc.dwHeight, DDRenderer)); return DD_OK; } @@ -181,9 +180,8 @@ HRESULT Direct3DRMImpl::CreateTexture(D3DRMIMAGE* image, IDirect3DRMTexture2** o } HRESULT Direct3DRMImpl::CreateTextureFromSurface(LPDIRECTDRAWSURFACE surface, IDirect3DRMTexture2** outTexture) - { - *outTexture = static_cast(new Direct3DRMTextureImpl(surface)); + *outTexture = static_cast(new Direct3DRMTextureImpl(surface, true)); return DD_OK; } diff --git a/miniwin/src/d3drm/d3drmdevice.cpp b/miniwin/src/d3drm/d3drmdevice.cpp index be850823..f6b2f9f7 100644 --- a/miniwin/src/d3drm/d3drmdevice.cpp +++ b/miniwin/src/d3drm/d3drmdevice.cpp @@ -11,8 +11,9 @@ #include Direct3DRMDevice2Impl::Direct3DRMDevice2Impl(DWORD width, DWORD height, Direct3DRMRenderer* renderer) - : m_width(width), m_height(height), m_renderer(renderer), m_viewports(new Direct3DRMViewportArrayImpl) + : m_virtualWidth(width), m_virtualHeight(height), m_renderer(renderer), m_viewports(new Direct3DRMViewportArrayImpl) { + Resize(); } Direct3DRMDevice2Impl::~Direct3DRMDevice2Impl() @@ -43,16 +44,6 @@ HRESULT Direct3DRMDevice2Impl::QueryInterface(const GUID& riid, void** ppvObject return E_NOINTERFACE; } -DWORD Direct3DRMDevice2Impl::GetWidth() -{ - return m_width; -} - -DWORD Direct3DRMDevice2Impl::GetHeight() -{ - return m_height; -} - HRESULT Direct3DRMDevice2Impl::SetBufferCount(int count) { MINIWIN_NOT_IMPLEMENTED(); @@ -133,7 +124,9 @@ HRESULT Direct3DRMDevice2Impl::Update() HRESULT Direct3DRMDevice2Impl::AddViewport(IDirect3DRMViewport* viewport) { - return m_viewports->AddElement(viewport); + HRESULT status = m_viewports->AddElement(viewport); + Resize(); + return status; } HRESULT Direct3DRMDevice2Impl::GetViewports(IDirect3DRMViewportArray** ppViewportArray) @@ -143,7 +136,53 @@ HRESULT Direct3DRMDevice2Impl::GetViewports(IDirect3DRMViewportArray** ppViewpor return DD_OK; } +ViewportTransform CalculateViewportTransform(int virtualW, int virtualH, int windowW, int windowH) +{ + float scaleX = (float) windowW / virtualW; + float scaleY = (float) windowH / virtualH; + float scale = (scaleX < scaleY) ? scaleX : scaleY; + + float viewportW = virtualW * scale; + float viewportH = virtualH * scale; + + float offsetX = (windowW - viewportW) * 0.5f; + float offsetY = (windowH - viewportH) * 0.5f; + + return {scale, offsetX, offsetY}; +} + +void Direct3DRMDevice2Impl::Resize() +{ + int width, height; + SDL_GetWindowSizeInPixels(DDWindow, &width, &height); + m_viewportTransform = CalculateViewportTransform(m_virtualWidth, m_virtualHeight, width, height); + m_renderer->Resize(width, height, m_viewportTransform); + for (int i = 0; i < m_viewports->GetSize(); i++) { + IDirect3DRMViewport* viewport; + m_viewports->GetElement(i, &viewport); + static_cast(viewport)->UpdateProjectionMatrix(); + } +} + bool Direct3DRMDevice2Impl::ConvertEventToRenderCoordinates(SDL_Event* event) { - return m_renderer->ConvertEventToRenderCoordinates(event); + switch (event->type) { + case SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED: { + Resize(); + break; + } + case SDL_EVENT_MOUSE_MOTION: + case SDL_EVENT_MOUSE_BUTTON_DOWN: + case SDL_EVENT_MOUSE_BUTTON_UP: { + int rawX = event->motion.x; + int rawY = event->motion.y; + float x = (rawX - m_viewportTransform.offsetX) / m_viewportTransform.scale; + float y = (rawY - m_viewportTransform.offsetY) / m_viewportTransform.scale; + event->motion.x = static_cast(x); + event->motion.y = static_cast(y); + break; + } break; + } + + return true; } diff --git a/miniwin/src/d3drm/d3drmmesh.cpp b/miniwin/src/d3drm/d3drmmesh.cpp index 5d96ac86..4545036b 100644 --- a/miniwin/src/d3drm/d3drmmesh.cpp +++ b/miniwin/src/d3drm/d3drmmesh.cpp @@ -59,7 +59,7 @@ HRESULT Direct3DRMMeshImpl::AddGroup( MeshGroup group; group.vertexPerFace = vertexPerFace; - DWORD* src = faceBuffer; + unsigned int* src = faceBuffer; group.indices.assign(src, src + faceCount * vertexPerFace); m_groups.push_back(std::move(group)); diff --git a/miniwin/src/d3drm/d3drmtexture.cpp b/miniwin/src/d3drm/d3drmtexture.cpp index c0a2ad59..a5d63588 100644 --- a/miniwin/src/d3drm/d3drmtexture.cpp +++ b/miniwin/src/d3drm/d3drmtexture.cpp @@ -6,8 +6,19 @@ Direct3DRMTextureImpl::Direct3DRMTextureImpl(D3DRMIMAGE* image) MINIWIN_NOT_IMPLEMENTED(); } -Direct3DRMTextureImpl::Direct3DRMTextureImpl(IDirectDrawSurface* surface) : m_surface(surface) +Direct3DRMTextureImpl::Direct3DRMTextureImpl(IDirectDrawSurface* surface, bool holdsRef) + : m_surface(surface), m_holdsRef(holdsRef) { + if (holdsRef && m_surface) { + m_surface->AddRef(); + } +} + +Direct3DRMTextureImpl::~Direct3DRMTextureImpl() +{ + if (m_holdsRef && m_surface) { + m_surface->Release(); + } } HRESULT Direct3DRMTextureImpl::QueryInterface(const GUID& riid, void** ppvObject) diff --git a/miniwin/src/d3drm/d3drmviewport.cpp b/miniwin/src/d3drm/d3drmviewport.cpp index 933cbbcd..e3bb79d3 100644 --- a/miniwin/src/d3drm/d3drmviewport.cpp +++ b/miniwin/src/d3drm/d3drmviewport.cpp @@ -15,7 +15,7 @@ #include Direct3DRMViewportImpl::Direct3DRMViewportImpl(DWORD width, DWORD height, Direct3DRMRenderer* renderer) - : m_width(width), m_height(height), m_renderer(renderer) + : m_virtualWidth(width), m_virtualHeight(height), m_renderer(renderer) { } @@ -151,7 +151,7 @@ void Direct3DRMViewportImpl::CollectLightsFromFrame( void Direct3DRMViewportImpl::BuildViewFrustumPlanes() { - float aspect = (float) m_width / (float) m_height; + float aspect = (float) m_renderer->GetWidth() / (float) m_renderer->GetHeight(); float tanFovX = m_field; float tanFovY = m_field / aspect; @@ -268,18 +268,22 @@ void Direct3DRMViewportImpl::CollectMeshesFromFrame(IDirect3DRMFrame* frame, D3D if (appearance.color.a != 255) { m_deferredDraws.push_back( {m_renderer->GetMeshId(mesh, &meshGroup), + {}, {}, {}, appearance, CalculateDepth(m_viewProjectionwMatrix, worldMatrix)} ); memcpy(m_deferredDraws.back().modelViewMatrix, modelViewMatrix, sizeof(D3DRMMATRIX4D)); + memcpy(m_deferredDraws.back().worldMatrix, worldMatrix, sizeof(D3DRMMATRIX4D)); memcpy(m_deferredDraws.back().normalMatrix, worldMatrixInvert, sizeof(Matrix3x3)); } else { m_renderer->SubmitDraw( m_renderer->GetMeshId(mesh, &meshGroup), modelViewMatrix, + worldMatrix, + m_viewMatrix, worldMatrixInvert, appearance ); @@ -325,7 +329,14 @@ HRESULT Direct3DRMViewportImpl::RenderScene() ); m_renderer->EnableTransparency(); for (const DeferredDrawCommand& cmd : m_deferredDraws) { - m_renderer->SubmitDraw(cmd.meshId, cmd.modelViewMatrix, cmd.normalMatrix, cmd.appearance); + m_renderer->SubmitDraw( + cmd.meshId, + cmd.modelViewMatrix, + cmd.worldMatrix, + m_viewMatrix, + cmd.normalMatrix, + cmd.appearance + ); } m_deferredDraws.clear(); @@ -349,16 +360,14 @@ HRESULT Direct3DRMViewportImpl::ForceUpdate(int x, int y, int w, int h) HRESULT Direct3DRMViewportImpl::Clear() { - if (!DDBackBuffer) { + if (!m_renderer) { return DDERR_GENERIC; } uint8_t r = (m_backgroundColor >> 16) & 0xFF; uint8_t g = (m_backgroundColor >> 8) & 0xFF; uint8_t b = m_backgroundColor & 0xFF; - - Uint32 color = SDL_MapRGB(SDL_GetPixelFormatDetails(DDBackBuffer->format), nullptr, r, g, b); - SDL_FillSurfaceRect(DDBackBuffer, nullptr, color); + m_renderer->Clear(r / 255.0f, g / 255.0f, b / 255.0f); return DD_OK; } @@ -427,13 +436,24 @@ HRESULT Direct3DRMViewportImpl::SetField(D3DVALUE field) void Direct3DRMViewportImpl::UpdateProjectionMatrix() { - float aspect = (float) m_width / (float) m_height; - float f = m_front / m_field; + float virtualAspect = (float) m_virtualWidth / (float) m_virtualHeight; + float windowAspect = (float) m_renderer->GetWidth() / (float) m_renderer->GetHeight(); + + float base_f = m_front / m_field; + float f_v = base_f * virtualAspect; + float f_h = base_f; + if (windowAspect >= virtualAspect) { + f_h *= virtualAspect / windowAspect; + } + else { + f_v *= windowAspect / virtualAspect; + } + float depth = m_back - m_front; D3DRMMATRIX4D projection = { - {f, 0, 0, 0}, - {0, f * aspect, 0, 0}, + {f_h, 0, 0, 0}, + {0, f_v, 0, 0}, {0, 0, m_back / depth, 1}, {0, 0, (-m_front * m_back) / depth, 0}, }; @@ -442,8 +462,8 @@ void Direct3DRMViewportImpl::UpdateProjectionMatrix() m_renderer->SetProjection(projection, m_front, m_back); D3DRMMATRIX4D inverseProjectionMatrix = { - {1.0f / f, 0, 0, 0}, - {0, 1.0f / (f * aspect), 0, 0}, + {1.0f / f_h, 0, 0, 0}, + {0, 1.0f / f_v, 0, 0}, {0, 0, 0, depth / (-m_front * m_back)}, {0, 0, 1, -(m_back / depth) * depth / (-m_front * m_back)}, }; @@ -455,16 +475,6 @@ D3DVALUE Direct3DRMViewportImpl::GetField() return m_field; } -DWORD Direct3DRMViewportImpl::GetWidth() -{ - return m_width; -} - -DWORD Direct3DRMViewportImpl::GetHeight() -{ - return m_height; -} - inline float FromNDC(float ndcCoord, float dim) { return (ndcCoord * 0.5f + 0.5f) * dim; @@ -492,8 +502,8 @@ HRESULT Direct3DRMViewportImpl::Transform(D3DRMVECTOR4D* screen, D3DVECTOR* worl float ndcX = projVec.x * invW; float ndcY = projVec.y * invW; - screen->x = FromNDC(ndcX, m_width); - screen->y = FromNDC(-ndcY, m_height); // Y-flip + screen->x = FromNDC(ndcX, m_virtualWidth); + screen->y = FromNDC(-ndcY, m_virtualHeight); // Y-flip // Undo perspective divide for screen-space coords screen->x *= projVec.z; @@ -509,8 +519,8 @@ HRESULT Direct3DRMViewportImpl::InverseTransform(D3DVECTOR* world, D3DRMVECTOR4D float screenY = screen->y / screen->w; // Convert screen coordinates to NDC - float ndcX = screenX / m_width * 2.0f - 1.0f; - float ndcY = 1.0f - (screenY / m_height) * 2.0f; + float ndcX = screenX / m_virtualWidth * 2.0f - 1.0f; + float ndcY = 1.0f - (screenY / m_virtualHeight) * 2.0f; D3DRMVECTOR4D clipVec = {ndcX * screen->w, ndcY * screen->w, screen->z, screen->w}; @@ -753,13 +763,13 @@ HRESULT Direct3DRMViewportImpl::Pick(float x, float y, LPDIRECT3DRMPICKEDARRAY* Ray pickRay = BuildPickingRay( x, y, - m_width, - m_height, + m_virtualWidth, + m_virtualHeight, m_camera, m_front, m_back, m_field, - (float) m_width / (float) m_height + (float) m_virtualWidth / (float) m_virtualHeight ); std::function&)> recurse; diff --git a/miniwin/src/ddraw/ddraw.cpp b/miniwin/src/ddraw/ddraw.cpp index bd1541a3..acf695eb 100644 --- a/miniwin/src/ddraw/ddraw.cpp +++ b/miniwin/src/ddraw/ddraw.cpp @@ -18,14 +18,13 @@ #include #include +#include #include #include #include SDL_Window* DDWindow; -SDL_Surface* DDBackBuffer; -FrameBufferImpl* DDFrameBuffer; -SDL_Renderer* DDRenderer; +Direct3DRMRenderer* DDRenderer; HRESULT DirectDrawImpl::QueryInterface(const GUID& riid, void** ppvObject) { @@ -77,18 +76,18 @@ HRESULT DirectDrawImpl::CreateSurface( if ((lpDDSurfaceDesc->dwFlags & DDSD_ZBUFFERBITDEPTH) != DDSD_ZBUFFERBITDEPTH) { return DDERR_INVALIDPARAMS; } - SDL_Log("Todo: Set %dbit Z-Buffer", lpDDSurfaceDesc->dwZBufferBitDepth); + SDL_Log("Todo: Set %" PRIu32 "bit Z-Buffer", lpDDSurfaceDesc->dwZBufferBitDepth); *lplpDDSurface = static_cast(new DummySurfaceImpl); return DD_OK; } if ((lpDDSurfaceDesc->ddsCaps.dwCaps & DDSCAPS_PRIMARYSURFACE) == DDSCAPS_PRIMARYSURFACE) { - DDFrameBuffer = new FrameBufferImpl(); - *lplpDDSurface = static_cast(DDFrameBuffer); + m_frameBuffer = new FrameBufferImpl(m_virtualWidth, m_virtualHeight); + *lplpDDSurface = static_cast(m_frameBuffer); return DD_OK; } if ((lpDDSurfaceDesc->ddsCaps.dwCaps & DDSCAPS_3DDEVICE) == DDSCAPS_3DDEVICE) { - DDFrameBuffer->AddRef(); - *lplpDDSurface = static_cast(DDFrameBuffer); + m_frameBuffer->AddRef(); + *lplpDDSurface = static_cast(m_frameBuffer); return DD_OK; } if ((lpDDSurfaceDesc->ddsCaps.dwCaps & DDSCAPS_TEXTURE) == DDSCAPS_TEXTURE) { @@ -100,7 +99,7 @@ HRESULT DirectDrawImpl::CreateSurface( #ifdef MINIWIN_PIXELFORMAT format = MINIWIN_PIXELFORMAT; #else - format = SDL_PIXELFORMAT_RGBA8888; + format = SDL_PIXELFORMAT_RGBA32; #endif if ((lpDDSurfaceDesc->dwFlags & DDSD_PIXELFORMAT) == DDSD_PIXELFORMAT) { if ((lpDDSurfaceDesc->ddpfPixelFormat.dwFlags & DDPF_RGB) == DDPF_RGB) { @@ -284,6 +283,12 @@ HRESULT DirectDrawImpl::SetCooperativeLevel(HWND hWnd, DDSCLFlags dwFlags) { SDL_Window* sdlWindow = reinterpret_cast(hWnd); + if (m_virtualWidth == 0 || m_virtualHeight == 0) { + if (!SDL_GetWindowSize(sdlWindow, &m_virtualWidth, &m_virtualHeight)) { + SDL_LogError(LOG_CATEGORY_MINIWIN, "SDL_GetWindowSizeInPixels: %s", SDL_GetError()); + } + } + if (sdlWindow) { bool fullscreen; if ((dwFlags & DDSCL_NORMAL) == DDSCL_NORMAL) { @@ -302,15 +307,14 @@ HRESULT DirectDrawImpl::SetCooperativeLevel(HWND hWnd, DDSCLFlags dwFlags) #endif } DDWindow = sdlWindow; - DDRenderer = SDL_CreateRenderer(DDWindow, NULL); - SDL_PropertiesID prop = SDL_GetRendererProperties(DDRenderer); - SDL_SetRenderLogicalPresentation(DDRenderer, 640, 480, SDL_LOGICAL_PRESENTATION_LETTERBOX); } return DD_OK; } HRESULT DirectDrawImpl::SetDisplayMode(DWORD dwWidth, DWORD dwHeight, DWORD dwBPP) { + m_virtualWidth = dwWidth; + m_virtualHeight = dwHeight; return DD_OK; } @@ -325,33 +329,32 @@ HRESULT DirectDrawImpl::CreateDevice( DDSDesc.dwSize = sizeof(DDSURFACEDESC); pBackBuffer->GetSurfaceDesc(&DDSDesc); - Direct3DRMRenderer* renderer; if (SDL_memcmp(&guid, &SDL3_GPU_GUID, sizeof(GUID)) == 0) { - renderer = Direct3DRMSDL3GPURenderer::Create(DDSDesc.dwWidth, DDSDesc.dwHeight); + DDRenderer = Direct3DRMSDL3GPURenderer::Create(DDSDesc.dwWidth, DDSDesc.dwHeight); } #ifdef USE_OPENGLES2 else if (SDL_memcmp(&guid, &OpenGLES2_GUID, sizeof(GUID)) == 0) { - renderer = OpenGLES2Renderer::Create(DDSDesc.dwWidth, DDSDesc.dwHeight); + DDRenderer = OpenGLES2Renderer::Create(DDSDesc.dwWidth, DDSDesc.dwHeight); } #endif #ifdef USE_OPENGL1 else if (SDL_memcmp(&guid, &OpenGL1_GUID, sizeof(GUID)) == 0) { - renderer = OpenGL1Renderer::Create(DDSDesc.dwWidth, DDSDesc.dwHeight); + DDRenderer = OpenGL1Renderer::Create(DDSDesc.dwWidth, DDSDesc.dwHeight); } #endif #ifdef _WIN32 else if (SDL_memcmp(&guid, &DirectX9_GUID, sizeof(GUID)) == 0) { - renderer = DirectX9Renderer::Create(DDSDesc.dwWidth, DDSDesc.dwHeight); + DDRenderer = DirectX9Renderer::Create(DDSDesc.dwWidth, DDSDesc.dwHeight); } #endif else if (SDL_memcmp(&guid, &SOFTWARE_GUID, sizeof(GUID)) == 0) { - renderer = new Direct3DRMSoftwareRenderer(DDSDesc.dwWidth, DDSDesc.dwHeight); + DDRenderer = new Direct3DRMSoftwareRenderer(DDSDesc.dwWidth, DDSDesc.dwHeight); } else { SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Device GUID not recognized"); return E_NOINTERFACE; } - *ppDirect3DDevice = static_cast(renderer); + *ppDirect3DDevice = static_cast(DDRenderer); return DD_OK; } diff --git a/miniwin/src/ddraw/ddsurface.cpp b/miniwin/src/ddraw/ddsurface.cpp index 59c4569a..de250dea 100644 --- a/miniwin/src/ddraw/ddsurface.cpp +++ b/miniwin/src/ddraw/ddsurface.cpp @@ -1,3 +1,4 @@ +#include "d3drmtexture_impl.h" #include "ddpalette_impl.h" #include "ddraw_impl.h" #include "ddsurface_impl.h" @@ -19,6 +20,9 @@ DirectDrawSurfaceImpl::~DirectDrawSurfaceImpl() if (m_palette) { m_palette->Release(); } + if (m_texture) { + m_texture->Release(); + } } // IUnknown interface @@ -69,6 +73,9 @@ HRESULT DirectDrawSurfaceImpl::Blt( if (blitSource != other->m_surface) { SDL_DestroySurface(blitSource); } + if (m_texture) { + m_texture->Changed(TRUE, FALSE); + } return DD_OK; } @@ -203,6 +210,10 @@ HRESULT DirectDrawSurfaceImpl::SetPalette(LPDIRECTDRAWPALETTE lpDDPalette) MINIWIN_NOT_IMPLEMENTED(); } + if (m_texture) { + m_texture->Changed(FALSE, TRUE); + } + if (m_palette) { m_palette->Release(); } @@ -216,5 +227,16 @@ HRESULT DirectDrawSurfaceImpl::SetPalette(LPDIRECTDRAWPALETTE lpDDPalette) HRESULT DirectDrawSurfaceImpl::Unlock(LPVOID lpSurfaceData) { SDL_UnlockSurface(m_surface); + if (m_texture) { + m_texture->Changed(TRUE, FALSE); + } return DD_OK; } + +IDirect3DRMTexture2* DirectDrawSurfaceImpl::ToTexture() +{ + if (!m_texture) { + m_texture = new Direct3DRMTextureImpl(this, false); + } + return m_texture; +} diff --git a/miniwin/src/ddraw/framebuffer.cpp b/miniwin/src/ddraw/framebuffer.cpp index eee8b7cb..eb21abef 100644 --- a/miniwin/src/ddraw/framebuffer.cpp +++ b/miniwin/src/ddraw/framebuffer.cpp @@ -6,21 +6,15 @@ #include -FrameBufferImpl::FrameBufferImpl() +FrameBufferImpl::FrameBufferImpl(DWORD virtualWidth, DWORD virtualHeight) + : m_virtualWidth(virtualWidth), m_virtualHeight(virtualHeight) { - int width, height; - SDL_GetRenderOutputSize(DDRenderer, &width, &height); - DDBackBuffer = SDL_CreateSurface(width, height, SDL_PIXELFORMAT_RGBA8888); - if (!DDBackBuffer) { - SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to create surface: %s", SDL_GetError()); - } - m_uploadBuffer = - SDL_CreateTexture(DDRenderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_STREAMING, width, height); + m_transferBuffer = new DirectDrawSurfaceImpl(m_virtualWidth, m_virtualHeight, SDL_PIXELFORMAT_RGBA32); } FrameBufferImpl::~FrameBufferImpl() { - SDL_DestroySurface(DDBackBuffer); + m_transferBuffer->Release(); if (m_palette) { m_palette->Release(); } @@ -51,44 +45,30 @@ HRESULT FrameBufferImpl::Blt( LPDDBLTFX lpDDBltFx ) { + if (!DDRenderer) { + return DDERR_GENERIC; + } if (dynamic_cast(lpDDSrcSurface) == this) { return Flip(nullptr, DDFLIP_WAIT); } if ((dwFlags & DDBLT_COLORFILL) == DDBLT_COLORFILL) { - SDL_Rect rect = {0, 0, DDBackBuffer->w, DDBackBuffer->h}; - const SDL_PixelFormatDetails* details = SDL_GetPixelFormatDetails(DDBackBuffer->format); Uint8 r = (lpDDBltFx->dwFillColor >> 16) & 0xFF; Uint8 g = (lpDDBltFx->dwFillColor >> 8) & 0xFF; Uint8 b = lpDDBltFx->dwFillColor & 0xFF; - DirectDrawPaletteImpl* ddPal = static_cast(m_palette); - SDL_Palette* sdlPalette = ddPal ? ddPal->m_palette : nullptr; - Uint32 color = SDL_MapRGB(details, sdlPalette, r, g, b); - SDL_FillSurfaceRect(DDBackBuffer, &rect, color); + DDRenderer->Clear(r / 255.0f, g / 255.0f, b / 255.0f); return DD_OK; } - auto other = static_cast(lpDDSrcSurface); - if (!other) { + auto surface = static_cast(lpDDSrcSurface); + if (!surface) { return DDERR_GENERIC; } - SDL_Rect srcRect = lpSrcRect ? ConvertRect(lpSrcRect) : SDL_Rect{0, 0, other->m_surface->w, other->m_surface->h}; - SDL_Rect dstRect = lpDestRect ? ConvertRect(lpDestRect) : SDL_Rect{0, 0, DDBackBuffer->w, DDBackBuffer->h}; + Uint32 textureId = DDRenderer->GetTextureId(surface->ToTexture()); + SDL_Rect srcRect = + lpSrcRect ? ConvertRect(lpSrcRect) : SDL_Rect{0, 0, surface->m_surface->w, surface->m_surface->h}; + SDL_Rect dstRect = + lpDestRect ? ConvertRect(lpDestRect) : SDL_Rect{0, 0, (int) m_virtualWidth, (int) m_virtualHeight}; + DDRenderer->Draw2DImage(textureId, srcRect, dstRect); - SDL_Surface* blitSource = other->m_surface; - - if (other->m_surface->format != DDBackBuffer->format) { - blitSource = SDL_ConvertSurface(other->m_surface, DDBackBuffer->format); - if (!blitSource) { - return DDERR_GENERIC; - } - } - - if (!SDL_BlitSurfaceScaled(blitSource, &srcRect, DDBackBuffer, &dstRect, SDL_SCALEMODE_NEAREST)) { - return DDERR_GENERIC; - } - - if (blitSource != other->m_surface) { - SDL_DestroySurface(blitSource); - } return DD_OK; } @@ -100,20 +80,20 @@ HRESULT FrameBufferImpl::BltFast( DDBltFastFlags dwTrans ) { - RECT destRect = { - (int) dwX, - (int) dwY, - (int) (lpSrcRect->right - lpSrcRect->left + dwX), - (int) (lpSrcRect->bottom - lpSrcRect->top + dwY) - }; + auto surface = static_cast(lpDDSrcSurface); + int width = lpSrcRect ? (lpSrcRect->right - lpSrcRect->left) : surface->m_surface->w; + int height = lpSrcRect ? (lpSrcRect->bottom - lpSrcRect->top) : surface->m_surface->h; + RECT destRect = {(int) dwX, (int) dwY, (int) (dwX + width), (int) (dwY + height)}; + return Blt(&destRect, lpDDSrcSurface, lpSrcRect, DDBLT_NONE, nullptr); } HRESULT FrameBufferImpl::Flip(LPDIRECTDRAWSURFACE lpDDSurfaceTargetOverride, DDFlipFlags dwFlags) { - SDL_UpdateTexture(m_uploadBuffer, nullptr, DDBackBuffer->pixels, DDBackBuffer->pitch); - SDL_RenderTexture(DDRenderer, m_uploadBuffer, nullptr, nullptr); - SDL_RenderPresent(DDRenderer); + if (!DDRenderer) { + return DDERR_GENERIC; + } + DDRenderer->Flip(); return DD_OK; } @@ -146,7 +126,7 @@ HRESULT FrameBufferImpl::GetPixelFormat(LPDDPIXELFORMAT lpDDPixelFormat) { memset(lpDDPixelFormat, 0, sizeof(*lpDDPixelFormat)); lpDDPixelFormat->dwFlags = DDPF_RGB; - const SDL_PixelFormatDetails* details = SDL_GetPixelFormatDetails(DDBackBuffer->format); + const SDL_PixelFormatDetails* details = SDL_GetPixelFormatDetails(m_transferBuffer->m_surface->format); if (details->bits_per_pixel == 8) { lpDDPixelFormat->dwFlags |= DDPF_PALETTEINDEXED8; } @@ -163,25 +143,28 @@ HRESULT FrameBufferImpl::GetSurfaceDesc(LPDDSURFACEDESC lpDDSurfaceDesc) lpDDSurfaceDesc->dwFlags = DDSD_PIXELFORMAT; GetPixelFormat(&lpDDSurfaceDesc->ddpfPixelFormat); lpDDSurfaceDesc->dwFlags |= DDSD_WIDTH | DDSD_HEIGHT; - lpDDSurfaceDesc->dwWidth = DDBackBuffer->w; - lpDDSurfaceDesc->dwHeight = DDBackBuffer->h; - return DD_OK; -} - -HRESULT FrameBufferImpl::IsLost() -{ + lpDDSurfaceDesc->dwWidth = m_transferBuffer->m_surface->w; + lpDDSurfaceDesc->dwHeight = m_transferBuffer->m_surface->h; return DD_OK; } HRESULT FrameBufferImpl::Lock(LPRECT lpDestRect, DDSURFACEDESC* lpDDSurfaceDesc, DDLockFlags dwFlags, HANDLE hEvent) { - if (!SDL_LockSurface(DDBackBuffer)) { + if (!DDRenderer) { return DDERR_GENERIC; } + if ((dwFlags & DDLOCK_WRITEONLY) == DDLOCK_WRITEONLY) { + SDL_Rect rect = {0, 0, m_transferBuffer->m_surface->w, m_transferBuffer->m_surface->h}; + const SDL_PixelFormatDetails* details = SDL_GetPixelFormatDetails(m_transferBuffer->m_surface->format); + SDL_Palette* palette = m_palette ? static_cast(m_palette)->m_palette : nullptr; + Uint32 color = SDL_MapRGBA(details, palette, 0, 0, 0, 0); + SDL_FillSurfaceRect(m_transferBuffer->m_surface, &rect, color); + } + else { + DDRenderer->Download(m_transferBuffer->m_surface); + } - GetSurfaceDesc(lpDDSurfaceDesc); - lpDDSurfaceDesc->lpSurface = DDBackBuffer->pixels; - lpDDSurfaceDesc->lPitch = DDBackBuffer->pitch; + m_transferBuffer->Lock(lpDestRect, lpDDSurfaceDesc, dwFlags, hEvent); return DD_OK; } @@ -198,11 +181,6 @@ HRESULT FrameBufferImpl::Restore() return DD_OK; } -HRESULT FrameBufferImpl::SetClipper(LPDIRECTDRAWCLIPPER lpDDClipper) -{ - return DD_OK; -} - HRESULT FrameBufferImpl::SetColorKey(DDColorKeyFlags dwFlags, LPDDCOLORKEY lpDDColorKey) { MINIWIN_NOT_IMPLEMENTED(); @@ -211,7 +189,7 @@ HRESULT FrameBufferImpl::SetColorKey(DDColorKeyFlags dwFlags, LPDDCOLORKEY lpDDC HRESULT FrameBufferImpl::SetPalette(LPDIRECTDRAWPALETTE lpDDPalette) { - if (DDBackBuffer->format != SDL_PIXELFORMAT_INDEX8) { + if (m_transferBuffer->m_surface->format != SDL_PIXELFORMAT_INDEX8) { MINIWIN_NOT_IMPLEMENTED(); } @@ -220,13 +198,15 @@ HRESULT FrameBufferImpl::SetPalette(LPDIRECTDRAWPALETTE lpDDPalette) } m_palette = lpDDPalette; - SDL_SetSurfacePalette(DDBackBuffer, ((DirectDrawPaletteImpl*) m_palette)->m_palette); + SDL_SetSurfacePalette(m_transferBuffer->m_surface, ((DirectDrawPaletteImpl*) m_palette)->m_palette); m_palette->AddRef(); return DD_OK; } HRESULT FrameBufferImpl::Unlock(LPVOID lpSurfaceData) { - SDL_UnlockSurface(DDBackBuffer); + m_transferBuffer->Unlock(lpSurfaceData); + BltFast(0, 0, m_transferBuffer, nullptr, DDBLTFAST_WAIT); + return DD_OK; } diff --git a/miniwin/src/internal/d3drmdevice_impl.h b/miniwin/src/internal/d3drmdevice_impl.h index ad30f75a..daab564a 100644 --- a/miniwin/src/internal/d3drmdevice_impl.h +++ b/miniwin/src/internal/d3drmdevice_impl.h @@ -11,8 +11,8 @@ struct Direct3DRMDevice2Impl : public Direct3DRMObjectBaseImpl vertices; std::vector indices; diff --git a/miniwin/src/internal/d3drmrenderer.h b/miniwin/src/internal/d3drmrenderer.h index e1e7e558..e76f0759 100644 --- a/miniwin/src/internal/d3drmrenderer.h +++ b/miniwin/src/internal/d3drmrenderer.h @@ -26,8 +26,6 @@ struct Plane { float d; }; -extern SDL_Renderer* DDRenderer; - class Direct3DRMRenderer : public IDirect3DDevice2 { public: virtual void PushLights(const SceneLight* vertices, size_t count) = 0; @@ -35,8 +33,10 @@ class Direct3DRMRenderer : public IDirect3DDevice2 { virtual void SetFrustumPlanes(const Plane* frustumPlanes) = 0; virtual Uint32 GetTextureId(IDirect3DRMTexture* texture) = 0; virtual Uint32 GetMeshId(IDirect3DRMMesh* mesh, const MeshGroup* meshGroup) = 0; - virtual DWORD GetWidth() = 0; - virtual DWORD GetHeight() = 0; + int GetWidth() { return m_width; } + int GetHeight() { return m_height; } + int GetVirtualWidth() { return m_virtualWidth; } + int GetVirtualHeight() { return m_virtualHeight; } virtual void GetDesc(D3DDEVICEDESC* halDesc, D3DDEVICEDESC* helDesc) = 0; virtual const char* GetName() = 0; virtual HRESULT BeginFrame() = 0; @@ -44,13 +44,20 @@ class Direct3DRMRenderer : public IDirect3DDevice2 { virtual void SubmitDraw( DWORD meshId, const D3DRMMATRIX4D& modelViewMatrix, + const D3DRMMATRIX4D& worldMatrix, + const D3DRMMATRIX4D& viewMatrix, const Matrix3x3& normalMatrix, const Appearance& appearance ) = 0; virtual HRESULT FinalizeFrame() = 0; + virtual void Resize(int width, int height, const ViewportTransform& viewportTransform) = 0; + virtual void Clear(float r, float g, float b) = 0; + virtual void Flip() = 0; + virtual void Draw2DImage(Uint32 textureId, const SDL_Rect& srcRect, const SDL_Rect& dstRect) = 0; + virtual void Download(SDL_Surface* target) = 0; - bool ConvertEventToRenderCoordinates(SDL_Event* event) - { - return SDL_ConvertEventToRenderCoordinates(DDRenderer, event); - } +protected: + int m_width, m_height; + int m_virtualWidth, m_virtualHeight; + ViewportTransform m_viewportTransform; }; diff --git a/miniwin/src/internal/d3drmrenderer_directx9.h b/miniwin/src/internal/d3drmrenderer_directx9.h index 8df63424..b7badb03 100644 --- a/miniwin/src/internal/d3drmrenderer_directx9.h +++ b/miniwin/src/internal/d3drmrenderer_directx9.h @@ -20,8 +20,6 @@ class DirectX9Renderer : public Direct3DRMRenderer { void SetFrustumPlanes(const Plane* frustumPlanes) override; Uint32 GetTextureId(IDirect3DRMTexture* texture) override; Uint32 GetMeshId(IDirect3DRMMesh* mesh, const MeshGroup* meshGroup) override; - DWORD GetWidth() override; - DWORD GetHeight() override; void GetDesc(D3DDEVICEDESC* halDesc, D3DDEVICEDESC* helDesc) override; const char* GetName() override; HRESULT BeginFrame() override; @@ -29,17 +27,23 @@ class DirectX9Renderer : public Direct3DRMRenderer { void SubmitDraw( DWORD meshId, const D3DRMMATRIX4D& modelViewMatrix, + const D3DRMMATRIX4D& worldMatrix, + const D3DRMMATRIX4D& viewMatrix, const Matrix3x3& normalMatrix, const Appearance& appearance ) override; HRESULT FinalizeFrame() override; + void Resize(int width, int height, const ViewportTransform& viewportTransform) override; + void Clear(float r, float g, float b) override; + void Flip() override; + void Draw2DImage(Uint32 textureId, const SDL_Rect& srcRect, const SDL_Rect& dstRect) override; + void Download(SDL_Surface* target) override; private: void AddTextureDestroyCallback(Uint32 id, IDirect3DRMTexture* texture); void AddMeshDestroyCallback(Uint32 id, IDirect3DRMMesh* mesh); SDL_Surface* m_renderedImage; - DWORD m_width, m_height; std::vector m_lights; std::vector m_meshs; std::vector m_textures; diff --git a/miniwin/src/internal/d3drmrenderer_opengl1.h b/miniwin/src/internal/d3drmrenderer_opengl1.h index 763509d8..d80621a5 100644 --- a/miniwin/src/internal/d3drmrenderer_opengl1.h +++ b/miniwin/src/internal/d3drmrenderer_opengl1.h @@ -1,48 +1,18 @@ #pragma once - +#include "../d3drm/backends/opengl1/actual.h" #include "d3drmrenderer.h" #include "d3drmtexture_impl.h" #include "ddraw_impl.h" -#ifdef __APPLE__ -#include -#else -#include -#endif - #include #include DEFINE_GUID(OpenGL1_GUID, 0x682656F3, 0x0000, 0x0000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03); -struct GLTextureCacheEntry { - IDirect3DRMTexture* texture; - Uint32 version; - GLuint glTextureId; -}; - -struct GLMeshCacheEntry { - const MeshGroup* meshGroup; - int version; - bool flat; - - // non-VBO cache - std::vector positions; - std::vector normals; - std::vector texcoords; - std::vector indices; - - // VBO cache - GLuint vboPositions; - GLuint vboNormals; - GLuint vboTexcoords; - GLuint ibo; -}; - class OpenGL1Renderer : public Direct3DRMRenderer { public: static Direct3DRMRenderer* Create(DWORD width, DWORD height); - OpenGL1Renderer(DWORD width, DWORD height, SDL_GLContext context, GLuint fbo, GLuint colorTex, GLuint depthRb); + OpenGL1Renderer(DWORD width, DWORD height, SDL_GLContext context); ~OpenGL1Renderer() override; void PushLights(const SceneLight* lightsArray, size_t count) override; @@ -50,8 +20,6 @@ class OpenGL1Renderer : public Direct3DRMRenderer { void SetFrustumPlanes(const Plane* frustumPlanes) override; Uint32 GetTextureId(IDirect3DRMTexture* texture) override; Uint32 GetMeshId(IDirect3DRMMesh* mesh, const MeshGroup* meshGroup) override; - DWORD GetWidth() override; - DWORD GetHeight() override; void GetDesc(D3DDEVICEDESC* halDesc, D3DDEVICEDESC* helDesc) override; const char* GetName() override; HRESULT BeginFrame() override; @@ -59,10 +27,17 @@ class OpenGL1Renderer : public Direct3DRMRenderer { void SubmitDraw( DWORD meshId, const D3DRMMATRIX4D& modelViewMatrix, + const D3DRMMATRIX4D& worldMatrix, + const D3DRMMATRIX4D& viewMatrix, const Matrix3x3& normalMatrix, const Appearance& appearance ) override; HRESULT FinalizeFrame() override; + void Resize(int width, int height, const ViewportTransform& viewportTransform) override; + void Clear(float r, float g, float b) override; + void Flip() override; + void Draw2DImage(Uint32 textureId, const SDL_Rect& srcRect, const SDL_Rect& dstRect) override; + void Download(SDL_Surface* target) override; private: void AddTextureDestroyCallback(Uint32 id, IDirect3DRMTexture* texture); @@ -72,13 +47,11 @@ class OpenGL1Renderer : public Direct3DRMRenderer { std::vector m_meshs; D3DRMMATRIX4D m_projection; SDL_Surface* m_renderedImage; - DWORD m_width, m_height; bool m_useVBOs; + bool m_dirty = false; std::vector m_lights; SDL_GLContext m_context; - GLuint m_fbo; - GLuint m_colorTex; - GLuint m_depthRb; + ViewportTransform m_viewportTransform; }; inline static void OpenGL1Renderer_EnumDevice(LPD3DENUMDEVICESCALLBACK cb, void* ctx) diff --git a/miniwin/src/internal/d3drmrenderer_opengles2.h b/miniwin/src/internal/d3drmrenderer_opengles2.h index 94ff70ee..7ea1ed9a 100644 --- a/miniwin/src/internal/d3drmrenderer_opengles2.h +++ b/miniwin/src/internal/d3drmrenderer_opengles2.h @@ -14,6 +14,8 @@ struct GLES2TextureCacheEntry { IDirect3DRMTexture* texture; Uint32 version; GLuint glTextureId; + uint16_t width; + uint16_t height; }; struct GLES2MeshCacheEntry { @@ -31,15 +33,7 @@ struct GLES2MeshCacheEntry { class OpenGLES2Renderer : public Direct3DRMRenderer { public: static Direct3DRMRenderer* Create(DWORD width, DWORD height); - OpenGLES2Renderer( - DWORD width, - DWORD height, - SDL_GLContext context, - GLuint fbo, - GLuint colorTex, - GLuint vertexBuffer, - GLuint shaderProgram - ); + OpenGLES2Renderer(DWORD width, DWORD height, SDL_GLContext context, GLuint shaderProgram); ~OpenGLES2Renderer() override; void PushLights(const SceneLight* lightsArray, size_t count) override; @@ -47,8 +41,6 @@ class OpenGLES2Renderer : public Direct3DRMRenderer { void SetFrustumPlanes(const Plane* frustumPlanes) override; Uint32 GetTextureId(IDirect3DRMTexture* texture) override; Uint32 GetMeshId(IDirect3DRMMesh* mesh, const MeshGroup* meshGroup) override; - DWORD GetWidth() override; - DWORD GetHeight() override; void GetDesc(D3DDEVICEDESC* halDesc, D3DDEVICEDESC* helDesc) override; const char* GetName() override; HRESULT BeginFrame() override; @@ -56,10 +48,17 @@ class OpenGLES2Renderer : public Direct3DRMRenderer { void SubmitDraw( DWORD meshId, const D3DRMMATRIX4D& modelViewMatrix, + const D3DRMMATRIX4D& worldMatrix, + const D3DRMMATRIX4D& viewMatrix, const Matrix3x3& normalMatrix, const Appearance& appearance ) override; HRESULT FinalizeFrame() override; + void Resize(int width, int height, const ViewportTransform& viewportTransform) override; + void Clear(float r, float g, float b) override; + void Flip() override; + void Draw2DImage(Uint32 textureId, const SDL_Rect& srcRect, const SDL_Rect& dstRect) override; + void Download(SDL_Surface* target) override; private: void AddTextureDestroyCallback(Uint32 id, IDirect3DRMTexture* texture); @@ -69,13 +68,11 @@ class OpenGLES2Renderer : public Direct3DRMRenderer { std::vector m_meshs; D3DRMMATRIX4D m_projection; SDL_Surface* m_renderedImage; - DWORD m_width, m_height; + bool m_dirty = false; std::vector m_lights; SDL_GLContext m_context; - GLuint m_fbo; - GLuint m_colorTex; - GLuint m_depthRb; GLuint m_shaderProgram; + ViewportTransform m_viewportTransform; }; inline static void OpenGLES2Renderer_EnumDevice(LPD3DENUMDEVICESCALLBACK cb, void* ctx) diff --git a/miniwin/src/internal/d3drmrenderer_sdl3gpu.h b/miniwin/src/internal/d3drmrenderer_sdl3gpu.h index 3a20000e..25485b1f 100644 --- a/miniwin/src/internal/d3drmrenderer_sdl3gpu.h +++ b/miniwin/src/internal/d3drmrenderer_sdl3gpu.h @@ -51,8 +51,6 @@ class Direct3DRMSDL3GPURenderer : public Direct3DRMRenderer { Uint32 GetMeshId(IDirect3DRMMesh* mesh, const MeshGroup* meshGroup) override; void SetProjection(const D3DRMMATRIX4D& projection, D3DVALUE front, D3DVALUE back) override; void SetFrustumPlanes(const Plane* frustumPlanes) override; - DWORD GetWidth() override; - DWORD GetHeight() override; void GetDesc(D3DDEVICEDESC* halDesc, D3DDEVICEDESC* helDesc) override; const char* GetName() override; HRESULT BeginFrame() override; @@ -60,10 +58,17 @@ class Direct3DRMSDL3GPURenderer : public Direct3DRMRenderer { void SubmitDraw( DWORD meshId, const D3DRMMATRIX4D& modelViewMatrix, + const D3DRMMATRIX4D& worldMatrix, + const D3DRMMATRIX4D& viewMatrix, const Matrix3x3& normalMatrix, const Appearance& appearance ) override; HRESULT FinalizeFrame() override; + void Resize(int width, int height, const ViewportTransform& viewportTransform) override; + void Clear(float r, float g, float b) override; + void Flip() override; + void Draw2DImage(Uint32 textureId, const SDL_Rect& srcRect, const SDL_Rect& dstRect) override; + void Download(SDL_Surface* target) override; private: Direct3DRMSDL3GPURenderer( @@ -72,12 +77,13 @@ class Direct3DRMSDL3GPURenderer : public Direct3DRMRenderer { SDL_GPUDevice* device, SDL_GPUGraphicsPipeline* opaquePipeline, SDL_GPUGraphicsPipeline* transparentPipeline, - SDL_GPUTexture* transferTexture, - SDL_GPUTexture* depthTexture, + SDL_GPUGraphicsPipeline* uiPipeline, SDL_GPUSampler* sampler, + SDL_GPUSampler* uiSampler, SDL_GPUTransferBuffer* uploadBuffer, - SDL_GPUTransferBuffer* downloadBuffer + int uploadBufferSize ); + void StartRenderPass(float r, float g, float b, bool clear); void WaitForPendingUpload(); void AddTextureDestroyCallback(Uint32 id, IDirect3DRMTexture* texture); SDL_GPUTransferBuffer* GetUploadBuffer(size_t size); @@ -85,26 +91,29 @@ class Direct3DRMSDL3GPURenderer : public Direct3DRMRenderer { void AddMeshDestroyCallback(Uint32 id, IDirect3DRMMesh* mesh); SDL3MeshCache UploadMesh(const MeshGroup& meshGroup); - DWORD m_width; - DWORD m_height; + MeshGroup m_uiMesh; + SDL3MeshCache m_uiMeshCache; D3DVALUE m_front; D3DVALUE m_back; ViewportUniforms m_uniforms; FragmentShadingData m_fragmentShadingData; D3DDEVICEDESC m_desc; + D3DRMMATRIX4D m_projection; std::vector m_textures; std::vector m_meshs; SDL_GPUDevice* m_device; SDL_GPUGraphicsPipeline* m_opaquePipeline; SDL_GPUGraphicsPipeline* m_transparentPipeline; - SDL_GPUTexture* m_transferTexture; - SDL_GPUTexture* m_depthTexture; + SDL_GPUGraphicsPipeline* m_uiPipeline; + SDL_GPUTexture* m_transferTexture = nullptr; + SDL_GPUTexture* m_depthTexture = nullptr; SDL_GPUTexture* m_dummyTexture; int m_uploadBufferSize; SDL_GPUTransferBuffer* m_uploadBuffer; - SDL_GPUTransferBuffer* m_downloadBuffer; + SDL_GPUTransferBuffer* m_downloadBuffer = nullptr; SDL_GPUBuffer* m_vertexBuffer = nullptr; SDL_GPUSampler* m_sampler; + SDL_GPUSampler* m_uiSampler; SDL_GPUCommandBuffer* m_cmdbuf = nullptr; SDL_GPURenderPass* m_renderPass = nullptr; SDL_GPUFence* m_uploadFence = nullptr; diff --git a/miniwin/src/internal/d3drmrenderer_software.h b/miniwin/src/internal/d3drmrenderer_software.h index 6df2b4a4..444a80a3 100644 --- a/miniwin/src/internal/d3drmrenderer_software.h +++ b/miniwin/src/internal/d3drmrenderer_software.h @@ -27,13 +27,12 @@ struct MeshCache { class Direct3DRMSoftwareRenderer : public Direct3DRMRenderer { public: Direct3DRMSoftwareRenderer(DWORD width, DWORD height); + ~Direct3DRMSoftwareRenderer() override; void PushLights(const SceneLight* vertices, size_t count) override; Uint32 GetTextureId(IDirect3DRMTexture* texture) override; Uint32 GetMeshId(IDirect3DRMMesh* mesh, const MeshGroup* meshGroup) override; void SetProjection(const D3DRMMATRIX4D& projection, D3DVALUE front, D3DVALUE back) override; void SetFrustumPlanes(const Plane* frustumPlanes) override; - DWORD GetWidth() override; - DWORD GetHeight() override; void GetDesc(D3DDEVICEDESC* halDesc, D3DDEVICEDESC* helDesc) override; const char* GetName() override; HRESULT BeginFrame() override; @@ -41,10 +40,17 @@ class Direct3DRMSoftwareRenderer : public Direct3DRMRenderer { void SubmitDraw( DWORD meshId, const D3DRMMATRIX4D& modelViewMatrix, + const D3DRMMATRIX4D& worldMatrix, + const D3DRMMATRIX4D& viewMatrix, const Matrix3x3& normalMatrix, const Appearance& appearance ) override; HRESULT FinalizeFrame() override; + void Resize(int width, int height, const ViewportTransform& viewportTransform) override; + void Clear(float r, float g, float b) override; + void Flip() override; + void Draw2DImage(Uint32 textureId, const SDL_Rect& srcRect, const SDL_Rect& dstRect) override; + void Download(SDL_Surface* target) override; private: void ClearZBuffer(); @@ -61,9 +67,10 @@ class Direct3DRMSoftwareRenderer : public Direct3DRMRenderer { void AddTextureDestroyCallback(Uint32 id, IDirect3DRMTexture* texture); void AddMeshDestroyCallback(Uint32 id, IDirect3DRMMesh* mesh); - DWORD m_width; - DWORD m_height; + SDL_Surface* m_renderedImage = nullptr; SDL_Palette* m_palette; + SDL_Texture* m_uploadBuffer = nullptr; + SDL_Renderer* m_renderer; const SDL_PixelFormatDetails* m_format; int m_bytesPerPixel; std::vector m_lights; diff --git a/miniwin/src/internal/d3drmtexture_impl.h b/miniwin/src/internal/d3drmtexture_impl.h index e81c3884..35ef7779 100644 --- a/miniwin/src/internal/d3drmtexture_impl.h +++ b/miniwin/src/internal/d3drmtexture_impl.h @@ -4,10 +4,12 @@ struct Direct3DRMTextureImpl : public Direct3DRMObjectBaseImpl { Direct3DRMTextureImpl(D3DRMIMAGE* image); - Direct3DRMTextureImpl(IDirectDrawSurface* surface); + Direct3DRMTextureImpl(IDirectDrawSurface* surface, bool holdsRef); + ~Direct3DRMTextureImpl() override; HRESULT QueryInterface(const GUID& riid, void** ppvObject) override; HRESULT Changed(BOOL pixels, BOOL palette) override; IDirectDrawSurface* m_surface = nullptr; Uint8 m_version = 0; + bool m_holdsRef; }; diff --git a/miniwin/src/internal/d3drmviewport_impl.h b/miniwin/src/internal/d3drmviewport_impl.h index c27af586..b23652d0 100644 --- a/miniwin/src/internal/d3drmviewport_impl.h +++ b/miniwin/src/internal/d3drmviewport_impl.h @@ -10,6 +10,7 @@ struct DeferredDrawCommand { DWORD meshId; D3DRMMATRIX4D modelViewMatrix; + D3DRMMATRIX4D worldMatrix; Matrix3x3 normalMatrix; Appearance appearance; float depth; @@ -36,24 +37,24 @@ struct Direct3DRMViewportImpl : public Direct3DRMObjectBaseImpl& lights); void CollectMeshesFromFrame(IDirect3DRMFrame* frame, D3DRMMATRIX4D parentMatrix); void BuildViewFrustumPlanes(); - void UpdateProjectionMatrix(); Direct3DRMRenderer* m_renderer; std::vector m_deferredDraws; D3DCOLOR m_backgroundColor = 0xFF000000; - DWORD m_width; - DWORD m_height; + DWORD m_virtualWidth; + DWORD m_virtualHeight; D3DRMMATRIX4D m_viewProjectionwMatrix; D3DRMMATRIX4D m_viewMatrix; D3DRMMATRIX4D m_projectionMatrix; diff --git a/miniwin/src/internal/ddraw_impl.h b/miniwin/src/internal/ddraw_impl.h index 7cefe2f6..f2604946 100644 --- a/miniwin/src/internal/ddraw_impl.h +++ b/miniwin/src/internal/ddraw_impl.h @@ -8,9 +8,7 @@ #include extern SDL_Window* DDWindow; -extern SDL_Surface* DDBackBuffer; -extern FrameBufferImpl* DDFrameBuffer; -extern SDL_Renderer* DDRenderer; +extern Direct3DRMRenderer* DDRenderer; inline static SDL_Rect ConvertRect(const RECT* r) { @@ -47,6 +45,11 @@ struct DirectDrawImpl : public IDirectDraw2, public IDirect3D2 { HRESULT CreateDevice(const GUID& guid, IDirectDrawSurface* pBackBuffer, IDirect3DDevice2** ppDirect3DDevice) override; HRESULT EnumDevices(LPD3DENUMDEVICESCALLBACK cb, void* ctx) override; + +private: + FrameBufferImpl* m_frameBuffer; + int m_virtualWidth = 0; + int m_virtualHeight = 0; }; HRESULT DirectDrawEnumerate(LPDDENUMCALLBACKA cb, void* context); diff --git a/miniwin/src/internal/ddsurface_impl.h b/miniwin/src/internal/ddsurface_impl.h index 4218e157..62fab18a 100644 --- a/miniwin/src/internal/ddsurface_impl.h +++ b/miniwin/src/internal/ddsurface_impl.h @@ -35,8 +35,11 @@ struct DirectDrawSurfaceImpl : public IDirectDrawSurface3 { HRESULT SetPalette(LPDIRECTDRAWPALETTE lpDDPalette) override; HRESULT Unlock(LPVOID lpSurfaceData) override; + IDirect3DRMTexture2* ToTexture(); + SDL_Surface* m_surface = nullptr; private: + IDirect3DRMTexture2* m_texture = nullptr; IDirectDrawPalette* m_palette = nullptr; }; diff --git a/miniwin/src/internal/framebuffer_impl.h b/miniwin/src/internal/framebuffer_impl.h index c2d9e3c8..5e40f7e8 100644 --- a/miniwin/src/internal/framebuffer_impl.h +++ b/miniwin/src/internal/framebuffer_impl.h @@ -5,7 +5,7 @@ #include struct FrameBufferImpl : public IDirectDrawSurface3 { - FrameBufferImpl(); + FrameBufferImpl(DWORD virtualWidth, DWORD virtualHeight); ~FrameBufferImpl() override; // IUnknown interface @@ -27,16 +27,18 @@ struct FrameBufferImpl : public IDirectDrawSurface3 { HRESULT GetPalette(LPDIRECTDRAWPALETTE* lplpDDPalette) override; HRESULT GetPixelFormat(LPDDPIXELFORMAT lpDDPixelFormat) override; HRESULT GetSurfaceDesc(DDSURFACEDESC* lpDDSurfaceDesc) override; - HRESULT IsLost() override; + HRESULT IsLost() override { return DD_OK; } HRESULT Lock(LPRECT lpDestRect, DDSURFACEDESC* lpDDSurfaceDesc, DDLockFlags dwFlags, HANDLE hEvent) override; HRESULT ReleaseDC(HDC hDC) override; HRESULT Restore() override; - HRESULT SetClipper(IDirectDrawClipper* lpDDClipper) override; + HRESULT SetClipper(IDirectDrawClipper* lpDDClipper) override { return DD_OK; } HRESULT SetColorKey(DDColorKeyFlags dwFlags, LPDDCOLORKEY lpDDColorKey) override; HRESULT SetPalette(LPDIRECTDRAWPALETTE lpDDPalette) override; HRESULT Unlock(LPVOID lpSurfaceData) override; private: - SDL_Texture* m_uploadBuffer; + uint32_t m_virtualWidth; + uint32_t m_virtualHeight; + DirectDrawSurfaceImpl* m_transferBuffer; IDirectDrawPalette* m_palette = nullptr; }; diff --git a/miniwin/src/internal/structs.h b/miniwin/src/internal/structs.h index 4f745098..43bda0ed 100644 --- a/miniwin/src/internal/structs.h +++ b/miniwin/src/internal/structs.h @@ -15,3 +15,9 @@ struct Appearance { uint32_t textureId; uint32_t flat; }; + +struct ViewportTransform { + float scale; + float offsetX; + float offsetY; +}; diff --git a/tools/ncc/skip.yml b/tools/ncc/skip.yml index 65de1ce7..c5ceef72 100644 --- a/tools/ncc/skip.yml +++ b/tools/ncc/skip.yml @@ -4,6 +4,7 @@ configureLegoModelPresenter(MxS32): 'DLL exported function' configureLegoPartPresenter(MxS32, MxS32): 'DLL exported function' configureLegoROI(int): 'DLL exported function' configureLegoWorldPresenter(MxS32): 'DLL exported function' +configureMxTransitionManager(TransitionType): 'DLL exported function' GetNoCD_SourceName(): 'DLL exported function' m_3dView: 'Allow this variable name' m_3dManager: 'Allow this variable name'