diff --git a/CMakeLists.txt b/CMakeLists.txt
index 978395a7..b6fa1dd0 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -482,6 +482,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)
@@ -541,6 +544,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/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
diff --git a/ISLE/emscripten/libwasmfs_fetch.js.patch b/ISLE/emscripten/emscripten.patch
similarity index 82%
rename from ISLE/emscripten/libwasmfs_fetch.js.patch
rename to ISLE/emscripten/emscripten.patch
index de8fab60..0bc8222d 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
@@ -126,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 8f69bf4e..d9a6d9b8 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();
@@ -440,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 {
@@ -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);
@@ -741,6 +754,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(
@@ -764,6 +780,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);
@@ -779,10 +802,6 @@ bool IsleApp::LoadConfig()
}
SDL_Log("Reading configuration from \"%s\"", iniConfig);
-#ifdef __EMSCRIPTEN__
- Emscripten_SetupConfig(iniConfig);
-#endif
-
dictionary* dict = iniparser_load(iniConfig);
// [library:config]
@@ -1025,15 +1044,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:
@@ -1045,12 +1068,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 00000000..eaa08ca6
Binary files /dev/null and b/ISLE/res/arrow.png differ
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 00000000..cd8f5bf1
Binary files /dev/null and b/ISLE/res/busy.png differ
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 00000000..968adccd
Binary files /dev/null and b/ISLE/res/no.png differ
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/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/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/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/legoomni/src/common/mxtransitionmanager.cpp b/LEGO1/lego/legoomni/src/common/mxtransitionmanager.cpp
index d54563ab..6fd211c6 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;
}
}
}
@@ -400,32 +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;
- 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
@@ -437,40 +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);
- memset(line, 0, ddsd.lPitch);
+ 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; i++) {
- line += ddsd.lPitch;
-
- memset(line + m_animationTimer * bytesPerPixel, 0, bytesPerPixel);
- memset(line + 640 + (-1 - m_animationTimer) * bytesPerPixel, 0, bytesPerPixel);
- }
-
- line += ddsd.lPitch;
- memset(line, 0, ddsd.lPitch);
-
- SetupCopyRect(&ddsd);
- m_ddSurface->Unlock(ddsd.lpSurface);
-
- m_animationTimer++;
- }
+ m_animationTimer++;
}
// FUNCTION: LEGO1 0x1004c3e0
diff --git a/LEGO1/lego/legoomni/src/race/carrace.cpp b/LEGO1/lego/legoomni/src/race/carrace.cpp
index 97ae49b8..62701294 100644
--- a/LEGO1/lego/legoomni/src/race/carrace.cpp
+++ b/LEGO1/lego/legoomni/src/race/carrace.cpp
@@ -335,12 +335,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 b520f8f3..7081d8eb 100644
--- a/LEGO1/lego/legoomni/src/race/jetskirace.cpp
+++ b/LEGO1/lego/legoomni/src/race/jetskirace.cpp
@@ -122,12 +122,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);
diff --git a/LEGO1/lego/legoomni/src/video/legovideomanager.cpp b/LEGO1/lego/legoomni/src/video/legovideomanager.cpp
index 7e2f7e42..cdb20197 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;
}
}
@@ -388,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
@@ -836,3 +827,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/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;
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);
diff --git a/LEGO1/mxdirectx/mxdirect3d.cpp b/LEGO1/mxdirectx/mxdirect3d.cpp
index d6043a2c..0dae36e1 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 = 0xFF000000;
- 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/mxdirectx/mxdirectdraw.cpp b/LEGO1/mxdirectx/mxdirectdraw.cpp
index bedf4d2e..7ccb78c2 100644
--- a/LEGO1/mxdirectx/mxdirectdraw.cpp
+++ b/LEGO1/mxdirectx/mxdirectdraw.cpp
@@ -519,35 +519,23 @@ BOOL MxDirectDraw::DDCreateSurfaces()
void MxDirectDraw::ClearBackBuffers()
{
HRESULT result;
- byte* line;
- DDSURFACEDESC ddsd;
+ DDBLTFX ddbltfx = {};
+ ddbltfx.dwSize = sizeof(DDBLTFX);
+ ddbltfx.dwFillColor = 0xFF000000;
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);
-
- 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);
}
diff --git a/LEGO1/omni/include/mxdisplaysurface.h b/LEGO1/omni/include/mxdisplaysurface.h
index 8d31ff4f..3a3dcd08 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"
@@ -70,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,
@@ -96,7 +89,7 @@ class MxDisplaySurface : public MxCore {
); // vtable+0x44
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 c2886ebe..b10330f2 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) {
@@ -74,12 +72,12 @@ 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(&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()) {
@@ -718,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)
{
@@ -781,21 +724,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");
}
}
@@ -814,7 +747,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();
@@ -1017,86 +950,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,
@@ -1298,3 +1151,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/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());
}
}
}
diff --git a/docker/emscripten/Dockerfile b/docker/emscripten/Dockerfile
index d15d2406..a213093c 100644
--- a/docker/emscripten/Dockerfile
+++ b/docker/emscripten/Dockerfile
@@ -16,12 +16,19 @@ 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 . .
+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
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;
};
diff --git a/miniwin/src/d3drm/backends/citro3d/renderer.cpp b/miniwin/src/d3drm/backends/citro3d/renderer.cpp
index 72d729bc..f71f9255 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)
@@ -444,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,
@@ -463,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);
}
@@ -520,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();
@@ -546,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;
@@ -564,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 74101b8d..3469e023 100644
--- a/miniwin/src/d3drm/backends/opengl1/actual.cpp
+++ b/miniwin/src/d3drm/backends/opengl1/actual.cpp
@@ -297,9 +297,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,
@@ -308,6 +309,7 @@ void GL11_Draw2DImage(
{
glDisable(GL_DEPTH_TEST);
glDepthMask(GL_FALSE);
+ glShadeModel(GL_FLAT);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
@@ -318,17 +320,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 65ebb20d..06c24b89 100644
--- a/miniwin/src/d3drm/backends/opengl1/renderer.cpp
+++ b/miniwin/src/d3drm/backends/opengl1/renderer.cpp
@@ -374,7 +374,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;
@@ -383,7 +383,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 6b19b219..993648d3 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;
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
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())