mirror of
https://github.com/isledecomp/isle-portable.git
synced 2026-05-02 18:43:56 +00:00
Add back 8bit rendering and also DOS support
This commit is contained in:
parent
c52a5204a4
commit
22cb69aea9
6
3rdparty/CMakeLists.txt
vendored
6
3rdparty/CMakeLists.txt
vendored
@ -34,6 +34,12 @@ target_compile_definitions(miniaudio PUBLIC
|
||||
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)
|
||||
include(FetchContent)
|
||||
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)")
|
||||
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 "Config app: ${ISLE_BUILD_CONFIG}")
|
||||
message(STATUS "Internal DirectX5 SDK: ${ISLE_USE_DX5}")
|
||||
|
||||
@ -155,11 +155,19 @@ IsleApp::IsleApp()
|
||||
m_using8bit = FALSE;
|
||||
m_using16bit = TRUE;
|
||||
m_hasLightSupport = FALSE;
|
||||
#ifdef __DJGPP__
|
||||
m_drawCursor = TRUE;
|
||||
#else
|
||||
m_drawCursor = FALSE;
|
||||
#endif
|
||||
m_use3dSound = TRUE;
|
||||
m_useMusic = TRUE;
|
||||
m_wideViewAngle = TRUE;
|
||||
#ifdef __DJGPP__
|
||||
m_islandQuality = 1;
|
||||
#else
|
||||
m_islandQuality = 2;
|
||||
#endif
|
||||
m_islandTexture = 1;
|
||||
m_gameStarted = FALSE;
|
||||
m_frameDelta = 10;
|
||||
@ -191,14 +199,22 @@ IsleApp::IsleApp()
|
||||
m_mediaPath = NULL;
|
||||
m_iniPath = NULL;
|
||||
m_maxLod = RealtimeView::GetUserMaxLOD();
|
||||
#ifdef __DJGPP__
|
||||
m_maxLod = 1.0f;
|
||||
#endif
|
||||
m_maxAllowedExtras = m_islandQuality <= 1 ? 10 : 20;
|
||||
m_transitionType = MxTransitionManager::e_mosaic;
|
||||
m_cursorSensitivity = 4;
|
||||
m_touchScheme = LegoInputManager::e_gamepad;
|
||||
m_haptic = TRUE;
|
||||
m_wasd = FALSE;
|
||||
#ifdef __DJGPP__
|
||||
m_xRes = 320;
|
||||
m_yRes = 200;
|
||||
#else
|
||||
m_xRes = 640;
|
||||
m_yRes = 480;
|
||||
#endif
|
||||
m_exclusiveXRes = m_xRes;
|
||||
m_exclusiveYRes = m_yRes;
|
||||
m_exclusiveFrameRate = 60.00f;
|
||||
@ -243,6 +259,10 @@ void IsleApp::Close()
|
||||
TransitionManager()->SetWaitIndicator(NULL);
|
||||
Lego()->Resume();
|
||||
|
||||
if (BackgroundAudioManager()) {
|
||||
BackgroundAudioManager()->Stop();
|
||||
}
|
||||
|
||||
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_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];
|
||||
SDL_snprintf(
|
||||
buffer,
|
||||
@ -717,11 +745,17 @@ SDL_AppResult SDL_AppEvent(void* appstate, SDL_Event* event)
|
||||
g_lastMouseX = event->motion.x;
|
||||
g_lastMouseY = event->motion.y;
|
||||
|
||||
#ifdef __DJGPP__
|
||||
if (VideoManager()) {
|
||||
VideoManager()->MoveCursor(Min((MxS32) g_lastMouseX, 639), Min((MxS32) g_lastMouseY, 479));
|
||||
}
|
||||
#else
|
||||
SDL_ShowCursor();
|
||||
g_isle->SetDrawCursor(FALSE);
|
||||
if (VideoManager()) {
|
||||
VideoManager()->SetCursorBitmap(NULL);
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
case SDL_EVENT_FINGER_MOTION: {
|
||||
g_mousemoved = TRUE;
|
||||
@ -924,6 +958,9 @@ MxResult IsleApp::SetupWindow()
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
g_targetWidth = m_xRes;
|
||||
g_targetHeight = m_yRes;
|
||||
|
||||
SetupVideoFlags(
|
||||
m_fullScreen,
|
||||
m_flipSurfaces,
|
||||
@ -954,7 +991,7 @@ MxResult IsleApp::SetupWindow()
|
||||
SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_HEIGHT_NUMBER, g_targetHeight);
|
||||
SDL_SetBooleanProperty(props, SDL_PROP_WINDOW_CREATE_FULLSCREEN_BOOLEAN, m_fullScreen);
|
||||
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_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
|
||||
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
|
||||
@ -969,6 +1006,17 @@ MxResult IsleApp::SetupWindow()
|
||||
|
||||
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) {
|
||||
SDL_DisplayMode closestMode;
|
||||
SDL_DisplayID displayID = SDL_GetDisplayForWindow(window);
|
||||
@ -983,6 +1031,7 @@ MxResult IsleApp::SetupWindow()
|
||||
SDL_SetWindowFullscreenMode(window, &closestMode);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef MINIWIN
|
||||
m_windowHandle = reinterpret_cast<HWND>(window);
|
||||
|
||||
@ -88,9 +88,6 @@ class LegoVideoManager : public MxVideoManager {
|
||||
|
||||
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
|
||||
Lego3DManager* m_3dManager; // 0x68
|
||||
LegoROI* m_viewROI; // 0x6c
|
||||
|
||||
@ -77,6 +77,10 @@ void MxBackgroundAudioManager::DestroyMusic()
|
||||
Streamer()->Close(m_script.GetInternal());
|
||||
m_enabled = FALSE;
|
||||
}
|
||||
|
||||
m_activePresenter = NULL;
|
||||
m_pendingPresenter = NULL;
|
||||
m_tickleState = MxPresenter::e_idle;
|
||||
}
|
||||
|
||||
// FUNCTION: LEGO1 0x1007ee40
|
||||
|
||||
@ -465,7 +465,45 @@ void LegoVideoManager::DrawFPS()
|
||||
if (m_unk0x528->Lock(NULL, &surfaceDesc, DDLOCK_WAIT, NULL) == DD_OK) {
|
||||
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 font[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 = font[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_unk0x550 = 1.f;
|
||||
@ -789,66 +827,6 @@ MxResult LegoVideoManager::ConfigureD3DRM()
|
||||
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)
|
||||
{
|
||||
if (p_cursorBitmap == NULL) {
|
||||
|
||||
@ -1499,7 +1499,7 @@ void Infocenter::StartCredits()
|
||||
GetViewManager()->RemoveAll(NULL);
|
||||
|
||||
InvokeAction(Extra::e_opendisk, *g_creditsScript, CreditsScript::c_LegoCredits, NULL);
|
||||
SetAppCursor(e_cursorArrow);
|
||||
SetAppCursor(e_cursorNone);
|
||||
}
|
||||
|
||||
// FUNCTION: LEGO1 0x10071250
|
||||
|
||||
@ -305,6 +305,7 @@ void MxDisplaySurface::Destroy()
|
||||
// FUNCTION: BETA10 0x1013fe15
|
||||
void MxDisplaySurface::SetPalette(MxPalette* p_palette)
|
||||
{
|
||||
#ifndef MINIWIN
|
||||
if ((m_surfaceDesc.ddpfPixelFormat.dwFlags & DDPF_PALETTEINDEXED8) == DDPF_PALETTEINDEXED8) {
|
||||
m_ddSurface1->SetPalette(p_palette->CreateNativePalette());
|
||||
m_ddSurface2->SetPalette(p_palette->CreateNativePalette());
|
||||
@ -326,8 +327,10 @@ void MxDisplaySurface::SetPalette(MxPalette* p_palette)
|
||||
DeleteObject(hpal);
|
||||
}
|
||||
}
|
||||
#else
|
||||
m_ddSurface1->SetPalette(p_palette->CreateNativePalette());
|
||||
m_ddSurface2->SetPalette(p_palette->CreateNativePalette());
|
||||
|
||||
#ifndef MINIWIN
|
||||
MxS32 bitCount = m_surfaceDesc.ddpfPixelFormat.dwRGBBitCount;
|
||||
if (bitCount == 8) {
|
||||
return;
|
||||
@ -449,17 +452,6 @@ void MxDisplaySurface::VTable0x28(
|
||||
}
|
||||
#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;
|
||||
memset(&tempDesc, 0, sizeof(tempDesc));
|
||||
tempDesc.dwSize = sizeof(tempDesc);
|
||||
@ -511,10 +503,10 @@ void MxDisplaySurface::VTable0x28(
|
||||
|
||||
if (m_videoParam.Flags().GetDoubleScaling()) {
|
||||
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 {
|
||||
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();
|
||||
@ -1083,10 +1075,6 @@ LPDIRECTDRAWSURFACE MxDisplaySurface::FUN_100bc8b0(MxS32 p_width, MxS32 p_height
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (surfaceDesc.ddpfPixelFormat.dwRGBBitCount == 8) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
surfaceDesc.dwWidth = p_width;
|
||||
surfaceDesc.dwHeight = p_height;
|
||||
surfaceDesc.dwFlags = DDSD_PIXELFORMAT | DDSD_WIDTH | DDSD_HEIGHT | DDSD_CAPS;
|
||||
|
||||
@ -5,7 +5,6 @@
|
||||
|
||||
#include <math.h>
|
||||
#include <memory.h>
|
||||
#include <string.h>
|
||||
|
||||
// FUNCTION: LEGO1 0x10001f80
|
||||
// FUNCTION: BETA10 0x10010a20
|
||||
|
||||
@ -5,7 +5,6 @@
|
||||
|
||||
#include <math.h>
|
||||
#include <memory.h>
|
||||
#include <string.h>
|
||||
|
||||
// FUNCTION: LEGO1 0x10002870
|
||||
// FUNCTION: BETA10 0x10048500
|
||||
|
||||
@ -238,7 +238,9 @@ inline void ViewManager::ManageVisibilityAndDetailRecursively(ViewROI* p_from, i
|
||||
const CompoundObject* comp = p_from->GetComp();
|
||||
|
||||
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());
|
||||
|
||||
if (RealtimeView::GetUserMaxLOD() <= 5.0f && projectedSize < seconds_allowed * g_viewDistance) {
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
|
||||
@ -73,6 +73,8 @@ if(DOS)
|
||||
list(REMOVE_ITEM GRAPHICS_BACKENDS USE_SDL_GPU USE_OPENGL1 USE_OPENGLES2) #USE_SDL_GPU
|
||||
endif()
|
||||
|
||||
list(APPEND GRAPHICS_BACKENDS USE_PALETTE_SW_RENDER)
|
||||
|
||||
if(NINTENDO_SWITCH)
|
||||
# Remove USE_OPENGL1 as incompatible.
|
||||
# Remove everything else as not needed.
|
||||
@ -143,6 +145,12 @@ if(USE_SOFTWARE_RENDER IN_LIST GRAPHICS_BACKENDS)
|
||||
)
|
||||
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_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)
|
||||
{
|
||||
SDL_Rect srcRect = {
|
||||
|
||||
@ -20,6 +20,9 @@
|
||||
#ifdef USE_SOFTWARE_RENDER
|
||||
#include "d3drmrenderer_software.h"
|
||||
#endif
|
||||
#ifdef USE_PALETTE_SW_RENDER
|
||||
#include "d3drmrenderer_palettesw.h"
|
||||
#endif
|
||||
#ifdef USE_GXM
|
||||
#include "d3drmrenderer_gxm.h"
|
||||
#endif
|
||||
@ -74,6 +77,11 @@ Direct3DRMRenderer* CreateDirect3DRMRenderer(
|
||||
if (SDL_memcmp(guid, &GXM_GUID, sizeof(GUID)) == 0) {
|
||||
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
|
||||
return nullptr;
|
||||
}
|
||||
@ -101,6 +109,9 @@ void Direct3DRMRenderer_EnumDevices(const IDirect3DMiniwin* d3d, LPD3DENUMDEVICE
|
||||
#ifdef USE_SOFTWARE_RENDER
|
||||
Direct3DRMSoftware_EnumDevice(cb, ctx);
|
||||
#endif
|
||||
#ifdef USE_PALETTE_SW_RENDER
|
||||
Direct3DRMPaletteSW_EnumDevice(cb, ctx);
|
||||
#endif
|
||||
#ifdef USE_GXM
|
||||
GXMRenderer_EnumDevice(cb, ctx);
|
||||
#endif
|
||||
|
||||
@ -245,7 +245,12 @@ HRESULT DirectDrawImpl::GetDisplayMode(LPDDSURFACEDESC lpDDSurfaceDesc)
|
||||
#ifdef MINIWIN_PIXELFORMAT
|
||||
format = MINIWIN_PIXELFORMAT;
|
||||
#else
|
||||
format = mode->format;
|
||||
if (m_virtualBPP == 8 || (m_frameBuffer && m_frameBuffer->IsIndex8())) {
|
||||
format = SDL_PIXELFORMAT_INDEX8;
|
||||
}
|
||||
else {
|
||||
format = mode->format;
|
||||
}
|
||||
#endif
|
||||
|
||||
const SDL_PixelFormatDetails* details = SDL_GetPixelFormatDetails(format);
|
||||
@ -308,6 +313,7 @@ HRESULT DirectDrawImpl::SetDisplayMode(DWORD dwWidth, DWORD dwHeight, DWORD dwBP
|
||||
{
|
||||
m_virtualWidth = dwWidth;
|
||||
m_virtualHeight = dwHeight;
|
||||
m_virtualBPP = dwBPP;
|
||||
return DD_OK;
|
||||
}
|
||||
|
||||
|
||||
@ -53,13 +53,20 @@ HRESULT DirectDrawSurfaceImpl::Blt(
|
||||
)
|
||||
{
|
||||
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;
|
||||
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 r = (lpDDBltFx->dwFillColor >> 16) & 0xFF;
|
||||
Uint8 g = (lpDDBltFx->dwFillColor >> 8) & 0xFF;
|
||||
Uint8 b = lpDDBltFx->dwFillColor & 0xFF;
|
||||
|
||||
const SDL_PixelFormatDetails* details = SDL_GetPixelFormatDetails(m_surface->format);
|
||||
Uint32 color = SDL_MapRGBA(details, nullptr, r, g, b, a);
|
||||
const SDL_PixelFormatDetails* details = SDL_GetPixelFormatDetails(m_surface->format);
|
||||
color = SDL_MapRGBA(details, nullptr, r, g, b, a);
|
||||
}
|
||||
if (lpDestRect) {
|
||||
SDL_Rect dstRect = ConvertRect(lpDestRect);
|
||||
SDL_FillSurfaceRect(m_surface, &dstRect, color);
|
||||
|
||||
@ -9,7 +9,11 @@
|
||||
FrameBufferImpl::FrameBufferImpl(DWORD virtualWidth, DWORD 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);
|
||||
#endif
|
||||
}
|
||||
|
||||
FrameBufferImpl::~FrameBufferImpl()
|
||||
@ -49,7 +53,7 @@ HRESULT FrameBufferImpl::Blt(
|
||||
return DDERR_GENERIC;
|
||||
}
|
||||
|
||||
if (dynamic_cast<FrameBufferImpl*>(lpDDSrcSurface) == this) {
|
||||
if (dynamic_cast<FrameBufferImpl*>(lpDDSrcSurface)) {
|
||||
return Flip(nullptr, DDFLIP_WAIT);
|
||||
}
|
||||
|
||||
@ -103,7 +107,11 @@ HRESULT FrameBufferImpl::BltFast(
|
||||
int height = lpSrcRect ? (lpSrcRect->bottom - lpSrcRect->top) : surface->m_surface->h;
|
||||
RECT destRect = {(int) dwX, (int) dwY, (int) (dwX + width), (int) (dwY + height)};
|
||||
|
||||
return Blt(&destRect, lpDDSrcSurface, lpSrcRect, DDBLT_NONE, nullptr);
|
||||
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)
|
||||
@ -210,8 +218,11 @@ HRESULT FrameBufferImpl::SetColorKey(DDColorKeyFlags dwFlags, LPDDCOLORKEY lpDDC
|
||||
|
||||
HRESULT FrameBufferImpl::SetPalette(LPDIRECTDRAWPALETTE lpDDPalette)
|
||||
{
|
||||
// If the transfer buffer is not INDEX8 yet, recreate it.
|
||||
// SetPalette being called proves the game wants 8-bit paletted mode.
|
||||
if (m_transferBuffer->m_surface->format != SDL_PIXELFORMAT_INDEX8) {
|
||||
MINIWIN_NOT_IMPLEMENTED();
|
||||
m_transferBuffer->Release();
|
||||
m_transferBuffer = new DirectDrawSurfaceImpl(m_virtualWidth, m_virtualHeight, SDL_PIXELFORMAT_INDEX8);
|
||||
}
|
||||
|
||||
lpDDPalette->AddRef();
|
||||
@ -222,6 +233,11 @@ HRESULT FrameBufferImpl::SetPalette(LPDIRECTDRAWPALETTE lpDDPalette)
|
||||
|
||||
m_palette = lpDDPalette;
|
||||
SDL_SetSurfacePalette(m_transferBuffer->m_surface, ((DirectDrawPaletteImpl*) m_palette)->m_palette);
|
||||
|
||||
if (DDRenderer) {
|
||||
DDRenderer->SetPalette(((DirectDrawPaletteImpl*) m_palette)->m_palette);
|
||||
}
|
||||
|
||||
return DD_OK;
|
||||
}
|
||||
|
||||
|
||||
@ -55,6 +55,7 @@ class Direct3DRMRenderer : public IDirect3DDevice2 {
|
||||
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;
|
||||
virtual void SetPalette(SDL_Palette* palette) {}
|
||||
|
||||
protected:
|
||||
int m_width, m_height;
|
||||
|
||||
115
miniwin/src/internal/d3drmrenderer_palettesw.h
Normal file
115
miniwin/src/internal/d3drmrenderer_palettesw.h
Normal file
@ -0,0 +1,115 @@
|
||||
#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;
|
||||
|
||||
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 Download(SDL_Surface* target) override;
|
||||
void SetDither(bool dither) override;
|
||||
void SetPalette(SDL_Palette* palette) override;
|
||||
|
||||
private:
|
||||
void ClearZBuffer();
|
||||
|
||||
@ -61,9 +61,10 @@ struct DirectDrawImpl : public IDirectDraw2, public IDirect3D2, public IDirect3D
|
||||
float GetAnisotropic() const override { return m_anisotropic; }
|
||||
|
||||
private:
|
||||
FrameBufferImpl* m_frameBuffer;
|
||||
FrameBufferImpl* m_frameBuffer = nullptr;
|
||||
int m_virtualWidth = 0;
|
||||
int m_virtualHeight = 0;
|
||||
int m_virtualBPP = 0;
|
||||
DWORD m_msaaSamples = 0;
|
||||
float m_anisotropic = 0.0f;
|
||||
};
|
||||
|
||||
@ -36,6 +36,8 @@ struct FrameBufferImpl : public IDirectDrawSurface3 {
|
||||
HRESULT SetPalette(LPDIRECTDRAWPALETTE lpDDPalette) override;
|
||||
HRESULT Unlock(LPVOID lpSurfaceData) override;
|
||||
|
||||
bool IsIndex8() const { return m_transferBuffer->m_surface->format == SDL_PIXELFORMAT_INDEX8; }
|
||||
|
||||
private:
|
||||
uint32_t m_virtualWidth;
|
||||
uint32_t m_virtualHeight;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user