mirror of
https://github.com/isledecomp/isle-portable.git
synced 2026-05-04 03:23:56 +00:00
Add back 8bit rendering and also DOS support
This commit is contained in:
parent
c52a5204a4
commit
77402ef7ec
6
3rdparty/CMakeLists.txt
vendored
6
3rdparty/CMakeLists.txt
vendored
@ -34,6 +34,12 @@ target_compile_definitions(miniaudio PUBLIC
|
|||||||
MA_NO_RUNTIME_LINKING
|
MA_NO_RUNTIME_LINKING
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if(DJGPP)
|
||||||
|
# DOS is single-threaded so we provide non-atomic __atomic_*_8 stubs
|
||||||
|
# (see CMakeLists.txt top-level comment about -march=i486).
|
||||||
|
target_sources(miniaudio PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/djgpp_atomic64.c")
|
||||||
|
endif()
|
||||||
|
|
||||||
if(DOWNLOAD_DEPENDENCIES)
|
if(DOWNLOAD_DEPENDENCIES)
|
||||||
include(FetchContent)
|
include(FetchContent)
|
||||||
FetchContent_Declare(
|
FetchContent_Declare(
|
||||||
|
|||||||
109
3rdparty/djgpp_atomic64.c
vendored
Normal file
109
3rdparty/djgpp_atomic64.c
vendored
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
/*
|
||||||
|
* Non-atomic 64-bit __atomic_*_8 stubs for DJGPP / DOS.
|
||||||
|
*
|
||||||
|
* DOS is single-threaded so real atomics are unnecessary. GCC emits calls to
|
||||||
|
* these helper functions when targeting i486 (or when __i586__ is undefined)
|
||||||
|
* because the ISA lacks a native 64-bit atomic instruction. Normally libatomic
|
||||||
|
* provides them, but DJGPP doesn't ship libatomic.
|
||||||
|
*
|
||||||
|
* Every function simply performs a plain (non-atomic) load/store/exchange/CAS
|
||||||
|
* which is perfectly safe in a single-threaded environment.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
uint64_t __atomic_load_8(const volatile void *ptr, int memorder)
|
||||||
|
{
|
||||||
|
(void)memorder;
|
||||||
|
uint64_t val;
|
||||||
|
memcpy(&val, (const void *)ptr, sizeof(val));
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
void __atomic_store_8(volatile void *ptr, uint64_t val, int memorder)
|
||||||
|
{
|
||||||
|
(void)memorder;
|
||||||
|
memcpy((void *)ptr, &val, sizeof(val));
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t __atomic_exchange_8(volatile void *ptr, uint64_t val, int memorder)
|
||||||
|
{
|
||||||
|
(void)memorder;
|
||||||
|
uint64_t old;
|
||||||
|
memcpy(&old, (void *)ptr, sizeof(old));
|
||||||
|
memcpy((void *)ptr, &val, sizeof(val));
|
||||||
|
return old;
|
||||||
|
}
|
||||||
|
|
||||||
|
int __atomic_compare_exchange_8(
|
||||||
|
volatile void *ptr,
|
||||||
|
void *expected,
|
||||||
|
uint64_t desired,
|
||||||
|
int success_memorder,
|
||||||
|
int failure_memorder
|
||||||
|
)
|
||||||
|
{
|
||||||
|
(void)success_memorder;
|
||||||
|
(void)failure_memorder;
|
||||||
|
uint64_t current;
|
||||||
|
memcpy(¤t, (void *)ptr, sizeof(current));
|
||||||
|
uint64_t exp;
|
||||||
|
memcpy(&exp, expected, sizeof(exp));
|
||||||
|
if (current == exp) {
|
||||||
|
memcpy((void *)ptr, &desired, sizeof(desired));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
memcpy(expected, ¤t, sizeof(current));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t __atomic_fetch_add_8(volatile void *ptr, uint64_t val, int memorder)
|
||||||
|
{
|
||||||
|
(void)memorder;
|
||||||
|
uint64_t old;
|
||||||
|
memcpy(&old, (void *)ptr, sizeof(old));
|
||||||
|
uint64_t new_val = old + val;
|
||||||
|
memcpy((void *)ptr, &new_val, sizeof(new_val));
|
||||||
|
return old;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t __atomic_fetch_sub_8(volatile void *ptr, uint64_t val, int memorder)
|
||||||
|
{
|
||||||
|
(void)memorder;
|
||||||
|
uint64_t old;
|
||||||
|
memcpy(&old, (void *)ptr, sizeof(old));
|
||||||
|
uint64_t new_val = old - val;
|
||||||
|
memcpy((void *)ptr, &new_val, sizeof(new_val));
|
||||||
|
return old;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t __atomic_fetch_and_8(volatile void *ptr, uint64_t val, int memorder)
|
||||||
|
{
|
||||||
|
(void)memorder;
|
||||||
|
uint64_t old;
|
||||||
|
memcpy(&old, (void *)ptr, sizeof(old));
|
||||||
|
uint64_t new_val = old & val;
|
||||||
|
memcpy((void *)ptr, &new_val, sizeof(new_val));
|
||||||
|
return old;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t __atomic_fetch_or_8(volatile void *ptr, uint64_t val, int memorder)
|
||||||
|
{
|
||||||
|
(void)memorder;
|
||||||
|
uint64_t old;
|
||||||
|
memcpy(&old, (void *)ptr, sizeof(old));
|
||||||
|
uint64_t new_val = old | val;
|
||||||
|
memcpy((void *)ptr, &new_val, sizeof(new_val));
|
||||||
|
return old;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t __atomic_fetch_xor_8(volatile void *ptr, uint64_t val, int memorder)
|
||||||
|
{
|
||||||
|
(void)memorder;
|
||||||
|
uint64_t old;
|
||||||
|
memcpy(&old, (void *)ptr, sizeof(old));
|
||||||
|
uint64_t new_val = old ^ val;
|
||||||
|
memcpy((void *)ptr, &new_val, sizeof(new_val));
|
||||||
|
return old;
|
||||||
|
}
|
||||||
@ -96,6 +96,15 @@ set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}" CACHE PATH "Directory w
|
|||||||
set(ISLE_EMSCRIPTEN_HOST "" CACHE STRING "Host URL for Emscripten streaming (e.g., https://test.com)")
|
set(ISLE_EMSCRIPTEN_HOST "" CACHE STRING "Host URL for Emscripten streaming (e.g., https://test.com)")
|
||||||
cmake_dependent_option(BUILD_SHARED_LIBS "Build lego1 as a shared library" ON "NOT DOS;NOT EMSCRIPTEN;NOT VITA" OFF)
|
cmake_dependent_option(BUILD_SHARED_LIBS "Build lego1 as a shared library" ON "NOT DOS;NOT EMSCRIPTEN;NOT VITA" OFF)
|
||||||
|
|
||||||
|
if(DOS)
|
||||||
|
# DJGPP targets i386 by default. We use i486 rather than i586 because i586
|
||||||
|
# enables cmpxchg8b which GCC uses for 64-bit atomics (lock cmpxchg8b) —
|
||||||
|
# an instruction DOSBox does not support. The missing __atomic_*_8 helpers
|
||||||
|
# (normally in libatomic, which DJGPP doesn't ship) are provided as simple
|
||||||
|
# non-atomic stubs in 3rdparty/djgpp_atomic64.c since DOS is single-threaded.
|
||||||
|
add_compile_options(-march=i486)
|
||||||
|
endif()
|
||||||
|
|
||||||
message(STATUS "Isle app: ${ISLE_BUILD_APP}")
|
message(STATUS "Isle app: ${ISLE_BUILD_APP}")
|
||||||
message(STATUS "Config app: ${ISLE_BUILD_CONFIG}")
|
message(STATUS "Config app: ${ISLE_BUILD_CONFIG}")
|
||||||
message(STATUS "Internal DirectX5 SDK: ${ISLE_USE_DX5}")
|
message(STATUS "Internal DirectX5 SDK: ${ISLE_USE_DX5}")
|
||||||
|
|||||||
@ -155,11 +155,19 @@ IsleApp::IsleApp()
|
|||||||
m_using8bit = FALSE;
|
m_using8bit = FALSE;
|
||||||
m_using16bit = TRUE;
|
m_using16bit = TRUE;
|
||||||
m_hasLightSupport = FALSE;
|
m_hasLightSupport = FALSE;
|
||||||
|
#ifdef __DJGPP__
|
||||||
|
m_drawCursor = TRUE;
|
||||||
|
#else
|
||||||
m_drawCursor = FALSE;
|
m_drawCursor = FALSE;
|
||||||
|
#endif
|
||||||
m_use3dSound = TRUE;
|
m_use3dSound = TRUE;
|
||||||
m_useMusic = TRUE;
|
m_useMusic = TRUE;
|
||||||
m_wideViewAngle = TRUE;
|
m_wideViewAngle = TRUE;
|
||||||
|
#ifdef __DJGPP__
|
||||||
|
m_islandQuality = 1;
|
||||||
|
#else
|
||||||
m_islandQuality = 2;
|
m_islandQuality = 2;
|
||||||
|
#endif
|
||||||
m_islandTexture = 1;
|
m_islandTexture = 1;
|
||||||
m_gameStarted = FALSE;
|
m_gameStarted = FALSE;
|
||||||
m_frameDelta = 10;
|
m_frameDelta = 10;
|
||||||
@ -191,14 +199,22 @@ IsleApp::IsleApp()
|
|||||||
m_mediaPath = NULL;
|
m_mediaPath = NULL;
|
||||||
m_iniPath = NULL;
|
m_iniPath = NULL;
|
||||||
m_maxLod = RealtimeView::GetUserMaxLOD();
|
m_maxLod = RealtimeView::GetUserMaxLOD();
|
||||||
|
#ifdef __DJGPP__
|
||||||
|
m_maxLod = 1.0f;
|
||||||
|
#endif
|
||||||
m_maxAllowedExtras = m_islandQuality <= 1 ? 10 : 20;
|
m_maxAllowedExtras = m_islandQuality <= 1 ? 10 : 20;
|
||||||
m_transitionType = MxTransitionManager::e_mosaic;
|
m_transitionType = MxTransitionManager::e_mosaic;
|
||||||
m_cursorSensitivity = 4;
|
m_cursorSensitivity = 4;
|
||||||
m_touchScheme = LegoInputManager::e_gamepad;
|
m_touchScheme = LegoInputManager::e_gamepad;
|
||||||
m_haptic = TRUE;
|
m_haptic = TRUE;
|
||||||
m_wasd = FALSE;
|
m_wasd = FALSE;
|
||||||
|
#ifdef __DJGPP__
|
||||||
|
m_xRes = 320;
|
||||||
|
m_yRes = 200;
|
||||||
|
#else
|
||||||
m_xRes = 640;
|
m_xRes = 640;
|
||||||
m_yRes = 480;
|
m_yRes = 480;
|
||||||
|
#endif
|
||||||
m_exclusiveXRes = m_xRes;
|
m_exclusiveXRes = m_xRes;
|
||||||
m_exclusiveYRes = m_yRes;
|
m_exclusiveYRes = m_yRes;
|
||||||
m_exclusiveFrameRate = 60.00f;
|
m_exclusiveFrameRate = 60.00f;
|
||||||
@ -243,6 +259,10 @@ void IsleApp::Close()
|
|||||||
TransitionManager()->SetWaitIndicator(NULL);
|
TransitionManager()->SetWaitIndicator(NULL);
|
||||||
Lego()->Resume();
|
Lego()->Resume();
|
||||||
|
|
||||||
|
if (BackgroundAudioManager()) {
|
||||||
|
BackgroundAudioManager()->Stop();
|
||||||
|
}
|
||||||
|
|
||||||
while (Streamer()->Close(NULL) == SUCCESS) {
|
while (Streamer()->Close(NULL) == SUCCESS) {
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -324,8 +344,16 @@ SDL_AppResult SDL_AppInit(void** appstate, int argc, char** argv)
|
|||||||
|
|
||||||
SDL_SetHint(SDL_HINT_MOUSE_TOUCH_EVENTS, "0");
|
SDL_SetHint(SDL_HINT_MOUSE_TOUCH_EVENTS, "0");
|
||||||
SDL_SetHint(SDL_HINT_TOUCH_MOUSE_EVENTS, "0");
|
SDL_SetHint(SDL_HINT_TOUCH_MOUSE_EVENTS, "0");
|
||||||
|
#ifdef __DJGPP__
|
||||||
|
SDL_SetHint("SDL_DOS_ALLOW_DIRECT_FRAMEBUFFER", "1");
|
||||||
|
#endif
|
||||||
|
|
||||||
if (!SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_GAMEPAD | SDL_INIT_HAPTIC)) {
|
Uint32 initFlags = SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_GAMEPAD;
|
||||||
|
#ifndef __DJGPP__
|
||||||
|
initFlags |= SDL_INIT_HAPTIC;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (!SDL_Init(initFlags)) {
|
||||||
char buffer[256];
|
char buffer[256];
|
||||||
SDL_snprintf(
|
SDL_snprintf(
|
||||||
buffer,
|
buffer,
|
||||||
@ -717,11 +745,17 @@ SDL_AppResult SDL_AppEvent(void* appstate, SDL_Event* event)
|
|||||||
g_lastMouseX = event->motion.x;
|
g_lastMouseX = event->motion.x;
|
||||||
g_lastMouseY = event->motion.y;
|
g_lastMouseY = event->motion.y;
|
||||||
|
|
||||||
|
#ifdef __DJGPP__
|
||||||
|
if (VideoManager()) {
|
||||||
|
VideoManager()->MoveCursor(Min((MxS32) g_lastMouseX, 639), Min((MxS32) g_lastMouseY, 479));
|
||||||
|
}
|
||||||
|
#else
|
||||||
SDL_ShowCursor();
|
SDL_ShowCursor();
|
||||||
g_isle->SetDrawCursor(FALSE);
|
g_isle->SetDrawCursor(FALSE);
|
||||||
if (VideoManager()) {
|
if (VideoManager()) {
|
||||||
VideoManager()->SetCursorBitmap(NULL);
|
VideoManager()->SetCursorBitmap(NULL);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
break;
|
break;
|
||||||
case SDL_EVENT_FINGER_MOTION: {
|
case SDL_EVENT_FINGER_MOTION: {
|
||||||
g_mousemoved = TRUE;
|
g_mousemoved = TRUE;
|
||||||
@ -924,6 +958,22 @@ MxResult IsleApp::SetupWindow()
|
|||||||
return FAILURE;
|
return FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if defined(MINIWIN)
|
||||||
|
// MINIWIN: window/VESA mode matches the game's rendering resolution.
|
||||||
|
g_targetWidth = m_xRes;
|
||||||
|
g_targetHeight = m_yRes;
|
||||||
|
#else
|
||||||
|
// DX5: fullscreen uses exclusive resolution for display mode switching.
|
||||||
|
if (m_fullScreen) {
|
||||||
|
g_targetWidth = m_exclusiveXRes;
|
||||||
|
g_targetHeight = m_exclusiveYRes;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
g_targetWidth = m_xRes;
|
||||||
|
g_targetHeight = m_yRes;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
SetupVideoFlags(
|
SetupVideoFlags(
|
||||||
m_fullScreen,
|
m_fullScreen,
|
||||||
m_flipSurfaces,
|
m_flipSurfaces,
|
||||||
@ -954,7 +1004,7 @@ MxResult IsleApp::SetupWindow()
|
|||||||
SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_HEIGHT_NUMBER, g_targetHeight);
|
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_FULLSCREEN_BOOLEAN, m_fullScreen);
|
||||||
SDL_SetStringProperty(props, SDL_PROP_WINDOW_CREATE_TITLE_STRING, WINDOW_TITLE);
|
SDL_SetStringProperty(props, SDL_PROP_WINDOW_CREATE_TITLE_STRING, WINDOW_TITLE);
|
||||||
#if defined(MINIWIN) && !defined(__3DS__) && !defined(WINDOWS_STORE) && !defined(__vita__)
|
#if defined(MINIWIN) && !defined(__3DS__) && !defined(WINDOWS_STORE) && !defined(__vita__) && !defined(__DJGPP__)
|
||||||
SDL_SetBooleanProperty(props, SDL_PROP_WINDOW_CREATE_OPENGL_BOOLEAN, true);
|
SDL_SetBooleanProperty(props, SDL_PROP_WINDOW_CREATE_OPENGL_BOOLEAN, true);
|
||||||
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
|
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
|
||||||
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
|
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
|
||||||
@ -969,6 +1019,17 @@ MxResult IsleApp::SetupWindow()
|
|||||||
|
|
||||||
SDL_SetPointerProperty(SDL_GetWindowProperties(window), ISLE_PROP_WINDOW_CREATE_VIDEO_PARAM, &m_videoParam);
|
SDL_SetPointerProperty(SDL_GetWindowProperties(window), ISLE_PROP_WINDOW_CREATE_VIDEO_PARAM, &m_videoParam);
|
||||||
|
|
||||||
|
#ifdef __DJGPP__
|
||||||
|
// DOS: request an 8-bit (INDEX8) fullscreen mode so the VESA
|
||||||
|
// framebuffer is paletted and we can blit INDEX8 surfaces directly.
|
||||||
|
{
|
||||||
|
SDL_DisplayMode mode = {};
|
||||||
|
mode.w = g_targetWidth;
|
||||||
|
mode.h = g_targetHeight;
|
||||||
|
mode.format = SDL_PIXELFORMAT_INDEX8;
|
||||||
|
SDL_SetWindowFullscreenMode(window, &mode);
|
||||||
|
}
|
||||||
|
#else
|
||||||
if (m_exclusiveFullScreen && m_fullScreen) {
|
if (m_exclusiveFullScreen && m_fullScreen) {
|
||||||
SDL_DisplayMode closestMode;
|
SDL_DisplayMode closestMode;
|
||||||
SDL_DisplayID displayID = SDL_GetDisplayForWindow(window);
|
SDL_DisplayID displayID = SDL_GetDisplayForWindow(window);
|
||||||
@ -983,6 +1044,7 @@ MxResult IsleApp::SetupWindow()
|
|||||||
SDL_SetWindowFullscreenMode(window, &closestMode);
|
SDL_SetWindowFullscreenMode(window, &closestMode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef MINIWIN
|
#ifdef MINIWIN
|
||||||
m_windowHandle = reinterpret_cast<HWND>(window);
|
m_windowHandle = reinterpret_cast<HWND>(window);
|
||||||
|
|||||||
@ -76,6 +76,7 @@ class LegoVideoManager : public MxVideoManager {
|
|||||||
void SetRender3D(MxBool p_render3d) { m_render3d = p_render3d; }
|
void SetRender3D(MxBool p_render3d) { m_render3d = p_render3d; }
|
||||||
|
|
||||||
void SetUnk0x554(MxBool p_unk0x554) { m_unk0x554 = p_unk0x554; }
|
void SetUnk0x554(MxBool p_unk0x554) { m_unk0x554 = p_unk0x554; }
|
||||||
|
MxBool GetDrawCursor() { return m_drawCursor; }
|
||||||
|
|
||||||
// SYNTHETIC: LEGO1 0x1007ab20
|
// SYNTHETIC: LEGO1 0x1007ab20
|
||||||
// SYNTHETIC: BETA10 0x100d8040
|
// SYNTHETIC: BETA10 0x100d8040
|
||||||
@ -88,9 +89,6 @@ class LegoVideoManager : public MxVideoManager {
|
|||||||
|
|
||||||
inline void DrawCursor();
|
inline void DrawCursor();
|
||||||
|
|
||||||
void DrawDigitToBuffer32(uint8_t* p_dst, int p_pitch, int p_x, int p_y, int p_digit, uint32_t p_color);
|
|
||||||
void DrawTextToSurface32(uint8_t* p_dst, int p_pitch, int p_x, int p_y, const char* p_text, uint32_t p_color);
|
|
||||||
|
|
||||||
Tgl::Renderer* m_renderer; // 0x64
|
Tgl::Renderer* m_renderer; // 0x64
|
||||||
Lego3DManager* m_3dManager; // 0x68
|
Lego3DManager* m_3dManager; // 0x68
|
||||||
LegoROI* m_viewROI; // 0x6c
|
LegoROI* m_viewROI; // 0x6c
|
||||||
|
|||||||
@ -49,7 +49,7 @@ class MxBackgroundAudioManager : public MxCore {
|
|||||||
|
|
||||||
void Init();
|
void Init();
|
||||||
void Update(MxS32 p_targetVolume, MxS32 p_speed, MxPresenter::TickleState p_tickleState);
|
void Update(MxS32 p_targetVolume, MxS32 p_speed, MxPresenter::TickleState p_tickleState);
|
||||||
void Stop();
|
LEGO1_EXPORT void Stop();
|
||||||
void LowerVolume();
|
void LowerVolume();
|
||||||
void RaiseVolume();
|
void RaiseVolume();
|
||||||
MxResult SetPendingPresenter(MxPresenter* p_presenter, MxS32 p_speed, MxPresenter::TickleState p_tickleState);
|
MxResult SetPendingPresenter(MxPresenter* p_presenter, MxS32 p_speed, MxPresenter::TickleState p_tickleState);
|
||||||
|
|||||||
@ -77,6 +77,10 @@ void MxBackgroundAudioManager::DestroyMusic()
|
|||||||
Streamer()->Close(m_script.GetInternal());
|
Streamer()->Close(m_script.GetInternal());
|
||||||
m_enabled = FALSE;
|
m_enabled = FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_activePresenter = NULL;
|
||||||
|
m_pendingPresenter = NULL;
|
||||||
|
m_tickleState = MxPresenter::e_idle;
|
||||||
}
|
}
|
||||||
|
|
||||||
// FUNCTION: LEGO1 0x1007ee40
|
// FUNCTION: LEGO1 0x1007ee40
|
||||||
|
|||||||
@ -465,7 +465,45 @@ void LegoVideoManager::DrawFPS()
|
|||||||
if (m_unk0x528->Lock(NULL, &surfaceDesc, DDLOCK_WAIT, NULL) == DD_OK) {
|
if (m_unk0x528->Lock(NULL, &surfaceDesc, DDLOCK_WAIT, NULL) == DD_OK) {
|
||||||
memset(surfaceDesc.lpSurface, 0, surfaceDesc.lPitch * surfaceDesc.dwHeight);
|
memset(surfaceDesc.lpSurface, 0, surfaceDesc.lPitch * surfaceDesc.dwHeight);
|
||||||
|
|
||||||
DrawTextToSurface32((uint8_t*) surfaceDesc.lpSurface, surfaceDesc.lPitch, 0, 0, buffer, 0xFF0000FF);
|
// 8-bit bitmap font for FPS display
|
||||||
|
uint8_t* dst = (uint8_t*) surfaceDesc.lpSurface;
|
||||||
|
int pitch = surfaceDesc.lPitch;
|
||||||
|
const char* p = buffer;
|
||||||
|
int px = 0;
|
||||||
|
static const uint8_t g_digitFont[5][10] = {
|
||||||
|
{0b1111, 0b0001, 0b1111, 0b1111, 0b1001, 0b1111, 0b1111, 0b1111, 0b1111, 0b1111},
|
||||||
|
{0b1001, 0b0001, 0b0001, 0b0001, 0b1001, 0b1000, 0b1000, 0b0001, 0b1001, 0b1001},
|
||||||
|
{0b1001, 0b0001, 0b1111, 0b1111, 0b1111, 0b1111, 0b1111, 0b0010, 0b1111, 0b1111},
|
||||||
|
{0b1001, 0b0001, 0b1000, 0b0001, 0b0001, 0b0001, 0b1001, 0b0010, 0b1001, 0b0001},
|
||||||
|
{0b1111, 0b0001, 0b1111, 0b1111, 0b0001, 0b1111, 0b1111, 0b0100, 0b1111, 0b1111},
|
||||||
|
};
|
||||||
|
while (*p) {
|
||||||
|
if (*p >= '0' && *p <= '9') {
|
||||||
|
int d = *p - '0';
|
||||||
|
for (int row = 0; row < 5; ++row) {
|
||||||
|
uint8_t bits = g_digitFont[row][d];
|
||||||
|
for (int col = 0; col < 5; ++col) {
|
||||||
|
if (bits & (1 << (4 - col))) {
|
||||||
|
for (int dy = 0; dy < 2; ++dy) {
|
||||||
|
for (int dx = 0; dx < 2; ++dx) {
|
||||||
|
dst[(row * 2 + dy) * pitch + (px + col * 2 + dx)] = 0xff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
px += 10;
|
||||||
|
}
|
||||||
|
else if (*p == '.') {
|
||||||
|
for (int dy = 0; dy < 2; ++dy) {
|
||||||
|
for (int dx = 0; dx < 2; ++dx) {
|
||||||
|
dst[(10 + dy) * pitch + (px + 2 + dx)] = 0xff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
px += 4;
|
||||||
|
}
|
||||||
|
++p;
|
||||||
|
}
|
||||||
|
|
||||||
m_unk0x528->Unlock(surfaceDesc.lpSurface);
|
m_unk0x528->Unlock(surfaceDesc.lpSurface);
|
||||||
m_unk0x550 = 1.f;
|
m_unk0x550 = 1.f;
|
||||||
@ -789,66 +827,6 @@ MxResult LegoVideoManager::ConfigureD3DRM()
|
|||||||
return SUCCESS;
|
return SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
void LegoVideoManager::DrawDigitToBuffer32(uint8_t* p_dst, int p_pitch, int p_x, int p_y, int p_digit, uint32_t p_color)
|
|
||||||
{
|
|
||||||
if (p_digit < 0 || p_digit > 9) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t* pixels = (uint32_t*) p_dst;
|
|
||||||
int rowStride = p_pitch / 4;
|
|
||||||
|
|
||||||
// 4x5 bitmap font
|
|
||||||
const uint8_t digitFont[5][10] = {
|
|
||||||
{0b1111, 0b0001, 0b1111, 0b1111, 0b1001, 0b1111, 0b1111, 0b1111, 0b1111, 0b1111},
|
|
||||||
{0b1001, 0b0001, 0b0001, 0b0001, 0b1001, 0b1000, 0b1000, 0b0001, 0b1001, 0b1001},
|
|
||||||
{0b1001, 0b0001, 0b1111, 0b1111, 0b1111, 0b1111, 0b1111, 0b0010, 0b1111, 0b1111},
|
|
||||||
{0b1001, 0b0001, 0b1000, 0b0001, 0b0001, 0b0001, 0b1001, 0b0010, 0b1001, 0b0001},
|
|
||||||
{0b1111, 0b0001, 0b1111, 0b1111, 0b0001, 0b1111, 0b1111, 0b0100, 0b1111, 0b1111},
|
|
||||||
};
|
|
||||||
|
|
||||||
for (int row = 0; row < 5; ++row) {
|
|
||||||
uint8_t bits = digitFont[row][p_digit];
|
|
||||||
for (int col = 0; col < 5; ++col) {
|
|
||||||
if (bits & (1 << (4 - col))) {
|
|
||||||
for (int dy = 0; dy < 2; ++dy) {
|
|
||||||
for (int dx = 0; dx < 2; ++dx) {
|
|
||||||
pixels[(p_y + row * 2 + dy) * rowStride + (p_x + col * 2 + dx)] = p_color;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void LegoVideoManager::DrawTextToSurface32(
|
|
||||||
uint8_t* p_dst,
|
|
||||||
int p_pitch,
|
|
||||||
int p_x,
|
|
||||||
int p_y,
|
|
||||||
const char* p_text,
|
|
||||||
uint32_t p_color
|
|
||||||
)
|
|
||||||
{
|
|
||||||
while (*p_text) {
|
|
||||||
if (*p_text >= '0' && *p_text <= '9') {
|
|
||||||
DrawDigitToBuffer32(p_dst, p_pitch, p_x, p_y, *p_text - '0', p_color);
|
|
||||||
p_x += 10;
|
|
||||||
}
|
|
||||||
else if (*p_text == '.') {
|
|
||||||
uint32_t* pixels = (uint32_t*) p_dst;
|
|
||||||
int rowStride = p_pitch / 4;
|
|
||||||
for (int dy = 0; dy < 2; ++dy) {
|
|
||||||
for (int dx = 0; dx < 2; ++dx) {
|
|
||||||
pixels[(p_y + 10 + dy) * rowStride + (p_x + 2 + dx)] = p_color;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
p_x += 4;
|
|
||||||
}
|
|
||||||
++p_text;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void LegoVideoManager::SetCursorBitmap(const CursorBitmap* p_cursorBitmap)
|
void LegoVideoManager::SetCursorBitmap(const CursorBitmap* p_cursorBitmap)
|
||||||
{
|
{
|
||||||
if (p_cursorBitmap == NULL) {
|
if (p_cursorBitmap == NULL) {
|
||||||
|
|||||||
@ -1499,7 +1499,7 @@ void Infocenter::StartCredits()
|
|||||||
GetViewManager()->RemoveAll(NULL);
|
GetViewManager()->RemoveAll(NULL);
|
||||||
|
|
||||||
InvokeAction(Extra::e_opendisk, *g_creditsScript, CreditsScript::c_LegoCredits, NULL);
|
InvokeAction(Extra::e_opendisk, *g_creditsScript, CreditsScript::c_LegoCredits, NULL);
|
||||||
SetAppCursor(e_cursorArrow);
|
SetAppCursor(VideoManager()->GetDrawCursor() ? e_cursorNone : e_cursorArrow);
|
||||||
}
|
}
|
||||||
|
|
||||||
// FUNCTION: LEGO1 0x10071250
|
// FUNCTION: LEGO1 0x10071250
|
||||||
|
|||||||
@ -305,6 +305,7 @@ void MxDisplaySurface::Destroy()
|
|||||||
// FUNCTION: BETA10 0x1013fe15
|
// FUNCTION: BETA10 0x1013fe15
|
||||||
void MxDisplaySurface::SetPalette(MxPalette* p_palette)
|
void MxDisplaySurface::SetPalette(MxPalette* p_palette)
|
||||||
{
|
{
|
||||||
|
#ifndef MINIWIN
|
||||||
if ((m_surfaceDesc.ddpfPixelFormat.dwFlags & DDPF_PALETTEINDEXED8) == DDPF_PALETTEINDEXED8) {
|
if ((m_surfaceDesc.ddpfPixelFormat.dwFlags & DDPF_PALETTEINDEXED8) == DDPF_PALETTEINDEXED8) {
|
||||||
m_ddSurface1->SetPalette(p_palette->CreateNativePalette());
|
m_ddSurface1->SetPalette(p_palette->CreateNativePalette());
|
||||||
m_ddSurface2->SetPalette(p_palette->CreateNativePalette());
|
m_ddSurface2->SetPalette(p_palette->CreateNativePalette());
|
||||||
@ -326,8 +327,10 @@ void MxDisplaySurface::SetPalette(MxPalette* p_palette)
|
|||||||
DeleteObject(hpal);
|
DeleteObject(hpal);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
m_ddSurface1->SetPalette(p_palette->CreateNativePalette());
|
||||||
|
m_ddSurface2->SetPalette(p_palette->CreateNativePalette());
|
||||||
|
|
||||||
#ifndef MINIWIN
|
|
||||||
MxS32 bitCount = m_surfaceDesc.ddpfPixelFormat.dwRGBBitCount;
|
MxS32 bitCount = m_surfaceDesc.ddpfPixelFormat.dwRGBBitCount;
|
||||||
if (bitCount == 8) {
|
if (bitCount == 8) {
|
||||||
return;
|
return;
|
||||||
@ -449,17 +452,6 @@ void MxDisplaySurface::VTable0x28(
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (m_surfaceDesc.ddpfPixelFormat.dwRGBBitCount != 32) {
|
|
||||||
DDCOLORKEY colorKey;
|
|
||||||
if (m_surfaceDesc.ddpfPixelFormat.dwRGBBitCount == 8) {
|
|
||||||
colorKey.dwColorSpaceLowValue = colorKey.dwColorSpaceHighValue = 0x10;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
colorKey.dwColorSpaceLowValue = colorKey.dwColorSpaceHighValue = RGB555_CREATE(0x1f, 0, 0x1f);
|
|
||||||
}
|
|
||||||
tempSurface->SetColorKey(DDCKEY_SRCBLT, &colorKey);
|
|
||||||
}
|
|
||||||
|
|
||||||
DDSURFACEDESC tempDesc;
|
DDSURFACEDESC tempDesc;
|
||||||
memset(&tempDesc, 0, sizeof(tempDesc));
|
memset(&tempDesc, 0, sizeof(tempDesc));
|
||||||
tempDesc.dwSize = sizeof(tempDesc);
|
tempDesc.dwSize = sizeof(tempDesc);
|
||||||
@ -511,10 +503,10 @@ void MxDisplaySurface::VTable0x28(
|
|||||||
|
|
||||||
if (m_videoParam.Flags().GetDoubleScaling()) {
|
if (m_videoParam.Flags().GetDoubleScaling()) {
|
||||||
RECT destRect = {p_right, p_bottom, p_right + p_width * 2, p_bottom + p_height * 2};
|
RECT destRect = {p_right, p_bottom, p_right + p_width * 2, p_bottom + p_height * 2};
|
||||||
m_ddSurface2->Blt(&destRect, tempSurface, NULL, DDBLT_WAIT | DDBLT_KEYSRC, NULL);
|
m_ddSurface2->Blt(&destRect, tempSurface, NULL, DDBLT_WAIT, NULL);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
m_ddSurface2->BltFast(p_right, p_bottom, tempSurface, NULL, DDBLTFAST_WAIT | DDBLTFAST_SRCCOLORKEY);
|
m_ddSurface2->BltFast(p_right, p_bottom, tempSurface, NULL, DDBLTFAST_WAIT);
|
||||||
}
|
}
|
||||||
|
|
||||||
tempSurface->Release();
|
tempSurface->Release();
|
||||||
@ -1083,10 +1075,6 @@ LPDIRECTDRAWSURFACE MxDisplaySurface::FUN_100bc8b0(MxS32 p_width, MxS32 p_height
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (surfaceDesc.ddpfPixelFormat.dwRGBBitCount == 8) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
surfaceDesc.dwWidth = p_width;
|
surfaceDesc.dwWidth = p_width;
|
||||||
surfaceDesc.dwHeight = p_height;
|
surfaceDesc.dwHeight = p_height;
|
||||||
surfaceDesc.dwFlags = DDSD_PIXELFORMAT | DDSD_WIDTH | DDSD_HEIGHT | DDSD_CAPS;
|
surfaceDesc.dwFlags = DDSD_PIXELFORMAT | DDSD_WIDTH | DDSD_HEIGHT | DDSD_CAPS;
|
||||||
|
|||||||
@ -5,7 +5,6 @@
|
|||||||
|
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include <memory.h>
|
#include <memory.h>
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
// FUNCTION: LEGO1 0x10001f80
|
// FUNCTION: LEGO1 0x10001f80
|
||||||
// FUNCTION: BETA10 0x10010a20
|
// FUNCTION: BETA10 0x10010a20
|
||||||
|
|||||||
@ -5,7 +5,6 @@
|
|||||||
|
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include <memory.h>
|
#include <memory.h>
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
// FUNCTION: LEGO1 0x10002870
|
// FUNCTION: LEGO1 0x10002870
|
||||||
// FUNCTION: BETA10 0x10048500
|
// FUNCTION: BETA10 0x10048500
|
||||||
|
|||||||
@ -238,7 +238,9 @@ inline void ViewManager::ManageVisibilityAndDetailRecursively(ViewROI* p_from, i
|
|||||||
const CompoundObject* comp = p_from->GetComp();
|
const CompoundObject* comp = p_from->GetComp();
|
||||||
|
|
||||||
if (p_lodLevel == ViewROI::c_lodLevelUnset) {
|
if (p_lodLevel == ViewROI::c_lodLevelUnset) {
|
||||||
if (p_from->GetWorldBoundingSphere().Radius() > 0.001F) {
|
// FIX: Use 0.002 threshold to avoid x87 extended precision boundary
|
||||||
|
// issues where 0.001 sentinel radius compares as > 0.001F on x87.
|
||||||
|
if (p_from->GetWorldBoundingSphere().Radius() > 0.002F) {
|
||||||
float projectedSize = ProjectedSize(p_from->GetWorldBoundingSphere());
|
float projectedSize = ProjectedSize(p_from->GetWorldBoundingSphere());
|
||||||
|
|
||||||
if (RealtimeView::GetUserMaxLOD() <= 5.0f && projectedSize < seconds_allowed * g_viewDistance) {
|
if (RealtimeView::GetUserMaxLOD() <= 5.0f && projectedSize < seconds_allowed * g_viewDistance) {
|
||||||
|
|||||||
@ -1,7 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <cstdlib>
|
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
|||||||
@ -73,6 +73,8 @@ if(DOS)
|
|||||||
list(REMOVE_ITEM GRAPHICS_BACKENDS USE_SDL_GPU USE_OPENGL1 USE_OPENGLES2) #USE_SDL_GPU
|
list(REMOVE_ITEM GRAPHICS_BACKENDS USE_SDL_GPU USE_OPENGL1 USE_OPENGLES2) #USE_SDL_GPU
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
list(APPEND GRAPHICS_BACKENDS USE_PALETTE_SW_RENDER)
|
||||||
|
|
||||||
if(NINTENDO_SWITCH)
|
if(NINTENDO_SWITCH)
|
||||||
# Remove USE_OPENGL1 as incompatible.
|
# Remove USE_OPENGL1 as incompatible.
|
||||||
# Remove everything else as not needed.
|
# Remove everything else as not needed.
|
||||||
@ -143,6 +145,12 @@ if(USE_SOFTWARE_RENDER IN_LIST GRAPHICS_BACKENDS)
|
|||||||
)
|
)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if(USE_PALETTE_SW_RENDER IN_LIST GRAPHICS_BACKENDS)
|
||||||
|
target_sources(miniwin PRIVATE
|
||||||
|
src/d3drm/backends/palettesw/renderer.cpp
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
target_compile_definitions(miniwin PUBLIC MINIWIN)
|
target_compile_definitions(miniwin PUBLIC MINIWIN)
|
||||||
|
|
||||||
target_include_directories(miniwin
|
target_include_directories(miniwin
|
||||||
|
|||||||
1479
miniwin/src/d3drm/backends/palettesw/renderer.cpp
Normal file
1479
miniwin/src/d3drm/backends/palettesw/renderer.cpp
Normal file
File diff suppressed because it is too large
Load Diff
@ -826,6 +826,13 @@ void Direct3DRMSoftwareRenderer::SetDither(bool dither)
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Direct3DRMSoftwareRenderer::SetPalette(SDL_Palette* palette)
|
||||||
|
{
|
||||||
|
if (m_renderedImage) {
|
||||||
|
SDL_SetSurfacePalette(m_renderedImage, palette);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Direct3DRMSoftwareRenderer::Download(SDL_Surface* target)
|
void Direct3DRMSoftwareRenderer::Download(SDL_Surface* target)
|
||||||
{
|
{
|
||||||
SDL_Rect srcRect = {
|
SDL_Rect srcRect = {
|
||||||
|
|||||||
@ -20,6 +20,9 @@
|
|||||||
#ifdef USE_SOFTWARE_RENDER
|
#ifdef USE_SOFTWARE_RENDER
|
||||||
#include "d3drmrenderer_software.h"
|
#include "d3drmrenderer_software.h"
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef USE_PALETTE_SW_RENDER
|
||||||
|
#include "d3drmrenderer_palettesw.h"
|
||||||
|
#endif
|
||||||
#ifdef USE_GXM
|
#ifdef USE_GXM
|
||||||
#include "d3drmrenderer_gxm.h"
|
#include "d3drmrenderer_gxm.h"
|
||||||
#endif
|
#endif
|
||||||
@ -74,6 +77,11 @@ Direct3DRMRenderer* CreateDirect3DRMRenderer(
|
|||||||
if (SDL_memcmp(guid, &GXM_GUID, sizeof(GUID)) == 0) {
|
if (SDL_memcmp(guid, &GXM_GUID, sizeof(GUID)) == 0) {
|
||||||
return GXMRenderer::Create(DDSDesc.dwWidth, DDSDesc.dwHeight, d3d->GetMSAASamples());
|
return GXMRenderer::Create(DDSDesc.dwWidth, DDSDesc.dwHeight, d3d->GetMSAASamples());
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
#ifdef USE_PALETTE_SW_RENDER
|
||||||
|
if (SDL_memcmp(guid, &PALETTE_SW_GUID, sizeof(GUID)) == 0) {
|
||||||
|
return new Direct3DRMPaletteSWRenderer(DDSDesc.dwWidth, DDSDesc.dwHeight);
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
@ -101,6 +109,9 @@ void Direct3DRMRenderer_EnumDevices(const IDirect3DMiniwin* d3d, LPD3DENUMDEVICE
|
|||||||
#ifdef USE_SOFTWARE_RENDER
|
#ifdef USE_SOFTWARE_RENDER
|
||||||
Direct3DRMSoftware_EnumDevice(cb, ctx);
|
Direct3DRMSoftware_EnumDevice(cb, ctx);
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef USE_PALETTE_SW_RENDER
|
||||||
|
Direct3DRMPaletteSW_EnumDevice(cb, ctx);
|
||||||
|
#endif
|
||||||
#ifdef USE_GXM
|
#ifdef USE_GXM
|
||||||
GXMRenderer_EnumDevice(cb, ctx);
|
GXMRenderer_EnumDevice(cb, ctx);
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@ -245,7 +245,12 @@ HRESULT DirectDrawImpl::GetDisplayMode(LPDDSURFACEDESC lpDDSurfaceDesc)
|
|||||||
#ifdef MINIWIN_PIXELFORMAT
|
#ifdef MINIWIN_PIXELFORMAT
|
||||||
format = MINIWIN_PIXELFORMAT;
|
format = MINIWIN_PIXELFORMAT;
|
||||||
#else
|
#else
|
||||||
|
if (m_virtualBPP == 8 || (m_frameBuffer && m_frameBuffer->IsIndex8())) {
|
||||||
|
format = SDL_PIXELFORMAT_INDEX8;
|
||||||
|
}
|
||||||
|
else {
|
||||||
format = mode->format;
|
format = mode->format;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
const SDL_PixelFormatDetails* details = SDL_GetPixelFormatDetails(format);
|
const SDL_PixelFormatDetails* details = SDL_GetPixelFormatDetails(format);
|
||||||
@ -308,6 +313,7 @@ HRESULT DirectDrawImpl::SetDisplayMode(DWORD dwWidth, DWORD dwHeight, DWORD dwBP
|
|||||||
{
|
{
|
||||||
m_virtualWidth = dwWidth;
|
m_virtualWidth = dwWidth;
|
||||||
m_virtualHeight = dwHeight;
|
m_virtualHeight = dwHeight;
|
||||||
|
m_virtualBPP = dwBPP;
|
||||||
return DD_OK;
|
return DD_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -53,13 +53,20 @@ HRESULT DirectDrawSurfaceImpl::Blt(
|
|||||||
)
|
)
|
||||||
{
|
{
|
||||||
if ((dwFlags & DDBLT_COLORFILL) == DDBLT_COLORFILL) {
|
if ((dwFlags & DDBLT_COLORFILL) == DDBLT_COLORFILL) {
|
||||||
|
Uint32 color;
|
||||||
|
if (m_surface->format == SDL_PIXELFORMAT_INDEX8) {
|
||||||
|
// For INDEX8 surfaces the fill color is a palette index, not RGBA.
|
||||||
|
color = lpDDBltFx->dwFillColor & 0xFF;
|
||||||
|
}
|
||||||
|
else {
|
||||||
Uint8 a = (lpDDBltFx->dwFillColor >> 24) & 0xFF;
|
Uint8 a = (lpDDBltFx->dwFillColor >> 24) & 0xFF;
|
||||||
Uint8 r = (lpDDBltFx->dwFillColor >> 16) & 0xFF;
|
Uint8 r = (lpDDBltFx->dwFillColor >> 16) & 0xFF;
|
||||||
Uint8 g = (lpDDBltFx->dwFillColor >> 8) & 0xFF;
|
Uint8 g = (lpDDBltFx->dwFillColor >> 8) & 0xFF;
|
||||||
Uint8 b = lpDDBltFx->dwFillColor & 0xFF;
|
Uint8 b = lpDDBltFx->dwFillColor & 0xFF;
|
||||||
|
|
||||||
const SDL_PixelFormatDetails* details = SDL_GetPixelFormatDetails(m_surface->format);
|
const SDL_PixelFormatDetails* details = SDL_GetPixelFormatDetails(m_surface->format);
|
||||||
Uint32 color = SDL_MapRGBA(details, nullptr, r, g, b, a);
|
color = SDL_MapRGBA(details, nullptr, r, g, b, a);
|
||||||
|
}
|
||||||
if (lpDestRect) {
|
if (lpDestRect) {
|
||||||
SDL_Rect dstRect = ConvertRect(lpDestRect);
|
SDL_Rect dstRect = ConvertRect(lpDestRect);
|
||||||
SDL_FillSurfaceRect(m_surface, &dstRect, color);
|
SDL_FillSurfaceRect(m_surface, &dstRect, color);
|
||||||
|
|||||||
@ -9,7 +9,11 @@
|
|||||||
FrameBufferImpl::FrameBufferImpl(DWORD virtualWidth, DWORD virtualHeight)
|
FrameBufferImpl::FrameBufferImpl(DWORD virtualWidth, DWORD virtualHeight)
|
||||||
: m_virtualWidth(virtualWidth), m_virtualHeight(virtualHeight)
|
: m_virtualWidth(virtualWidth), m_virtualHeight(virtualHeight)
|
||||||
{
|
{
|
||||||
|
#ifdef __DJGPP__
|
||||||
|
m_transferBuffer = new DirectDrawSurfaceImpl(m_virtualWidth, m_virtualHeight, SDL_PIXELFORMAT_INDEX8);
|
||||||
|
#else
|
||||||
m_transferBuffer = new DirectDrawSurfaceImpl(m_virtualWidth, m_virtualHeight, SDL_PIXELFORMAT_RGBA32);
|
m_transferBuffer = new DirectDrawSurfaceImpl(m_virtualWidth, m_virtualHeight, SDL_PIXELFORMAT_RGBA32);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
FrameBufferImpl::~FrameBufferImpl()
|
FrameBufferImpl::~FrameBufferImpl()
|
||||||
@ -49,7 +53,7 @@ HRESULT FrameBufferImpl::Blt(
|
|||||||
return DDERR_GENERIC;
|
return DDERR_GENERIC;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dynamic_cast<FrameBufferImpl*>(lpDDSrcSurface) == this) {
|
if (dynamic_cast<FrameBufferImpl*>(lpDDSrcSurface)) {
|
||||||
return Flip(nullptr, DDFLIP_WAIT);
|
return Flip(nullptr, DDFLIP_WAIT);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -103,7 +107,11 @@ HRESULT FrameBufferImpl::BltFast(
|
|||||||
int height = lpSrcRect ? (lpSrcRect->bottom - lpSrcRect->top) : surface->m_surface->h;
|
int height = lpSrcRect ? (lpSrcRect->bottom - lpSrcRect->top) : surface->m_surface->h;
|
||||||
RECT destRect = {(int) dwX, (int) dwY, (int) (dwX + width), (int) (dwY + height)};
|
RECT destRect = {(int) dwX, (int) dwY, (int) (dwX + width), (int) (dwY + height)};
|
||||||
|
|
||||||
return Blt(&destRect, lpDDSrcSurface, lpSrcRect, DDBLT_NONE, nullptr);
|
DDBltFlags flags = DDBLT_NONE;
|
||||||
|
if ((dwTrans & DDBLTFAST_SRCCOLORKEY) == DDBLTFAST_SRCCOLORKEY) {
|
||||||
|
flags = flags | DDBLT_KEYSRC;
|
||||||
|
}
|
||||||
|
return Blt(&destRect, lpDDSrcSurface, lpSrcRect, flags, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
HRESULT FrameBufferImpl::Flip(LPDIRECTDRAWSURFACE lpDDSurfaceTargetOverride, DDFlipFlags dwFlags)
|
HRESULT FrameBufferImpl::Flip(LPDIRECTDRAWSURFACE lpDDSurfaceTargetOverride, DDFlipFlags dwFlags)
|
||||||
@ -210,8 +218,13 @@ HRESULT FrameBufferImpl::SetColorKey(DDColorKeyFlags dwFlags, LPDDCOLORKEY lpDDC
|
|||||||
|
|
||||||
HRESULT FrameBufferImpl::SetPalette(LPDIRECTDRAWPALETTE lpDDPalette)
|
HRESULT FrameBufferImpl::SetPalette(LPDIRECTDRAWPALETTE lpDDPalette)
|
||||||
{
|
{
|
||||||
if (m_transferBuffer->m_surface->format != SDL_PIXELFORMAT_INDEX8) {
|
// If the transfer buffer is not INDEX8 yet, recreate it — but only when
|
||||||
MINIWIN_NOT_IMPLEMENTED();
|
// the renderer actually works with paletted surfaces (palette SW / DOS).
|
||||||
|
// GL-based renderers use RGBA32 transfer buffers and convert on upload.
|
||||||
|
if (m_transferBuffer->m_surface->format != SDL_PIXELFORMAT_INDEX8 && DDRenderer &&
|
||||||
|
DDRenderer->UsesPalettedSurfaces()) {
|
||||||
|
m_transferBuffer->Release();
|
||||||
|
m_transferBuffer = new DirectDrawSurfaceImpl(m_virtualWidth, m_virtualHeight, SDL_PIXELFORMAT_INDEX8);
|
||||||
}
|
}
|
||||||
|
|
||||||
lpDDPalette->AddRef();
|
lpDDPalette->AddRef();
|
||||||
@ -222,6 +235,11 @@ HRESULT FrameBufferImpl::SetPalette(LPDIRECTDRAWPALETTE lpDDPalette)
|
|||||||
|
|
||||||
m_palette = lpDDPalette;
|
m_palette = lpDDPalette;
|
||||||
SDL_SetSurfacePalette(m_transferBuffer->m_surface, ((DirectDrawPaletteImpl*) m_palette)->m_palette);
|
SDL_SetSurfacePalette(m_transferBuffer->m_surface, ((DirectDrawPaletteImpl*) m_palette)->m_palette);
|
||||||
|
|
||||||
|
if (DDRenderer) {
|
||||||
|
DDRenderer->SetPalette(((DirectDrawPaletteImpl*) m_palette)->m_palette);
|
||||||
|
}
|
||||||
|
|
||||||
return DD_OK;
|
return DD_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -55,6 +55,8 @@ class Direct3DRMRenderer : public IDirect3DDevice2 {
|
|||||||
virtual void Draw2DImage(Uint32 textureId, const SDL_Rect& srcRect, const SDL_Rect& dstRect, FColor color) = 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 Download(SDL_Surface* target) = 0;
|
||||||
virtual void SetDither(bool dither) = 0;
|
virtual void SetDither(bool dither) = 0;
|
||||||
|
virtual void SetPalette(SDL_Palette* palette) {}
|
||||||
|
virtual bool UsesPalettedSurfaces() const { return false; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
int m_width, m_height;
|
int m_width, m_height;
|
||||||
|
|||||||
116
miniwin/src/internal/d3drmrenderer_palettesw.h
Normal file
116
miniwin/src/internal/d3drmrenderer_palettesw.h
Normal file
@ -0,0 +1,116 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "d3drmrenderer.h"
|
||||||
|
#include "d3drmtexture_impl.h"
|
||||||
|
#include "ddraw_impl.h"
|
||||||
|
|
||||||
|
#include <SDL3/SDL.h>
|
||||||
|
#include <cstddef>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
DEFINE_GUID(PALETTE_SW_GUID, 0x682656F3, 0x0000, 0x0000, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07);
|
||||||
|
|
||||||
|
struct PaletteTextureCache {
|
||||||
|
Direct3DRMTextureImpl* texture;
|
||||||
|
Uint8 version;
|
||||||
|
SDL_Surface* cached;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct PaletteMeshCache {
|
||||||
|
const MeshGroup* meshGroup;
|
||||||
|
int version;
|
||||||
|
bool flat;
|
||||||
|
std::vector<D3DRMVERTEX> vertices;
|
||||||
|
std::vector<uint16_t> indices;
|
||||||
|
};
|
||||||
|
|
||||||
|
class Direct3DRMPaletteSWRenderer : public Direct3DRMRenderer {
|
||||||
|
public:
|
||||||
|
Direct3DRMPaletteSWRenderer(DWORD width, DWORD height);
|
||||||
|
~Direct3DRMPaletteSWRenderer() override;
|
||||||
|
void PushLights(const SceneLight* vertices, size_t count) override;
|
||||||
|
Uint32 GetTextureId(IDirect3DRMTexture* texture, bool isUI, float scaleX, float scaleY) override;
|
||||||
|
Uint32 GetMeshId(IDirect3DRMMesh* mesh, const MeshGroup* meshGroup) override;
|
||||||
|
void SetProjection(const D3DRMMATRIX4D& projection, D3DVALUE front, D3DVALUE back) override;
|
||||||
|
void SetFrustumPlanes(const Plane* frustumPlanes) override;
|
||||||
|
HRESULT BeginFrame() override;
|
||||||
|
void EnableTransparency() override;
|
||||||
|
void SubmitDraw(
|
||||||
|
DWORD meshId,
|
||||||
|
const D3DRMMATRIX4D& modelViewMatrix,
|
||||||
|
const D3DRMMATRIX4D& worldMatrix,
|
||||||
|
const D3DRMMATRIX4D& viewMatrix,
|
||||||
|
const Matrix3x3& normalMatrix,
|
||||||
|
const Appearance& appearance
|
||||||
|
) override;
|
||||||
|
HRESULT FinalizeFrame() override;
|
||||||
|
void Resize(int width, int height, const ViewportTransform& viewportTransform) override;
|
||||||
|
void Clear(float r, float g, float b) override;
|
||||||
|
void Flip() override;
|
||||||
|
void Draw2DImage(Uint32 textureId, const SDL_Rect& srcRect, const SDL_Rect& dstRect, FColor color) override;
|
||||||
|
void Download(SDL_Surface* target) override;
|
||||||
|
void SetDither(bool dither) override;
|
||||||
|
void SetPalette(SDL_Palette* palette) override;
|
||||||
|
bool UsesPalettedSurfaces() const override { return true; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
void ClearZBuffer();
|
||||||
|
void DrawTriangleProjected(
|
||||||
|
const D3DRMVERTEX& v0,
|
||||||
|
const D3DRMVERTEX& v1,
|
||||||
|
const D3DRMVERTEX& v2,
|
||||||
|
const Appearance& appearance
|
||||||
|
);
|
||||||
|
void DrawTriangleClipped(const D3DRMVERTEX (&v)[3], const Appearance& appearance);
|
||||||
|
void ProjectVertex(const D3DVECTOR& v, D3DRMVECTOR4D& p) const;
|
||||||
|
Uint8 ApplyLighting(const D3DVECTOR& position, const D3DVECTOR& normal, const Appearance& appearance, Uint8 texel);
|
||||||
|
void BuildLightingLUT();
|
||||||
|
void BuildBlendLUT();
|
||||||
|
void AddTextureDestroyCallback(Uint32 id, IDirect3DRMTexture* texture);
|
||||||
|
void AddMeshDestroyCallback(Uint32 id, IDirect3DRMMesh* mesh);
|
||||||
|
|
||||||
|
SDL_Surface* m_renderedImage = nullptr;
|
||||||
|
SDL_Palette* m_palette = nullptr;
|
||||||
|
SDL_Palette* m_flipPalette = nullptr; // Palette snapshot taken at Flip time (the correct one)
|
||||||
|
bool m_flipPaletteDirty = false;
|
||||||
|
std::vector<SceneLight> m_lights;
|
||||||
|
std::vector<PaletteTextureCache> m_textures;
|
||||||
|
std::vector<PaletteMeshCache> m_meshes;
|
||||||
|
D3DVALUE m_front;
|
||||||
|
D3DVALUE m_back;
|
||||||
|
Matrix3x3 m_normalMatrix;
|
||||||
|
D3DRMMATRIX4D m_projection;
|
||||||
|
std::vector<float> m_zBuffer;
|
||||||
|
std::vector<D3DRMVERTEX> m_transformedVerts;
|
||||||
|
Plane m_frustumPlanes[6];
|
||||||
|
|
||||||
|
// Lighting LUT: for each of 256 palette entries x 32 brightness levels,
|
||||||
|
// store the best-matching palette index.
|
||||||
|
// Usage: m_lightLUT[paletteIndex * 32 + brightnessLevel]
|
||||||
|
static constexpr int LIGHT_LEVELS = 32;
|
||||||
|
Uint8 m_lightLUT[256 * LIGHT_LEVELS];
|
||||||
|
|
||||||
|
// Blend LUT: for any two palette indices, the pre-computed 50/50 blend
|
||||||
|
// result mapped to the nearest palette colour.
|
||||||
|
// Usage: m_blendLUT[srcIndex * 256 + dstIndex]
|
||||||
|
Uint8 m_blendLUT[256 * 256];
|
||||||
|
|
||||||
|
bool m_lightLUTDirty = true;
|
||||||
|
bool m_transparencyEnabled = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
inline static void Direct3DRMPaletteSW_EnumDevice(LPD3DENUMDEVICESCALLBACK cb, void* ctx)
|
||||||
|
{
|
||||||
|
D3DDEVICEDESC halDesc = {};
|
||||||
|
|
||||||
|
D3DDEVICEDESC helDesc = {};
|
||||||
|
helDesc.dcmColorModel = D3DCOLOR_RGB;
|
||||||
|
helDesc.dwFlags = D3DDD_DEVICEZBUFFERBITDEPTH;
|
||||||
|
helDesc.dwDeviceZBufferBitDepth = DDBD_16;
|
||||||
|
helDesc.dwDeviceRenderBitDepth = DDBD_8;
|
||||||
|
helDesc.dpcTriCaps.dwTextureCaps = D3DPTEXTURECAPS_PERSPECTIVE;
|
||||||
|
helDesc.dpcTriCaps.dwShadeCaps = D3DPSHADECAPS_ALPHAFLATBLEND;
|
||||||
|
helDesc.dpcTriCaps.dwTextureFilterCaps = D3DPTFILTERCAPS_LINEAR;
|
||||||
|
|
||||||
|
EnumDevice(cb, ctx, "Miniwin Paletted Software", &halDesc, &helDesc, PALETTE_SW_GUID);
|
||||||
|
}
|
||||||
@ -50,6 +50,7 @@ class Direct3DRMSoftwareRenderer : public Direct3DRMRenderer {
|
|||||||
void Draw2DImage(Uint32 textureId, const SDL_Rect& srcRect, const SDL_Rect& dstRect, FColor color) override;
|
void Draw2DImage(Uint32 textureId, const SDL_Rect& srcRect, const SDL_Rect& dstRect, FColor color) override;
|
||||||
void Download(SDL_Surface* target) override;
|
void Download(SDL_Surface* target) override;
|
||||||
void SetDither(bool dither) override;
|
void SetDither(bool dither) override;
|
||||||
|
void SetPalette(SDL_Palette* palette) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void ClearZBuffer();
|
void ClearZBuffer();
|
||||||
|
|||||||
@ -61,9 +61,10 @@ struct DirectDrawImpl : public IDirectDraw2, public IDirect3D2, public IDirect3D
|
|||||||
float GetAnisotropic() const override { return m_anisotropic; }
|
float GetAnisotropic() const override { return m_anisotropic; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
FrameBufferImpl* m_frameBuffer;
|
FrameBufferImpl* m_frameBuffer = nullptr;
|
||||||
int m_virtualWidth = 0;
|
int m_virtualWidth = 0;
|
||||||
int m_virtualHeight = 0;
|
int m_virtualHeight = 0;
|
||||||
|
int m_virtualBPP = 0;
|
||||||
DWORD m_msaaSamples = 0;
|
DWORD m_msaaSamples = 0;
|
||||||
float m_anisotropic = 0.0f;
|
float m_anisotropic = 0.0f;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -36,6 +36,8 @@ struct FrameBufferImpl : public IDirectDrawSurface3 {
|
|||||||
HRESULT SetPalette(LPDIRECTDRAWPALETTE lpDDPalette) override;
|
HRESULT SetPalette(LPDIRECTDRAWPALETTE lpDDPalette) override;
|
||||||
HRESULT Unlock(LPVOID lpSurfaceData) override;
|
HRESULT Unlock(LPVOID lpSurfaceData) override;
|
||||||
|
|
||||||
|
bool IsIndex8() const { return m_transferBuffer->m_surface->format == SDL_PIXELFORMAT_INDEX8; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
uint32_t m_virtualWidth;
|
uint32_t m_virtualWidth;
|
||||||
uint32_t m_virtualHeight;
|
uint32_t m_virtualHeight;
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user