From fde5e6ced33d9dd31a6146b49de499e5243504ad Mon Sep 17 00:00:00 2001 From: Joshua Peisach Date: Thu, 3 Jul 2025 06:43:27 -0400 Subject: [PATCH 01/17] citro3d: Let SDL3 take care of initiatizing/deinitializing GFX (#500) --- miniwin/src/d3drm/backends/citro3d/renderer.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/miniwin/src/d3drm/backends/citro3d/renderer.cpp b/miniwin/src/d3drm/backends/citro3d/renderer.cpp index 72d729bc..f076cf70 100644 --- a/miniwin/src/d3drm/backends/citro3d/renderer.cpp +++ b/miniwin/src/d3drm/backends/citro3d/renderer.cpp @@ -26,7 +26,7 @@ Citro3DRenderer::Citro3DRenderer(DWORD width, DWORD height) m_virtualWidth = width; m_virtualHeight = height; - gfxInitDefault(); + gfxSetScreenFormat(GFX_BOTTOM, GSP_BGR8_OES); consoleInit(GFX_TOP, nullptr); C3D_Init(C3D_DEFAULT_CMDBUF_SIZE); @@ -66,7 +66,6 @@ Citro3DRenderer::~Citro3DRenderer() shaderProgramFree(&program); DVLB_Free(vshader_dvlb); C3D_Fini(); - gfxExit(); } void Citro3DRenderer::PushLights(const SceneLight* lights, size_t count) From b2ee6c114e34c619427eb993d5e779b256524635 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gregor=20W=C3=BCnsch?= <41543402+gwuen@users.noreply.github.com> Date: Thu, 3 Jul 2025 16:14:09 +0200 Subject: [PATCH 02/17] Add `StartupWMClass` to the desktop file (#501) This explicitly adds a `StartupWMClass` to the desktop file to help desktop environments properly track the game window and associate it with the correct app icon and name. This adheres to the XDG Desktop Entry Specification [^1]. [^1]: https://specifications.freedesktop.org/desktop-entry-spec/latest/recognized-keys.html --- packaging/linux/isledecomp.desktop.in | 1 + 1 file changed, 1 insertion(+) diff --git a/packaging/linux/isledecomp.desktop.in b/packaging/linux/isledecomp.desktop.in index 28309205..3bb0a870 100644 --- a/packaging/linux/isledecomp.desktop.in +++ b/packaging/linux/isledecomp.desktop.in @@ -21,6 +21,7 @@ Keywords[ru]=LEGO;lego;Остров LEGO Keywords[uk_UA]=LEGO;lego;LEGO острів SingleMainWindow=true +StartupWMClass=isle TryExec=isle Exec=isle From 8e9f531b880364c7294f3a1e0d6b1e21907938d7 Mon Sep 17 00:00:00 2001 From: Anders Jenbo Date: Thu, 3 Jul 2025 16:58:32 +0200 Subject: [PATCH 03/17] Render surfaces in a single blit (#489) --- LEGO1/omni/src/video/mxvideopresenter.cpp | 76 ++++++++--------------- 1 file changed, 26 insertions(+), 50 deletions(-) diff --git a/LEGO1/omni/src/video/mxvideopresenter.cpp b/LEGO1/omni/src/video/mxvideopresenter.cpp index 84b1c663..e5ed4564 100644 --- a/LEGO1/omni/src/video/mxvideopresenter.cpp +++ b/LEGO1/omni/src/video/mxvideopresenter.cpp @@ -275,61 +275,37 @@ void MxVideoPresenter::PutFrame() } } else { - MxRegionCursor cursor(region); - MxRect32* regionRect; + RECT src, dest; - while ((regionRect = cursor.Next(rect))) { - if (regionRect->GetWidth() >= 1 && regionRect->GetHeight() >= 1) { - RECT src, dest; + if (m_unk0x58) { + src.left = 0; + src.top = 0; + src.right = GetWidth(); + src.bottom = GetHeight(); - if (m_unk0x58) { - src.left = regionRect->GetLeft() - GetX(); - src.top = regionRect->GetTop() - GetY(); - src.right = src.left + regionRect->GetWidth(); - src.bottom = src.top + regionRect->GetHeight(); + dest.left = GetX(); + dest.top = GetY(); + dest.right = dest.left + GetWidth(); + dest.bottom = dest.top + GetHeight(); + } - dest.left = regionRect->GetLeft(); - dest.top = regionRect->GetTop(); - dest.right = dest.left + regionRect->GetWidth(); - dest.bottom = dest.top + regionRect->GetHeight(); - } - - if (m_action->GetFlags() & MxDSAction::c_bit4) { - if (m_unk0x58) { - if (PrepareRects(src, dest) >= 0) { - ddSurface->Blt(&dest, m_unk0x58, &src, DDBLT_KEYSRC, NULL); - } - } - else { - displaySurface->VTable0x30( - m_frameBitmap, - regionRect->GetLeft() - GetX(), - regionRect->GetTop() - GetY(), - regionRect->GetLeft(), - regionRect->GetTop(), - regionRect->GetWidth(), - regionRect->GetHeight(), - FALSE - ); - } - } - else if (m_unk0x58) { - if (PrepareRects(src, dest) >= 0) { - ddSurface->Blt(&dest, m_unk0x58, &src, DDBLT_NONE, NULL); - } - } - else { - displaySurface->VTable0x28( - m_frameBitmap, - regionRect->GetLeft() - GetX(), - regionRect->GetTop() - GetY(), - regionRect->GetLeft(), - regionRect->GetTop(), - regionRect->GetWidth(), - regionRect->GetHeight() - ); + if (m_action->GetFlags() & MxDSAction::c_bit4) { + if (m_unk0x58) { + if (PrepareRects(src, dest) >= 0) { + ddSurface->Blt(&dest, m_unk0x58, &src, DDBLT_KEYSRC, NULL); } } + else { + displaySurface->VTable0x30(m_frameBitmap, 0, 0, GetX(), GetY(), GetWidth(), GetHeight(), FALSE); + } + } + else if (m_unk0x58) { + if (PrepareRects(src, dest) >= 0) { + ddSurface->Blt(&dest, m_unk0x58, &src, DDBLT_NONE, NULL); + } + } + else { + displaySurface->VTable0x28(m_frameBitmap, 0, 0, GetX(), GetY(), GetWidth(), GetHeight()); } } } From 0191be7461b812c336bbc4c9c006355a8f501f79 Mon Sep 17 00:00:00 2001 From: Helloyunho Date: Fri, 4 Jul 2025 01:05:46 +0900 Subject: [PATCH 04/17] Make `draw cursor` feature work for modern platforms (#480) --- CMakeLists.txt | 36 ++++++ ISLE/isleapp.cpp | 38 +++++- ISLE/isleapp.h | 5 + ISLE/res/arrow.png | Bin 0 -> 165 bytes ISLE/res/arrow_bmp.h | 37 ++++++ ISLE/res/busy.png | Bin 0 -> 173 bytes ISLE/res/busy_bmp.h | 37 ++++++ ISLE/res/no.png | Bin 0 -> 191 bytes ISLE/res/no_bmp.h | 37 ++++++ LEGO1/cursor.h | 8 ++ .../lego/legoomni/include/legovideomanager.h | 2 + .../legoomni/src/video/legovideomanager.cpp | 36 +++++- LEGO1/omni/include/mxdisplaysurface.h | 2 + LEGO1/omni/src/video/mxdisplaysurface.cpp | 122 ++++++++++++++++++ tools/curpng2h.py | 75 +++++++++++ 15 files changed, 426 insertions(+), 9 deletions(-) create mode 100644 ISLE/res/arrow.png create mode 100644 ISLE/res/arrow_bmp.h create mode 100644 ISLE/res/busy.png create mode 100644 ISLE/res/busy_bmp.h create mode 100644 ISLE/res/no.png create mode 100644 ISLE/res/no_bmp.h create mode 100644 LEGO1/cursor.h create mode 100755 tools/curpng2h.py diff --git a/CMakeLists.txt b/CMakeLists.txt index 3808cbe1..00ba25ea 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -473,6 +473,9 @@ if (ISLE_BUILD_APP) ISLE/res/isle.rc ISLE/isleapp.cpp ISLE/islefiles.cpp + ${CMAKE_SOURCE_DIR}/ISLE/res/arrow_bmp.h + ${CMAKE_SOURCE_DIR}/ISLE/res/busy_bmp.h + ${CMAKE_SOURCE_DIR}/ISLE/res/no_bmp.h ) list(APPEND isle_targets isle) if (WIN32) @@ -529,6 +532,39 @@ if (ISLE_BUILD_APP) ISLE/3ds/config.cpp ) endif() + if(Python3_FOUND) + if(NOT DEFINED PYTHON_PIL_AVAILABLE) + execute_process( + COMMAND ${Python3_EXECUTABLE} -c "import PIL; print('pil')" + RESULT_VARIABLE PIL_RESULT + OUTPUT_VARIABLE PIL_OUTPUT + ERROR_QUIET + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + if(PIL_RESULT EQUAL 0 AND PIL_OUTPUT STREQUAL "pil") + set(PIL_AVAILABLE 1) + else() + message(STATUS "Python PIL not found, using pre-generated headers.") + set(PIL_AVAILABLE 0) + endif() + set(PYTHON_PIL_AVAILABLE ${PIL_AVAILABLE} CACHE BOOL "Is Python3 Pillow available?") + endif() + if(PYTHON_PIL_AVAILABLE) + add_custom_command( + OUTPUT + ${CMAKE_SOURCE_DIR}/ISLE/res/arrow_bmp.h + ${CMAKE_SOURCE_DIR}/ISLE/res/busy_bmp.h + ${CMAKE_SOURCE_DIR}/ISLE/res/no_bmp.h + COMMAND ${Python3_EXECUTABLE} tools/curpng2h.py ISLE/res/arrow.png ISLE/res/busy.png ISLE/res/no.png + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} + DEPENDS + ${CMAKE_SOURCE_DIR}/tools/curpng2h.py + ${CMAKE_SOURCE_DIR}/ISLE/res/arrow.png + ${CMAKE_SOURCE_DIR}/ISLE/res/busy.png + ${CMAKE_SOURCE_DIR}/ISLE/res/no.png + ) + endif() + endif() endif() if (ISLE_BUILD_CONFIG) diff --git a/ISLE/isleapp.cpp b/ISLE/isleapp.cpp index e12f9183..cfa3c50a 100644 --- a/ISLE/isleapp.cpp +++ b/ISLE/isleapp.cpp @@ -28,7 +28,10 @@ #include "mxtransitionmanager.h" #include "mxutilities.h" #include "mxvariabletable.h" +#include "res/arrow_bmp.h" +#include "res/busy_bmp.h" #include "res/isle_bmp.h" +#include "res/no_bmp.h" #include "res/resource.h" #include "roi/legoroi.h" #include "tgl/d3drm/impl.h" @@ -135,6 +138,10 @@ IsleApp::IsleApp() m_cursorBusy = NULL; m_cursorNo = NULL; m_cursorCurrent = NULL; + m_cursorArrowBitmap = NULL; + m_cursorBusyBitmap = NULL; + m_cursorNoBitmap = NULL; + m_cursorCurrentBitmap = NULL; LegoOmni::CreateInstance(); @@ -656,6 +663,12 @@ MxResult IsleApp::SetupWindow() m_cursorBusy = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_WAIT); m_cursorNo = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_NOT_ALLOWED); SDL_SetCursor(m_cursorCurrent); + if (g_isle->GetDrawCursor()) { + SDL_HideCursor(); + m_cursorCurrentBitmap = m_cursorArrowBitmap = &arrow_cursor; + m_cursorBusyBitmap = &busy_cursor; + m_cursorNoBitmap = &no_cursor; + } SDL_PropertiesID props = SDL_CreateProperties(); SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_WIDTH_NUMBER, g_targetWidth); @@ -739,6 +752,9 @@ MxResult IsleApp::SetupWindow() LegoOmni::GetInstance()->GetInputManager()->SetUseJoystick(m_useJoystick); LegoOmni::GetInstance()->GetInputManager()->SetJoystickIndex(m_joystickIndex); } + if (LegoOmni::GetInstance()->GetVideoManager() && g_isle->GetDrawCursor()) { + LegoOmni::GetInstance()->GetVideoManager()->SetCursorBitmap(m_cursorCurrentBitmap); + } MxDirect3D* d3d = LegoOmni::GetInstance()->GetVideoManager()->GetDirect3D(); if (d3d) { SDL_Log( @@ -1023,15 +1039,19 @@ void IsleApp::SetupCursor(Cursor p_cursor) switch (p_cursor) { case e_cursorArrow: m_cursorCurrent = m_cursorArrow; + m_cursorCurrentBitmap = m_cursorArrowBitmap; break; case e_cursorBusy: m_cursorCurrent = m_cursorBusy; + m_cursorCurrentBitmap = m_cursorBusyBitmap; break; case e_cursorNo: m_cursorCurrent = m_cursorNo; + m_cursorCurrentBitmap = m_cursorNoBitmap; break; case e_cursorNone: m_cursorCurrent = NULL; + m_cursorCurrentBitmap = NULL; case e_cursorUnused3: case e_cursorUnused4: case e_cursorUnused5: @@ -1043,12 +1063,22 @@ void IsleApp::SetupCursor(Cursor p_cursor) break; } - if (m_cursorCurrent != NULL) { - SDL_SetCursor(m_cursorCurrent); - SDL_ShowCursor(); + if (g_isle->GetDrawCursor()) { + if (m_cursorCurrentBitmap == NULL) { + VideoManager()->SetCursorBitmap(NULL); + } + else { + VideoManager()->SetCursorBitmap(m_cursorCurrentBitmap); + } } else { - SDL_HideCursor(); + if (m_cursorCurrent != NULL) { + SDL_SetCursor(m_cursorCurrent); + SDL_ShowCursor(); + } + else { + SDL_HideCursor(); + } } } diff --git a/ISLE/isleapp.h b/ISLE/isleapp.h index d0a7f523..4064dc25 100644 --- a/ISLE/isleapp.h +++ b/ISLE/isleapp.h @@ -1,6 +1,7 @@ #ifndef ISLEAPP_H #define ISLEAPP_H +#include "cursor.h" #include "lego1_export.h" #include "legoutils.h" #include "mxtransitionmanager.h" @@ -87,6 +88,10 @@ class IsleApp { SDL_Cursor* m_cursorBusy; // 0x80 SDL_Cursor* m_cursorNo; // 0x84 SDL_Cursor* m_cursorCurrent; // 0x88 + const CursorBitmap* m_cursorArrowBitmap; + const CursorBitmap* m_cursorBusyBitmap; + const CursorBitmap* m_cursorNoBitmap; + const CursorBitmap* m_cursorCurrentBitmap; char* m_mediaPath; char* m_iniPath; diff --git a/ISLE/res/arrow.png b/ISLE/res/arrow.png new file mode 100644 index 0000000000000000000000000000000000000000..eaa08ca6315b98cd5e563f32ebb208680d377a5a GIT binary patch literal 165 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE3?yBabR7dyoB=)|u0R?H{{R2qeE0k%Ad9gi z$S;_|;n|HeAjiwo#WBR<^xI2@d<=>_%#PRo*PE~gw7EX&(k`%VeY(VySAv7hML^Jn zMbPkon@>PDtCyj*!&V8-phsH{3$=~-+aE?8yFUsY~#=Z+2-l$=d#Wz Gp$PyxA2M_R literal 0 HcmV?d00001 diff --git a/ISLE/res/arrow_bmp.h b/ISLE/res/arrow_bmp.h new file mode 100644 index 00000000..84e3452d --- /dev/null +++ b/ISLE/res/arrow_bmp.h @@ -0,0 +1,37 @@ +#pragma once + +// Generated from ISLE/res/arrow.png +// Dimensions: 32x32 +// This file is auto-generated, do not edit it. + +#include "cursor.h" + +static const unsigned char arrow_data[] = { + 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, + 0x48, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, + 0x41, 0x00, 0x00, 0x00, 0x40, 0x80, 0x00, 0x00, 0x40, 0x40, 0x00, 0x00, + 0x40, 0x20, 0x00, 0x00, 0x41, 0xF0, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00, + 0x54, 0x80, 0x00, 0x00, 0x64, 0x80, 0x00, 0x00, 0x42, 0x40, 0x00, 0x00, + 0x02, 0x40, 0x00, 0x00, 0x01, 0x20, 0x00, 0x00, 0x01, 0x20, 0x00, 0x00, + 0x00, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +static const unsigned char arrow_mask[] = { + 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, + 0x78, 0x00, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x00, + 0x7F, 0x00, 0x00, 0x00, 0x7F, 0x80, 0x00, 0x00, 0x7F, 0xC0, 0x00, 0x00, + 0x7F, 0xE0, 0x00, 0x00, 0x7F, 0xF0, 0x00, 0x00, 0x7F, 0x00, 0x00, 0x00, + 0x77, 0x80, 0x00, 0x00, 0x67, 0x80, 0x00, 0x00, 0x43, 0xC0, 0x00, 0x00, + 0x03, 0xC0, 0x00, 0x00, 0x01, 0xE0, 0x00, 0x00, 0x01, 0xE0, 0x00, 0x00, + 0x00, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +static const CursorBitmap arrow_cursor = { 32, 32, arrow_data, arrow_mask }; diff --git a/ISLE/res/busy.png b/ISLE/res/busy.png new file mode 100644 index 0000000000000000000000000000000000000000..cd8f5bf13ffca8b24d9e283ce7fb289a7c33b64f GIT binary patch literal 173 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE3?yBabR7dyoB=)|u0R?H{{R2qeE0k%Ad9gi z$S;_|;n|HeAScMv#WBR<^wmj@TtKZXvj6|T;7b%)(lp^hTzN!E=o9V2S4=PTxH#Qe zKJhpN+9U|h%WrvqTf(JOt&VvD@65HHceXrLKRzo|yubD5oyNZ9wM!XIxEPoG3)-g) Ovenbo&t;ucLK6V#COQlN literal 0 HcmV?d00001 diff --git a/ISLE/res/busy_bmp.h b/ISLE/res/busy_bmp.h new file mode 100644 index 00000000..020512bc --- /dev/null +++ b/ISLE/res/busy_bmp.h @@ -0,0 +1,37 @@ +#pragma once + +// Generated from ISLE/res/busy.png +// Dimensions: 32x32 +// This file is auto-generated, do not edit it. + +#include "cursor.h" + +static const unsigned char busy_data[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0x00, + 0x00, 0x40, 0x01, 0x00, 0x00, 0x7F, 0xFF, 0x00, 0x00, 0x20, 0x02, 0x00, + 0x00, 0x20, 0x02, 0x00, 0x00, 0x20, 0x02, 0x00, 0x00, 0x22, 0xA2, 0x00, + 0x00, 0x11, 0x44, 0x00, 0x00, 0x08, 0x88, 0x00, 0x00, 0x04, 0x10, 0x00, + 0x00, 0x02, 0x20, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x02, 0x20, 0x00, + 0x00, 0x02, 0x20, 0x00, 0x00, 0x04, 0x10, 0x00, 0x00, 0x08, 0x88, 0x00, + 0x00, 0x10, 0x04, 0x00, 0x00, 0x20, 0x82, 0x00, 0x00, 0x21, 0x42, 0x00, + 0x00, 0x22, 0xA2, 0x00, 0x00, 0x25, 0x52, 0x00, 0x00, 0x7F, 0xFF, 0x00, + 0x00, 0x40, 0x01, 0x00, 0x00, 0x7F, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +static const unsigned char busy_mask[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0xFF, 0x00, + 0x00, 0x7F, 0xFF, 0x00, 0x00, 0x7F, 0xFF, 0x00, 0x00, 0x3F, 0xFE, 0x00, + 0x00, 0x3F, 0xFE, 0x00, 0x00, 0x3F, 0xFE, 0x00, 0x00, 0x3F, 0xFE, 0x00, + 0x00, 0x1F, 0xFC, 0x00, 0x00, 0x0F, 0xF8, 0x00, 0x00, 0x07, 0xF0, 0x00, + 0x00, 0x03, 0xE0, 0x00, 0x00, 0x03, 0xE0, 0x00, 0x00, 0x03, 0xE0, 0x00, + 0x00, 0x03, 0xE0, 0x00, 0x00, 0x07, 0xF0, 0x00, 0x00, 0x0F, 0xF8, 0x00, + 0x00, 0x1F, 0xFC, 0x00, 0x00, 0x3F, 0xFE, 0x00, 0x00, 0x3F, 0xFE, 0x00, + 0x00, 0x3F, 0xFE, 0x00, 0x00, 0x3F, 0xFE, 0x00, 0x00, 0x7F, 0xFF, 0x00, + 0x00, 0x7F, 0xFF, 0x00, 0x00, 0x7F, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +static const CursorBitmap busy_cursor = { 32, 32, busy_data, busy_mask }; diff --git a/ISLE/res/no.png b/ISLE/res/no.png new file mode 100644 index 0000000000000000000000000000000000000000..968adccd3c3cecf10e849b01e2d43a42fa9ea577 GIT binary patch literal 191 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE3?yBabR7dyoB=)|u0R?H{{R2qeE0k%Ad9gi z$S;_|;n|HeAScDs#WBR<^xaF2dM1U#oHb+G*%N}MG#%l+T#wFQ#HZ}TdJaB3XHxOX`ss2geh0G#>#Vk)09&ZX* iw>jeb&xCX8<@q)TSQ$g^@=L4&xx>@d&t;ucLK6VSOhO_6 literal 0 HcmV?d00001 diff --git a/ISLE/res/no_bmp.h b/ISLE/res/no_bmp.h new file mode 100644 index 00000000..a4ebe829 --- /dev/null +++ b/ISLE/res/no_bmp.h @@ -0,0 +1,37 @@ +#pragma once + +// Generated from ISLE/res/no.png +// Dimensions: 32x32 +// This file is auto-generated, do not edit it. + +#include "cursor.h" + +static const unsigned char no_data[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xE0, 0x00, 0x00, 0x1F, 0xF8, 0x00, + 0x00, 0x3C, 0x3C, 0x00, 0x00, 0x70, 0x0E, 0x00, 0x00, 0xF8, 0x07, 0x00, + 0x00, 0xDC, 0x03, 0x00, 0x01, 0xCE, 0x03, 0x80, 0x01, 0x87, 0x01, 0x80, + 0x01, 0x83, 0x81, 0x80, 0x01, 0x81, 0xC1, 0x80, 0x01, 0x80, 0xE1, 0x80, + 0x01, 0xC0, 0x73, 0x80, 0x00, 0xC0, 0x3B, 0x00, 0x00, 0xE0, 0x1F, 0x00, + 0x00, 0x70, 0x0E, 0x00, 0x00, 0x3C, 0x1C, 0x00, 0x00, 0x1F, 0xF8, 0x00, + 0x00, 0x07, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +static const unsigned char no_mask[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x07, 0xE0, 0x00, 0x00, 0x1F, 0xF8, 0x00, 0x00, 0x3F, 0xFC, 0x00, + 0x00, 0x7F, 0xFE, 0x00, 0x00, 0xFC, 0x3F, 0x00, 0x01, 0xFC, 0x0F, 0x80, + 0x01, 0xFE, 0x07, 0x80, 0x03, 0xFF, 0x07, 0xC0, 0x03, 0xCF, 0x83, 0xC0, + 0x03, 0xC7, 0xC3, 0xC0, 0x03, 0xC3, 0xE3, 0xC0, 0x03, 0xC1, 0xF3, 0xC0, + 0x03, 0xE0, 0xFF, 0xC0, 0x01, 0xE0, 0x7F, 0x80, 0x01, 0xF0, 0x3F, 0x80, + 0x00, 0xFC, 0x1F, 0x00, 0x00, 0x7F, 0xFE, 0x00, 0x00, 0x3F, 0xFC, 0x00, + 0x00, 0x1F, 0xF8, 0x00, 0x00, 0x07, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +static const CursorBitmap no_cursor = { 32, 32, no_data, no_mask }; diff --git a/LEGO1/cursor.h b/LEGO1/cursor.h new file mode 100644 index 00000000..171972c2 --- /dev/null +++ b/LEGO1/cursor.h @@ -0,0 +1,8 @@ +#pragma once + +typedef struct CursorBitmap { + int width; + int height; + const unsigned char* data; + const unsigned char* mask; +} CursorBitmap; diff --git a/LEGO1/lego/legoomni/include/legovideomanager.h b/LEGO1/lego/legoomni/include/legovideomanager.h index 6c12d863..ba96541c 100644 --- a/LEGO1/lego/legoomni/include/legovideomanager.h +++ b/LEGO1/lego/legoomni/include/legovideomanager.h @@ -1,6 +1,7 @@ #ifndef LEGOVIDEOMANAGER_H #define LEGOVIDEOMANAGER_H +#include "cursor.h" #include "decomp.h" #include "lego1_export.h" #include "legophonemelist.h" @@ -37,6 +38,7 @@ class LegoVideoManager : public MxVideoManager { void EnableFullScreenMovie(MxBool p_enable); LEGO1_EXPORT void EnableFullScreenMovie(MxBool p_enable, MxBool p_scale); LEGO1_EXPORT void MoveCursor(MxS32 p_cursorX, MxS32 p_cursorY); + LEGO1_EXPORT void SetCursorBitmap(const CursorBitmap* p_cursorBitmap); void ToggleFPS(MxBool p_visible); MxResult Tickle() override; // vtable+0x08 diff --git a/LEGO1/lego/legoomni/src/video/legovideomanager.cpp b/LEGO1/lego/legoomni/src/video/legovideomanager.cpp index 7e2f7e42..8b92065c 100644 --- a/LEGO1/lego/legoomni/src/video/legovideomanager.cpp +++ b/LEGO1/lego/legoomni/src/video/legovideomanager.cpp @@ -272,14 +272,13 @@ void LegoVideoManager::MoveCursor(MxS32 p_cursorX, MxS32 p_cursorY) { m_cursorX = p_cursorX; m_cursorY = p_cursorY; - m_drawCursor = TRUE; - if (623 < p_cursorX) { - m_cursorX = 623; + if (640 < p_cursorX) { + m_cursorX = 640; } - if (463 < p_cursorY) { - m_cursorY = 463; + if (480 < p_cursorY) { + m_cursorY = 480; } } @@ -836,3 +835,30 @@ void LegoVideoManager::DrawTextToSurface32( ++p_text; } } + +void LegoVideoManager::SetCursorBitmap(const CursorBitmap* p_cursorBitmap) +{ + if (p_cursorBitmap == NULL) { + m_drawCursor = FALSE; + return; + } + + if (m_cursorSurface != NULL) { + m_cursorSurface->Release(); + m_cursorSurface = NULL; + } + + m_cursorRect.top = 0; + m_cursorRect.left = 0; + m_cursorRect.bottom = p_cursorBitmap->height; + m_cursorRect.right = p_cursorBitmap->width; + + m_cursorSurface = MxDisplaySurface::CreateCursorSurface(p_cursorBitmap); + + if (m_cursorSurface == NULL) { + m_drawCursor = FALSE; + return; + } + + m_drawCursor = TRUE; +} diff --git a/LEGO1/omni/include/mxdisplaysurface.h b/LEGO1/omni/include/mxdisplaysurface.h index 8d31ff4f..ec9c6aa5 100644 --- a/LEGO1/omni/include/mxdisplaysurface.h +++ b/LEGO1/omni/include/mxdisplaysurface.h @@ -1,6 +1,7 @@ #ifndef MXDISPLAYSURFACE_H #define MXDISPLAYSURFACE_H +#include "cursor.h" #include "decomp.h" #include "mxcore.h" #include "mxvideoparam.h" @@ -97,6 +98,7 @@ class MxDisplaySurface : public MxCore { void ClearScreen(); static LPDIRECTDRAWSURFACE CreateCursorSurface(); + static LPDIRECTDRAWSURFACE CreateCursorSurface(const CursorBitmap* p_cursorBitmap); static LPDIRECTDRAWSURFACE CopySurface(LPDIRECTDRAWSURFACE p_src); LPDIRECTDRAWSURFACE GetDirectDrawSurface1() { return m_ddSurface1; } diff --git a/LEGO1/omni/src/video/mxdisplaysurface.cpp b/LEGO1/omni/src/video/mxdisplaysurface.cpp index badf05d1..bcd38000 100644 --- a/LEGO1/omni/src/video/mxdisplaysurface.cpp +++ b/LEGO1/omni/src/video/mxdisplaysurface.cpp @@ -1296,3 +1296,125 @@ LPDIRECTDRAWSURFACE MxDisplaySurface::FUN_100bc8b0(MxS32 p_width, MxS32 p_height return surface; } + +LPDIRECTDRAWSURFACE MxDisplaySurface::CreateCursorSurface(const CursorBitmap* p_cursorBitmap) +{ + LPDIRECTDRAWSURFACE newSurface = NULL; + IDirectDraw* draw = MVideoManager()->GetDirectDraw(); + MVideoManager(); + + DDSURFACEDESC ddsd; + memset(&ddsd, 0, sizeof(ddsd)); + ddsd.dwSize = sizeof(ddsd); + + if (draw->GetDisplayMode(&ddsd) != DD_OK) { + return NULL; + } + + MxS32 bytesPerPixel = ddsd.ddpfPixelFormat.dwRGBBitCount / 8; + + ddsd.dwWidth = p_cursorBitmap->width; + ddsd.dwHeight = p_cursorBitmap->height; + ddsd.dwFlags = DDSD_PIXELFORMAT | DDSD_WIDTH | DDSD_HEIGHT | DDSD_CAPS; + ddsd.ddsCaps.dwCaps = DDSCAPS_VIDEOMEMORY | DDSCAPS_OFFSCREENPLAIN; + + if (draw->CreateSurface(&ddsd, &newSurface, NULL) != DD_OK) { + ddsd.ddsCaps.dwCaps &= ~DDSCAPS_VIDEOMEMORY; + ddsd.ddsCaps.dwCaps |= DDSCAPS_SYSTEMMEMORY; + + if (draw->CreateSurface(&ddsd, &newSurface, NULL) != DD_OK) { + goto done; + } + } + + memset(&ddsd, 0, sizeof(ddsd)); + ddsd.dwSize = sizeof(ddsd); + + if (newSurface->Lock(NULL, &ddsd, DDLOCK_WAIT | DDLOCK_WRITEONLY, NULL) != DD_OK) { + goto done; + } + else { + for (int y = 0; y < p_cursorBitmap->height; y++) { + for (int x = 0; x < p_cursorBitmap->width; x++) { + MxS32 bitIndex = y * p_cursorBitmap->width + x; + MxS32 byteIndex = bitIndex / 8; + MxS32 bitOffset = 7 - (bitIndex % 8); + + MxBool isOpaque = (p_cursorBitmap->mask[byteIndex] >> bitOffset) & 1; + MxBool isBlack = (p_cursorBitmap->data[byteIndex] >> bitOffset) & 1; + + switch (bytesPerPixel) { + case 1: { + MxU8* surface = (MxU8*) ddsd.lpSurface; + + MxU8 pixel; + if (!isOpaque) { + pixel = 0x10; + } + else { + pixel = isBlack ? 0 : 0xff; + } + } + case 2: { + MxU16* surface = (MxU16*) ddsd.lpSurface; + + MxU16 pixel; + if (!isOpaque) { + pixel = RGB555_CREATE(0x1f, 0, 0x1f); + } + else { + pixel = isBlack ? RGB555_CREATE(0, 0, 0) : RGB555_CREATE(0x1f, 0x1f, 0x1f); + } + + surface[x + y * p_cursorBitmap->width] = pixel; + break; + } + default: { + MxU32* surface = (MxU32*) ddsd.lpSurface; + + MxS32 pixel; + if (!isOpaque) { + pixel = RGB8888_CREATE(0, 0, 0, 0); // Transparent pixel + } + else { + pixel = isBlack ? RGB8888_CREATE(0, 0, 0, 0xff) : RGB8888_CREATE(0xff, 0xff, 0xff, 0xff); + } + + surface[x + y * p_cursorBitmap->width] = pixel; + break; + } + } + } + } + + newSurface->Unlock(ddsd.lpSurface); + switch (bytesPerPixel) { + case 1: { + DDCOLORKEY colorkey; + colorkey.dwColorSpaceHighValue = 0x10; + colorkey.dwColorSpaceLowValue = 0x10; + newSurface->SetColorKey(DDCKEY_SRCBLT, &colorkey); + break; + } + case 2: { + DDCOLORKEY colorkey; + colorkey.dwColorSpaceHighValue = RGB555_CREATE(0x1f, 0, 0x1f); + colorkey.dwColorSpaceLowValue = RGB555_CREATE(0x1f, 0, 0x1f); + newSurface->SetColorKey(DDCKEY_SRCBLT, &colorkey); + break; + } + default: { + break; + } + } + + return newSurface; + } + +done: + if (newSurface) { + newSurface->Release(); + } + + return NULL; +} diff --git a/tools/curpng2h.py b/tools/curpng2h.py new file mode 100755 index 00000000..d55231b0 --- /dev/null +++ b/tools/curpng2h.py @@ -0,0 +1,75 @@ +#!/usr/bin/env python3 +import argparse +import itertools +from PIL import Image +from pathlib import Path + + +def encode_cursor(image_path: Path): + img = Image.open(image_path).convert("RGBA") + width, height = img.size + pixels = img.load() + + num_pixels = width * height + num_bytes = (num_pixels + 7) // 8 + + data = bytearray(num_bytes) + mask = bytearray(num_bytes) + + for y in range(height): + for x in range(width): + i = y * width + x + byte_index = i // 8 + bit_offset = 7 - (i % 8) + + r, g, b, a = pixels[x, y] + + if a >= 128: + mask[byte_index] |= 1 << bit_offset # opaque + lum = int(0.299 * r + 0.587 * g + 0.114 * b) + if lum < 128: + data[byte_index] |= 1 << bit_offset # black pixel + + return data, mask, width, height + + +def to_c_array(name, data): + lines = [] + for rowdata in itertools.batched(data, 12): + lines.append(", ".join(f"0x{byte:02X}" for byte in rowdata) + ",") + array_str = "\n ".join(lines) + return f"static const unsigned char {name}[] = {{\n {array_str}\n}};\n" + + +def main(): + parser = argparse.ArgumentParser(allow_abbrev=False) + parser.add_argument("inputs", nargs="+", help="PNG images", type=Path) + args = parser.parse_args() + + input_files: list[Path] = args.inputs + + for input_file in input_files: + data, mask, width, height = encode_cursor(input_file) + + input_file_name = input_file.stem + output_file = input_file.with_name(f"{input_file_name}_bmp.h") + + with output_file.open("w", newline="\n") as f: + f.write(f"#pragma once\n\n") + f.write(f"// Generated from {input_file}\n") + f.write(f"// Dimensions: {width}x{height}\n") + f.write("// This file is auto-generated, do not edit it.\n\n") + f.write(f'#include "cursor.h"\n\n') + f.write(to_c_array(f"{input_file_name}_data", data)) + f.write("\n") + f.write(to_c_array(f"{input_file_name}_mask", mask)) + f.write("\n") + f.write( + f"static const CursorBitmap {input_file_name}_cursor = {'{'} {width}, {height}, {input_file_name}_data, {input_file_name}_mask {'}'};\n" + ) + + print(f"Written {output_file} with cursor data.") + + +if __name__ == "__main__": + raise SystemExit(main()) From 3868071fb8d155bc29979fed124ab9855ba69be2 Mon Sep 17 00:00:00 2001 From: Anders Jenbo Date: Thu, 3 Jul 2025 20:12:55 +0200 Subject: [PATCH 05/17] Use DDBLT_COLORFILL to clear screen (#505) --- LEGO1/mxdirectx/mxdirectdraw.cpp | 24 +++++++----------------- 1 file changed, 7 insertions(+), 17 deletions(-) diff --git a/LEGO1/mxdirectx/mxdirectdraw.cpp b/LEGO1/mxdirectx/mxdirectdraw.cpp index bedf4d2e..1bec4624 100644 --- a/LEGO1/mxdirectx/mxdirectdraw.cpp +++ b/LEGO1/mxdirectx/mxdirectdraw.cpp @@ -519,35 +519,25 @@ BOOL MxDirectDraw::DDCreateSurfaces() void MxDirectDraw::ClearBackBuffers() { HRESULT result; - byte* line; - DDSURFACEDESC ddsd; + DDBLTFX ddbltfx; int count = m_bFlipSurfaces ? 2 : 1; - int value = 0; for (int i = 0; i < count; i++) { - memset(&ddsd, 0, sizeof(ddsd)); - ddsd.dwSize = sizeof(ddsd); + memset(&ddbltfx, 0, sizeof(ddbltfx)); + ddbltfx.dwSize = sizeof(ddbltfx); + ddbltfx.dwFillColor = 0; - result = m_pBackBuffer->Lock(NULL, &ddsd, DDLOCK_WAIT | DDLOCK_WRITEONLY, NULL); + result = m_pBackBuffer->Blt(NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &ddbltfx); if (result == DDERR_SURFACELOST) { m_pBackBuffer->Restore(); - result = m_pBackBuffer->Lock(NULL, &ddsd, DDLOCK_WAIT | DDLOCK_WRITEONLY, NULL); + result = m_pBackBuffer->Blt(NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &ddbltfx); } if (result != DD_OK) { - // lock failed + // blt failed return; } - // clear backBuffer - line = (byte*) ddsd.lpSurface; - for (int j = ddsd.dwHeight; j--;) { - memset(line, value, ddsd.dwWidth); - line += ddsd.lPitch; - } - - m_pBackBuffer->Unlock(ddsd.lpSurface); - if (m_bFlipSurfaces) { m_pFrontBuffer->Flip(NULL, DDFLIP_WAIT); } From 920ba63a31b73c733f1f346c5d2d13e0b20742c2 Mon Sep 17 00:00:00 2001 From: Anders Jenbo Date: Thu, 3 Jul 2025 21:56:58 +0200 Subject: [PATCH 06/17] Avoid texture updates when we just need the size (#507) --- LEGO1/lego/sources/misc/legocontainer.cpp | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/LEGO1/lego/sources/misc/legocontainer.cpp b/LEGO1/lego/sources/misc/legocontainer.cpp index 98836d6a..693f9b27 100644 --- a/LEGO1/lego/sources/misc/legocontainer.cpp +++ b/LEGO1/lego/sources/misc/legocontainer.cpp @@ -22,10 +22,9 @@ 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 | DDLOCK_WRITEONLY, NULL) == DD_OK) { + if (p_textureInfo->m_surface->GetSurfaceDesc(&desc) == DD_OK) { width = desc.dwWidth; height = desc.dwHeight; - p_textureInfo->m_surface->Unlock(desc.lpSurface); } for (LegoCachedTextureList::iterator it = m_cached.begin(); it != m_cached.end(); it++) { @@ -35,15 +34,8 @@ LegoTextureInfo* LegoTextureContainer::GetCached(LegoTextureInfo* p_textureInfo) memset(&newDesc, 0, sizeof(newDesc)); newDesc.dwSize = sizeof(newDesc); - if (surface->Lock(NULL, &newDesc, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WRITEONLY, NULL) == DD_OK) { - BOOL und = FALSE; + if (surface->GetSurfaceDesc(&newDesc) == DD_OK) { if (newDesc.dwWidth == width && newDesc.dwHeight == height) { - und = TRUE; - } - - surface->Unlock(newDesc.lpSurface); - - if (und) { (*it).second = TRUE; (*it).first->m_texture->AddRef(); return (*it).first; From 1ae9933bd5fe1b5972737cd3cb9d8db9d8bb8129 Mon Sep 17 00:00:00 2001 From: Anders Jenbo Date: Thu, 3 Jul 2025 22:04:13 +0200 Subject: [PATCH 07/17] Drop old cursor code (#509) --- .../legoomni/src/video/legovideomanager.cpp | 10 +-- LEGO1/omni/include/mxdisplaysurface.h | 1 - LEGO1/omni/src/video/mxdisplaysurface.cpp | 80 ------------------- 3 files changed, 1 insertion(+), 90 deletions(-) diff --git a/LEGO1/lego/legoomni/src/video/legovideomanager.cpp b/LEGO1/lego/legoomni/src/video/legovideomanager.cpp index 8b92065c..cdb20197 100644 --- a/LEGO1/lego/legoomni/src/video/legovideomanager.cpp +++ b/LEGO1/lego/legoomni/src/video/legovideomanager.cpp @@ -387,15 +387,7 @@ inline void LegoVideoManager::DrawCursor() LPDIRECTDRAWSURFACE ddSurface2 = m_displaySurface->GetDirectDrawSurface2(); if (!m_cursorSurface) { - m_cursorRect.top = 0; - m_cursorRect.left = 0; - m_cursorRect.bottom = 16; - m_cursorRect.right = 16; - m_cursorSurface = MxDisplaySurface::CreateCursorSurface(); - - if (!m_cursorSurface) { - m_drawCursor = FALSE; - } + return; } ddSurface2 diff --git a/LEGO1/omni/include/mxdisplaysurface.h b/LEGO1/omni/include/mxdisplaysurface.h index ec9c6aa5..df57c5c4 100644 --- a/LEGO1/omni/include/mxdisplaysurface.h +++ b/LEGO1/omni/include/mxdisplaysurface.h @@ -97,7 +97,6 @@ class MxDisplaySurface : public MxCore { ); // vtable+0x44 void ClearScreen(); - static LPDIRECTDRAWSURFACE CreateCursorSurface(); static LPDIRECTDRAWSURFACE CreateCursorSurface(const CursorBitmap* p_cursorBitmap); static LPDIRECTDRAWSURFACE CopySurface(LPDIRECTDRAWSURFACE p_src); diff --git a/LEGO1/omni/src/video/mxdisplaysurface.cpp b/LEGO1/omni/src/video/mxdisplaysurface.cpp index bcd38000..8d137e34 100644 --- a/LEGO1/omni/src/video/mxdisplaysurface.cpp +++ b/LEGO1/omni/src/video/mxdisplaysurface.cpp @@ -1015,86 +1015,6 @@ LPDIRECTDRAWSURFACE MxDisplaySurface::CopySurface(LPDIRECTDRAWSURFACE p_src) return newSurface; } -// FUNCTION: LEGO1 0x100bc070 -LPDIRECTDRAWSURFACE MxDisplaySurface::CreateCursorSurface() -{ - LPDIRECTDRAWSURFACE newSurface = NULL; - IDirectDraw* draw = MVideoManager()->GetDirectDraw(); - MVideoManager(); - - DDSURFACEDESC ddsd; - memset(&ddsd, 0, sizeof(ddsd)); - ddsd.dwSize = sizeof(ddsd); - - if (draw->GetDisplayMode(&ddsd) != DD_OK) { - return NULL; - } - - if (ddsd.ddpfPixelFormat.dwRGBBitCount != 16) { - return NULL; - } - - ddsd.dwWidth = 16; - ddsd.dwHeight = 16; - ddsd.dwFlags = DDSD_PIXELFORMAT | DDSD_WIDTH | DDSD_HEIGHT | DDSD_CAPS; - ddsd.ddsCaps.dwCaps = DDSCAPS_VIDEOMEMORY | DDSCAPS_OFFSCREENPLAIN; - - if (draw->CreateSurface(&ddsd, &newSurface, NULL) != DD_OK) { - ddsd.ddsCaps.dwCaps &= ~DDSCAPS_VIDEOMEMORY; - ddsd.ddsCaps.dwCaps |= DDSCAPS_SYSTEMMEMORY; - - if (draw->CreateSurface(&ddsd, &newSurface, NULL) != DD_OK) { - goto done; - } - } - - memset(&ddsd, 0, sizeof(ddsd)); - ddsd.dwSize = sizeof(ddsd); - - if (newSurface->Lock(NULL, &ddsd, DDLOCK_WAIT | DDLOCK_WRITEONLY, NULL) != DD_OK) { - goto done; - } - else { - MxU16* surface = (MxU16*) ddsd.lpSurface; - MxLong pitch = ddsd.lPitch; - - // draw a simple cursor to the surface - for (MxS32 x = 0; x < 16; x++) { - MxU16* surface2 = surface; - for (MxS32 y = 0; y < 16; y++) { - if ((y > 10 || x) && (x > 10 || y) && x + y != 10) { - if (x + y > 10) { - *surface2 = RGB555_CREATE(0x1f, 0, 0x1f); - } - else { - *surface2 = -1; - } - } - else { - *surface2 = 0; - } - surface2++; - } - surface = (MxU16*) ((MxU8*) surface + pitch); - } - - newSurface->Unlock(ddsd.lpSurface); - DDCOLORKEY colorkey; - colorkey.dwColorSpaceHighValue = RGB555_CREATE(0x1f, 0, 0x1f); - colorkey.dwColorSpaceLowValue = RGB555_CREATE(0x1f, 0, 0x1f); - newSurface->SetColorKey(DDCKEY_SRCBLT, &colorkey); - - return newSurface; - } - -done: - if (newSurface) { - newSurface->Release(); - } - - return NULL; -} - // FUNCTION: LEGO1 0x100bc200 void MxDisplaySurface::VTable0x24( LPDDSURFACEDESC p_desc, From e2eda71883cd872a88d8a016d8a314e2d585de61 Mon Sep 17 00:00:00 2001 From: Anders Jenbo Date: Thu, 3 Jul 2025 22:04:21 +0200 Subject: [PATCH 08/17] Yet another clearscreen ported to use COLORFILL (#508) --- LEGO1/mxdirectx/mxdirect3d.cpp | 2 +- LEGO1/mxdirectx/mxdirectdraw.cpp | 8 +++----- LEGO1/omni/src/video/mxdisplaysurface.cpp | 22 ++++++---------------- miniwin/include/miniwin/ddraw.h | 6 +++++- 4 files changed, 15 insertions(+), 23 deletions(-) diff --git a/LEGO1/mxdirectx/mxdirect3d.cpp b/LEGO1/mxdirectx/mxdirect3d.cpp index e338046f..0dae36e1 100644 --- a/LEGO1/mxdirectx/mxdirect3d.cpp +++ b/LEGO1/mxdirectx/mxdirect3d.cpp @@ -172,7 +172,7 @@ BOOL MxDirect3D::D3DSetMode() DDBLTFX ddBltFx = {}; ddBltFx.dwSize = sizeof(DDBLTFX); - ddBltFx.dwFillColor = 0; + ddBltFx.dwFillColor = 0xFF000000; if (backBuffer->Blt(NULL, NULL, NULL, DDBLT_WAIT | DDBLT_COLORFILL, &ddBltFx) != DD_OK) { SDL_Log("MxDirect3D::D3DSetMode() color fill failed\n"); diff --git a/LEGO1/mxdirectx/mxdirectdraw.cpp b/LEGO1/mxdirectx/mxdirectdraw.cpp index 1bec4624..7ccb78c2 100644 --- a/LEGO1/mxdirectx/mxdirectdraw.cpp +++ b/LEGO1/mxdirectx/mxdirectdraw.cpp @@ -519,14 +519,12 @@ BOOL MxDirectDraw::DDCreateSurfaces() void MxDirectDraw::ClearBackBuffers() { HRESULT result; - DDBLTFX ddbltfx; + DDBLTFX ddbltfx = {}; + ddbltfx.dwSize = sizeof(DDBLTFX); + ddbltfx.dwFillColor = 0xFF000000; int count = m_bFlipSurfaces ? 2 : 1; for (int i = 0; i < count; i++) { - memset(&ddbltfx, 0, sizeof(ddbltfx)); - ddbltfx.dwSize = sizeof(ddbltfx); - ddbltfx.dwFillColor = 0; - result = m_pBackBuffer->Blt(NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &ddbltfx); if (result == DDERR_SURFACELOST) { m_pBackBuffer->Restore(); diff --git a/LEGO1/omni/src/video/mxdisplaysurface.cpp b/LEGO1/omni/src/video/mxdisplaysurface.cpp index 8d137e34..d38cb093 100644 --- a/LEGO1/omni/src/video/mxdisplaysurface.cpp +++ b/LEGO1/omni/src/video/mxdisplaysurface.cpp @@ -72,7 +72,7 @@ void MxDisplaySurface::ClearScreen() DDBLTFX ddBltFx = {}; ddBltFx.dwSize = sizeof(DDBLTFX); - ddBltFx.dwFillColor = 0; + ddBltFx.dwFillColor = 0xFF000000; for (MxS32 i = 0; i < backBuffers; i++) { if (m_ddSurface2->Blt(NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &ddBltFx) == DDERR_SURFACELOST) { @@ -779,21 +779,11 @@ void MxDisplaySurface::Display(MxS32 p_left, MxS32 p_top, MxS32 p_left2, MxS32 p if (g_unk0x1010215c < 2) { g_unk0x1010215c++; - DDSURFACEDESC ddsd; - memset(&ddsd, 0, sizeof(ddsd)); - ddsd.dwSize = sizeof(ddsd); - if (m_ddSurface2->Lock(NULL, &ddsd, DDLOCK_WAIT | DDLOCK_WRITEONLY, NULL) == DD_OK) { - MxU8* surface = (MxU8*) ddsd.lpSurface; - MxS32 height = m_videoParam.GetRect().GetHeight(); + DDBLTFX ddbltfx = {}; + ddbltfx.dwSize = sizeof(ddbltfx); + ddbltfx.dwFillColor = 0xFF000000; - for (MxU32 i = 0; i < ddsd.dwHeight; i++) { - memset(surface, 0, ddsd.lPitch); - surface += ddsd.lPitch; - } - - m_ddSurface2->Unlock(ddsd.lpSurface); - } - else { + if (m_ddSurface2->Blt(NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &ddbltfx) != DD_OK) { SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "MxDisplaySurface::Display error\n"); } } @@ -812,7 +802,7 @@ void MxDisplaySurface::Display(MxS32 p_left, MxS32 p_top, MxS32 p_left2, MxS32 p DDBLTFX data; memset(&data, 0, sizeof(data)); data.dwSize = sizeof(data); - data.dwDDFX = 8; + data.dwDDFX = DDBLTFX_NOTEARING; if (m_ddSurface1->Blt((LPRECT) &b, m_ddSurface2, (LPRECT) &a, DDBLT_NONE, &data) == DDERR_SURFACELOST) { m_ddSurface1->Restore(); diff --git a/miniwin/include/miniwin/ddraw.h b/miniwin/include/miniwin/ddraw.h index 1e3fd17f..2a8932a2 100644 --- a/miniwin/include/miniwin/ddraw.h +++ b/miniwin/include/miniwin/ddraw.h @@ -246,9 +246,13 @@ struct DDSCAPS { }; typedef struct DDSCAPS* LPDDSCAPS; +#define DDBLTFX_NOTEARING DDBLTFXFlags::NOTEARING +enum class DDBLTFXFlags : uint8_t { + NOTEARING = 1 << 3, +}; struct DDBLTFX { DWORD dwSize; - DWORD dwDDFX; + DDBLTFXFlags dwDDFX; DWORD dwROP; DWORD dwFillColor; }; From c63d725b641eade5cc0be158ea933a5ead68ed36 Mon Sep 17 00:00:00 2001 From: Anders Jenbo Date: Fri, 4 Jul 2025 00:20:31 +0200 Subject: [PATCH 09/17] Port WipeDown and Window to use DDBLT_COLORFILL (#506) --- .../src/common/mxtransitionmanager.cpp | 116 ++++-------------- .../src/d3drm/backends/citro3d/renderer.cpp | 85 +++++++------ .../src/d3drm/backends/directx9/actual.cpp | 73 +++++------ miniwin/src/d3drm/backends/directx9/actual.h | 2 +- .../src/d3drm/backends/directx9/renderer.cpp | 4 +- miniwin/src/d3drm/backends/opengl1/actual.cpp | 33 +++-- miniwin/src/d3drm/backends/opengl1/actual.h | 3 +- .../src/d3drm/backends/opengl1/renderer.cpp | 9 +- .../src/d3drm/backends/opengles2/renderer.cpp | 43 ++++--- .../src/d3drm/backends/sdl3gpu/renderer.cpp | 44 ++++--- .../src/d3drm/backends/software/renderer.cpp | 25 +++- miniwin/src/ddraw/framebuffer.cpp | 20 ++- miniwin/src/internal/d3drmrenderer.h | 2 +- miniwin/src/internal/d3drmrenderer_citro3d.h | 2 +- miniwin/src/internal/d3drmrenderer_directx9.h | 2 +- miniwin/src/internal/d3drmrenderer_opengl1.h | 2 +- .../src/internal/d3drmrenderer_opengles2.h | 2 +- miniwin/src/internal/d3drmrenderer_sdl3gpu.h | 2 +- miniwin/src/internal/d3drmrenderer_software.h | 2 +- 19 files changed, 248 insertions(+), 223 deletions(-) diff --git a/LEGO1/lego/legoomni/src/common/mxtransitionmanager.cpp b/LEGO1/lego/legoomni/src/common/mxtransitionmanager.cpp index 8c2c994d..6fd211c6 100644 --- a/LEGO1/lego/legoomni/src/common/mxtransitionmanager.cpp +++ b/LEGO1/lego/legoomni/src/common/mxtransitionmanager.cpp @@ -400,47 +400,18 @@ void MxTransitionManager::WipeDownTransition() return; } - DDSURFACEDESC ddsd; - memset(&ddsd, 0, sizeof(ddsd)); - ddsd.dwSize = sizeof(ddsd); + RECT fillRect = g_fullScreenRect; + // For each of the 240 animation ticks, blank out two scanlines + // starting at the top of the screen. + fillRect.bottom = 2 * (m_animationTimer + 1); - 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 | DDLOCK_WRITEONLY, NULL); - } + DDBLTFX bltFx = {}; + bltFx.dwSize = sizeof(bltFx); + bltFx.dwFillColor = 0xFF000000; - if (res == DD_OK) { - SubmitCopyRect(&ddsd); + m_ddSurface->Blt(&fillRect, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &bltFx); - // For each of the 240 animation ticks, blank out two scanlines - // starting at the top of the screen. - MxU8* line = (MxU8*) ddsd.lpSurface + 2 * ddsd.lPitch * m_animationTimer; - - if (ddsd.ddpfPixelFormat.dwRGBBitCount == 32) { - MxU32* pixels = (MxU32*) line; - int pixelsPerLine = ddsd.lPitch / 4; - for (int i = 0; i < pixelsPerLine; i++) { - pixels[i] = 0xFF000000; - } - line += ddsd.lPitch; - pixels = (MxU32*) line; - for (int i = 0; i < pixelsPerLine; i++) { - pixels[i] = 0xFF000000; - } - } - else { - memset(line, 0, ddsd.lPitch); - - line += ddsd.lPitch; - memset(line, 0, ddsd.lPitch); - } - - SetupCopyRect(&ddsd); - m_ddSurface->Unlock(ddsd.lpSurface); - - m_animationTimer++; - } + m_animationTimer++; } // FUNCTION: LEGO1 0x1004c270 @@ -452,65 +423,28 @@ void MxTransitionManager::WindowsTransition() return; } - DDSURFACEDESC ddsd; - memset(&ddsd, 0, sizeof(ddsd)); - ddsd.dwSize = sizeof(ddsd); + DDBLTFX bltFx = {}; + bltFx.dwSize = sizeof(bltFx); + bltFx.dwFillColor = 0xFF000000; - 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 | DDLOCK_WRITEONLY, NULL); - } + int top = m_animationTimer; + int bottom = 480 - m_animationTimer - 1; + int left = m_animationTimer; + int right = 639 - m_animationTimer; - if (res == DD_OK) { - SubmitCopyRect(&ddsd); + RECT topRect = {0, top, 640, top + 1}; + m_ddSurface->Blt(&topRect, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &bltFx); - MxU8* line = (MxU8*) ddsd.lpSurface + m_animationTimer * ddsd.lPitch; + RECT bottomRect = {0, bottom, 640, bottom + 1}; + m_ddSurface->Blt(&bottomRect, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &bltFx); - MxS32 bytesPerPixel = ddsd.ddpfPixelFormat.dwRGBBitCount / 8; + RECT leftRect = {left, top + 1, left + 1, bottom}; + m_ddSurface->Blt(&leftRect, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &bltFx); - if (bytesPerPixel == 4) { - MxU32* pixels = (MxU32*) line; - for (int i = 0; i < 640; i++) { - pixels[i] = 0xFF000000; - } + RECT rightRect = {right, top + 1, right + 1, bottom}; + m_ddSurface->Blt(&rightRect, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &bltFx); - for (MxS32 i = m_animationTimer + 1; i < 480 - m_animationTimer - 1; i++) { - line += ddsd.lPitch; - pixels = (MxU32*) line; - pixels[m_animationTimer] = 0xFF000000; - pixels[639 - m_animationTimer] = 0xFF000000; - } - - if (m_animationTimer < 240 - 1) { - line += ddsd.lPitch; - pixels = (MxU32*) line; - for (int i = 0; i < 640; i++) { - pixels[i] = 0xFF000000; - } - } - } - else { - memset(line, 0, 640 * bytesPerPixel); - - for (MxS32 i = m_animationTimer + 1; i < 480 - m_animationTimer - 1; i++) { - line += ddsd.lPitch; - - memset(line + m_animationTimer * bytesPerPixel, 0, bytesPerPixel); - memset(line + (639 - m_animationTimer) * bytesPerPixel, 0, bytesPerPixel); - } - - if (m_animationTimer < 240 - 1) { - line += ddsd.lPitch; - memset(line, 0, 640 * bytesPerPixel); - } - } - - SetupCopyRect(&ddsd); - m_ddSurface->Unlock(ddsd.lpSurface); - - m_animationTimer++; - } + m_animationTimer++; } // FUNCTION: LEGO1 0x1004c3e0 diff --git a/miniwin/src/d3drm/backends/citro3d/renderer.cpp b/miniwin/src/d3drm/backends/citro3d/renderer.cpp index f076cf70..f71f9255 100644 --- a/miniwin/src/d3drm/backends/citro3d/renderer.cpp +++ b/miniwin/src/d3drm/backends/citro3d/renderer.cpp @@ -443,6 +443,32 @@ void ConvertMatrix(const D3DRMMATRIX4D in, C3D_Mtx* out) } } +void SetMaterialAppearance( + const FColor& color, + float shininess, + int uLoc_meshColor, + int uLoc_shininess, + C3D_Tex* textures +) +{ + C3D_FVUnifSet(GPU_VERTEX_SHADER, uLoc_meshColor, color.r, color.g, color.b, color.a); + C3D_FVUnifSet(GPU_VERTEX_SHADER, uLoc_shininess, shininess, 0.0f, 0.0f, 0.0f); + + C3D_TexEnv* env = C3D_GetTexEnv(0); + C3D_TexEnvInit(env); + + if (textures) { + C3D_TexBind(0, textures); + C3D_TexEnvSrc(env, C3D_Both, GPU_TEXTURE0, GPU_PRIMARY_COLOR, GPU_PRIMARY_COLOR); + C3D_TexEnvFunc(env, C3D_Both, GPU_MODULATE); + } + else { + C3D_TexBind(0, nullptr); + C3D_TexEnvSrc(env, C3D_Both, GPU_PRIMARY_COLOR, GPU_PRIMARY_COLOR, GPU_PRIMARY_COLOR); + C3D_TexEnvFunc(env, C3D_Both, GPU_REPLACE); + } +} + void Citro3DRenderer::SubmitDraw( DWORD meshId, const D3DRMMATRIX4D& modelViewMatrix, @@ -462,32 +488,17 @@ void Citro3DRenderer::SubmitDraw( BufInfo_Init(bufInfo); BufInfo_Add(bufInfo, mesh.vbo, sizeof(D3DRMVERTEX), 3, 0x210); - C3D_FVUnifSet( - GPU_VERTEX_SHADER, + SetMaterialAppearance( + {appearance.color.r / 255.0f, + appearance.color.g / 255.0f, + appearance.color.b / 255.0f, + appearance.color.a / 255.0f}, + appearance.shininess, uLoc_meshColor, - appearance.color.r / 255.0f, - appearance.color.g / 255.0f, - appearance.color.b / 255.0f, - appearance.color.a / 255.0f + uLoc_shininess, + appearance.textureId != NO_TEXTURE_ID ? &m_textures[appearance.textureId].c3dTex : nullptr ); - C3D_FVUnifSet(GPU_VERTEX_SHADER, uLoc_shininess, appearance.shininess / 255.0f, 0.0f, 0.0f, 0.0f); - - if (appearance.textureId != NO_TEXTURE_ID) { - C3D_TexBind(0, &m_textures[appearance.textureId].c3dTex); - C3D_TexEnv* env = C3D_GetTexEnv(0); - C3D_TexEnvInit(env); - C3D_TexEnvSrc(env, C3D_Both, GPU_TEXTURE0, GPU_PRIMARY_COLOR, GPU_PRIMARY_COLOR); - C3D_TexEnvFunc(env, C3D_Both, GPU_MODULATE); - } - else { - C3D_TexBind(0, nullptr); - C3D_TexEnv* env = C3D_GetTexEnv(0); - C3D_TexEnvInit(env); - C3D_TexEnvSrc(env, C3D_Both, GPU_PRIMARY_COLOR, GPU_PRIMARY_COLOR, GPU_PRIMARY_COLOR); - C3D_TexEnvFunc(env, C3D_Both, GPU_REPLACE); - } - C3D_DrawArrays(GPU_TRIANGLES, 0, mesh.vertexCount); } @@ -519,7 +530,7 @@ void Citro3DRenderer::Flip() g_rendering = false; } -void Citro3DRenderer::Draw2DImage(Uint32 textureId, const SDL_Rect& srcRect, const SDL_Rect& dstRect) +void Citro3DRenderer::Draw2DImage(Uint32 textureId, const SDL_Rect& srcRect, const SDL_Rect& dstRect, FColor color) { C3D_AlphaBlend(GPU_BLEND_ADD, GPU_BLEND_ADD, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA); StartFrame(); @@ -545,16 +556,9 @@ void Citro3DRenderer::Draw2DImage(Uint32 textureId, const SDL_Rect& srcRect, con C3D_FVUnifSet(GPU_VERTEX_SHADER, uLoc_lightClr + 1, 0.0f, 0.0f, 0.0f, 0.0f); C3D_FVUnifSet(GPU_VERTEX_SHADER, uLoc_lightClr + 2, 1.0f, 1.0f, 1.0f, 1.0f); // Ambient - C3D_FVUnifSet(GPU_VERTEX_SHADER, uLoc_shininess, 0.0f, 0.0f, 0.0f, 0.0f); - C3D_FVUnifSet(GPU_VERTEX_SHADER, uLoc_meshColor, 1.0f, 1.0f, 1.0f, 1.0f); + C3DTextureCacheEntry* texture = (textureId != NO_TEXTURE_ID) ? &m_textures[textureId] : nullptr; - C3DTextureCacheEntry& texture = m_textures[textureId]; - - C3D_TexBind(0, &texture.c3dTex); - C3D_TexEnv* env = C3D_GetTexEnv(0); - C3D_TexEnvInit(env); - C3D_TexEnvSrc(env, C3D_Both, GPU_TEXTURE0, GPU_PRIMARY_COLOR, GPU_PRIMARY_COLOR); - C3D_TexEnvFunc(env, C3D_Both, GPU_MODULATE); + SetMaterialAppearance(color, 0.0f, uLoc_meshColor, uLoc_shininess, texture ? &texture->c3dTex : nullptr); float scale = m_viewportTransform.scale; @@ -563,10 +567,17 @@ void Citro3DRenderer::Draw2DImage(Uint32 textureId, const SDL_Rect& srcRect, con float x2 = x1 + static_cast(dstRect.w); float y2 = y1 + static_cast(dstRect.h); - float u0 = (srcRect.x * scale) / texture.width; - float u1 = ((srcRect.x + srcRect.w) * scale) / texture.width; - float v0 = (srcRect.y * scale) / texture.height; - float v1 = ((srcRect.y + srcRect.h) * scale) / texture.height; + float u0 = 0.0f; + float u1 = 0.0f; + float v0 = 0.0f; + float v1 = 0.0f; + + if (texture) { + u0 = (srcRect.x * scale) / texture->width; + u1 = ((srcRect.x + srcRect.w) * scale) / texture->width; + v0 = (srcRect.y * scale) / texture->height; + v1 = ((srcRect.y + srcRect.h) * scale) / texture->height; + } C3D_ImmDrawBegin(GPU_TRIANGLES); diff --git a/miniwin/src/d3drm/backends/directx9/actual.cpp b/miniwin/src/d3drm/backends/directx9/actual.cpp index 33dc2864..4ccea210 100644 --- a/miniwin/src/d3drm/backends/directx9/actual.cpp +++ b/miniwin/src/d3drm/backends/directx9/actual.cpp @@ -297,44 +297,23 @@ D3DMATRIX ToD3DMATRIX(const Matrix4x4& in) return out; } -void Actual_SubmitDraw( - const D3D9MeshCacheEntry* mesh, - const Matrix4x4* modelViewMatrix, - const Matrix4x4* worldMatrix, - const Matrix4x4* viewMatrix, - const Matrix3x3* normalMatrix, - const Appearance* appearance, - IDirect3DTexture9* texture -) +void SetMaterialAndTexture(const FColor& color, float shininess, IDirect3DTexture9* texture) { - 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; - mat.Diffuse.g = appearance->color.g / 255.0f; - mat.Diffuse.b = appearance->color.b / 255.0f; - mat.Diffuse.a = appearance->color.a / 255.0f; + mat.Diffuse.r = color.r / 255.0f; + mat.Diffuse.g = color.g / 255.0f; + mat.Diffuse.b = color.b / 255.0f; + mat.Diffuse.a = color.a / 255.0f; mat.Ambient = mat.Diffuse; - if (appearance->shininess != 0) { + if (shininess != 0) { g_device->SetRenderState(D3DRS_SPECULARENABLE, TRUE); - mat.Specular.r = 1.0f; - mat.Specular.g = 1.0f; - mat.Specular.b = 1.0f; - mat.Specular.a = 1.0f; - mat.Power = appearance->shininess; + mat.Specular = {1.0f, 1.0f, 1.0f, 1.0f}; + mat.Power = shininess; } else { g_device->SetRenderState(D3DRS_SPECULARENABLE, FALSE); - mat.Specular.r = 0.0f; - mat.Specular.g = 0.0f; - mat.Specular.b = 0.0f; - mat.Specular.a = 0.0f; + mat.Specular = {0.0f, 0.0f, 0.0f, 0.0f}; mat.Power = 0.0f; } @@ -352,6 +331,33 @@ void Actual_SubmitDraw( else { g_device->SetTexture(0, nullptr); } +} + +void Actual_SubmitDraw( + const D3D9MeshCacheEntry* mesh, + const Matrix4x4* modelViewMatrix, + const Matrix4x4* worldMatrix, + const Matrix4x4* viewMatrix, + const Matrix3x3* normalMatrix, + const Appearance* appearance, + IDirect3DTexture9* texture +) +{ + 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); + + SetMaterialAndTexture( + {appearance->color.r / 255.0f, + appearance->color.g / 255.0f, + appearance->color.b / 255.0f, + appearance->color.a / 255.0f}, + appearance->shininess, + texture + ); g_device->SetRenderState(D3DRS_SHADEMODE, mesh->flat ? D3DSHADE_FLAT : D3DSHADE_GOURAUD); @@ -367,7 +373,7 @@ uint32_t Actual_Flip() return g_device->Present(nullptr, nullptr, nullptr, nullptr); } -void Actual_Draw2DImage(IDirect3DTexture9* texture, const SDL_Rect& srcRect, const SDL_Rect& dstRect) +void Actual_Draw2DImage(IDirect3DTexture9* texture, const SDL_Rect& srcRect, const SDL_Rect& dstRect, FColor color) { StartScene(); @@ -405,10 +411,7 @@ void Actual_Draw2DImage(IDirect3DTexture9* texture, const SDL_Rect& srcRect, con 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); + SetMaterialAndTexture(color, 0, texture); D3DSURFACE_DESC texDesc; texture->GetLevelDesc(0, &texDesc); diff --git a/miniwin/src/d3drm/backends/directx9/actual.h b/miniwin/src/d3drm/backends/directx9/actual.h index e3369ec9..bf09cb00 100644 --- a/miniwin/src/d3drm/backends/directx9/actual.h +++ b/miniwin/src/d3drm/backends/directx9/actual.h @@ -78,5 +78,5 @@ void Actual_SubmitDraw( 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); +void Actual_Draw2DImage(IDirect3DTexture9* texture, const SDL_Rect& srcRect, const SDL_Rect& dstRect, FColor color); 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 2701528b..5c8a2354 100644 --- a/miniwin/src/d3drm/backends/directx9/renderer.cpp +++ b/miniwin/src/d3drm/backends/directx9/renderer.cpp @@ -273,9 +273,9 @@ void DirectX9Renderer::Flip() Actual_Flip(); } -void DirectX9Renderer::Draw2DImage(Uint32 textureId, const SDL_Rect& srcRect, const SDL_Rect& dstRect) +void DirectX9Renderer::Draw2DImage(Uint32 textureId, const SDL_Rect& srcRect, const SDL_Rect& dstRect, FColor color) { - Actual_Draw2DImage(m_textures[textureId].dxTexture, srcRect, dstRect); + Actual_Draw2DImage(m_textures[textureId].dxTexture, srcRect, dstRect, color); } void DirectX9Renderer::SetDither(bool dither) diff --git a/miniwin/src/d3drm/backends/opengl1/actual.cpp b/miniwin/src/d3drm/backends/opengl1/actual.cpp index d75eb04e..b1a464d5 100644 --- a/miniwin/src/d3drm/backends/opengl1/actual.cpp +++ b/miniwin/src/d3drm/backends/opengl1/actual.cpp @@ -285,9 +285,10 @@ void GL11_Clear(float r, float g, float b) } void GL11_Draw2DImage( - GLTextureCacheEntry& cache, + const GLTextureCacheEntry* cache, const SDL_Rect& srcRect, const SDL_Rect& dstRect, + const FColor& color, float left, float right, float bottom, @@ -296,6 +297,7 @@ void GL11_Draw2DImage( { glDisable(GL_DEPTH_TEST); glDepthMask(GL_FALSE); + glShadeModel(GL_FLAT); glMatrixMode(GL_PROJECTION); glLoadIdentity(); @@ -306,17 +308,28 @@ void GL11_Draw2DImage( glLoadIdentity(); glDisable(GL_LIGHTING); - glColor4f(1.0f, 1.0f, 1.0f, 1.0f); + glColor4f(color.r, color.g, color.b, color.a); - glEnable(GL_TEXTURE_2D); - glBindTexture(GL_TEXTURE_2D, cache.glTextureId); - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + float u1 = 0; + float v1 = 0; + float u2 = 0; + float v2 = 0; - float u1 = srcRect.x / cache.width; - float v1 = srcRect.y / cache.height; - float u2 = (srcRect.x + srcRect.w) / cache.width; - float v2 = (srcRect.y + srcRect.h) / cache.height; + if (cache) { + glEnable(GL_TEXTURE_2D); + glBindTexture(GL_TEXTURE_2D, cache->glTextureId); + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + u1 = srcRect.x / cache->width; + v1 = srcRect.y / cache->height; + u2 = (srcRect.x + srcRect.w) / cache->width; + v2 = (srcRect.y + srcRect.h) / cache->height; + } + else { + glDisable(GL_TEXTURE_2D); + glDisableClientState(GL_TEXTURE_COORD_ARRAY); + } float x1 = (float) dstRect.x; float y1 = (float) dstRect.y; diff --git a/miniwin/src/d3drm/backends/opengl1/actual.h b/miniwin/src/d3drm/backends/opengl1/actual.h index 7a6a4432..9460119c 100644 --- a/miniwin/src/d3drm/backends/opengl1/actual.h +++ b/miniwin/src/d3drm/backends/opengl1/actual.h @@ -79,9 +79,10 @@ void GL11_SubmitDraw( void GL11_Resize(int width, int height); void GL11_Clear(float r, float g, float b); void GL11_Draw2DImage( - GLTextureCacheEntry& cache, + const GLTextureCacheEntry* cache, const SDL_Rect& srcRect, const SDL_Rect& dstRect, + const FColor& color, float left, float right, float bottom, diff --git a/miniwin/src/d3drm/backends/opengl1/renderer.cpp b/miniwin/src/d3drm/backends/opengl1/renderer.cpp index 4c6aacf9..8c43d14a 100644 --- a/miniwin/src/d3drm/backends/opengl1/renderer.cpp +++ b/miniwin/src/d3drm/backends/opengl1/renderer.cpp @@ -372,7 +372,7 @@ void OpenGL1Renderer::Flip() } } -void OpenGL1Renderer::Draw2DImage(Uint32 textureId, const SDL_Rect& srcRect, const SDL_Rect& dstRect) +void OpenGL1Renderer::Draw2DImage(Uint32 textureId, const SDL_Rect& srcRect, const SDL_Rect& dstRect, FColor color) { m_dirty = true; @@ -381,7 +381,12 @@ void OpenGL1Renderer::Draw2DImage(Uint32 textureId, const SDL_Rect& srcRect, con float top = -m_viewportTransform.offsetY / m_viewportTransform.scale; float bottom = (m_height - m_viewportTransform.offsetY) / m_viewportTransform.scale; - GL11_Draw2DImage(m_textures[textureId], srcRect, dstRect, left, right, bottom, top); + const GLTextureCacheEntry* texture = nullptr; + if (textureId != NO_TEXTURE_ID) { + texture = &m_textures[textureId]; + } + + GL11_Draw2DImage(texture, srcRect, dstRect, color, left, right, bottom, top); } void OpenGL1Renderer::SetDither(bool dither) diff --git a/miniwin/src/d3drm/backends/opengles2/renderer.cpp b/miniwin/src/d3drm/backends/opengles2/renderer.cpp index 28466bea..850e8b6e 100644 --- a/miniwin/src/d3drm/backends/opengles2/renderer.cpp +++ b/miniwin/src/d3drm/backends/opengles2/renderer.cpp @@ -598,7 +598,7 @@ void OpenGLES2Renderer::Flip() } } -void OpenGLES2Renderer::Draw2DImage(Uint32 textureId, const SDL_Rect& srcRect, const SDL_Rect& dstRect) +void OpenGLES2Renderer::Draw2DImage(Uint32 textureId, const SDL_Rect& srcRect, const SDL_Rect& dstRect, FColor color) { m_dirty = true; @@ -607,25 +607,37 @@ void OpenGLES2Renderer::Draw2DImage(Uint32 textureId, const SDL_Rect& srcRect, c glUseProgram(m_shaderProgram); - float color[] = {1.0f, 1.0f, 1.0f, 1.0f}; + float ambient[] = {1.0f, 1.0f, 1.0f, 1.0f}; float blank[] = {0.0f, 0.0f, 0.0f, 0.0f}; - glUniform4fv(u_lightLocs[0][0], 1, color); + glUniform4fv(u_lightLocs[0][0], 1, ambient); glUniform4fv(u_lightLocs[0][1], 1, blank); glUniform4fv(u_lightLocs[0][2], 1, blank); glUniform1i(m_lightCountLoc, 1); - glUniform4f(m_colorLoc, 1.0f, 1.0f, 1.0f, 1.0f); + glUniform4f(m_colorLoc, color.r, color.g, color.b, color.a); glUniform1f(m_shinLoc, 0.0f); - const GLES2TextureCacheEntry& texture = m_textures[textureId]; - 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(texture.width * scaleX)), - static_cast(std::round(texture.height * scaleY)) - }; + SDL_Rect expandedDstRect; + if (textureId != NO_TEXTURE_ID) { + const GLES2TextureCacheEntry& texture = m_textures[textureId]; + float scaleX = static_cast(dstRect.w) / srcRect.w; + float scaleY = static_cast(dstRect.h) / srcRect.h; + expandedDstRect = { + static_cast(std::round(dstRect.x - srcRect.x * scaleX)), + static_cast(std::round(dstRect.y - srcRect.y * scaleY)), + static_cast(std::round(texture.width * scaleX)), + static_cast(std::round(texture.height * scaleY)) + }; + + glActiveTexture(GL_TEXTURE0); + glUniform1i(m_useTextureLoc, 1); + glBindTexture(GL_TEXTURE_2D, texture.glTextureId); + glUniform1i(m_textureLoc, 0); + } + else { + expandedDstRect = dstRect; + glUniform1i(m_useTextureLoc, 0); + } D3DRMMATRIX4D modelView, projection; Create2DTransformMatrix( @@ -645,11 +657,6 @@ void OpenGLES2Renderer::Draw2DImage(Uint32 textureId, const SDL_Rect& srcRect, c glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glActiveTexture(GL_TEXTURE0); - glUniform1i(m_useTextureLoc, 1); - glBindTexture(GL_TEXTURE_2D, texture.glTextureId); - glUniform1i(m_textureLoc, 0); - glEnable(GL_SCISSOR_TEST); glScissor( static_cast(std::round(dstRect.x * m_viewportTransform.scale + m_viewportTransform.offsetX)), diff --git a/miniwin/src/d3drm/backends/sdl3gpu/renderer.cpp b/miniwin/src/d3drm/backends/sdl3gpu/renderer.cpp index 69b326b6..c6324f03 100644 --- a/miniwin/src/d3drm/backends/sdl3gpu/renderer.cpp +++ b/miniwin/src/d3drm/backends/sdl3gpu/renderer.cpp @@ -884,24 +884,37 @@ void Direct3DRMSDL3GPURenderer::Flip() m_cmdbuf = nullptr; } -void Direct3DRMSDL3GPURenderer::Draw2DImage(Uint32 textureId, const SDL_Rect& srcRect, const SDL_Rect& dstRect) +void Direct3DRMSDL3GPURenderer::Draw2DImage( + Uint32 textureId, + const SDL_Rect& srcRect, + const SDL_Rect& dstRect, + FColor color +) { 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)), - }; + SDL_GPUTexture* tex; + SDL_Rect expandedDstRect; + if (textureId == NO_TEXTURE_ID) { + expandedDstRect = dstRect; + tex = m_dummyTexture; + } + else { + SDL3TextureCache& cache = m_textures[textureId]; + tex = cache.gpuTexture; + auto surface = static_cast(cache.texture->m_surface); + float scaleX = static_cast(dstRect.w) / srcRect.w; + float scaleY = static_cast(dstRect.h) / srcRect.h; + 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, @@ -916,11 +929,14 @@ void Direct3DRMSDL3GPURenderer::Draw2DImage(Uint32 textureId, const SDL_Rect& sr 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.color.r = static_cast(color.r * 255); + m_fragmentShadingData.color.g = static_cast(color.g * 255); + m_fragmentShadingData.color.b = static_cast(color.b * 255); + m_fragmentShadingData.color.a = static_cast(color.a * 255); m_fragmentShadingData.shininess = 0.0f; m_fragmentShadingData.useTexture = 1; - SDL_GPUTextureSamplerBinding samplerBinding = {tex.gpuTexture, m_uiSampler}; + SDL_GPUTextureSamplerBinding samplerBinding = {tex, 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)); diff --git a/miniwin/src/d3drm/backends/software/renderer.cpp b/miniwin/src/d3drm/backends/software/renderer.cpp index b4fab671..2ae8697e 100644 --- a/miniwin/src/d3drm/backends/software/renderer.cpp +++ b/miniwin/src/d3drm/backends/software/renderer.cpp @@ -774,16 +774,35 @@ void Direct3DRMSoftwareRenderer::Flip() SDL_RenderPresent(m_renderer); } -void Direct3DRMSoftwareRenderer::Draw2DImage(Uint32 textureId, const SDL_Rect& srcRect, const SDL_Rect& dstRect) +void Direct3DRMSoftwareRenderer::Draw2DImage( + Uint32 textureId, + const SDL_Rect& srcRect, + const SDL_Rect& dstRect, + FColor color +) { - 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), }; + + if (textureId == NO_TEXTURE_ID) { + Uint32 sdlColor = SDL_MapRGBA( + m_format, + m_palette, + static_cast(color.r * 255), + static_cast(color.g * 255), + static_cast(color.b * 255), + static_cast(color.a * 255) + ); + SDL_FillSurfaceRect(m_renderedImage, ¢eredRect, sdlColor); + return; + } + + SDL_Surface* surface = m_textures[textureId].cached; + SDL_UnlockSurface(surface); SDL_BlitSurfaceScaled(surface, &srcRect, m_renderedImage, ¢eredRect, SDL_SCALEMODE_LINEAR); SDL_LockSurface(surface); } diff --git a/miniwin/src/ddraw/framebuffer.cpp b/miniwin/src/ddraw/framebuffer.cpp index 9f4224fd..20490b42 100644 --- a/miniwin/src/ddraw/framebuffer.cpp +++ b/miniwin/src/ddraw/framebuffer.cpp @@ -48,16 +48,32 @@ HRESULT FrameBufferImpl::Blt( if (!DDRenderer) { return DDERR_GENERIC; } + if (dynamic_cast(lpDDSrcSurface) == this) { return Flip(nullptr, DDFLIP_WAIT); } + if ((dwFlags & DDBLT_COLORFILL) == DDBLT_COLORFILL) { + Uint8 a = (lpDDBltFx->dwFillColor >> 24) & 0xFF; Uint8 r = (lpDDBltFx->dwFillColor >> 16) & 0xFF; Uint8 g = (lpDDBltFx->dwFillColor >> 8) & 0xFF; Uint8 b = lpDDBltFx->dwFillColor & 0xFF; - DDRenderer->Clear(r / 255.0f, g / 255.0f, b / 255.0f); + + float fa = a / 255.0f; + float fr = r / 255.0f; + float fg = g / 255.0f; + float fb = b / 255.0f; + + if (lpDestRect) { + SDL_Rect dstRect = ConvertRect(lpDestRect); + DDRenderer->Draw2DImage(NO_TEXTURE_ID, SDL_Rect{}, dstRect, {fr, fg, fb, fa}); + } + else { + DDRenderer->Clear(fr, fg, fb); + } return DD_OK; } + auto surface = static_cast(lpDDSrcSurface); if (!surface) { return DDERR_GENERIC; @@ -67,7 +83,7 @@ HRESULT FrameBufferImpl::Blt( 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); + DDRenderer->Draw2DImage(textureId, srcRect, dstRect, {1.0f, 1.0f, 1.0f, 1.0f}); return DD_OK; } diff --git a/miniwin/src/internal/d3drmrenderer.h b/miniwin/src/internal/d3drmrenderer.h index a871bb26..d6464eb7 100644 --- a/miniwin/src/internal/d3drmrenderer.h +++ b/miniwin/src/internal/d3drmrenderer.h @@ -51,7 +51,7 @@ class Direct3DRMRenderer : public IDirect3DDevice2 { 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 Draw2DImage(Uint32 textureId, const SDL_Rect& srcRect, const SDL_Rect& dstRect, FColor color) = 0; virtual void Download(SDL_Surface* target) = 0; virtual void SetDither(bool dither) = 0; diff --git a/miniwin/src/internal/d3drmrenderer_citro3d.h b/miniwin/src/internal/d3drmrenderer_citro3d.h index af91b3dc..34863497 100644 --- a/miniwin/src/internal/d3drmrenderer_citro3d.h +++ b/miniwin/src/internal/d3drmrenderer_citro3d.h @@ -48,7 +48,7 @@ class Citro3DRenderer : public Direct3DRMRenderer { 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 Draw2DImage(Uint32 textureId, const SDL_Rect& srcRect, const SDL_Rect& dstRect, FColor color) override; void Download(SDL_Surface* target) override; void SetDither(bool dither) override; diff --git a/miniwin/src/internal/d3drmrenderer_directx9.h b/miniwin/src/internal/d3drmrenderer_directx9.h index 18ac126f..d1b0a581 100644 --- a/miniwin/src/internal/d3drmrenderer_directx9.h +++ b/miniwin/src/internal/d3drmrenderer_directx9.h @@ -34,7 +34,7 @@ class DirectX9Renderer : public Direct3DRMRenderer { 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 Draw2DImage(Uint32 textureId, const SDL_Rect& srcRect, const SDL_Rect& dstRect, FColor color) override; void Download(SDL_Surface* target) override; void SetDither(bool dither) override; diff --git a/miniwin/src/internal/d3drmrenderer_opengl1.h b/miniwin/src/internal/d3drmrenderer_opengl1.h index 656a964b..bd0fa003 100644 --- a/miniwin/src/internal/d3drmrenderer_opengl1.h +++ b/miniwin/src/internal/d3drmrenderer_opengl1.h @@ -34,7 +34,7 @@ class OpenGL1Renderer : public Direct3DRMRenderer { 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 Draw2DImage(Uint32 textureId, const SDL_Rect& srcRect, const SDL_Rect& dstRect, FColor color) override; void Download(SDL_Surface* target) override; void SetDither(bool dither) override; diff --git a/miniwin/src/internal/d3drmrenderer_opengles2.h b/miniwin/src/internal/d3drmrenderer_opengles2.h index 0aaec63d..7dbb1f4b 100644 --- a/miniwin/src/internal/d3drmrenderer_opengles2.h +++ b/miniwin/src/internal/d3drmrenderer_opengles2.h @@ -55,7 +55,7 @@ class OpenGLES2Renderer : public Direct3DRMRenderer { 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 Draw2DImage(Uint32 textureId, const SDL_Rect& srcRect, const SDL_Rect& dstRect, FColor color) override; void Download(SDL_Surface* target) override; void SetDither(bool dither) override; diff --git a/miniwin/src/internal/d3drmrenderer_sdl3gpu.h b/miniwin/src/internal/d3drmrenderer_sdl3gpu.h index cf68a8c4..b3afd674 100644 --- a/miniwin/src/internal/d3drmrenderer_sdl3gpu.h +++ b/miniwin/src/internal/d3drmrenderer_sdl3gpu.h @@ -65,7 +65,7 @@ class Direct3DRMSDL3GPURenderer : public Direct3DRMRenderer { 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 Draw2DImage(Uint32 textureId, const SDL_Rect& srcRect, const SDL_Rect& dstRect, FColor color) override; void Download(SDL_Surface* target) override; void SetDither(bool dither) override; diff --git a/miniwin/src/internal/d3drmrenderer_software.h b/miniwin/src/internal/d3drmrenderer_software.h index 91abac32..8b8c0dde 100644 --- a/miniwin/src/internal/d3drmrenderer_software.h +++ b/miniwin/src/internal/d3drmrenderer_software.h @@ -47,7 +47,7 @@ class Direct3DRMSoftwareRenderer : public Direct3DRMRenderer { 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 Draw2DImage(Uint32 textureId, const SDL_Rect& srcRect, const SDL_Rect& dstRect, FColor color) override; void Download(SDL_Surface* target) override; void SetDither(bool dither) override; From f1b22ee02568779b1ea23c944936eadf9bd6f76c Mon Sep 17 00:00:00 2001 From: Christian Semmler Date: Thu, 3 Jul 2025 16:28:45 -0700 Subject: [PATCH 10/17] Allow Web port to be playable in Firefox Private (#513) --- ISLE/emscripten/emscripten.patch | 18 ++++++++++++++++++ ISLE/emscripten/filesystem.cpp | 17 +++++++++++++---- ISLE/emscripten/filesystem.h | 2 +- ISLE/isleapp.cpp | 11 +++++++---- 4 files changed, 39 insertions(+), 9 deletions(-) diff --git a/ISLE/emscripten/emscripten.patch b/ISLE/emscripten/emscripten.patch index 899d72eb..0bc8222d 100644 --- a/ISLE/emscripten/emscripten.patch +++ b/ISLE/emscripten/emscripten.patch @@ -139,3 +139,21 @@ index e8c9f7e21..caf1971d2 100644 }, - }); +diff --git a/src/preamble.js b/src/preamble.js +index 572694517..0d2f4421b 100644 +--- a/src/preamble.js ++++ b/src/preamble.js +@@ -1062,3 +1062,13 @@ function getCompilerSetting(name) { + // dynamic linker as symbols are loaded. + var asyncifyStubs = {}; + #endif ++ ++(async () => { ++ try { ++ await navigator.storage.getDirectory(); ++ Module["disableOpfs"] = false; ++ } catch (e) { ++ Module["disableOpfs"] = true; ++ } ++})(); ++ diff --git a/ISLE/emscripten/filesystem.cpp b/ISLE/emscripten/filesystem.cpp index 395242a1..50cd9012 100644 --- a/ISLE/emscripten/filesystem.cpp +++ b/ISLE/emscripten/filesystem.cpp @@ -6,6 +6,7 @@ #include #include +#include #include static backend_t opfs = nullptr; @@ -13,10 +14,16 @@ static backend_t fetchfs = nullptr; extern const char* g_files[46]; -void Emscripten_SetupConfig(const char* p_iniConfig) +bool Emscripten_OPFSDisabled() { - if (!p_iniConfig || !*p_iniConfig) { - return; + return MAIN_THREAD_EM_ASM_INT({return !!Module["disableOpfs"]}); +} + +bool Emscripten_SetupConfig(const char* p_iniConfig) +{ + if (Emscripten_OPFSDisabled()) { + SDL_Log("OPFS is disabled; ignoring .ini path"); + return false; } opfs = wasmfs_create_opfs_backend(); @@ -28,6 +35,8 @@ void Emscripten_SetupConfig(const char* p_iniConfig) wasmfs_create_directory(iniConfig.GetData(), 0644, opfs); *parse = '/'; } + + return true; } void Emscripten_SetupFilesystem() @@ -66,7 +75,7 @@ void Emscripten_SetupFilesystem() registerFile(file); } - if (GameState()->GetSavePath() && *GameState()->GetSavePath()) { + if (GameState()->GetSavePath() && *GameState()->GetSavePath() && !Emscripten_OPFSDisabled()) { if (!opfs) { opfs = wasmfs_create_opfs_backend(); } diff --git a/ISLE/emscripten/filesystem.h b/ISLE/emscripten/filesystem.h index 131df1c8..ad78a349 100644 --- a/ISLE/emscripten/filesystem.h +++ b/ISLE/emscripten/filesystem.h @@ -10,7 +10,7 @@ inline static const char* Emscripten_savePath = "/save"; inline static const char* Emscripten_streamPath = "/"; inline static const char* Emscripten_streamHost = ISLE_EMSCRIPTEN_HOST; -void Emscripten_SetupConfig(const char* p_iniConfig); +bool Emscripten_SetupConfig(const char* p_iniConfig); void Emscripten_SetupFilesystem(); #endif // EMSCRIPTEN_FILESYSTEM_H diff --git a/ISLE/isleapp.cpp b/ISLE/isleapp.cpp index cfa3c50a..2e2066d8 100644 --- a/ISLE/isleapp.cpp +++ b/ISLE/isleapp.cpp @@ -778,6 +778,13 @@ bool IsleApp::LoadConfig() { char* prefPath = SDL_GetPrefPath("isledecomp", "isle"); char* iniConfig; + +#ifdef __EMSCRIPTEN__ + if (m_iniPath && !Emscripten_SetupConfig(m_iniPath)) { + m_iniPath = NULL; + } +#endif + if (m_iniPath) { iniConfig = new char[strlen(m_iniPath) + 1]; strcpy(iniConfig, m_iniPath); @@ -793,10 +800,6 @@ bool IsleApp::LoadConfig() } SDL_Log("Reading configuration from \"%s\"", iniConfig); -#ifdef __EMSCRIPTEN__ - Emscripten_SetupConfig(iniConfig); -#endif - dictionary* dict = iniparser_load(iniConfig); // [library:config] From 4167c55c051e4aea4d4b055b5f56aca9e72a212c Mon Sep 17 00:00:00 2001 From: Steven <139715581+StevenSYS@users.noreply.github.com> Date: Fri, 4 Jul 2025 02:41:22 +0000 Subject: [PATCH 11/17] Added changing the transition type to the config tool (#511) --- CONFIG/MainDlg.cpp | 9 +++++ CONFIG/MainDlg.h | 1 + CONFIG/config.cpp | 4 ++ CONFIG/config.h | 1 + CONFIG/res/maindialog.ui | 85 +++++++++++++++++++++++++++++++++------- 5 files changed, 85 insertions(+), 15 deletions(-) diff --git a/CONFIG/MainDlg.cpp b/CONFIG/MainDlg.cpp index e2c526f6..828395bd 100644 --- a/CONFIG/MainDlg.cpp +++ b/CONFIG/MainDlg.cpp @@ -59,6 +59,7 @@ CMainDialog::CMainDialog(QWidget* pParent) : QDialog(pParent) 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->transitionTypeComboBox, &QComboBox::currentIndexChanged, this, &CMainDialog::TransitionTypeChanged); 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); @@ -212,6 +213,7 @@ void CMainDialog::UpdateInterface() m_ui->joystickCheckBox->setChecked(currentConfigApp->m_use_joystick); m_ui->musicCheckBox->setChecked(currentConfigApp->m_music); m_ui->fullscreenCheckBox->setChecked(currentConfigApp->m_full_screen); + m_ui->transitionTypeComboBox->setCurrentIndex(currentConfigApp->m_transition_type); m_ui->dataPath->setText(QString::fromStdString(currentConfigApp->m_cd_path)); m_ui->savePath->setText(QString::fromStdString(currentConfigApp->m_save_path)); } @@ -296,6 +298,13 @@ void CMainDialog::OnCheckboxFullscreen(bool checked) UpdateInterface(); } +void CMainDialog::TransitionTypeChanged(int index) +{ + currentConfigApp->m_transition_type = index; + m_modified = true; + UpdateInterface(); +} + void CMainDialog::SelectDataPathDialog() { QString data_path = QString::fromStdString(currentConfigApp->m_cd_path); diff --git a/CONFIG/MainDlg.h b/CONFIG/MainDlg.h index 372a1156..72062486 100644 --- a/CONFIG/MainDlg.h +++ b/CONFIG/MainDlg.h @@ -43,6 +43,7 @@ private slots: void OnCheckboxJoystick(bool checked); void OnCheckboxMusic(bool checked); void OnCheckboxFullscreen(bool checked); + void TransitionTypeChanged(int index); void accept() override; void reject() override; void launch(); diff --git a/CONFIG/config.cpp b/CONFIG/config.cpp index 9030ae67..b4435298 100644 --- a/CONFIG/config.cpp +++ b/CONFIG/config.cpp @@ -70,6 +70,7 @@ bool CConfigApp::InitInstance() m_driver = NULL; m_device = NULL; m_full_screen = TRUE; + m_transition_type = 3; // 3: Mosaic m_wide_view_angle = TRUE; m_use_joystick = TRUE; m_music = TRUE; @@ -153,6 +154,7 @@ bool CConfigApp::ReadRegisterSettings() m_display_bit_depth = iniparser_getint(dict, "isle:Display Bit Depth", -1); m_flip_surfaces = iniparser_getboolean(dict, "isle:Flip Surfaces", m_flip_surfaces); m_full_screen = iniparser_getboolean(dict, "isle:Full Screen", m_full_screen); + m_transition_type = iniparser_getint(dict, "isle:Transition Type", m_transition_type); m_3d_video_ram = iniparser_getboolean(dict, "isle:Back Buffers in Video RAM", m_3d_video_ram); m_wide_view_angle = iniparser_getboolean(dict, "isle:Wide View Angle", m_wide_view_angle); m_3d_sound = iniparser_getboolean(dict, "isle:3DSound", m_3d_sound); @@ -308,6 +310,8 @@ void CConfigApp::WriteRegisterSettings() const SetIniBool(dict, "isle:Full Screen", m_full_screen); SetIniBool(dict, "isle:Wide View Angle", m_wide_view_angle); + SetIniInt(dict, "isle:Transition Type", m_transition_type); + SetIniBool(dict, "isle:3DSound", m_3d_sound); SetIniBool(dict, "isle:Music", m_music); diff --git a/CONFIG/config.h b/CONFIG/config.h index a621655a..dffc2b6c 100644 --- a/CONFIG/config.h +++ b/CONFIG/config.h @@ -65,6 +65,7 @@ class CConfigApp { int m_display_bit_depth; bool m_flip_surfaces; bool m_full_screen; + int m_transition_type; bool m_3d_video_ram; bool m_wide_view_angle; bool m_3d_sound; diff --git a/CONFIG/res/maindialog.ui b/CONFIG/res/maindialog.ui index c2d429ae..66e2b52e 100644 --- a/CONFIG/res/maindialog.ui +++ b/CONFIG/res/maindialog.ui @@ -57,7 +57,7 @@ false - Qt::AlignCenter + Qt::AlignmentFlag::AlignCenter @@ -129,10 +129,10 @@ Save Path: - Qt::PlainText + Qt::TextFormat::PlainText - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter @@ -162,10 +162,10 @@ Data Path: - Qt::PlainText + Qt::TextFormat::PlainText - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + Qt::AlignmentFlag::AlignRight|Qt::AlignmentFlag::AlignTrailing|Qt::AlignmentFlag::AlignVCenter @@ -241,7 +241,7 @@ Maximum LOD - Qt::AlignCenter + Qt::AlignmentFlag::AlignCenter @@ -262,10 +262,10 @@ false - Qt::Horizontal + Qt::Orientation::Horizontal - QSlider::TicksBothSides + QSlider::TickPosition::TicksBothSides 10 @@ -316,7 +316,7 @@ Maximum Actors (5..40) - Qt::AlignCenter + Qt::AlignmentFlag::AlignCenter @@ -340,10 +340,10 @@ false - Qt::Horizontal + Qt::Orientation::Horizontal - QSlider::TicksBothSides + QSlider::TickPosition::TicksBothSides 5 @@ -402,6 +402,61 @@ + + + + Transition Type + + + + + + + Sets the transition effect to be used in game. + + + Idle - Broken + + + + + + + Idle - Broken + + + + + No Animation + + + + + Dissolve + + + + + Mosaic + + + + + Wipe Down + + + + + Windows + + + + + Unknown - Broken + + + + @@ -417,7 +472,7 @@ - Qt::AlignCenter + Qt::AlignmentFlag::AlignCenter false @@ -453,7 +508,7 @@ Direct 3D Devices - Qt::AlignCenter + Qt::AlignmentFlag::AlignCenter @@ -475,13 +530,13 @@ - QAbstractItemView::NoEditTriggers + QAbstractItemView::EditTrigger::NoEditTriggers true - QAbstractItemView::SelectRows + QAbstractItemView::SelectionBehavior::SelectRows From 92a96282b3960b30677ebd06433596b724800d60 Mon Sep 17 00:00:00 2001 From: Anders Jenbo Date: Fri, 4 Jul 2025 04:48:09 +0200 Subject: [PATCH 12/17] Fix tabbign in and out of fullscreen (#514) --- ISLE/isleapp.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ISLE/isleapp.cpp b/ISLE/isleapp.cpp index 2e2066d8..6cb0375c 100644 --- a/ISLE/isleapp.cpp +++ b/ISLE/isleapp.cpp @@ -447,7 +447,7 @@ SDL_AppResult SDL_AppEvent(void* appstate, SDL_Event* event) SDL_Keycode keyCode = event->key.key; - if (event->key.mod == SDL_KMOD_LALT && keyCode == SDLK_RETURN) { + if ((event->key.mod & SDL_KMOD_LALT) && keyCode == SDLK_RETURN) { SDL_SetWindowFullscreen(window, !(SDL_GetWindowFlags(window) & SDL_WINDOW_FULLSCREEN)); } else { From 5e62e7e39fc0e618cc3eda2e18df673dba0526a9 Mon Sep 17 00:00:00 2001 From: Anders Jenbo Date: Fri, 4 Jul 2025 05:32:35 +0200 Subject: [PATCH 13/17] Remove unused rendering function (#517) --- LEGO1/omni/include/mxdisplaysurface.h | 8 ---- LEGO1/omni/src/video/mxdisplaysurface.cpp | 55 ----------------------- 2 files changed, 63 deletions(-) diff --git a/LEGO1/omni/include/mxdisplaysurface.h b/LEGO1/omni/include/mxdisplaysurface.h index df57c5c4..3a3dcd08 100644 --- a/LEGO1/omni/include/mxdisplaysurface.h +++ b/LEGO1/omni/include/mxdisplaysurface.h @@ -71,14 +71,6 @@ class MxDisplaySurface : public MxCore { MxS32 p_height, MxBool p_RLE ); // vtable+0x30 - virtual void VTable0x34( - MxU8* p_pixels, - MxS32 p_bpp, - MxS32 p_width, - MxS32 p_height, - MxS32 p_x, - MxS32 p_y - ); // vtable+0x34 virtual void Display( MxS32 p_left, MxS32 p_top, diff --git a/LEGO1/omni/src/video/mxdisplaysurface.cpp b/LEGO1/omni/src/video/mxdisplaysurface.cpp index d38cb093..b10330f2 100644 --- a/LEGO1/omni/src/video/mxdisplaysurface.cpp +++ b/LEGO1/omni/src/video/mxdisplaysurface.cpp @@ -716,61 +716,6 @@ void MxDisplaySurface::DrawTransparentRLE( } } -// FUNCTION: LEGO1 0x100bb850 -// FUNCTION: BETA10 0x10141191 -void MxDisplaySurface::VTable0x34(MxU8* p_pixels, MxS32 p_bpp, MxS32 p_width, MxS32 p_height, MxS32 p_x, MxS32 p_y) -{ - DDSURFACEDESC surfaceDesc; - memset(&surfaceDesc, 0, sizeof(surfaceDesc)); - surfaceDesc.dwSize = sizeof(surfaceDesc); - - 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 | DDLOCK_WRITEONLY, NULL); - } - - if (result == DD_OK) { - MxU8* pixels = p_pixels; - MxS32 bytesPerPixel = m_surfaceDesc.ddpfPixelFormat.dwRGBBitCount / 8; - if (p_bpp != 8 && bytesPerPixel != p_bpp) { - MxTrace("Source format to display format NOT_IMPLEMENTED"); - assert(0); - return; - } - - MxU8* dst = (MxU8*) surfaceDesc.lpSurface + p_y * surfaceDesc.lPitch + bytesPerPixel * p_x; - MxLong stride = p_width * bytesPerPixel; - MxLong length = -bytesPerPixel * p_width + surfaceDesc.lPitch; - - if (bytesPerPixel == p_bpp) { - while (p_height--) { - memcpy(dst, pixels, p_width * bytesPerPixel); - pixels += stride; - dst += length; - } - } - else { - for (MxS32 i = 0; i < p_height; i++) { - for (MxS32 j = 0; j < p_width; j++) { - if (bytesPerPixel == 2) { - *(MxU16*) dst = m_16bitPal[*pixels++]; - } - else { - *(MxU32*) dst = m_32bitPal[*pixels++]; - } - dst += bytesPerPixel; - } - pixels += stride; - dst += length; - } - } - - m_ddSurface2->Unlock(surfaceDesc.lpSurface); - } -} - // FUNCTION: LEGO1 0x100bba50 void MxDisplaySurface::Display(MxS32 p_left, MxS32 p_top, MxS32 p_left2, MxS32 p_top2, MxS32 p_width, MxS32 p_height) { From 4983da422c56e71f193658273ee337d7286928fa Mon Sep 17 00:00:00 2001 From: Anders Jenbo Date: Fri, 4 Jul 2025 14:47:24 +0200 Subject: [PATCH 14/17] OpenGL: Respect max supported texture size (#518) --- miniwin/src/d3drm/backends/opengl1/actual.cpp | 7 +++++++ miniwin/src/d3drm/backends/opengl1/actual.h | 1 + miniwin/src/d3drm/backends/opengl1/renderer.cpp | 17 ++++++++++++++--- 3 files changed, 22 insertions(+), 3 deletions(-) diff --git a/miniwin/src/d3drm/backends/opengl1/actual.cpp b/miniwin/src/d3drm/backends/opengl1/actual.cpp index b1a464d5..a86ebec1 100644 --- a/miniwin/src/d3drm/backends/opengl1/actual.cpp +++ b/miniwin/src/d3drm/backends/opengl1/actual.cpp @@ -42,6 +42,13 @@ void GL11_DestroyTexture(GLuint texId) glDeleteTextures(1, &texId); } +int GL11_GetMaxTextureSize() +{ + GLint maxTextureSize = 0; + glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize); + return maxTextureSize; +} + GLuint GL11_UploadTextureData(void* pixels, int width, int height, bool isUi) { GLuint texId; diff --git a/miniwin/src/d3drm/backends/opengl1/actual.h b/miniwin/src/d3drm/backends/opengl1/actual.h index 9460119c..87f33687 100644 --- a/miniwin/src/d3drm/backends/opengl1/actual.h +++ b/miniwin/src/d3drm/backends/opengl1/actual.h @@ -64,6 +64,7 @@ struct GLMeshCacheEntry { void GL11_InitState(); void GL11_LoadExtensions(); void GL11_DestroyTexture(GLuint texId); +int GL11_GetMaxTextureSize(); GLuint GL11_UploadTextureData(void* pixels, int width, int height, bool isUI); void GL11_UploadMesh(GLMeshCacheEntry& cache, bool hasTexture); void GL11_DestroyMesh(GLMeshCacheEntry& cache); diff --git a/miniwin/src/d3drm/backends/opengl1/renderer.cpp b/miniwin/src/d3drm/backends/opengl1/renderer.cpp index 8c43d14a..00088da9 100644 --- a/miniwin/src/d3drm/backends/opengl1/renderer.cpp +++ b/miniwin/src/d3drm/backends/opengl1/renderer.cpp @@ -132,10 +132,21 @@ static Uint32 UploadTextureData(SDL_Surface* src, bool useNPOT, bool isUi) SDL_Surface* finalSurface = working; - int newW = NextPowerOfTwo(working->w); - int newH = NextPowerOfTwo(working->h); + int newW = working->w; + int newH = working->h; + if (!useNPOT) { + newW = NextPowerOfTwo(newW); + newH = NextPowerOfTwo(newH); + } + int max = GL11_GetMaxTextureSize(); + if (newW > max) { + newW = max; + } + if (newH > max) { + newH = max; + } - if (!useNPOT && (newW != working->w || newH != working->h)) { + if (newW != working->w || newH != working->h) { SDL_Surface* resized = SDL_CreateSurface(newW, newH, working->format); if (!resized) { SDL_Log("SDL_CreateSurface (resize) failed: %s", SDL_GetError()); From 0d2cbd50d58eb217311c8ceb2160bd1ce76acb8e Mon Sep 17 00:00:00 2001 From: Anders Jenbo Date: Fri, 4 Jul 2025 14:48:01 +0200 Subject: [PATCH 15/17] Fake mosaic transition (#516) --- .../legoomni/include/mxtransitionmanager.h | 4 +- .../src/common/mxtransitionmanager.cpp | 128 ++++++++++++++++++ LEGO1/omni/include/mxdisplaysurface.h | 3 + LEGO1/omni/src/video/mxdisplaysurface.cpp | 3 - 4 files changed, 134 insertions(+), 4 deletions(-) diff --git a/LEGO1/lego/legoomni/include/mxtransitionmanager.h b/LEGO1/lego/legoomni/include/mxtransitionmanager.h index dd9dc9ed..7c31daf7 100644 --- a/LEGO1/lego/legoomni/include/mxtransitionmanager.h +++ b/LEGO1/lego/legoomni/include/mxtransitionmanager.h @@ -48,7 +48,8 @@ class MxTransitionManager : public MxCore { e_mosaic, e_wipeDown, e_windows, - e_broken // Unknown what this is supposed to be, it locks the game up + e_broken, // Unknown what this is supposed to be, it locks the game up + e_fakeMosaic }; MxResult StartTransition(TransitionType p_animationType, MxS32 p_speed, MxBool p_doCopy, MxBool p_playMusicInAnim); @@ -68,6 +69,7 @@ class MxTransitionManager : public MxCore { void WipeDownTransition(); void WindowsTransition(); void BrokenTransition(); + void FakeMosaicTransition(); void SubmitCopyRect(LPDDSURFACEDESC p_ddsc); void SetupCopyRect(LPDDSURFACEDESC p_ddsc); diff --git a/LEGO1/lego/legoomni/src/common/mxtransitionmanager.cpp b/LEGO1/lego/legoomni/src/common/mxtransitionmanager.cpp index 6fd211c6..1987b6cd 100644 --- a/LEGO1/lego/legoomni/src/common/mxtransitionmanager.cpp +++ b/LEGO1/lego/legoomni/src/common/mxtransitionmanager.cpp @@ -84,6 +84,9 @@ MxResult MxTransitionManager::Tickle() case e_broken: BrokenTransition(); break; + case e_fakeMosaic: + FakeMosaicTransition(); + break; } return SUCCESS; } @@ -613,3 +616,128 @@ void MxTransitionManager::configureMxTransitionManager(TransitionType p_transiti { g_transitionManagerConfig = p_transitionManagerConfig; } + +int g_colorOffset; +int GetColorIndexWithLocality(int p_col, int p_row) +{ + int islandX = p_col / 8; + int islandY = p_row / 8; // Dvide screen in 8x6 tiles + + int island = islandY * 8 + islandX; // tile id + + if (SDL_rand(3) > island / 8) { + return 6 + SDL_rand(2); // emulate sky + } + + if (SDL_rand(16) > 2) { + island += SDL_rand(3) - 1 + (SDL_rand(3) - 1) * 8; // blure tiles + } + + int hash = (island + g_colorOffset) * 2654435761u; + int scrambled = (hash >> 16) % 32; + + int finalIndex = scrambled + SDL_rand(3) - 1; + return finalIndex % 32; +} + +void MxTransitionManager::FakeMosaicTransition() +{ + if (m_animationTimer == 16) { + m_animationTimer = 0; + EndTransition(TRUE); + return; + } + + if (m_animationTimer == 0) { + g_colorOffset = SDL_rand(32); + for (MxS32 i = 0; i < 64; i++) { + m_columnOrder[i] = i; + } + for (MxS32 i = 0; i < 64; i++) { + MxS32 swap = SDL_rand(64); + std::swap(m_columnOrder[i], m_columnOrder[swap]); + } + for (MxS32 i = 0; i < 48; i++) { + m_randomShift[i] = SDL_rand(64); + } + } + + DDSURFACEDESC ddsd = {}; + ddsd.dwSize = sizeof(ddsd); + 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 | DDLOCK_WRITEONLY, NULL); + } + + if (res == DD_OK) { + SubmitCopyRect(&ddsd); + + static const MxU8 g_palette[32][3] = { + {0x00, 0x00, 0x00}, {0x12, 0x1e, 0x50}, {0x00, 0x22, 0x6c}, {0x14, 0x2d, 0x9f}, {0x0e, 0x36, 0xb0}, + {0x0e, 0x39, 0xd0}, {0x47, 0x96, 0xe2}, {0x79, 0xaa, 0xca}, {0xff, 0xff, 0xff}, {0xc9, 0xcd, 0xcb}, + {0xad, 0xad, 0xab}, {0xa6, 0x91, 0x8e}, {0xaf, 0x59, 0x49}, {0xc0, 0x00, 0x00}, {0xab, 0x18, 0x18}, + {0x61, 0x0c, 0x0c}, {0x04, 0x38, 0x12}, {0x2c, 0x67, 0x28}, {0x4a, 0xb4, 0x6b}, {0x94, 0xb7, 0x7c}, + {0xb6, 0xb9, 0x87}, {0x52, 0x4a, 0x67}, {0x87, 0x8d, 0x8a}, {0xa6, 0x91, 0x8e}, {0xf8, 0xee, 0xdc}, + {0xf4, 0xe2, 0xc3}, {0x87, 0x8d, 0x8a}, {0xba, 0x9f, 0x12}, {0xb5, 0x83, 0x00}, {0x6a, 0x44, 0x27}, + {0x36, 0x37, 0x34}, {0x2b, 0x23, 0x0f} + }; + + MxS32 bytesPerPixel = ddsd.ddpfPixelFormat.dwRGBBitCount / 8; + + for (MxS32 col = 0; col < 64; col++) { + if (m_animationTimer * 4 > m_columnOrder[col]) { + continue; + } + if (m_animationTimer * 4 + 3 < m_columnOrder[col]) { + continue; + } + + for (MxS32 row = 0; row < 48; row++) { + MxS32 xShift = 10 * ((m_randomShift[row] + col) % 64); + MxS32 yStart = 10 * row; + + int paletteIndex = GetColorIndexWithLocality(xShift / 10, row); + + const MxU8* color = g_palette[paletteIndex]; + + for (MxS32 y = 0; y < 10; y++) { + MxU8* dest = (MxU8*) ddsd.lpSurface + (yStart + y) * ddsd.lPitch + xShift * bytesPerPixel; + switch (bytesPerPixel) { + case 1: + memset(dest, paletteIndex, 10); + break; + case 2: { + MxU32 pixel = RGB555_CREATE(color[2], color[1], color[0]); + MxU16* p = (MxU16*) dest; + for (MxS32 i = 0; i < 10; i++) { + p[i] = pixel; + } + break; + } + default: { + MxU32 pixel = RGB8888_CREATE(color[2], color[1], color[0], 255); + MxU32* p = (MxU32*) dest; + for (MxS32 i = 0; i < 10; i++) { + p[i] = pixel; + } + break; + } + } + } + } + } + + SetupCopyRect(&ddsd); + m_ddSurface->Unlock(ddsd.lpSurface); + + if (VideoManager()->GetVideoParam().Flags().GetFlipSurfaces()) { + VideoManager() + ->GetDisplaySurface() + ->GetDirectDrawSurface1() + ->BltFast(0, 0, m_ddSurface, &g_fullScreenRect, DDBLTFAST_WAIT); + } + + m_animationTimer++; + } +} diff --git a/LEGO1/omni/include/mxdisplaysurface.h b/LEGO1/omni/include/mxdisplaysurface.h index 3a3dcd08..aa30b543 100644 --- a/LEGO1/omni/include/mxdisplaysurface.h +++ b/LEGO1/omni/include/mxdisplaysurface.h @@ -12,6 +12,9 @@ #include #endif +#define RGB555_CREATE(R, G, B) (((R) << 10) | (G) << 5 | (B) << 0) +#define RGB8888_CREATE(R, G, B, A) (((A) << 24) | ((R) << 16) | ((G) << 8) | (B)) + class MxBitmap; class MxPalette; diff --git a/LEGO1/omni/src/video/mxdisplaysurface.cpp b/LEGO1/omni/src/video/mxdisplaysurface.cpp index b10330f2..c07f475e 100644 --- a/LEGO1/omni/src/video/mxdisplaysurface.cpp +++ b/LEGO1/omni/src/video/mxdisplaysurface.cpp @@ -18,9 +18,6 @@ DECOMP_SIZE_ASSERT(MxDisplaySurface, 0xac); -#define RGB555_CREATE(R, G, B) (((R) << 10) | (G) << 5 | (B) << 0) -#define RGB8888_CREATE(R, G, B, A) (((A) << 24) | ((R) << 16) | ((G) << 8) | (B)) - // GLOBAL: LEGO1 0x1010215c MxU32 g_unk0x1010215c = 0; From af045eefed747ca26e4f90f50131cff9141aaa3c Mon Sep 17 00:00:00 2001 From: Anders Jenbo Date: Fri, 4 Jul 2025 17:41:18 +0200 Subject: [PATCH 16/17] Add fake mosaic to config tool (#522) --- CONFIG/res/maindialog.ui | 5 +++++ ISLE/3ds/config.cpp | 2 +- LEGO1/lego/legoomni/src/common/mxtransitionmanager.cpp | 2 +- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/CONFIG/res/maindialog.ui b/CONFIG/res/maindialog.ui index 66e2b52e..12739f27 100644 --- a/CONFIG/res/maindialog.ui +++ b/CONFIG/res/maindialog.ui @@ -455,6 +455,11 @@ Unknown - Broken + + + Fake Mosaic + + diff --git a/ISLE/3ds/config.cpp b/ISLE/3ds/config.cpp index dc5dd8dc..e70ec4dd 100644 --- a/ISLE/3ds/config.cpp +++ b/ISLE/3ds/config.cpp @@ -18,5 +18,5 @@ void N3DS_SetupDefaultConfigOverrides(dictionary* p_dictionary) iniparser_set(p_dictionary, "isle:savepath", "sdmc:/3ds/isle"); // Use e_noAnimation/cut transition - iniparser_set(p_dictionary, "isle:Transition Type", "1"); + iniparser_set(p_dictionary, "isle:Transition Type", "7"); } diff --git a/LEGO1/lego/legoomni/src/common/mxtransitionmanager.cpp b/LEGO1/lego/legoomni/src/common/mxtransitionmanager.cpp index 1987b6cd..6c4f94ea 100644 --- a/LEGO1/lego/legoomni/src/common/mxtransitionmanager.cpp +++ b/LEGO1/lego/legoomni/src/common/mxtransitionmanager.cpp @@ -637,7 +637,7 @@ int GetColorIndexWithLocality(int p_col, int p_row) int scrambled = (hash >> 16) % 32; int finalIndex = scrambled + SDL_rand(3) - 1; - return finalIndex % 32; + return abs(finalIndex) % 32; } void MxTransitionManager::FakeMosaicTransition() From 77c832c237fe90c5bc2793c6349d2f52c7502bc6 Mon Sep 17 00:00:00 2001 From: Anders Jenbo Date: Fri, 4 Jul 2025 21:27:01 +0200 Subject: [PATCH 17/17] Use sprites to render things on screen (#478) --- LEGO1/omni/src/video/mxdisplaysurface.cpp | 119 +++++++++++----------- 1 file changed, 57 insertions(+), 62 deletions(-) diff --git a/LEGO1/omni/src/video/mxdisplaysurface.cpp b/LEGO1/omni/src/video/mxdisplaysurface.cpp index c07f475e..5d08a64b 100644 --- a/LEGO1/omni/src/video/mxdisplaysurface.cpp +++ b/LEGO1/omni/src/video/mxdisplaysurface.cpp @@ -396,86 +396,81 @@ void MxDisplaySurface::VTable0x28( DDSURFACEDESC ddsd; memset(&ddsd, 0, sizeof(ddsd)); ddsd.dwSize = sizeof(ddsd); + ddsd.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT | DDSD_CAPS; + ddsd.dwWidth = p_width; + ddsd.dwHeight = p_height; + ddsd.ddpfPixelFormat = m_surfaceDesc.ddpfPixelFormat; + ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN; - HRESULT hr = m_ddSurface2->Lock(NULL, &ddsd, DDLOCK_WAIT | DDLOCK_WRITEONLY, NULL); + LPDIRECTDRAWSURFACE tempSurface = nullptr; + LPDIRECTDRAW draw = MVideoManager()->GetDirectDraw(); + HRESULT hr = draw->CreateSurface(&ddsd, &tempSurface, nullptr); + if (hr != DD_OK || !tempSurface) { + return; + } + + DDCOLORKEY colorKey; + colorKey.dwColorSpaceLowValue = colorKey.dwColorSpaceHighValue = RGB555_CREATE(0x1f, 0, 0x1f); + tempSurface->SetColorKey(DDCKEY_SRCBLT, &colorKey); + + DDSURFACEDESC tempDesc; + memset(&tempDesc, 0, sizeof(tempDesc)); + tempDesc.dwSize = sizeof(tempDesc); + + hr = tempSurface->Lock(NULL, &tempDesc, DDLOCK_WAIT | DDLOCK_WRITEONLY, NULL); if (hr == DDERR_SURFACELOST) { - m_ddSurface2->Restore(); - hr = m_ddSurface2->Lock(NULL, &ddsd, DDLOCK_WAIT | DDLOCK_WRITEONLY, NULL); + tempSurface->Restore(); + hr = tempSurface->Lock(NULL, &tempDesc, DDLOCK_WAIT | DDLOCK_WRITEONLY, NULL); } if (hr != DD_OK) { + tempSurface->Release(); return; } MxU8* data = p_bitmap->GetStart(p_left, p_top); MxS32 bytesPerPixel = m_surfaceDesc.ddpfPixelFormat.dwRGBBitCount / 8; - if (m_videoParam.Flags().GetF1bit3()) { - p_bottom *= 2; - p_right *= 2; + MxU8* surface = (MxU8*) tempDesc.lpSurface; - MxU8* surface = (MxU8*) ddsd.lpSurface + (bytesPerPixel * p_right) + (p_bottom * ddsd.lPitch); - MxLong stride = -p_width + GetAdjustedStride(p_bitmap); - MxS32 copyWidth = p_width * bytesPerPixel * 2; - MxLong length = -(copyWidth) + ddsd.lPitch; + MxLong stride = (bytesPerPixel == 1) ? GetAdjustedStride(p_bitmap) : -p_width + GetAdjustedStride(p_bitmap); + MxLong length = tempDesc.lPitch - (p_width * bytesPerPixel); - while (p_height--) { - MxU8* surfaceBefore = surface; - - for (MxS32 i = 0; i < p_width; i++) { - if (bytesPerPixel == 1) { - surface[0] = surface[1] = *data; - } - else if (bytesPerPixel == 2) { - ((MxU16*) surface)[0] = ((MxU16*) surface)[1] = m_16bitPal[*data]; - } - else { - ((MxU32*) surface)[0] = ((MxU32*) surface)[1] = m_32bitPal[*data]; - } - surface += bytesPerPixel * 2; - data++; - } - - if (stride || length != ddsd.lPitch - copyWidth) { - data += stride; - surface += length; - } - - memcpy(surface, surfaceBefore, copyWidth); - surface += ddsd.lPitch; + for (MxS32 i = 0; i < p_height; i++) { + if (bytesPerPixel == 1) { + memcpy(surface, data, p_width); + surface += length + p_width; } + else if (bytesPerPixel == 2) { + for (MxS32 j = 0; j < p_width; j++) { + *(MxU16*) surface = m_16bitPal[*data++]; + surface += bytesPerPixel; + } + + surface += length; + } + else { + for (MxS32 j = 0; j < p_width; j++) { + *(MxU32*) surface = m_32bitPal[*data++]; + surface += bytesPerPixel; + } + surface += length; + } + + data += stride; + } + + tempSurface->Unlock(NULL); + + if (m_videoParam.Flags().GetF1bit3()) { + RECT destRect = {p_right, p_bottom, p_right + p_width * 2, p_bottom + p_height * 2}; + m_ddSurface2->Blt(&destRect, tempSurface, NULL, DDBLT_WAIT | DDBLT_KEYSRC, NULL); } else { - MxU8* surface = (MxU8*) ddsd.lpSurface + (bytesPerPixel * p_right) + (p_bottom * ddsd.lPitch); - MxLong stride = (bytesPerPixel == 1) ? GetAdjustedStride(p_bitmap) : -p_width + GetAdjustedStride(p_bitmap); - MxLong length = ddsd.lPitch - (p_width * bytesPerPixel); - - for (MxS32 i = 0; i < p_height; i++) { - if (bytesPerPixel == 1) { - memcpy(surface, data, p_width); - surface += length + p_width; - } - else if (bytesPerPixel == 2) { - for (MxS32 j = 0; j < p_width; j++) { - *(MxU16*) surface = m_16bitPal[*data++]; - surface += bytesPerPixel; - } - - surface += length; - } - else { - for (MxS32 j = 0; j < p_width; j++) { - *(MxU32*) surface = m_32bitPal[*data++]; - surface += bytesPerPixel; - } - surface += length; - } - - data += stride; - } + m_ddSurface2->BltFast(p_right, p_bottom, tempSurface, NULL, DDBLTFAST_WAIT | DDBLTFAST_SRCCOLORKEY); } - m_ddSurface2->Unlock(ddsd.lpSurface); + tempSurface->Release(); } // FUNCTION: LEGO1 0x100bb1d0