mirror of
https://github.com/isledecomp/isle-portable.git
synced 2026-05-02 02:23:56 +00:00
Merge 22cb69aea9 into 57dfd0adde
This commit is contained in:
commit
7a78aed5a5
71
.github/actions/setup-djgpp-toolchain/action.yml
vendored
Normal file
71
.github/actions/setup-djgpp-toolchain/action.yml
vendored
Normal file
@ -0,0 +1,71 @@
|
||||
name: 'Setup DJGPP toolchain'
|
||||
description: 'Download DJGPP and setup CMake toolchain'
|
||||
runs:
|
||||
using: 'composite'
|
||||
steps:
|
||||
- name: 'Calculate variables'
|
||||
id: calc
|
||||
shell: sh
|
||||
run: |
|
||||
version="12.2.0"
|
||||
case "${{ runner.os }}-${{ runner.arch }}" in
|
||||
"Linux-X86")
|
||||
archive="djgpp-linux32-gcc1220.tar.bz2"
|
||||
;;
|
||||
"Linux-X64")
|
||||
archive="djgpp-linux64-gcc1220.tar.bz2"
|
||||
;;
|
||||
"macOS-X86" | "macOS-X64" | "macOS-ARM64")
|
||||
archive="djgpp-osx-gcc1220.tar.bz2"
|
||||
;;
|
||||
"Windows-X86" | "Windows-X64")
|
||||
archive="djgpp-mingw-gcc1220.zip"
|
||||
;;
|
||||
*)
|
||||
echo "Unsupported ${{ runner.os }}-${{ runner.arch }}"
|
||||
exit 1;
|
||||
;;
|
||||
esac
|
||||
echo "url=https://github.com/andrewwutw/build-djgpp/releases/download/v3.4/${archive}" >> ${GITHUB_OUTPUT}
|
||||
echo "archive=${archive}" >> ${GITHUB_OUTPUT}
|
||||
echo "version=${version}" >> ${GITHUB_OUTPUT}
|
||||
echo "cache-key=${archive}-${{ inputs.version }}-${{ runner.os }}-${{ runner.arch }}" >> ${GITHUB_OUTPUT}
|
||||
- name: 'Restore cached ${{ steps.calc.outputs.archive }}'
|
||||
id: cache-restore
|
||||
uses: actions/cache/restore@v5
|
||||
with:
|
||||
path: '${{ runner.temp }}/${{ steps.calc.outputs.archive }}'
|
||||
key: ${{ steps.calc.outputs.cache-key }}
|
||||
- name: 'Download DJGPP ${{ steps.calc.outputs.version }} for ${{ runner.os }} (${{ runner.arch }})'
|
||||
if: ${{ !steps.cache-restore.outputs.cache-hit || steps.cache-restore.outputs.cache-hit == 'false' }}
|
||||
shell: pwsh
|
||||
run: |
|
||||
Invoke-WebRequest "${{ steps.calc.outputs.url }}" -OutFile "${{ runner.temp }}/${{ steps.calc.outputs.archive }}"
|
||||
- name: 'Cache ${{ steps.calc.outputs.archive }}'
|
||||
if: ${{ !steps.cache-restore.outputs.cache-hit || steps.cache-restore.outputs.cache-hit == 'false' }}
|
||||
uses: actions/cache/save@v5
|
||||
with:
|
||||
path: '${{ runner.temp }}/${{ steps.calc.outputs.archive }}'
|
||||
key: ${{ steps.calc.outputs.cache-key }}
|
||||
- name: 'Extract DJGP archive'
|
||||
shell: pwsh
|
||||
run: |
|
||||
$archive = "${{ steps.calc.outputs.archive }}";
|
||||
if ($archive.EndsWith(".bz2")) {
|
||||
# Remove ".bz2" suffix
|
||||
$tar_archive = $archive.Substring(0, $archive.Length - 4)
|
||||
7z "-o${{ runner.temp }}" x "${{ runner.temp }}/${{ steps.calc.outputs.archive }}"
|
||||
7z "-o${{ runner.temp }}" x "${{ runner.temp }}/$tar_archive"
|
||||
} else {
|
||||
7z "-o${{ runner.temp }}" x "${{ runner.temp }}/${{ steps.calc.outputs.archive }}"
|
||||
}
|
||||
- name: 'Install Linux dependenciy'
|
||||
if: ${{ runner.os == 'Linux' }}
|
||||
shell: sh
|
||||
run: |
|
||||
sudo apt-get install -y libfl-dev
|
||||
- name: 'Set output variables'
|
||||
id: final
|
||||
shell: pwsh
|
||||
run: |
|
||||
echo "${{ runner.temp }}/djgpp/bin" >> $env:GITHUB_PATH
|
||||
27
.github/workflows/ci.yml
vendored
27
.github/workflows/ci.yml
vendored
@ -14,7 +14,7 @@ jobs:
|
||||
name: 'clang-format'
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v6
|
||||
- name: Run clang-format
|
||||
run: |
|
||||
find CONFIG LEGO1 ISLE miniwin -iname '*.h' -o -iname '*.cpp' | xargs \
|
||||
@ -48,10 +48,11 @@ jobs:
|
||||
- { name: 'iOS', os: 'macos-15', generator: 'Xcode', dx5: false, config: false, brew: true, werror: true, clang-tidy: false, cmake-args: '-DCMAKE_SYSTEM_NAME=iOS', ios: true }
|
||||
- { name: 'Emscripten', os: 'ubuntu-latest', generator: 'Ninja', dx5: false, config: false, emsdk: true, werror: true, clang-tidy: false, cmake-wrapper: 'emcmake' }
|
||||
- { name: 'Nintendo 3DS', os: 'ubuntu-latest', generator: 'Ninja', dx5: false, config: false, n3ds: true, werror: true, clang-tidy: false, container: 'devkitpro/devkitarm:latest', cmake-args: '-DCMAKE_TOOLCHAIN_FILE=/opt/devkitpro/cmake/3DS.cmake' }
|
||||
- { name: 'Nintendo Switch', os: 'ubuntu-latest', generator: 'Ninja', dx5: false, config: false, nx: true, werror: true, clang-tidy: false, container: 'devkitpro/devkita64:latest', cmake-args: '-DCMAKE_TOOLCHAIN_FILE=/opt/devkitpro/cmake/Switch.cmake' }
|
||||
- { name: 'Nintendo Switch', os: 'ubuntu-latest', generator: 'Ninja', dx5: false, config: false, nx: true, werror: true, clang-tidy: false, container: 'devkitpro/devkita64:latest', cmake-args: '-DCMAKE_TOOLCHAIN_FILE=/opt/devkitpro/cmake/Switch.cmake' }
|
||||
- { name: 'Xbox One', os: 'windows-latest', generator: 'Visual Studio 17 2022', dx5: false, config: false, msvc: true, werror: false, clang-tidy: false, vc-arch: 'amd64', cmake-args: '-DCMAKE_SYSTEM_NAME=WindowsStore -DCMAKE_SYSTEM_VERSION=10.0.26100.0', xbox-one: true}
|
||||
- { name: 'Android', os: 'ubuntu-latest', generator: 'Ninja', dx5: false, config: false, android: true, werror: true, clang-tidy: false,}
|
||||
- { name: 'Vita', os: 'ubuntu-latest', generator: 'Ninja', dx5: false, config: false, vita: true, werror: true, clang-tidy: false, cmake-args: '--toolchain /usr/local/vitasdk/share/vita.toolchain.cmake'}
|
||||
- { name: 'DOS', os: 'ubuntu-latest', generator: 'Ninja', dx5: false, config: false, dos: true, werror: true, clang-tidy: false, cmake-args: '--toolchain $GITHUB_WORKSPACE/CMake/i586-pc-msdosdjgpp.cmake'}
|
||||
steps:
|
||||
- name: Setup vcvars
|
||||
if: ${{ !!matrix.msvc }}
|
||||
@ -134,7 +135,7 @@ jobs:
|
||||
echo "$VITASDK/bin" >> $GITHUB_PATH
|
||||
./install-all.sh
|
||||
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v6
|
||||
|
||||
- name: Checkout LFS
|
||||
if: ${{ matrix.build-assets }}
|
||||
@ -143,11 +144,15 @@ jobs:
|
||||
|
||||
- name: Setup Java (Android)
|
||||
if: ${{ matrix.android }}
|
||||
uses: actions/setup-java@v4
|
||||
uses: actions/setup-java@v5
|
||||
with:
|
||||
distribution: 'temurin'
|
||||
java-version: '17'
|
||||
|
||||
- name: 'Set up DJGPP toolchain'
|
||||
uses: ./.github/actions/setup-djgpp-toolchain
|
||||
if: ${{ matrix.dos }}
|
||||
|
||||
- name: Get CMake (Android)
|
||||
if: ${{ matrix.android }}
|
||||
uses: lukka/get-cmake@latest
|
||||
@ -271,7 +276,7 @@ jobs:
|
||||
run: (cd build/assets && zip -r ../dist/isle-assets.zip .)
|
||||
|
||||
- name: Upload Build Artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: '${{ matrix.name }}'
|
||||
path: |
|
||||
@ -287,7 +292,7 @@ jobs:
|
||||
name: 'FreeBSD'
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v6
|
||||
|
||||
- name: Build on FreeBSD
|
||||
uses: vmactions/freebsd-vm@v1
|
||||
@ -307,7 +312,7 @@ jobs:
|
||||
cd build && cpack .
|
||||
|
||||
- name: Upload Build Artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: 'FreeBSD'
|
||||
path: build/dist/isle-*
|
||||
@ -331,7 +336,7 @@ jobs:
|
||||
options: --privileged
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v6
|
||||
|
||||
- name: Build Flatpak
|
||||
uses: flatpak/flatpak-github-actions/flatpak-builder@v6
|
||||
@ -345,7 +350,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v6
|
||||
|
||||
- name: Install LLVM and Clang
|
||||
uses: KyleMayes/install-llvm-action@v1
|
||||
@ -389,14 +394,14 @@ jobs:
|
||||
- freebsd
|
||||
steps:
|
||||
- name: Download All Artifacts
|
||||
uses: actions/download-artifact@main
|
||||
uses: actions/download-artifact@v8
|
||||
with:
|
||||
pattern: "*"
|
||||
path: Release
|
||||
merge-multiple: true
|
||||
|
||||
- name: Checkout uploadtool
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
repository: 'probonopd/uploadtool'
|
||||
path: 'uploadtool'
|
||||
|
||||
4
.github/workflows/docker.yml
vendored
4
.github/workflows/docker.yml
vendored
@ -22,7 +22,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Log in to the Container registry
|
||||
uses: docker/login-action@65b78e6e13532edd9afa3aa52ac7964289d1a9c1
|
||||
@ -48,7 +48,7 @@ jobs:
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
|
||||
- name: Generate artifact attestation
|
||||
uses: actions/attest-build-provenance@v2
|
||||
uses: actions/attest-build-provenance@v4
|
||||
with:
|
||||
subject-name: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME}}
|
||||
subject-digest: ${{ steps.push.outputs.digest }}
|
||||
|
||||
10
3rdparty/CMakeLists.txt
vendored
10
3rdparty/CMakeLists.txt
vendored
@ -5,8 +5,8 @@ if(DOWNLOAD_DEPENDENCIES)
|
||||
include(FetchContent)
|
||||
FetchContent_Declare(
|
||||
miniaudio
|
||||
URL https://github.com/mackron/miniaudio/archive/refs/tags/0.11.24.tar.gz
|
||||
URL_MD5 19e8eb21223c56a4a2d167d04decddc9
|
||||
URL https://github.com/mackron/miniaudio/archive/refs/tags/0.11.25.tar.gz
|
||||
URL_HASH MD5=6fae6da8f30afb3ddcba26fcaa64f540
|
||||
)
|
||||
block()
|
||||
set(BUILD_SHARED_LIBS OFF)
|
||||
@ -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;
|
||||
}
|
||||
2
3rdparty/miniaudio
vendored
2
3rdparty/miniaudio
vendored
@ -1 +1 @@
|
||||
Subproject commit 13d161bc8d856ad61ae46b798bbeffc0f49808e8
|
||||
Subproject commit 9634bedb5b5a2ca38c1ee7108a9358a4e233f14d
|
||||
17
CMake/djgpp-platform-overrides.cmake
Normal file
17
CMake/djgpp-platform-overrides.cmake
Normal file
@ -0,0 +1,17 @@
|
||||
# DJGPP platform overrides for DOS
|
||||
#
|
||||
# CMake's built-in Platform/DOS.cmake assumes OpenWatcom naming conventions
|
||||
# (no prefix, .lib suffix, CMAKE_LINK_LIBRARY_SUFFIX=".lib"). DJGPP uses
|
||||
# standard Unix/GCC conventions for its system libraries (lib prefix, .a
|
||||
# suffix — e.g. libm.a).
|
||||
#
|
||||
# This file is loaded via CMAKE_USER_MAKE_RULES_OVERRIDE in the toolchain
|
||||
# file, which runs *after* the platform module has set its defaults, giving
|
||||
# us the final say on these variables.
|
||||
|
||||
set(CMAKE_STATIC_LIBRARY_PREFIX "lib")
|
||||
set(CMAKE_STATIC_LIBRARY_SUFFIX ".a")
|
||||
set(CMAKE_LINK_LIBRARY_SUFFIX "")
|
||||
set(CMAKE_FIND_LIBRARY_PREFIXES "lib" "")
|
||||
set(CMAKE_FIND_LIBRARY_SUFFIXES ".a" ".lib")
|
||||
set(CMAKE_EXECUTABLE_SUFFIX ".exe")
|
||||
82
CMake/i586-pc-msdosdjgpp.cmake
Normal file
82
CMake/i586-pc-msdosdjgpp.cmake
Normal file
@ -0,0 +1,82 @@
|
||||
set(CMAKE_SYSTEM_NAME DOS)
|
||||
|
||||
set(DJGPP TRUE)
|
||||
|
||||
# CMake's Platform/DOS.cmake assumes OpenWatcom naming conventions (no prefix,
|
||||
# .lib suffix). DJGPP uses standard Unix/GCC conventions for its system
|
||||
# libraries (lib prefix, .a suffix — e.g. libm.a), so we override the platform
|
||||
# defaults via CMAKE_USER_MAKE_RULES_OVERRIDE, which runs *after* the platform
|
||||
# module has set its defaults, giving us the final say on these variables.
|
||||
# The path must be cached because CMake re-parses the toolchain file during
|
||||
# try_compile, where CMAKE_CURRENT_LIST_DIR may point elsewhere.
|
||||
set(DJGPP_PLATFORM_OVERRIDES "${CMAKE_CURRENT_LIST_DIR}/djgpp-platform-overrides.cmake" CACHE FILEPATH "" FORCE)
|
||||
set(CMAKE_USER_MAKE_RULES_OVERRIDE "${DJGPP_PLATFORM_OVERRIDES}")
|
||||
|
||||
set(CMAKE_STATIC_LIBRARY_PREFIX "lib")
|
||||
set(CMAKE_STATIC_LIBRARY_SUFFIX ".a")
|
||||
set(CMAKE_SHARED_LIBRARY_PREFIX "")
|
||||
set(CMAKE_SHARED_LIBRARY_SUFFIX ".dll")
|
||||
set(CMAKE_IMPORT_LIBRARY_PREFIX "lib")
|
||||
set(CMAKE_IMPORT_LIBRARY_SUFFIX ".a")
|
||||
set(CMAKE_EXECUTABLE_SUFFIX ".exe")
|
||||
set(CMAKE_LINK_LIBRARY_SUFFIX "")
|
||||
set(CMAKE_DL_LIBS "")
|
||||
|
||||
set(CMAKE_FIND_LIBRARY_PREFIXES "lib")
|
||||
set(CMAKE_FIND_LIBRARY_SUFFIXES ".a")
|
||||
|
||||
#
|
||||
# CMake toolchain file for DJGPP. Usage:
|
||||
#
|
||||
# 1. Download and extract DGJPP
|
||||
# 2. Add directory containing i586-pc-msdosdjgpp-gcc to PATH environment variable
|
||||
# 3. When configuring your CMake project, specify the toolchain file like this:
|
||||
#
|
||||
# cmake -DCMAKE_TOOLCHAIN_FILE=path/to/i586-pc-msdosdjgpp.cmake ...
|
||||
#
|
||||
|
||||
# specify the cross compiler
|
||||
find_program(CMAKE_C_COMPILER NAMES "i586-pc-msdosdjgpp-gcc" "i386-pc-msdosdjgpp-gcc" REQUIRED)
|
||||
find_program(CMAKE_CXX_COMPILER NAMES "i586-pc-msdosdjgpp-g++" "i386-pc-msdosdjgpp-g++" REQUIRED)
|
||||
|
||||
execute_process(COMMAND "${CMAKE_C_COMPILER}" -print-search-dirs
|
||||
RESULT_VARIABLE CC_SEARCH_DIRS_RESULT
|
||||
OUTPUT_VARIABLE CC_SEARCH_DIRS_OUTPUT)
|
||||
|
||||
if(CC_SEARCH_DIRS_RESULT)
|
||||
message(FATAL_ERROR "Could not determine search dirs")
|
||||
endif()
|
||||
|
||||
string(REGEX MATCH ".*libraries: (.*).*" CC_SD_LIBS "${CC_SEARCH_DIRS_OUTPUT}")
|
||||
string(STRIP "${CMAKE_MATCH_1}" CC_SEARCH_DIRS)
|
||||
string(REPLACE ":" ";" CC_SEARCH_DIRS "${CC_SEARCH_DIRS}")
|
||||
|
||||
foreach(CC_SEARCH_DIR ${CC_SEARCH_DIRS})
|
||||
if(CC_SEARCH_DIR MATCHES "=.*")
|
||||
string(REGEX MATCH "=(.*)" CC_LIB "${CC_SEARCH_DIR}")
|
||||
set(CC_SEARCH_DIR "${CMAKE_MATCH_1}")
|
||||
endif()
|
||||
if(IS_DIRECTORY "${CC_SEARCH_DIR}")
|
||||
if(IS_DIRECTORY "${CC_SEARCH_DIR}/../include" OR IS_DIRECTORY "${CC_SEARCH_DIR}/../lib" OR IS_DIRECTORY "${CC_SEARCH_DIR}/../bin")
|
||||
list(APPEND CC_ROOTS "${CC_SEARCH_DIR}/..")
|
||||
else()
|
||||
list(APPEND CC_ROOTS "${CC_SEARCH_DIR}")
|
||||
endif()
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
list(APPEND CMAKE_FIND_ROOT_PATH ${CC_ROOTS})
|
||||
|
||||
# search for programs in the host directories
|
||||
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
|
||||
|
||||
# for libraries, headers and packages in the target directories
|
||||
if(NOT DEFINED CACHE{CMAKE_FIND_ROOT_PATH_MODE_LIBRARY})
|
||||
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
|
||||
endif()
|
||||
if(NOT DEFINED CACHE{CMAKE_FIND_ROOT_PATH_MODE_INCLUDE})
|
||||
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
|
||||
endif()
|
||||
if(NOT DEFINED CACHE{CMAKE_FIND_ROOT_PATH_MODE_PACKAGE})
|
||||
set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)
|
||||
endif()
|
||||
@ -86,15 +86,24 @@ option(ISLE_WERROR "Treat warnings as errors" OFF)
|
||||
cmake_dependent_option(ISLE_USE_DX5 "Build with internal DirectX 5 SDK" "${NOT_MINGW}" "WIN32;CMAKE_SIZEOF_VOID_P EQUAL 4" OFF)
|
||||
cmake_dependent_option(ISLE_MINIWIN "Use miniwin" ON "NOT ISLE_USE_DX5" OFF)
|
||||
cmake_dependent_option(ISLE_EXTENSIONS "Use extensions" ON "NOT ISLE_USE_DX5;NOT WINDOWS_STORE" OFF)
|
||||
cmake_dependent_option(ISLE_USE_LWS "Use libwebsockets for native multiplayer" ON "ISLE_EXTENSIONS;NOT EMSCRIPTEN;NOT NINTENDO_3DS;NOT NINTENDO_SWITCH;NOT VITA" OFF)
|
||||
cmake_dependent_option(ISLE_BUILD_CONFIG "Build CONFIG.EXE application" ON "MSVC OR ISLE_MINIWIN;NOT NINTENDO_3DS;NOT NINTENDO_SWITCH;NOT WINDOWS_STORE;NOT VITA" OFF)
|
||||
cmake_dependent_option(ISLE_USE_LWS "Use libwebsockets for native multiplayer" ON "ISLE_EXTENSIONS;NOT DOS;NOT EMSCRIPTEN;NOT NINTENDO_3DS;NOT NINTENDO_SWITCH;NOT VITA" OFF)
|
||||
cmake_dependent_option(ISLE_BUILD_CONFIG "Build CONFIG.EXE application" ON "MSVC OR ISLE_MINIWIN;NOT DOS;NOT NINTENDO_3DS;NOT NINTENDO_SWITCH;NOT WINDOWS_STORE;NOT VITA" OFF)
|
||||
cmake_dependent_option(ISLE_COMPILE_SHADERS "Compile shaders" ON "SDL_SHADERCROSS_BIN;TARGET Python3::Interpreter" OFF)
|
||||
cmake_dependent_option(CMAKE_POSITION_INDEPENDENT_CODE "Build with -fPIC" ON "NOT VITA" OFF)
|
||||
cmake_dependent_option(CMAKE_POSITION_INDEPENDENT_CODE "Build with -fPIC" ON "NOT DOS;NOT VITA" OFF)
|
||||
option(ENABLE_CLANG_TIDY "Enable clang-tidy")
|
||||
option(DOWNLOAD_DEPENDENCIES "Download dependencies" ON)
|
||||
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}" CACHE PATH "Directory where to put executables and dll")
|
||||
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 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 "Config app: ${ISLE_BUILD_CONFIG}")
|
||||
|
||||
@ -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);
|
||||
@ -1251,7 +1300,7 @@ bool IsleApp::LoadConfig()
|
||||
m_videoParam.GetRect() = MxRect32(0, 0, (m_xRes - 1), (m_yRes - 1));
|
||||
}
|
||||
m_frameRate = (1000.0f / iniparser_getdouble(dict, "isle:Frame Delta", m_frameDelta));
|
||||
m_frameDelta = static_cast<int>(std::round(iniparser_getdouble(dict, "isle:Frame Delta", m_frameDelta)));
|
||||
m_frameDelta = static_cast<int>(iniparser_getdouble(dict, "isle:Frame Delta", m_frameDelta));
|
||||
m_videoParam.SetMSAASamples((m_msaaSamples = iniparser_getint(dict, "isle:MSAA", m_msaaSamples)));
|
||||
m_videoParam.SetAnisotropic((m_anisotropic = iniparser_getdouble(dict, "isle:Anisotropic", m_anisotropic)));
|
||||
m_activeInBackground = iniparser_getboolean(dict, "isle:Active in Background", m_activeInBackground);
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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) {
|
||||
|
||||
@ -69,6 +69,12 @@ if(NOT (VITA OR WINDOWS_STORE))
|
||||
endif()
|
||||
endif()
|
||||
|
||||
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.
|
||||
@ -139,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
@ -64,14 +64,14 @@ void Direct3DRMSoftwareRenderer::ClearZBuffer()
|
||||
const float inf = std::numeric_limits<float>::infinity();
|
||||
size_t i = 0;
|
||||
|
||||
#if defined(__x86_64__) || defined(_M_X64) || defined(__i386__) || defined(_M_IX86)
|
||||
#if (defined(__x86_64__) || defined(_M_X64) || defined(__i386__) || defined(_M_IX86)) && defined(__SSE2__)
|
||||
if (SDL_HasSSE2()) {
|
||||
__m128 inf4 = _mm_set1_ps(inf);
|
||||
for (; i + 4 <= size; i += 4) {
|
||||
_mm_storeu_ps(&m_zBuffer[i], inf4);
|
||||
}
|
||||
}
|
||||
#if defined(__i386__) || defined(_M_IX86)
|
||||
#if (defined(__i386__) || defined(_M_IX86)) && defined(__MMX__)
|
||||
else if (SDL_HasMMX()) {
|
||||
const __m64 mm_inf = _mm_set_pi32(0x7F800000, 0x7F800000);
|
||||
for (; i + 2 <= size; i += 2) {
|
||||
@ -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