From 0e70735549d59d848bbda5f751d2f1fb100509f5 Mon Sep 17 00:00:00 2001 From: VoxelTek <53562267+VoxelTek@users.noreply.github.com> Date: Wed, 2 Jul 2025 23:16:54 +1000 Subject: [PATCH 01/23] Add resizable property to window creation (#477) Add resizable property to window creation. Allows Close button to be present in some cases where it did not appear. --- ISLE/isleapp.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/ISLE/isleapp.cpp b/ISLE/isleapp.cpp index e12f9183..dd45a1b0 100644 --- a/ISLE/isleapp.cpp +++ b/ISLE/isleapp.cpp @@ -661,6 +661,7 @@ MxResult IsleApp::SetupWindow() SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_WIDTH_NUMBER, g_targetWidth); SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_HEIGHT_NUMBER, g_targetHeight); SDL_SetBooleanProperty(props, SDL_PROP_WINDOW_CREATE_FULLSCREEN_BOOLEAN, m_fullScreen); + SDL_SetBooleanProperty(props, SDL_PROP_WINDOW_CREATE_RESIZABLE_BOOLEAN, true); SDL_SetStringProperty(props, SDL_PROP_WINDOW_CREATE_TITLE_STRING, WINDOW_TITLE); #if defined(MINIWIN) && !defined(__3DS__) SDL_SetBooleanProperty(props, SDL_PROP_WINDOW_CREATE_OPENGL_BOOLEAN, true); From 10b6d28cf810f469e7a5479878b63040bc964127 Mon Sep 17 00:00:00 2001 From: Christian Semmler Date: Wed, 2 Jul 2025 08:06:09 -0700 Subject: [PATCH 02/23] Revert "Add resizable property to window creation (#477)" This reverts commit 0e70735549d59d848bbda5f751d2f1fb100509f5. --- ISLE/isleapp.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/ISLE/isleapp.cpp b/ISLE/isleapp.cpp index dd45a1b0..e12f9183 100644 --- a/ISLE/isleapp.cpp +++ b/ISLE/isleapp.cpp @@ -661,7 +661,6 @@ MxResult IsleApp::SetupWindow() SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_WIDTH_NUMBER, g_targetWidth); SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_HEIGHT_NUMBER, g_targetHeight); SDL_SetBooleanProperty(props, SDL_PROP_WINDOW_CREATE_FULLSCREEN_BOOLEAN, m_fullScreen); - SDL_SetBooleanProperty(props, SDL_PROP_WINDOW_CREATE_RESIZABLE_BOOLEAN, true); SDL_SetStringProperty(props, SDL_PROP_WINDOW_CREATE_TITLE_STRING, WINDOW_TITLE); #if defined(MINIWIN) && !defined(__3DS__) SDL_SetBooleanProperty(props, SDL_PROP_WINDOW_CREATE_OPENGL_BOOLEAN, true); From 8f429e85fba310870e4e6b8fa595c71a9b76c993 Mon Sep 17 00:00:00 2001 From: Christian Semmler Date: Wed, 2 Jul 2025 08:48:23 -0700 Subject: [PATCH 03/23] Improve Web port Docker setup (#479) --- docker/emscripten/Dockerfile | 17 +++-- docker/emscripten/nginx.conf | 65 +++++++++++++++++-- docker/emscripten/ssl_example/Caddyfile | 3 + .../emscripten/ssl_example/docker-compose.yml | 18 +++++ 4 files changed, 93 insertions(+), 10 deletions(-) create mode 100644 docker/emscripten/ssl_example/Caddyfile create mode 100644 docker/emscripten/ssl_example/docker-compose.yml diff --git a/docker/emscripten/Dockerfile b/docker/emscripten/Dockerfile index d15d2406..f234e9ed 100644 --- a/docker/emscripten/Dockerfile +++ b/docker/emscripten/Dockerfile @@ -21,7 +21,14 @@ RUN cd /emsdk/upstream/emscripten && \ git apply --check /tmp/libwasmfs_fetch.js.patch && \ git apply /tmp/libwasmfs_fetch.js.patch -COPY --chown=emscripten:emscripten . . +COPY --chown=emscripten:emscripten 3rdparty/ ./3rdparty/ +COPY --chown=emscripten:emscripten LEGO1/ ./LEGO1/ +COPY --chown=emscripten:emscripten ISLE/ ./ISLE/ +COPY --chown=emscripten:emscripten miniwin/ ./miniwin/ +COPY --chown=emscripten:emscripten util/ ./util/ +COPY --chown=emscripten:emscripten CMake/ ./CMake/ +COPY --chown=emscripten:emscripten packaging/ ./packaging/ +COPY --chown=emscripten:emscripten CMakeLists.txt . RUN emcmake cmake -S . -B build -DISLE_BUILD_CONFIG=OFF -DISLE_DEBUG=OFF -DCMAKE_BUILD_TYPE=Release -DISLE_EMSCRIPTEN_HOST=/assets && \ emmake cmake --build build -j 32 @@ -29,9 +36,9 @@ RUN emcmake cmake -S . -B build -DISLE_BUILD_CONFIG=OFF -DISLE_DEBUG=OFF -DCMAKE RUN echo "Fetching isle.pizza frontend..."; \ git clone --depth 1 https://github.com/isledecomp/isle.pizza /tmp/isle.pizza; -FROM nginx:alpine +FROM openresty/openresty:alpine -COPY docker/emscripten/nginx.conf /etc/nginx/nginx.conf -COPY --from=builder /tmp/isle.pizza /usr/share/nginx/html -COPY --from=builder /src/build/isle.* /usr/share/nginx/html +COPY docker/emscripten/nginx.conf /usr/local/openresty/nginx/conf/nginx.conf +COPY --from=builder /tmp/isle.pizza /usr/local/openresty/nginx/html +COPY --from=builder /src/build/isle.* /usr/local/openresty/nginx/html EXPOSE 6931 diff --git a/docker/emscripten/nginx.conf b/docker/emscripten/nginx.conf index 30d9e34d..cbd53d25 100644 --- a/docker/emscripten/nginx.conf +++ b/docker/emscripten/nginx.conf @@ -3,7 +3,43 @@ events { } http { - include /etc/nginx/mime.types; + init_by_lua_block { + function find_entry_in_dir(parent_dir, name_to_find) + local safe_parent_dir = string.gsub(parent_dir, "'", "'\\''") + local lower_name_to_find = string.lower(name_to_find) + local pipe = io.popen("ls -A '" .. safe_parent_dir .. "' 2>/dev/null") + if not pipe then return nil end + + for entry in pipe:lines() do + if string.lower(entry) == lower_name_to_find then + pipe:close() + return entry + end + end + pipe:close() + return nil + end + + function find_recursive_path(path_to_check) + local current_resolved_path = "/" + + for component in string.gmatch(path_to_check, "([^/]+)") do + local found_entry = find_entry_in_dir(current_resolved_path, component) + if not found_entry then + return nil + end + + if current_resolved_path == "/" then + current_resolved_path = current_resolved_path .. found_entry + else + current_resolved_path = current_resolved_path .. "/" .. found_entry + end + end + return current_resolved_path + end + } + + include /usr/local/openresty/nginx/conf/mime.types; server { listen 6931; @@ -14,14 +50,33 @@ http { add_header 'Cross-Origin-Resource-Policy' 'cross-origin'; location / { - root /usr/share/nginx/html; + root /usr/local/openresty/nginx/html; index index.html isle.html; try_files $uri $uri/ =404; } - location ~* ^/assets/(.*)$ { - alias /assets/; - try_files /$1 /DATA/disk/$1 =404; + location /assets/ { + content_by_lua_block { + local request_uri = ngx.var.uri + local resolved_path = find_recursive_path(request_uri) + + if not resolved_path then + local fallback_uri = ngx.re.sub(request_uri, [[^/assets/]], "/assets/DATA/disk/", "i") + resolved_path = find_recursive_path(fallback_uri) + end + + if resolved_path then + ngx.exec("/internal" .. resolved_path) + else + ngx.exit(ngx.HTTP_NOT_FOUND) + end + } + } + + location /internal/assets/ { + internal; + root /; + rewrite ^/internal(.*)$ $1 break; } } } diff --git a/docker/emscripten/ssl_example/Caddyfile b/docker/emscripten/ssl_example/Caddyfile new file mode 100644 index 00000000..a5fc9766 --- /dev/null +++ b/docker/emscripten/ssl_example/Caddyfile @@ -0,0 +1,3 @@ +https://localhost:6932 { + reverse_proxy app:6931 +} diff --git a/docker/emscripten/ssl_example/docker-compose.yml b/docker/emscripten/ssl_example/docker-compose.yml new file mode 100644 index 00000000..84e88ea9 --- /dev/null +++ b/docker/emscripten/ssl_example/docker-compose.yml @@ -0,0 +1,18 @@ +services: + app: + image: ghcr.io/isledecomp/isle-portable-emscripten:master + ports: + - "6931:6931" + volumes: + - ${ASSETS_PATH}:/assets + + caddy: + image: caddy:latest + ports: + - "6932:6932" + volumes: + - ./Caddyfile:/etc/caddy/Caddyfile + - caddy_data:/data + +volumes: + caddy_data: \ No newline at end of file From 40ec9118118530ef6b1324cbd911616c040964bf Mon Sep 17 00:00:00 2001 From: Fabian Neundorf Date: Wed, 2 Jul 2025 21:09:25 +0200 Subject: [PATCH 04/23] Clear unknown in `MxWavePresenter` (#1600) --- LEGO1/omni/include/mxwavepresenter.h | 2 +- LEGO1/omni/src/audio/mxwavepresenter.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/LEGO1/omni/include/mxwavepresenter.h b/LEGO1/omni/include/mxwavepresenter.h index cf64b90f..52758951 100644 --- a/LEGO1/omni/include/mxwavepresenter.h +++ b/LEGO1/omni/include/mxwavepresenter.h @@ -71,7 +71,7 @@ class MxWavePresenter : public MxSoundPresenter { void Destroy(MxBool p_fromDestructor); MxS8 GetPlayedChunks(); - MxBool FUN_100b1ba0(); + MxBool ReadyForNextChunk(); void WriteToSoundBuffer(void* p_audioPtr, MxU32 p_length); WaveFormat* m_waveFormat; // 0x54 diff --git a/LEGO1/omni/src/audio/mxwavepresenter.cpp b/LEGO1/omni/src/audio/mxwavepresenter.cpp index ffc7e708..37a75e5e 100644 --- a/LEGO1/omni/src/audio/mxwavepresenter.cpp +++ b/LEGO1/omni/src/audio/mxwavepresenter.cpp @@ -67,7 +67,7 @@ MxS8 MxWavePresenter::GetPlayedChunks() } // FUNCTION: LEGO1 0x100b1ba0 -MxBool MxWavePresenter::FUN_100b1ba0() +MxBool MxWavePresenter::ReadyForNextChunk() { return !m_started || GetPlayedChunks() != m_writtenChunks; } @@ -248,7 +248,7 @@ MxResult MxWavePresenter::PutData() if (IsEnabled()) { switch (m_currentTickleState) { case e_streaming: - if (m_currentChunk && FUN_100b1ba0()) { + if (m_currentChunk && ReadyForNextChunk()) { WriteToSoundBuffer(m_currentChunk->GetData(), m_currentChunk->GetLength()); m_subscriber->FreeDataChunk(m_currentChunk); m_currentChunk = NULL; From 89fe7fa9246b4dfbb0e5a53eec4e030fbffd60ac Mon Sep 17 00:00:00 2001 From: Christian Semmler Date: Wed, 2 Jul 2025 13:43:57 -0700 Subject: [PATCH 05/23] Fix wrong notification type in `LegoRace::Notify` (#1601) --- LEGO1/lego/legoomni/include/carrace.h | 14 +++++++------- LEGO1/lego/legoomni/include/jetskirace.h | 12 ++++++------ LEGO1/lego/legoomni/include/legorace.h | 4 ++-- LEGO1/lego/legoomni/src/race/carrace.cpp | 8 +++----- LEGO1/lego/legoomni/src/race/jetskirace.cpp | 6 +++--- LEGO1/lego/legoomni/src/race/legorace.cpp | 4 ++-- 6 files changed, 23 insertions(+), 25 deletions(-) diff --git a/LEGO1/lego/legoomni/include/carrace.h b/LEGO1/lego/legoomni/include/carrace.h index 03e7a958..7a3b2f6f 100644 --- a/LEGO1/lego/legoomni/include/carrace.h +++ b/LEGO1/lego/legoomni/include/carrace.h @@ -52,13 +52,13 @@ class CarRace : public LegoRace { return !strcmp(p_name, CarRace::ClassName()) || LegoRace::IsA(p_name); } - MxResult Create(MxDSAction& p_dsAction) override; // vtable+0x18 - void ReadyWorld() override; // vtable+0x50 - MxBool Escape() override; // vtable+0x64 - MxLong HandleClick(LegoEventNotificationParam&) override; // vtable+0x6c - MxLong HandlePathStruct(LegoPathStructNotificationParam&) override; // vtable+0x70 - MxLong HandleEndAction(MxEndActionNotificationParam&) override; // vtable+0x74 - MxLong HandleType0Notification(MxNotificationParam&) override; // vtable+0x78 + MxResult Create(MxDSAction& p_dsAction) override; // vtable+0x18 + void ReadyWorld() override; // vtable+0x50 + MxBool Escape() override; // vtable+0x64 + MxLong HandleControl(LegoControlManagerNotificationParam&) override; // vtable+0x6c + MxLong HandlePathStruct(LegoPathStructNotificationParam&) override; // vtable+0x70 + MxLong HandleEndAction(MxEndActionNotificationParam&) override; // vtable+0x74 + MxLong HandleType0Notification(MxNotificationParam&) override; // vtable+0x78 // FUNCTION: BETA10 0x100cd060 RaceSkel* GetSkeleton() { return m_skeleton; } diff --git a/LEGO1/lego/legoomni/include/jetskirace.h b/LEGO1/lego/legoomni/include/jetskirace.h index 7542d851..61407cce 100644 --- a/LEGO1/lego/legoomni/include/jetskirace.h +++ b/LEGO1/lego/legoomni/include/jetskirace.h @@ -29,12 +29,12 @@ class JetskiRace : public LegoRace { return !strcmp(p_name, JetskiRace::ClassName()) || LegoRace::IsA(p_name); } - MxResult Create(MxDSAction& p_dsAction) override; // vtable+0x18 - void ReadyWorld() override; // vtable+0x50 - MxBool Escape() override; // vtable+0x64 - MxLong HandleClick(LegoEventNotificationParam&) override; // vtable+0x6c - MxLong HandlePathStruct(LegoPathStructNotificationParam&) override; // vtable+0x70 - MxLong HandleEndAction(MxEndActionNotificationParam&) override; // vtable+0x74 + MxResult Create(MxDSAction& p_dsAction) override; // vtable+0x18 + void ReadyWorld() override; // vtable+0x50 + MxBool Escape() override; // vtable+0x64 + MxLong HandleControl(LegoControlManagerNotificationParam&) override; // vtable+0x6c + MxLong HandlePathStruct(LegoPathStructNotificationParam&) override; // vtable+0x70 + MxLong HandleEndAction(MxEndActionNotificationParam&) override; // vtable+0x74 void FUN_10016930(MxS32 p_param1, MxS16 p_param2); diff --git a/LEGO1/lego/legoomni/include/legorace.h b/LEGO1/lego/legoomni/include/legorace.h index 55d43785..e1b93211 100644 --- a/LEGO1/lego/legoomni/include/legorace.h +++ b/LEGO1/lego/legoomni/include/legorace.h @@ -11,7 +11,7 @@ #include "mxtypes.h" class Act1State; -class LegoEventNotificationParam; +class LegoControlManagerNotificationParam; class LegoPathActor; class MxEndActionNotificationParam; class MxNotificationParam; @@ -117,7 +117,7 @@ class LegoRace : public LegoWorld { MxResult Create(MxDSAction& p_dsAction) override; // vtable+0x18 - virtual MxLong HandleClick(LegoEventNotificationParam&) = 0; // vtable+0x6c + virtual MxLong HandleControl(LegoControlManagerNotificationParam&) = 0; // vtable+0x6c // FUNCTION: LEGO1 0x10015b70 virtual MxLong HandlePathStruct(LegoPathStructNotificationParam&) { return 0; } // vtable+0x70 diff --git a/LEGO1/lego/legoomni/src/race/carrace.cpp b/LEGO1/lego/legoomni/src/race/carrace.cpp index 86c50b4a..0c3c3a51 100644 --- a/LEGO1/lego/legoomni/src/race/carrace.cpp +++ b/LEGO1/lego/legoomni/src/race/carrace.cpp @@ -333,12 +333,10 @@ MxLong CarRace::HandlePathStruct(LegoPathStructNotificationParam& p_param) } // FUNCTION: LEGO1 0x10017650 -MxLong CarRace::HandleClick(LegoEventNotificationParam& p_param) +MxLong CarRace::HandleControl(LegoControlManagerNotificationParam& p_param) { - LegoControlManagerNotificationParam* param = (LegoControlManagerNotificationParam*) &p_param; - - if (param->m_unk0x28 == 1) { - switch (param->m_clickedObjectId) { + if (p_param.m_unk0x28 == 1) { + switch (p_param.m_clickedObjectId) { case 3: InvokeAction(Extra::e_stop, *g_carraceScript, CarraceScript::c_irtx08ra_PlayWav, NULL); m_act1State->m_unk0x018 = 0; diff --git a/LEGO1/lego/legoomni/src/race/jetskirace.cpp b/LEGO1/lego/legoomni/src/race/jetskirace.cpp index 54ad806c..1297ed36 100644 --- a/LEGO1/lego/legoomni/src/race/jetskirace.cpp +++ b/LEGO1/lego/legoomni/src/race/jetskirace.cpp @@ -120,12 +120,12 @@ MxLong JetskiRace::HandleEndAction(MxEndActionNotificationParam& p_param) } // FUNCTION: LEGO1 0x100165a0 -MxLong JetskiRace::HandleClick(LegoEventNotificationParam& p_param) +MxLong JetskiRace::HandleControl(LegoControlManagerNotificationParam& p_param) { MxLong result = 0; - if (((LegoControlManagerNotificationParam*) &p_param)->m_unk0x28 == 1) { - switch (((LegoControlManagerNotificationParam*) &p_param)->m_clickedObjectId) { + if (p_param.m_unk0x28 == 1) { + switch (p_param.m_clickedObjectId) { case JetraceScript::c_JetskiArms_Ctl: m_act1State->m_unk0x018 = 0; VariableTable()->SetVariable(g_raceState, ""); diff --git a/LEGO1/lego/legoomni/src/race/legorace.cpp b/LEGO1/lego/legoomni/src/race/legorace.cpp index a2c0555d..91374766 100644 --- a/LEGO1/lego/legoomni/src/race/legorace.cpp +++ b/LEGO1/lego/legoomni/src/race/legorace.cpp @@ -82,8 +82,8 @@ MxLong LegoRace::Notify(MxParam& p_param) case c_notificationEndAction: result = HandleEndAction((MxEndActionNotificationParam&) p_param); break; - case c_notificationClick: - result = HandleClick((LegoEventNotificationParam&) p_param); + case c_notificationControl: + result = HandleControl((LegoControlManagerNotificationParam&) p_param); break; case c_notificationPathStruct: result = HandlePathStruct((LegoPathStructNotificationParam&) p_param); From d74e6ab4014053a8d1a863d2833213644da5df68 Mon Sep 17 00:00:00 2001 From: Anders Jenbo Date: Thu, 3 Jul 2025 00:49:47 +0200 Subject: [PATCH 06/23] Use DDBLT_COLORFILL to clear screen on start (#487) --- LEGO1/mxdirectx/mxdirect3d.cpp | 35 ++++------------------- LEGO1/omni/src/video/mxdisplaysurface.cpp | 6 ++-- 2 files changed, 8 insertions(+), 33 deletions(-) diff --git a/LEGO1/mxdirectx/mxdirect3d.cpp b/LEGO1/mxdirectx/mxdirect3d.cpp index d6043a2c..e338046f 100644 --- a/LEGO1/mxdirectx/mxdirect3d.cpp +++ b/LEGO1/mxdirectx/mxdirect3d.cpp @@ -170,39 +170,16 @@ BOOL MxDirect3D::D3DSetMode() LPDIRECTDRAWSURFACE frontBuffer = FrontBuffer(); LPDIRECTDRAWSURFACE backBuffer = BackBuffer(); - DDSURFACEDESC desc; - memset(&desc, 0, sizeof(desc)); - desc.dwSize = sizeof(desc); + DDBLTFX ddBltFx = {}; + ddBltFx.dwSize = sizeof(DDBLTFX); + ddBltFx.dwFillColor = 0; - if (backBuffer->Lock(NULL, &desc, DDLOCK_WAIT | DDLOCK_WRITEONLY, NULL) == DD_OK) { - unsigned char* surface = (unsigned char*) desc.lpSurface; - - for (int i = 0; i < mode.height; i++) { - memset(surface, 0, desc.lPitch); - surface += desc.lPitch; - } - - backBuffer->Unlock(desc.lpSurface); - } - else { - SDL_Log("MxDirect3D::D3DSetMode() back lock failed\n"); + if (backBuffer->Blt(NULL, NULL, NULL, DDBLT_WAIT | DDBLT_COLORFILL, &ddBltFx) != DD_OK) { + SDL_Log("MxDirect3D::D3DSetMode() color fill failed\n"); } if (IsFullScreen()) { - memset(&desc, 0, sizeof(desc)); - desc.dwSize = sizeof(desc); - - if (frontBuffer->Lock(NULL, &desc, DDLOCK_WAIT | DDLOCK_WRITEONLY, NULL) == DD_OK) { - unsigned char* surface = (unsigned char*) desc.lpSurface; - - for (int i = 0; i < mode.height; i++) { - memset(surface, 0, desc.lPitch); - surface += desc.lPitch; - } - - frontBuffer->Unlock(desc.lpSurface); - } - else { + if (frontBuffer->Blt(NULL, NULL, NULL, DDBLT_WAIT | DDBLT_COLORFILL, &ddBltFx) != DD_OK) { SDL_Log("MxDirect3D::D3DSetMode() front lock failed\n"); } } diff --git a/LEGO1/omni/src/video/mxdisplaysurface.cpp b/LEGO1/omni/src/video/mxdisplaysurface.cpp index c2886ebe..badf05d1 100644 --- a/LEGO1/omni/src/video/mxdisplaysurface.cpp +++ b/LEGO1/omni/src/video/mxdisplaysurface.cpp @@ -64,8 +64,6 @@ void MxDisplaySurface::ClearScreen() MxS32 width = m_videoParam.GetRect().GetWidth(); MxS32 height = m_videoParam.GetRect().GetHeight(); - RECT rc = {0, 0, width, height}; - memset(&desc, 0, sizeof(desc)); desc.dwSize = sizeof(desc); if (m_ddSurface2->GetSurfaceDesc(&desc) != DD_OK) { @@ -77,9 +75,9 @@ void MxDisplaySurface::ClearScreen() ddBltFx.dwFillColor = 0; for (MxS32 i = 0; i < backBuffers; i++) { - if (m_ddSurface2->Blt(&rc, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &ddBltFx) == DDERR_SURFACELOST) { + if (m_ddSurface2->Blt(NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &ddBltFx) == DDERR_SURFACELOST) { m_ddSurface2->Restore(); - m_ddSurface2->Blt(&rc, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &ddBltFx); + m_ddSurface2->Blt(NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &ddBltFx); } if (m_videoParam.Flags().GetFlipSurfaces()) { From 04b0e9a47015160124d419873c7cf3fd47f65216 Mon Sep 17 00:00:00 2001 From: Christian Semmler Date: Wed, 2 Jul 2025 17:45:21 -0700 Subject: [PATCH 07/23] Fix saving of default textures (#490) --- LEGO1/lego/legoomni/src/common/legoutils.cpp | 8 ++++---- LEGO1/lego/sources/misc/legoimage.h | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/LEGO1/lego/legoomni/src/common/legoutils.cpp b/LEGO1/lego/legoomni/src/common/legoutils.cpp index 0946a0ab..a2ffbe5e 100644 --- a/LEGO1/lego/legoomni/src/common/legoutils.cpp +++ b/LEGO1/lego/legoomni/src/common/legoutils.cpp @@ -708,19 +708,19 @@ void WriteDefaultTexture(LegoStorage* p_storage, const char* p_name) memset(&desc, 0, sizeof(desc)); desc.dwSize = sizeof(desc); - if (surface->Lock(NULL, &desc, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WRITEONLY, NULL) == DD_OK) { + if (surface->Lock(NULL, &desc, DDLOCK_SURFACEMEMORYPTR, NULL) == DD_OK) { LegoImage* image = new LegoImage(desc.dwWidth, desc.dwHeight); if (image != NULL) { if (desc.dwWidth == desc.lPitch) { - memcpy(desc.lpSurface, image->GetBits(), desc.dwWidth * desc.dwHeight); + memcpy(image->GetBits(), desc.lpSurface, desc.dwWidth * desc.dwHeight); } else { MxU8* surface = (MxU8*) desc.lpSurface; - const LegoU8* bits = image->GetBits(); + LegoU8* bits = image->GetBits(); for (MxS32 i = 0; i < desc.dwHeight; i++) { - memcpy(surface, bits, desc.dwWidth); + memcpy(bits, surface, desc.dwWidth); surface += desc.lPitch; bits += desc.dwWidth; } diff --git a/LEGO1/lego/sources/misc/legoimage.h b/LEGO1/lego/sources/misc/legoimage.h index ee1dc55d..d0269b82 100644 --- a/LEGO1/lego/sources/misc/legoimage.h +++ b/LEGO1/lego/sources/misc/legoimage.h @@ -46,7 +46,7 @@ class LegoImage { { m_palette->colors[p_i] = p_paletteEntry.GetColor(); } - const LegoU8* GetBits() const { return (LegoU8*) m_surface->pixels; } + LegoU8* GetBits() const { return (LegoU8*) m_surface->pixels; } LegoResult Read(LegoStorage* p_storage, LegoU32 p_square); LegoResult Write(LegoStorage* p_storage); From 3894d58efc25004e51c7eb6662ab320a196a533a Mon Sep 17 00:00:00 2001 From: Anders Jenbo Date: Thu, 3 Jul 2025 04:06:45 +0200 Subject: [PATCH 08/23] Fix disolve and wipe transitions on 32bit (#492) --- .../src/common/mxtransitionmanager.cpp | 23 +++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/LEGO1/lego/legoomni/src/common/mxtransitionmanager.cpp b/LEGO1/lego/legoomni/src/common/mxtransitionmanager.cpp index d54563ab..9e052430 100644 --- a/LEGO1/lego/legoomni/src/common/mxtransitionmanager.cpp +++ b/LEGO1/lego/legoomni/src/common/mxtransitionmanager.cpp @@ -248,7 +248,7 @@ void MxTransitionManager::DissolveTransition() } else { MxU8* surf = (MxU8*) ddsd.lpSurface + ddsd.lPitch * row + xShift * 4; - *(MxU32*) surf = 0; + *(MxU32*) surf = 0xFF000000; } } } @@ -416,10 +416,25 @@ void MxTransitionManager::WipeDownTransition() // 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; - memset(line, 0, ddsd.lPitch); - line += ddsd.lPitch; - memset(line, 0, ddsd.lPitch); + 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); From be73b40ae8bb16bd51d08fbfda2c823886b5f093 Mon Sep 17 00:00:00 2001 From: Christian Semmler Date: Wed, 2 Jul 2025 19:10:02 -0700 Subject: [PATCH 09/23] Add monkey patch to Emscripten to disable `OffscreenCanvas` at runtime (#493) * Add runtime option to disable OffscreenCanvas in web port * Remove old patch --- .../{libwasmfs_fetch.js.patch => emscripten.patch} | 13 +++++++++++++ docker/emscripten/Dockerfile | 6 +++--- 2 files changed, 16 insertions(+), 3 deletions(-) rename ISLE/emscripten/{libwasmfs_fetch.js.patch => emscripten.patch} (88%) diff --git a/ISLE/emscripten/libwasmfs_fetch.js.patch b/ISLE/emscripten/emscripten.patch similarity index 88% rename from ISLE/emscripten/libwasmfs_fetch.js.patch rename to ISLE/emscripten/emscripten.patch index de8fab60..899d72eb 100644 --- a/ISLE/emscripten/libwasmfs_fetch.js.patch +++ b/ISLE/emscripten/emscripten.patch @@ -1,3 +1,16 @@ +diff --git a/src/lib/libpthread.js b/src/lib/libpthread.js +index 6d979627e..97e3f8684 100644 +--- a/src/lib/libpthread.js ++++ b/src/lib/libpthread.js +@@ -697,7 +697,7 @@ var LibraryPThread = { + { + transferredCanvasNames = UTF8ToString(transferredCanvasNames).trim(); + } +- transferredCanvasNames = transferredCanvasNames ? transferredCanvasNames.split(',') : []; ++ transferredCanvasNames = transferredCanvasNames && !Module['disableOffscreenCanvases'] ? transferredCanvasNames.split(',') : []; + #if GL_DEBUG + dbg(`pthread_create: transferredCanvasNames="${transferredCanvasNames}"`); + #endif diff --git a/src/lib/libwasmfs_fetch.js b/src/lib/libwasmfs_fetch.js index e8c9f7e21..caf1971d2 100644 --- a/src/lib/libwasmfs_fetch.js diff --git a/docker/emscripten/Dockerfile b/docker/emscripten/Dockerfile index f234e9ed..a213093c 100644 --- a/docker/emscripten/Dockerfile +++ b/docker/emscripten/Dockerfile @@ -16,10 +16,10 @@ RUN chown -R emscripten:emscripten /src USER emscripten -COPY ISLE/emscripten/libwasmfs_fetch.js.patch /tmp/ +COPY ISLE/emscripten/emscripten.patch /tmp/ RUN cd /emsdk/upstream/emscripten && \ - git apply --check /tmp/libwasmfs_fetch.js.patch && \ - git apply /tmp/libwasmfs_fetch.js.patch + git apply --check /tmp/emscripten.patch && \ + git apply /tmp/emscripten.patch COPY --chown=emscripten:emscripten 3rdparty/ ./3rdparty/ COPY --chown=emscripten:emscripten LEGO1/ ./LEGO1/ From 605163b755273fd46fad57194bddd186b221b259 Mon Sep 17 00:00:00 2001 From: Anders Jenbo Date: Thu, 3 Jul 2025 04:57:57 +0200 Subject: [PATCH 10/23] Fix WindowsTransition (#495) --- .../src/common/mxtransitionmanager.cpp | 39 +++++++++++++++---- 1 file changed, 32 insertions(+), 7 deletions(-) diff --git a/LEGO1/lego/legoomni/src/common/mxtransitionmanager.cpp b/LEGO1/lego/legoomni/src/common/mxtransitionmanager.cpp index 9e052430..8c2c994d 100644 --- a/LEGO1/lego/legoomni/src/common/mxtransitionmanager.cpp +++ b/LEGO1/lego/legoomni/src/common/mxtransitionmanager.cpp @@ -469,17 +469,42 @@ void MxTransitionManager::WindowsTransition() MxS32 bytesPerPixel = ddsd.ddpfPixelFormat.dwRGBBitCount / 8; - memset(line, 0, ddsd.lPitch); + if (bytesPerPixel == 4) { + MxU32* pixels = (MxU32*) line; + for (int i = 0; i < 640; i++) { + pixels[i] = 0xFF000000; + } - for (MxS32 i = m_animationTimer + 1; i < 480 - m_animationTimer; i++) { - line += ddsd.lPitch; + 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; + } - memset(line + m_animationTimer * bytesPerPixel, 0, bytesPerPixel); - memset(line + 640 + (-1 - m_animationTimer) * bytesPerPixel, 0, bytesPerPixel); + 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); - line += ddsd.lPitch; - memset(line, 0, ddsd.lPitch); + 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); From fde5e6ced33d9dd31a6146b49de499e5243504ad Mon Sep 17 00:00:00 2001 From: Joshua Peisach Date: Thu, 3 Jul 2025 06:43:27 -0400 Subject: [PATCH 11/23] 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 12/23] 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 13/23] 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 14/23] 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 15/23] 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 16/23] 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 17/23] 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 18/23] 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 19/23] 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 20/23] 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 21/23] 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 22/23] 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 23/23] 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) {